mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 11:56:30 +00:00
Plugins - Adjusted namespaces
This commit is contained in:
1 parent
c71faba2c9
commit
f68d2629b7
144 files changed
+267
-252
No files matched your search
+19
@@ -0,0 +1,19 @@
|
||||
namespace Artemis.Core.Plugins.Modules.ActivationRequirements
|
||||
{
|
||||
/// <summary>
|
||||
/// Evaluates to true or false by returning the value of ActivationMet
|
||||
/// </summary>
|
||||
public class BooleanActivationRequirement : IModuleActivationRequirement
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets whether the activation requirement is met
|
||||
/// </summary>
|
||||
public bool ActivationMet { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Evaluate()
|
||||
{
|
||||
return ActivationMet;
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
namespace Artemis.Core.Plugins.Modules.ActivationRequirements
|
||||
{
|
||||
/// <summary>
|
||||
/// Evaluates to true or false by checking requirements specific to the implementation
|
||||
/// </summary>
|
||||
public interface IModuleActivationRequirement
|
||||
{
|
||||
/// <summary>
|
||||
/// Called to determine whether the activation requirement is met
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool Evaluate();
|
||||
}
|
||||
}
|
||||
+20
-10
@@ -3,34 +3,44 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Extensions;
|
||||
|
||||
namespace Artemis.Core.Plugins.Modules
|
||||
namespace Artemis.Core.Plugins.Modules.ActivationRequirements
|
||||
{
|
||||
/// <summary>
|
||||
/// Evaluates to true or false by checking if the specified process is running
|
||||
/// </summary>
|
||||
public class ProcessActivationRequirement : IModuleActivationRequirement
|
||||
{
|
||||
public string ProcessName { get; set; }
|
||||
public string Location { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="ProcessActivationRequirement" /> class
|
||||
/// </summary>
|
||||
/// <param name="processName">The name of the process that must run</param>
|
||||
/// <param name="location">The location of where the process must be running from (optional)</param>
|
||||
public ProcessActivationRequirement(string processName, string location = null)
|
||||
{
|
||||
ProcessName = processName;
|
||||
Location = location;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The name of the process that must run
|
||||
/// </summary>
|
||||
public string ProcessName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The location of where the process must be running from
|
||||
/// </summary>
|
||||
public string Location { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
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
|
||||
return Location != null
|
||||
? processes.Any(p => Path.GetDirectoryName(p.GetProcessFilename()) == Location)
|
||||
: processes.Any();
|
||||
}
|
||||
}
|
||||
|
||||
public interface IModuleActivationRequirement
|
||||
{
|
||||
bool Evaluate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Models.Surface;
|
||||
using Artemis.Core.Plugins.DataModelExpansions;
|
||||
using Artemis.Core.Plugins.DataModelExpansions.Attributes;
|
||||
using Artemis.Core.Plugins.Modules.ActivationRequirements;
|
||||
using Artemis.Storage.Entities.Module;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core.Plugins.Modules
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows you to add support for new games/applications while utilizing your own data model
|
||||
/// </summary>
|
||||
public abstract class Module<T> : Module where T : DataModel
|
||||
{
|
||||
/// <summary>
|
||||
/// The data model driving this module
|
||||
/// </summary>
|
||||
public T DataModel
|
||||
{
|
||||
get => (T) InternalDataModel;
|
||||
internal set => InternalDataModel = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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{T}" /> plugin instead.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public bool ExpandsDataModel
|
||||
{
|
||||
get => InternalExpandsMainDataModel;
|
||||
set => InternalExpandsMainDataModel = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override to provide your own data model description. By default this returns a description matching your plugin
|
||||
/// name and description
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual DataModelPropertyAttribute GetDataModelDescription()
|
||||
{
|
||||
return new DataModelPropertyAttribute {Name = PluginInfo.Name, Description = PluginInfo.Description};
|
||||
}
|
||||
|
||||
internal override void InternalEnablePlugin()
|
||||
{
|
||||
DataModel = Activator.CreateInstance<T>();
|
||||
DataModel.PluginInfo = PluginInfo;
|
||||
DataModel.DataModelDescription = GetDataModelDescription();
|
||||
base.InternalEnablePlugin();
|
||||
}
|
||||
|
||||
internal override void InternalDisablePlugin()
|
||||
{
|
||||
DataModel = null;
|
||||
base.InternalDisablePlugin();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Allows you to add support for new games/applications
|
||||
/// </summary>
|
||||
public abstract class Module : Plugin
|
||||
{
|
||||
/// <summary>
|
||||
/// The modules display name that's shown in the menu
|
||||
/// </summary>
|
||||
public string DisplayName { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// The modules display icon that's shown in the menu see <see href="https://materialdesignicons.com" /> for available
|
||||
/// icons
|
||||
/// </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; } = new List<IModuleActivationRequirement>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the activation requirement mode, defaults to <see cref="ActivationRequirementType.Any" />
|
||||
/// </summary>
|
||||
public ActivationRequirementType ActivationRequirementMode { get; set; } = ActivationRequirementType.Any;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default priority category for this module, defaults to
|
||||
/// <see cref="ModulePriorityCategory.Normal" />
|
||||
/// </summary>
|
||||
public ModulePriorityCategory DefaultPriorityCategory { get; set; } = ModulePriorityCategory.Normal;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current priority category of this module
|
||||
/// </summary>
|
||||
public ModulePriorityCategory PriorityCategory { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current priority of this module within its priority category
|
||||
/// </summary>
|
||||
public int Priority { get; internal set; }
|
||||
|
||||
internal DataModel InternalDataModel { get; set; }
|
||||
|
||||
internal bool InternalExpandsMainDataModel { get; set; }
|
||||
internal ModuleSettingsEntity Entity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of custom module tabs that show in the UI
|
||||
/// </summary>
|
||||
public IEnumerable<ModuleTab> ModuleTabs { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Called each frame when the module must update
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">Time in seconds since the last update</param>
|
||||
public abstract void Update(double deltaTime);
|
||||
|
||||
/// <summary>
|
||||
/// Called each frame when the module must render
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">Time since the last render</param>
|
||||
/// <param name="surface">The RGB Surface to render to</param>
|
||||
/// <param name="canvas"></param>
|
||||
/// <param name="canvasInfo"></param>
|
||||
public abstract void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas, SKImageInfo canvasInfo);
|
||||
|
||||
/// <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();
|
||||
}
|
||||
|
||||
internal void ApplyToEntity()
|
||||
{
|
||||
if (Entity == null)
|
||||
Entity = new ModuleSettingsEntity();
|
||||
|
||||
Entity.PluginGuid = PluginInfo.Guid;
|
||||
Entity.PriorityCategory = (int) PriorityCategory;
|
||||
Entity.Priority = Priority;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes in what way the activation requirements of a module must be met
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes the priority category of a module
|
||||
/// </summary>
|
||||
public enum ModulePriorityCategory
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates a normal render priority
|
||||
/// </summary>
|
||||
Normal,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the module renders for a specific application/game, rendering on top of normal modules
|
||||
/// </summary>
|
||||
Application,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the module renders an overlay, always rendering on top
|
||||
/// </summary>
|
||||
Overlay
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using Artemis.Core.Plugins.Abstract;
|
||||
using Artemis.Core.Plugins.Abstract.ViewModels;
|
||||
|
||||
namespace Artemis.Core.Plugins.Modules
|
||||
{
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.Core.Plugins.Modules
|
||||
{
|
||||
/// <summary>
|
||||
/// The base class for any view model that belongs to a module
|
||||
/// </summary>
|
||||
public abstract class ModuleViewModel : Screen
|
||||
{
|
||||
/// <summary>
|
||||
/// The base class for any view model that belongs to a module
|
||||
/// </summary>
|
||||
/// <param name="module">The module this view model belongs to</param>
|
||||
/// <param name="displayName">The name of the tab that's shown on the modules UI page</param>
|
||||
protected ModuleViewModel(Module module, string displayName)
|
||||
{
|
||||
Module = module;
|
||||
DisplayName = displayName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the module this view model belongs to
|
||||
/// </summary>
|
||||
public Module Module { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core.Exceptions;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Models.Surface;
|
||||
using Artemis.Core.Plugins.DataModelExpansions;
|
||||
using Artemis.Core.Plugins.DataModelExpansions.Attributes;
|
||||
using Artemis.Core.Utilities;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core.Plugins.Modules
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows you to add support for new games/applications while utilizing Artemis' profile engine and your own data
|
||||
/// model
|
||||
/// </summary>
|
||||
public abstract class ProfileModule<T> : ProfileModule where T : DataModel
|
||||
{
|
||||
/// <summary>
|
||||
/// The data model driving this module
|
||||
/// </summary>
|
||||
public T DataModel
|
||||
{
|
||||
get => (T) InternalDataModel;
|
||||
internal set => InternalDataModel = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public bool ExpandsDataModel
|
||||
{
|
||||
get => InternalExpandsMainDataModel;
|
||||
set => InternalExpandsMainDataModel = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override to provide your own data model description. By default this returns a description matching your plugin
|
||||
/// name and description
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual DataModelPropertyAttribute GetDataModelDescription()
|
||||
{
|
||||
return new DataModelPropertyAttribute {Name = PluginInfo.Name, Description = PluginInfo.Description};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hide the provided property using a lambda expression, e.g. HideProperty(dm => dm.TimeDataModel.CurrentTimeUTC)
|
||||
/// </summary>
|
||||
/// <param name="propertyLambda">A lambda expression pointing to the property to ignore</param>
|
||||
public void HideProperty<TProperty>(Expression<Func<T, TProperty>> propertyLambda)
|
||||
{
|
||||
var propertyInfo = ReflectionUtilities.GetPropertyInfo(DataModel, propertyLambda);
|
||||
if (!HiddenPropertiesList.Any(p => p.Equals(propertyInfo)))
|
||||
HiddenPropertiesList.Add(propertyInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop hiding the provided property using a lambda expression, e.g. ShowProperty(dm =>
|
||||
/// dm.TimeDataModel.CurrentTimeUTC)
|
||||
/// </summary>
|
||||
/// <param name="propertyLambda">A lambda expression pointing to the property to stop ignoring</param>
|
||||
public void ShowProperty<TProperty>(Expression<Func<T, TProperty>> propertyLambda)
|
||||
{
|
||||
var propertyInfo = ReflectionUtilities.GetPropertyInfo(DataModel, propertyLambda);
|
||||
HiddenPropertiesList.RemoveAll(p => p.Equals(propertyInfo));
|
||||
}
|
||||
|
||||
internal override void InternalEnablePlugin()
|
||||
{
|
||||
DataModel = Activator.CreateInstance<T>();
|
||||
DataModel.PluginInfo = PluginInfo;
|
||||
DataModel.DataModelDescription = GetDataModelDescription();
|
||||
base.InternalEnablePlugin();
|
||||
}
|
||||
|
||||
internal override void InternalDisablePlugin()
|
||||
{
|
||||
DataModel = null;
|
||||
base.InternalDisablePlugin();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows you to add support for new games/applications while utilizing Artemis' profile engine
|
||||
/// </summary>
|
||||
public abstract class ProfileModule : Module
|
||||
{
|
||||
protected ProfileModule()
|
||||
{
|
||||
OpacityOverride = 1;
|
||||
}
|
||||
|
||||
protected readonly List<PropertyInfo> HiddenPropertiesList = new List<PropertyInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all properties ignored at runtime using IgnoreProperty(x => x.y)
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<PropertyInfo> HiddenProperties => HiddenPropertiesList.AsReadOnly();
|
||||
|
||||
public Profile ActiveProfile { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Disables updating the profile, rendering does continue
|
||||
/// </summary>
|
||||
public bool IsProfileUpdatingDisabled { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(double deltaTime)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
OpacityOverride = AnimatingProfileChange
|
||||
? Math.Max(0, OpacityOverride - 0.1)
|
||||
: Math.Min(1, OpacityOverride + 0.1);
|
||||
|
||||
// Update the profile
|
||||
if (!IsProfileUpdatingDisabled)
|
||||
ActiveProfile?.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas, SKImageInfo canvasInfo)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
// Render the profile
|
||||
ActiveProfile?.Render(deltaTime, canvas, canvasInfo);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task ChangeActiveProfileAnimated(Profile profile, ArtemisSurface surface)
|
||||
{
|
||||
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;
|
||||
|
||||
AnimatingProfileChange = true;
|
||||
|
||||
while (OpacityOverride > 0)
|
||||
await Task.Delay(50);
|
||||
|
||||
ChangeActiveProfile(profile, surface);
|
||||
AnimatingProfileChange = false;
|
||||
|
||||
while (OpacityOverride < 1)
|
||||
await Task.Delay(50);
|
||||
}
|
||||
|
||||
internal void ChangeActiveProfile(Profile profile, ArtemisSurface surface)
|
||||
{
|
||||
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)
|
||||
return;
|
||||
|
||||
ActiveProfile?.Dispose();
|
||||
|
||||
ActiveProfile = profile;
|
||||
ActiveProfile?.Activate(surface);
|
||||
}
|
||||
|
||||
OnActiveProfileChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the opacity of the root folder
|
||||
/// </summary>
|
||||
public double OpacityOverride { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether or not a profile change is being animated
|
||||
/// </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;
|
||||
|
||||
protected virtual void OnActiveProfileChanged()
|
||||
{
|
||||
ActiveProfileChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user