mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 03:48:56 +00:00
Code style - Use file scoped namespaces
Code style - Ran code cleanup
This commit is contained in:
1 parent
e68e16df4d
commit
f6090dc296
691 files changed
+37301
-38119
No files matched your search
+17
-18
@@ -1,25 +1,24 @@
|
||||
namespace Artemis.Core.Modules
|
||||
namespace Artemis.Core.Modules;
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates to true or false by returning the value of ActivationMet
|
||||
/// </summary>
|
||||
public class BooleanActivationRequirement : IModuleActivationRequirement
|
||||
{
|
||||
/// <summary>
|
||||
/// Evaluates to true or false by returning the value of ActivationMet
|
||||
/// Gets or sets whether the activation requirement is met
|
||||
/// </summary>
|
||||
public class BooleanActivationRequirement : IModuleActivationRequirement
|
||||
public bool ActivationMet { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Evaluate()
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets whether the activation requirement is met
|
||||
/// </summary>
|
||||
public bool ActivationMet { get; set; }
|
||||
return ActivationMet;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Evaluate()
|
||||
{
|
||||
return ActivationMet;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string GetUserFriendlyDescription()
|
||||
{
|
||||
return "No description available";
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public string GetUserFriendlyDescription()
|
||||
{
|
||||
return "No description available";
|
||||
}
|
||||
}
|
||||
+14
-15
@@ -1,20 +1,19 @@
|
||||
namespace Artemis.Core.Modules
|
||||
namespace Artemis.Core.Modules;
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates to true or false by checking requirements specific to the implementation
|
||||
/// </summary>
|
||||
public interface IModuleActivationRequirement
|
||||
{
|
||||
/// <summary>
|
||||
/// Evaluates to true or false by checking requirements specific to the implementation
|
||||
/// Called to determine whether the activation requirement is met
|
||||
/// </summary>
|
||||
public interface IModuleActivationRequirement
|
||||
{
|
||||
/// <summary>
|
||||
/// Called to determine whether the activation requirement is met
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool Evaluate();
|
||||
/// <returns></returns>
|
||||
bool Evaluate();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a user-friendly description of the activation requirement, should include parameters if applicable
|
||||
/// </summary>
|
||||
/// <returns>A user-friendly description of the activation requirement</returns>
|
||||
string GetUserFriendlyDescription();
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a user-friendly description of the activation requirement, should include parameters if applicable
|
||||
/// </summary>
|
||||
/// <returns>A user-friendly description of the activation requirement</returns>
|
||||
string GetUserFriendlyDescription();
|
||||
}
|
||||
+43
-44
@@ -5,62 +5,61 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Services;
|
||||
|
||||
namespace Artemis.Core.Modules
|
||||
namespace Artemis.Core.Modules;
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates to true or false by checking if the specified process is running
|
||||
/// </summary>
|
||||
public class ProcessActivationRequirement : IModuleActivationRequirement
|
||||
{
|
||||
/// <summary>
|
||||
/// Evaluates to true or false by checking if the specified process is running
|
||||
/// Creates a new instance of the <see cref="ProcessActivationRequirement" /> class
|
||||
/// </summary>
|
||||
public class ProcessActivationRequirement : IModuleActivationRequirement
|
||||
/// <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)
|
||||
{
|
||||
/// <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)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(processName) && string.IsNullOrWhiteSpace(location))
|
||||
throw new ArgumentNullException($"Atleast one {nameof(processName)} and {nameof(location)} must not be null");
|
||||
if (string.IsNullOrWhiteSpace(processName) && string.IsNullOrWhiteSpace(location))
|
||||
throw new ArgumentNullException($"Atleast one {nameof(processName)} and {nameof(location)} must not be null");
|
||||
|
||||
ProcessName = processName;
|
||||
Location = location;
|
||||
}
|
||||
ProcessName = processName;
|
||||
Location = location;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The name of the process that must run
|
||||
/// </summary>
|
||||
public string? ProcessName { get; set; }
|
||||
/// <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; }
|
||||
/// <summary>
|
||||
/// The location of where the process must be running from
|
||||
/// </summary>
|
||||
public string? Location { get; set; }
|
||||
|
||||
internal static IProcessMonitorService? ProcessMonitorService { get; set; }
|
||||
internal static IProcessMonitorService? ProcessMonitorService { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Evaluate()
|
||||
{
|
||||
if (ProcessMonitorService == null || ProcessName == null && Location == null)
|
||||
return false;
|
||||
/// <inheritdoc />
|
||||
public bool Evaluate()
|
||||
{
|
||||
if (ProcessMonitorService == null || (ProcessName == null && Location == null))
|
||||
return false;
|
||||
|
||||
IEnumerable<Process> processes = ProcessMonitorService.GetRunningProcesses();
|
||||
if (ProcessName != null)
|
||||
processes = processes.Where(p => string.Equals(p.ProcessName, ProcessName, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (Location != null)
|
||||
processes = processes.Where(p => string.Equals(Path.GetDirectoryName(p.GetProcessFilename()), Location, StringComparison.InvariantCultureIgnoreCase));
|
||||
IEnumerable<Process> processes = ProcessMonitorService.GetRunningProcesses();
|
||||
if (ProcessName != null)
|
||||
processes = processes.Where(p => string.Equals(p.ProcessName, ProcessName, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (Location != null)
|
||||
processes = processes.Where(p => string.Equals(Path.GetDirectoryName(p.GetProcessFilename()), Location, StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
return processes.Any();
|
||||
}
|
||||
return processes.Any();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string GetUserFriendlyDescription()
|
||||
{
|
||||
string description = $"Requirement met when \"{ProcessName}.exe\" is running";
|
||||
if (Location != null)
|
||||
description += $" from \"{Location}\"";
|
||||
/// <inheritdoc />
|
||||
public string GetUserFriendlyDescription()
|
||||
{
|
||||
string description = $"Requirement met when \"{ProcessName}.exe\" is running";
|
||||
if (Location != null)
|
||||
description += $" from \"{Location}\"";
|
||||
|
||||
return description;
|
||||
}
|
||||
return description;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.Core.Modules
|
||||
namespace Artemis.Core.Modules;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an attribute that marks a data model property to be ignored by the UI
|
||||
/// </summary>
|
||||
public class DataModelIgnoreAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an attribute that marks a data model property to be ignored by the UI
|
||||
/// </summary>
|
||||
public class DataModelIgnoreAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,51 +1,50 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.Core.Modules
|
||||
namespace Artemis.Core.Modules;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an attribute that describes a data model property
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class DataModelPropertyAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an attribute that describes a data model property
|
||||
/// Gets or sets the user-friendly name for this property, shown in the UI.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class DataModelPropertyAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user-friendly name for this property, shown in the UI.
|
||||
/// </summary>
|
||||
public string? Name { get; set; }
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user-friendly description for this property, shown in the UI.
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the user-friendly description for this property, shown in the UI.
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the an optional prefix to show before displaying elements in the UI.
|
||||
/// </summary>
|
||||
public string? Prefix { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the an optional prefix to show before displaying elements in the UI.
|
||||
/// </summary>
|
||||
public string? Prefix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an optional affix to show behind displaying elements in the UI.
|
||||
/// </summary>
|
||||
public string? Affix { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets an optional affix to show behind displaying elements in the UI.
|
||||
/// </summary>
|
||||
public string? Affix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of list items, only applicable to enumerable data model properties
|
||||
/// </summary>
|
||||
public string? ListItemName { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the name of list items, only applicable to enumerable data model properties
|
||||
/// </summary>
|
||||
public string? ListItemName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an optional maximum value, this value is not enforced but used for percentage calculations.
|
||||
/// </summary>
|
||||
public object? MaxValue { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets an optional maximum value, this value is not enforced but used for percentage calculations.
|
||||
/// </summary>
|
||||
public object? MaxValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an optional minimum value, this value is not enforced but used for percentage calculations.
|
||||
/// </summary>
|
||||
public object? MinValue { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets an optional minimum value, this value is not enforced but used for percentage calculations.
|
||||
/// </summary>
|
||||
public object? MinValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether this property resets the max depth of the data model, defaults to true
|
||||
/// </summary>
|
||||
public bool ResetsDepth { get; set; } = true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets whether this property resets the max depth of the data model, defaults to true
|
||||
/// </summary>
|
||||
public bool ResetsDepth { get; set; } = true;
|
||||
}
|
||||
@@ -7,381 +7,372 @@ using System.Reflection;
|
||||
using Humanizer;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Artemis.Core.Modules
|
||||
namespace Artemis.Core.Modules;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a data model that contains information on a game/application etc.
|
||||
/// </summary>
|
||||
public abstract class DataModel
|
||||
{
|
||||
private readonly List<DataModelPath> _activePaths = new();
|
||||
private readonly HashSet<string> _activePathsHashSet = new();
|
||||
private readonly Dictionary<string, DynamicChild> _dynamicChildren = new();
|
||||
|
||||
/// <summary>
|
||||
/// Represents a data model that contains information on a game/application etc.
|
||||
/// Creates a new instance of the <see cref="DataModel" /> class
|
||||
/// </summary>
|
||||
public abstract class DataModel
|
||||
protected DataModel()
|
||||
{
|
||||
private readonly HashSet<string> _activePathsHashSet = new();
|
||||
private readonly List<DataModelPath> _activePaths = new();
|
||||
private readonly Dictionary<string, DynamicChild> _dynamicChildren = new();
|
||||
// These are both set right after construction to keep the constructor of inherited classes clean
|
||||
Module = null!;
|
||||
DataModelDescription = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="DataModel" /> class
|
||||
/// </summary>
|
||||
protected DataModel()
|
||||
ActivePaths = new ReadOnlyCollection<DataModelPath>(_activePaths);
|
||||
DynamicChildren = new ReadOnlyDictionary<string, DynamicChild>(_dynamicChildren);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the module this data model belongs to
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
[DataModelIgnore]
|
||||
public Module Module { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="DataModelPropertyAttribute" /> describing this data model
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
[DataModelIgnore]
|
||||
public DataModelPropertyAttribute DataModelDescription { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the is expansion status indicating whether this data model expands the main data model
|
||||
/// </summary>
|
||||
[DataModelIgnore]
|
||||
public bool IsExpansion { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets an read-only dictionary of all dynamic children
|
||||
/// </summary>
|
||||
[DataModelIgnore]
|
||||
public ReadOnlyDictionary<string, DynamicChild> DynamicChildren { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a read-only list of <see cref="DataModelPath" />s targeting this data model
|
||||
/// </summary>
|
||||
[DataModelIgnore]
|
||||
public ReadOnlyCollection<DataModelPath> ActivePaths { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a read-only collection of all properties in this datamodel that are to be ignored
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ReadOnlyCollection<PropertyInfo> GetHiddenProperties()
|
||||
{
|
||||
return Module.HiddenProperties;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property description of the provided property info
|
||||
/// </summary>
|
||||
/// <returns>If found, the property description attribute, otherwise <see langword="null" />.</returns>
|
||||
public virtual DataModelPropertyAttribute? GetPropertyDescription(PropertyInfo propertyInfo)
|
||||
{
|
||||
return (DataModelPropertyAttribute?) Attribute.GetCustomAttribute(propertyInfo, typeof(DataModelPropertyAttribute));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a dynamic child has been added to this data model
|
||||
/// </summary>
|
||||
public event EventHandler<DynamicDataModelChildEventArgs>? DynamicChildAdded;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a dynamic child has been removed from this data model
|
||||
/// </summary>
|
||||
public event EventHandler<DynamicDataModelChildEventArgs>? DynamicChildRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a dynamic child has been added to this data model
|
||||
/// </summary>
|
||||
public event EventHandler<DataModelPathEventArgs>? ActivePathAdded;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a dynamic child has been removed from this data model
|
||||
/// </summary>
|
||||
public event EventHandler<DataModelPathEventArgs>? ActivePathRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="DynamicChildAdded" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnDynamicDataModelAdded(DynamicDataModelChildEventArgs e)
|
||||
{
|
||||
DynamicChildAdded?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="DynamicChildRemoved" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnDynamicDataModelRemoved(DynamicDataModelChildEventArgs e)
|
||||
{
|
||||
DynamicChildRemoved?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="ActivePathAdded" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnActivePathAdded(DataModelPathEventArgs e)
|
||||
{
|
||||
ActivePathAdded?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="ActivePathRemoved" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnActivePathRemoved(DataModelPathEventArgs e)
|
||||
{
|
||||
ActivePathRemoved?.Invoke(this, e);
|
||||
}
|
||||
|
||||
#region Dynamic children
|
||||
|
||||
/// <summary>
|
||||
/// Adds a dynamic child to this data model
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the child, must be unique to this data model</param>
|
||||
/// <param name="initialValue">The initial value of the dynamic child</param>
|
||||
/// <returns>The resulting dynamic child which can be used to further update the value</returns>
|
||||
public DynamicChild<T> AddDynamicChild<T>(string key, T initialValue)
|
||||
{
|
||||
return AddDynamicChild(key, initialValue, new DataModelPropertyAttribute());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a dynamic child to this data model
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the child, must be unique to this data model</param>
|
||||
/// <param name="initialValue">The initial value of the dynamic child</param>
|
||||
/// <param name="name">A human readable name for your dynamic child, shown in the UI</param>
|
||||
/// <param name="description">An optional description, shown in the UI</param>
|
||||
/// <returns>The resulting dynamic child which can be used to further update the value</returns>
|
||||
public DynamicChild<T> AddDynamicChild<T>(string key, T initialValue, string name, string? description = null)
|
||||
{
|
||||
return AddDynamicChild(key, initialValue, new DataModelPropertyAttribute {Name = name, Description = description});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a dynamic child to this data model
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the child, must be unique to this data model</param>
|
||||
/// <param name="initialValue">The initial value of the dynamic child</param>
|
||||
/// <param name="attribute">A data model property attribute describing the dynamic child</param>
|
||||
/// <returns>The resulting dynamic child which can be used to further update the value</returns>
|
||||
public DynamicChild<T> AddDynamicChild<T>(string key, T initialValue, DataModelPropertyAttribute attribute)
|
||||
{
|
||||
if (key == null) throw new ArgumentNullException(nameof(key));
|
||||
if (initialValue == null) throw new ArgumentNullException(nameof(initialValue));
|
||||
if (attribute == null) throw new ArgumentNullException(nameof(attribute));
|
||||
if (key.Contains('.'))
|
||||
throw new ArtemisCoreException("The provided key contains an illegal character (.)");
|
||||
if (_dynamicChildren.ContainsKey(key))
|
||||
throw new ArtemisCoreException($"Cannot add a dynamic child with key '{key}' " +
|
||||
"because the key is already in use on by another dynamic property this data model.");
|
||||
|
||||
if (GetType().GetProperty(key) != null)
|
||||
throw new ArtemisCoreException($"Cannot add a dynamic child with key '{key}' " +
|
||||
"because the key is already in use by a static property on this data model.");
|
||||
|
||||
// Make sure a name is on the attribute or funny things might happen
|
||||
attribute.Name ??= key.Humanize();
|
||||
if (initialValue is DataModel dynamicDataModel)
|
||||
{
|
||||
// These are both set right after construction to keep the constructor of inherited classes clean
|
||||
Module = null!;
|
||||
DataModelDescription = null!;
|
||||
|
||||
ActivePaths = new ReadOnlyCollection<DataModelPath>(_activePaths);
|
||||
DynamicChildren = new ReadOnlyDictionary<string, DynamicChild>(_dynamicChildren);
|
||||
dynamicDataModel.Module = Module;
|
||||
dynamicDataModel.DataModelDescription = attribute;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the module this data model belongs to
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
[DataModelIgnore]
|
||||
public Module Module { get; internal set; }
|
||||
DynamicChild<T> dynamicChild = new(initialValue, key, attribute);
|
||||
_dynamicChildren.Add(key, dynamicChild);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="DataModelPropertyAttribute" /> describing this data model
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
[DataModelIgnore]
|
||||
public DataModelPropertyAttribute DataModelDescription { get; internal set; }
|
||||
OnDynamicDataModelAdded(new DynamicDataModelChildEventArgs(dynamicChild, key));
|
||||
return dynamicChild;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the is expansion status indicating whether this data model expands the main data model
|
||||
/// </summary>
|
||||
[DataModelIgnore]
|
||||
public bool IsExpansion { get; internal set; }
|
||||
/// <summary>
|
||||
/// Gets a previously added dynamic child by its key
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the dynamic child</param>
|
||||
public DynamicChild GetDynamicChild(string key)
|
||||
{
|
||||
if (key == null) throw new ArgumentNullException(nameof(key));
|
||||
return DynamicChildren[key];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an read-only dictionary of all dynamic children
|
||||
/// </summary>
|
||||
[DataModelIgnore]
|
||||
public ReadOnlyDictionary<string, DynamicChild> DynamicChildren { get; }
|
||||
/// <summary>
|
||||
/// Gets a previously added dynamic child by its key
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The typer of dynamic child you are expecting</typeparam>
|
||||
/// <param name="key">The key of the dynamic child</param>
|
||||
/// <returns></returns>
|
||||
public DynamicChild<T> GetDynamicChild<T>(string key)
|
||||
{
|
||||
if (key == null) throw new ArgumentNullException(nameof(key));
|
||||
return (DynamicChild<T>) DynamicChildren[key];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a read-only list of <see cref="DataModelPath" />s targeting this data model
|
||||
/// </summary>
|
||||
[DataModelIgnore]
|
||||
public ReadOnlyCollection<DataModelPath> ActivePaths { get; }
|
||||
/// <summary>
|
||||
/// Gets a previously added dynamic child by its key
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the dynamic child</param>
|
||||
/// <param name="dynamicChild">
|
||||
/// When this method returns, the <see cref="DynamicChild" /> associated with the specified key,
|
||||
/// if the key is found; otherwise, <see langword="null" />. This parameter is passed uninitialized.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the data model contains the dynamic child; otherwise <see langword="false" />
|
||||
/// </returns>
|
||||
public bool TryGetDynamicChild(string key, [MaybeNullWhen(false)] out DynamicChild dynamicChild)
|
||||
{
|
||||
if (key == null) throw new ArgumentNullException(nameof(key));
|
||||
|
||||
/// <summary>
|
||||
/// Returns a read-only collection of all properties in this datamodel that are to be ignored
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ReadOnlyCollection<PropertyInfo> GetHiddenProperties()
|
||||
dynamicChild = null;
|
||||
if (!DynamicChildren.TryGetValue(key, out DynamicChild? value))
|
||||
return false;
|
||||
|
||||
dynamicChild = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a previously added dynamic child by its key
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The typer of dynamic child you are expecting</typeparam>
|
||||
/// <param name="key">The key of the dynamic child</param>
|
||||
/// <param name="dynamicChild">
|
||||
/// When this method returns, the <see cref="DynamicChild{T}" /> associated with the specified
|
||||
/// key, if the key is found and the type matches; otherwise, <see langword="null" />. This parameter is passed
|
||||
/// uninitialized.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the data model contains the dynamic child; otherwise <see langword="false" />
|
||||
/// </returns>
|
||||
public bool TryGetDynamicChild<T>(string key, [MaybeNullWhen(false)] out DynamicChild<T> dynamicChild)
|
||||
{
|
||||
if (key == null) throw new ArgumentNullException(nameof(key));
|
||||
|
||||
dynamicChild = null;
|
||||
if (!DynamicChildren.TryGetValue(key, out DynamicChild? value))
|
||||
return false;
|
||||
if (value is not DynamicChild<T> typedDynamicChild)
|
||||
return false;
|
||||
dynamicChild = typedDynamicChild;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a dynamic child from the data model by its key
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the dynamic child to remove</param>
|
||||
public void RemoveDynamicChildByKey(string key)
|
||||
{
|
||||
if (key == null) throw new ArgumentNullException(nameof(key));
|
||||
if (!_dynamicChildren.TryGetValue(key, out DynamicChild? dynamicChild))
|
||||
return;
|
||||
|
||||
_dynamicChildren.Remove(key);
|
||||
OnDynamicDataModelRemoved(new DynamicDataModelChildEventArgs(dynamicChild, key));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a dynamic child from this data model
|
||||
/// </summary>
|
||||
/// <param name="dynamicChild">The dynamic data child to remove</param>
|
||||
public void RemoveDynamicChild(DynamicChild dynamicChild)
|
||||
{
|
||||
if (dynamicChild == null) throw new ArgumentNullException(nameof(dynamicChild));
|
||||
List<string> keys = _dynamicChildren.Where(kvp => kvp.Value.BaseValue == dynamicChild).Select(kvp => kvp.Key).ToList();
|
||||
foreach (string key in keys)
|
||||
{
|
||||
return Module.HiddenProperties;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property description of the provided property info
|
||||
/// </summary>
|
||||
/// <returns>If found, the property description attribute, otherwise <see langword="null"/>.</returns>
|
||||
public virtual DataModelPropertyAttribute? GetPropertyDescription(PropertyInfo propertyInfo)
|
||||
{
|
||||
return (DataModelPropertyAttribute?) Attribute.GetCustomAttribute(propertyInfo, typeof(DataModelPropertyAttribute));
|
||||
}
|
||||
|
||||
#region Dynamic children
|
||||
|
||||
/// <summary>
|
||||
/// Adds a dynamic child to this data model
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the child, must be unique to this data model</param>
|
||||
/// <param name="initialValue">The initial value of the dynamic child</param>
|
||||
/// <returns>The resulting dynamic child which can be used to further update the value</returns>
|
||||
public DynamicChild<T> AddDynamicChild<T>(string key, T initialValue)
|
||||
{
|
||||
return AddDynamicChild(key, initialValue, new DataModelPropertyAttribute());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a dynamic child to this data model
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the child, must be unique to this data model</param>
|
||||
/// <param name="initialValue">The initial value of the dynamic child</param>
|
||||
/// <param name="name">A human readable name for your dynamic child, shown in the UI</param>
|
||||
/// <param name="description">An optional description, shown in the UI</param>
|
||||
/// <returns>The resulting dynamic child which can be used to further update the value</returns>
|
||||
public DynamicChild<T> AddDynamicChild<T>(string key, T initialValue, string name, string? description = null)
|
||||
{
|
||||
return AddDynamicChild(key, initialValue, new DataModelPropertyAttribute {Name = name, Description = description});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a dynamic child to this data model
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the child, must be unique to this data model</param>
|
||||
/// <param name="initialValue">The initial value of the dynamic child</param>
|
||||
/// <param name="attribute">A data model property attribute describing the dynamic child</param>
|
||||
/// <returns>The resulting dynamic child which can be used to further update the value</returns>
|
||||
public DynamicChild<T> AddDynamicChild<T>(string key, T initialValue, DataModelPropertyAttribute attribute)
|
||||
{
|
||||
if (key == null) throw new ArgumentNullException(nameof(key));
|
||||
if (initialValue == null) throw new ArgumentNullException(nameof(initialValue));
|
||||
if (attribute == null) throw new ArgumentNullException(nameof(attribute));
|
||||
if (key.Contains('.'))
|
||||
throw new ArtemisCoreException("The provided key contains an illegal character (.)");
|
||||
if (_dynamicChildren.ContainsKey(key))
|
||||
{
|
||||
throw new ArtemisCoreException($"Cannot add a dynamic child with key '{key}' " +
|
||||
"because the key is already in use on by another dynamic property this data model.");
|
||||
}
|
||||
|
||||
if (GetType().GetProperty(key) != null)
|
||||
{
|
||||
throw new ArtemisCoreException($"Cannot add a dynamic child with key '{key}' " +
|
||||
"because the key is already in use by a static property on this data model.");
|
||||
}
|
||||
|
||||
// Make sure a name is on the attribute or funny things might happen
|
||||
attribute.Name ??= key.Humanize();
|
||||
if (initialValue is DataModel dynamicDataModel)
|
||||
{
|
||||
dynamicDataModel.Module = Module;
|
||||
dynamicDataModel.DataModelDescription = attribute;
|
||||
}
|
||||
|
||||
DynamicChild<T> dynamicChild = new(initialValue, key, attribute);
|
||||
_dynamicChildren.Add(key, dynamicChild);
|
||||
|
||||
OnDynamicDataModelAdded(new DynamicDataModelChildEventArgs(dynamicChild, key));
|
||||
return dynamicChild;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a previously added dynamic child by its key
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the dynamic child</param>
|
||||
public DynamicChild GetDynamicChild(string key)
|
||||
{
|
||||
if (key == null) throw new ArgumentNullException(nameof(key));
|
||||
return DynamicChildren[key];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a previously added dynamic child by its key
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The typer of dynamic child you are expecting</typeparam>
|
||||
/// <param name="key">The key of the dynamic child</param>
|
||||
/// <returns></returns>
|
||||
public DynamicChild<T> GetDynamicChild<T>(string key)
|
||||
{
|
||||
if (key == null) throw new ArgumentNullException(nameof(key));
|
||||
return (DynamicChild<T>) DynamicChildren[key];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a previously added dynamic child by its key
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the dynamic child</param>
|
||||
/// <param name="dynamicChild">
|
||||
/// When this method returns, the <see cref="DynamicChild" /> associated with the specified key,
|
||||
/// if the key is found; otherwise, <see langword="null" />. This parameter is passed uninitialized.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the data model contains the dynamic child; otherwise <see langword="false" />
|
||||
/// </returns>
|
||||
public bool TryGetDynamicChild(string key, [MaybeNullWhen(false)] out DynamicChild dynamicChild)
|
||||
{
|
||||
if (key == null) throw new ArgumentNullException(nameof(key));
|
||||
|
||||
dynamicChild = null;
|
||||
if (!DynamicChildren.TryGetValue(key, out DynamicChild? value))
|
||||
return false;
|
||||
|
||||
dynamicChild = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a previously added dynamic child by its key
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The typer of dynamic child you are expecting</typeparam>
|
||||
/// <param name="key">The key of the dynamic child</param>
|
||||
/// <param name="dynamicChild">
|
||||
/// When this method returns, the <see cref="DynamicChild{T}" /> associated with the specified
|
||||
/// key, if the key is found and the type matches; otherwise, <see langword="null" />. This parameter is passed
|
||||
/// uninitialized.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the data model contains the dynamic child; otherwise <see langword="false" />
|
||||
/// </returns>
|
||||
public bool TryGetDynamicChild<T>(string key, [MaybeNullWhen(false)] out DynamicChild<T> dynamicChild)
|
||||
{
|
||||
if (key == null) throw new ArgumentNullException(nameof(key));
|
||||
|
||||
dynamicChild = null;
|
||||
if (!DynamicChildren.TryGetValue(key, out DynamicChild? value))
|
||||
return false;
|
||||
if (value is not DynamicChild<T> typedDynamicChild)
|
||||
return false;
|
||||
dynamicChild = typedDynamicChild;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a dynamic child from the data model by its key
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the dynamic child to remove</param>
|
||||
public void RemoveDynamicChildByKey(string key)
|
||||
{
|
||||
if (key == null) throw new ArgumentNullException(nameof(key));
|
||||
if (!_dynamicChildren.TryGetValue(key, out DynamicChild? dynamicChild))
|
||||
return;
|
||||
|
||||
_dynamicChildren.Remove(key);
|
||||
OnDynamicDataModelRemoved(new DynamicDataModelChildEventArgs(dynamicChild, key));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a dynamic child from this data model
|
||||
/// </summary>
|
||||
/// <param name="dynamicChild">The dynamic data child to remove</param>
|
||||
public void RemoveDynamicChild(DynamicChild dynamicChild)
|
||||
/// <summary>
|
||||
/// Removes all dynamic children from this data model
|
||||
/// </summary>
|
||||
public void ClearDynamicChildren()
|
||||
{
|
||||
while (_dynamicChildren.Any())
|
||||
RemoveDynamicChildByKey(_dynamicChildren.First().Key);
|
||||
}
|
||||
|
||||
// Used a runtime by data model paths only
|
||||
internal T? GetDynamicChildValue<T>(string key)
|
||||
{
|
||||
if (TryGetDynamicChild(key, out DynamicChild? dynamicChild) && dynamicChild.BaseValue != null)
|
||||
{
|
||||
if (dynamicChild == null) throw new ArgumentNullException(nameof(dynamicChild));
|
||||
List<string> keys = _dynamicChildren.Where(kvp => kvp.Value.BaseValue == dynamicChild).Select(kvp => kvp.Key).ToList();
|
||||
foreach (string key in keys)
|
||||
{
|
||||
_dynamicChildren.Remove(key);
|
||||
OnDynamicDataModelRemoved(new DynamicDataModelChildEventArgs(dynamicChild, key));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all dynamic children from this data model
|
||||
/// </summary>
|
||||
public void ClearDynamicChildren()
|
||||
{
|
||||
while (_dynamicChildren.Any())
|
||||
RemoveDynamicChildByKey(_dynamicChildren.First().Key);
|
||||
}
|
||||
|
||||
// Used a runtime by data model paths only
|
||||
internal T? GetDynamicChildValue<T>(string key)
|
||||
{
|
||||
if (TryGetDynamicChild(key, out DynamicChild? dynamicChild) && dynamicChild.BaseValue != null)
|
||||
{
|
||||
if (dynamicChild.BaseValue is T value)
|
||||
return value;
|
||||
return default;
|
||||
}
|
||||
|
||||
if (dynamicChild.BaseValue is T value)
|
||||
return value;
|
||||
return default;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Paths
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the provided dot-separated path is in use
|
||||
/// </summary>
|
||||
/// <param name="path">The path to check per example: <c>MyDataModelChild.MyDataModelProperty</c></param>
|
||||
/// <param name="includeChildren">
|
||||
/// If <see langword="true" /> any child of the given path will return true as well; if
|
||||
/// <see langword="false" /> only an exact path match returns <see langword="true" />.
|
||||
/// </param>
|
||||
internal bool IsPropertyInUse(string path, bool includeChildren)
|
||||
{
|
||||
path = path.ToUpperInvariant();
|
||||
lock (_activePaths)
|
||||
{
|
||||
return includeChildren
|
||||
? _activePathsHashSet.Any(p => p.StartsWith(path, StringComparison.Ordinal))
|
||||
: _activePathsHashSet.Contains(path);
|
||||
}
|
||||
}
|
||||
|
||||
internal void AddDataModelPath(DataModelPath path)
|
||||
{
|
||||
lock (_activePaths)
|
||||
{
|
||||
if (_activePaths.Contains(path))
|
||||
return;
|
||||
|
||||
_activePaths.Add(path);
|
||||
|
||||
// Add to the hashset if this is the first path pointing
|
||||
string hashPath = path.Path.ToUpperInvariant();
|
||||
if (!_activePathsHashSet.Contains(hashPath))
|
||||
_activePathsHashSet.Add(hashPath);
|
||||
}
|
||||
|
||||
OnActivePathAdded(new DataModelPathEventArgs(path));
|
||||
}
|
||||
|
||||
internal void RemoveDataModelPath(DataModelPath path)
|
||||
{
|
||||
lock (_activePaths)
|
||||
{
|
||||
if (!_activePaths.Remove(path))
|
||||
return;
|
||||
|
||||
// Remove from the hashset if this was the last path pointing there
|
||||
if (_activePaths.All(p => p.Path != path.Path))
|
||||
_activePathsHashSet.Remove(path.Path.ToUpperInvariant());
|
||||
}
|
||||
|
||||
OnActivePathRemoved(new DataModelPathEventArgs(path));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a dynamic child has been added to this data model
|
||||
/// </summary>
|
||||
public event EventHandler<DynamicDataModelChildEventArgs>? DynamicChildAdded;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a dynamic child has been removed from this data model
|
||||
/// </summary>
|
||||
public event EventHandler<DynamicDataModelChildEventArgs>? DynamicChildRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a dynamic child has been added to this data model
|
||||
/// </summary>
|
||||
public event EventHandler<DataModelPathEventArgs>? ActivePathAdded;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a dynamic child has been removed from this data model
|
||||
/// </summary>
|
||||
public event EventHandler<DataModelPathEventArgs>? ActivePathRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="DynamicChildAdded" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnDynamicDataModelAdded(DynamicDataModelChildEventArgs e)
|
||||
{
|
||||
DynamicChildAdded?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="DynamicChildRemoved" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnDynamicDataModelRemoved(DynamicDataModelChildEventArgs e)
|
||||
{
|
||||
DynamicChildRemoved?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="ActivePathAdded" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnActivePathAdded(DataModelPathEventArgs e)
|
||||
{
|
||||
ActivePathAdded?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="ActivePathRemoved" /> event
|
||||
/// </summary>
|
||||
protected virtual void OnActivePathRemoved(DataModelPathEventArgs e)
|
||||
{
|
||||
ActivePathRemoved?.Invoke(this, e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
return default;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Paths
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the provided dot-separated path is in use
|
||||
/// </summary>
|
||||
/// <param name="path">The path to check per example: <c>MyDataModelChild.MyDataModelProperty</c></param>
|
||||
/// <param name="includeChildren">
|
||||
/// If <see langword="true" /> any child of the given path will return true as well; if
|
||||
/// <see langword="false" /> only an exact path match returns <see langword="true" />.
|
||||
/// </param>
|
||||
internal bool IsPropertyInUse(string path, bool includeChildren)
|
||||
{
|
||||
path = path.ToUpperInvariant();
|
||||
lock (_activePaths)
|
||||
{
|
||||
return includeChildren
|
||||
? _activePathsHashSet.Any(p => p.StartsWith(path, StringComparison.Ordinal))
|
||||
: _activePathsHashSet.Contains(path);
|
||||
}
|
||||
}
|
||||
|
||||
internal void AddDataModelPath(DataModelPath path)
|
||||
{
|
||||
lock (_activePaths)
|
||||
{
|
||||
if (_activePaths.Contains(path))
|
||||
return;
|
||||
|
||||
_activePaths.Add(path);
|
||||
|
||||
// Add to the hashset if this is the first path pointing
|
||||
string hashPath = path.Path.ToUpperInvariant();
|
||||
if (!_activePathsHashSet.Contains(hashPath))
|
||||
_activePathsHashSet.Add(hashPath);
|
||||
}
|
||||
|
||||
OnActivePathAdded(new DataModelPathEventArgs(path));
|
||||
}
|
||||
|
||||
internal void RemoveDataModelPath(DataModelPath path)
|
||||
{
|
||||
lock (_activePaths)
|
||||
{
|
||||
if (!_activePaths.Remove(path))
|
||||
return;
|
||||
|
||||
// Remove from the hashset if this was the last path pointing there
|
||||
if (_activePaths.All(p => p.Path != path.Path))
|
||||
_activePathsHashSet.Remove(path.Path.ToUpperInvariant());
|
||||
}
|
||||
|
||||
OnActivePathRemoved(new DataModelPathEventArgs(path));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,66 +1,65 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.Core.Modules
|
||||
namespace Artemis.Core.Modules;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a dynamic child value with its property attribute
|
||||
/// </summary>
|
||||
public class DynamicChild<T> : DynamicChild
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a dynamic child value with its property attribute
|
||||
/// </summary>
|
||||
public class DynamicChild<T> : DynamicChild
|
||||
internal DynamicChild(T value, string key, DataModelPropertyAttribute attribute) : base(key, attribute, typeof(T))
|
||||
{
|
||||
internal DynamicChild(T value, string key, DataModelPropertyAttribute attribute) : base(key, attribute, typeof(T))
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current value of the dynamic child
|
||||
/// </summary>
|
||||
public T Value { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override object? GetValue()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a dynamic child value with its property attribute
|
||||
/// Gets or sets the current value of the dynamic child
|
||||
/// </summary>
|
||||
public abstract class DynamicChild
|
||||
public T Value { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override object? GetValue()
|
||||
{
|
||||
internal DynamicChild(string key, DataModelPropertyAttribute attribute, Type type)
|
||||
{
|
||||
if (type == null) throw new ArgumentNullException(nameof(type));
|
||||
Key = key ?? throw new ArgumentNullException(nameof(key));
|
||||
Attribute = attribute ?? throw new ArgumentNullException(nameof(attribute));
|
||||
Type = type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the key of the dynamic child
|
||||
/// </summary>
|
||||
public string Key { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the attribute describing the dynamic child
|
||||
/// </summary>
|
||||
public DataModelPropertyAttribute Attribute { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of <see cref="BaseValue" />
|
||||
/// </summary>
|
||||
public Type Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value of the dynamic child
|
||||
/// </summary>
|
||||
public object? BaseValue => GetValue();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value of the dynamic child
|
||||
/// </summary>
|
||||
/// <returns>The current value of the dynamic child</returns>
|
||||
protected abstract object? GetValue();
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a dynamic child value with its property attribute
|
||||
/// </summary>
|
||||
public abstract class DynamicChild
|
||||
{
|
||||
internal DynamicChild(string key, DataModelPropertyAttribute attribute, Type type)
|
||||
{
|
||||
if (type == null) throw new ArgumentNullException(nameof(type));
|
||||
Key = key ?? throw new ArgumentNullException(nameof(key));
|
||||
Attribute = attribute ?? throw new ArgumentNullException(nameof(attribute));
|
||||
Type = type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the key of the dynamic child
|
||||
/// </summary>
|
||||
public string Key { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the attribute describing the dynamic child
|
||||
/// </summary>
|
||||
public DataModelPropertyAttribute Attribute { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of <see cref="BaseValue" />
|
||||
/// </summary>
|
||||
public Type Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value of the dynamic child
|
||||
/// </summary>
|
||||
public object? BaseValue => GetValue();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value of the dynamic child
|
||||
/// </summary>
|
||||
/// <returns>The current value of the dynamic child</returns>
|
||||
protected abstract object? GetValue();
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
namespace Artemis.Core.Modules
|
||||
namespace Artemis.Core.Modules;
|
||||
|
||||
/// <summary>
|
||||
/// The base class for any view model that belongs to a module
|
||||
/// </summary>
|
||||
public interface IModuleViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// The base class for any view model that belongs to a module
|
||||
/// </summary>
|
||||
public interface IModuleViewModel
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -7,341 +7,340 @@ using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Artemis.Core.Modules
|
||||
namespace Artemis.Core.Modules;
|
||||
|
||||
/// <summary>
|
||||
/// Allows you to add new data to the Artemis data model
|
||||
/// </summary>
|
||||
public abstract class Module<T> : Module where T : DataModel, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows you to add new data to the Artemis data model
|
||||
/// The data model driving this module
|
||||
/// <para>Note: This default data model is automatically registered and instantiated upon plugin enable</para>
|
||||
/// </summary>
|
||||
public abstract class Module<T> : Module where T : DataModel, new()
|
||||
public T DataModel
|
||||
{
|
||||
/// <summary>
|
||||
/// The data model driving this module
|
||||
/// <para>Note: This default data model is automatically registered and instantiated upon plugin enable</para>
|
||||
/// </summary>
|
||||
public T DataModel
|
||||
{
|
||||
get => InternalDataModel as T ?? throw new InvalidOperationException("Internal datamodel does not match the type of the data model");
|
||||
internal set => InternalDataModel = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hide the provided property using a lambda expression, e.g.
|
||||
/// <c>HideProperty(dm => dm.TimeDataModel.CurrentTimeUTC)</c>
|
||||
/// </summary>
|
||||
/// <param name="propertyLambda">A lambda expression pointing to the property to ignore</param>
|
||||
public void HideProperty<TProperty>(Expression<Func<T, TProperty>> propertyLambda)
|
||||
{
|
||||
PropertyInfo 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.
|
||||
/// <c>ShowProperty(dm => dm.TimeDataModel.CurrentTimeUTC)</c>
|
||||
/// </summary>
|
||||
/// <param name="propertyLambda">A lambda expression pointing to the property to stop ignoring</param>
|
||||
public void ShowProperty<TProperty>(Expression<Func<T, TProperty>> propertyLambda)
|
||||
{
|
||||
PropertyInfo propertyInfo = ReflectionUtilities.GetPropertyInfo(DataModel, propertyLambda);
|
||||
HiddenPropertiesList.RemoveAll(p => p.Equals(propertyInfo));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the provided dot-separated path is actively being used by Artemis
|
||||
/// <para>Note: <see cref="IsPropertyInUse" /> is slightly faster but string-based.</para>
|
||||
/// </summary>
|
||||
/// <param name="propertyLambda">
|
||||
/// The path to check per example: <c>IsPropertyInUse(dm => dm.TimeDataModel.CurrentTimeUTC)</c>
|
||||
/// </param>
|
||||
/// <param name="includeChildren">
|
||||
/// If <see langword="true" /> any child of the given path will return true as well; if
|
||||
/// <see langword="false" /> only an exact path match returns <see langword="true" />.
|
||||
/// </param>
|
||||
public bool IsPropertyInUse<TProperty>(Expression<Func<T, TProperty>> propertyLambda, bool includeChildren)
|
||||
{
|
||||
string path = GetMemberPath((MemberExpression) propertyLambda.Body);
|
||||
return IsPropertyInUse(path, includeChildren);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the provided dot-separated path is actively being used by Artemis
|
||||
/// </summary>
|
||||
/// <param name="path">The path to check per example: <c>MyDataModelChild.MyDataModelProperty</c></param>
|
||||
/// <param name="includeChildren">
|
||||
/// If <see langword="true" /> any child of the given path will return true as well; if
|
||||
/// <see langword="false" /> only an exact path match returns <see langword="true" />.
|
||||
/// </param>
|
||||
public bool IsPropertyInUse(string path, bool includeChildren)
|
||||
{
|
||||
return DataModel.IsPropertyInUse(path, includeChildren);
|
||||
}
|
||||
|
||||
internal override void InternalEnable()
|
||||
{
|
||||
DataModel = new T();
|
||||
DataModel.Module = this;
|
||||
DataModel.DataModelDescription = GetDataModelDescription();
|
||||
base.InternalEnable();
|
||||
}
|
||||
|
||||
internal override void InternalDisable()
|
||||
{
|
||||
Deactivate(true);
|
||||
base.InternalDisable();
|
||||
}
|
||||
|
||||
private static string GetMemberPath(MemberExpression? me)
|
||||
{
|
||||
StringBuilder builder = new();
|
||||
while (me != null)
|
||||
{
|
||||
builder.Insert(0, me.Member.Name);
|
||||
me = me.Expression as MemberExpression;
|
||||
if (me != null)
|
||||
builder.Insert(0, ".");
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
get => InternalDataModel as T ?? throw new InvalidOperationException("Internal datamodel does not match the type of the data model");
|
||||
internal set => InternalDataModel = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For internal use only, please use <see cref="Module{T}" />.
|
||||
/// Hide the provided property using a lambda expression, e.g.
|
||||
/// <c>HideProperty(dm => dm.TimeDataModel.CurrentTimeUTC)</c>
|
||||
/// </summary>
|
||||
public abstract class Module : PluginFeature
|
||||
/// <param name="propertyLambda">A lambda expression pointing to the property to ignore</param>
|
||||
public void HideProperty<TProperty>(Expression<Func<T, TProperty>> propertyLambda)
|
||||
{
|
||||
private readonly List<(DefaultCategoryName, string)> _defaultProfilePaths = new();
|
||||
private readonly List<(DefaultCategoryName, string)> _pendingDefaultProfilePaths = new();
|
||||
PropertyInfo propertyInfo = ReflectionUtilities.GetPropertyInfo(DataModel, propertyLambda);
|
||||
if (!HiddenPropertiesList.Any(p => p.Equals(propertyInfo)))
|
||||
HiddenPropertiesList.Add(propertyInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all properties ignored at runtime using <c>IgnoreProperty(x => x.y)</c>
|
||||
/// </summary>
|
||||
protected internal readonly List<PropertyInfo> HiddenPropertiesList = new();
|
||||
/// <summary>
|
||||
/// Stop hiding the provided property using a lambda expression, e.g.
|
||||
/// <c>ShowProperty(dm => dm.TimeDataModel.CurrentTimeUTC)</c>
|
||||
/// </summary>
|
||||
/// <param name="propertyLambda">A lambda expression pointing to the property to stop ignoring</param>
|
||||
public void ShowProperty<TProperty>(Expression<Func<T, TProperty>> propertyLambda)
|
||||
{
|
||||
PropertyInfo propertyInfo = ReflectionUtilities.GetPropertyInfo(DataModel, propertyLambda);
|
||||
HiddenPropertiesList.RemoveAll(p => p.Equals(propertyInfo));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The base constructor of the <see cref="Module" /> class.
|
||||
/// </summary>
|
||||
protected Module()
|
||||
/// <summary>
|
||||
/// Determines whether the provided dot-separated path is actively being used by Artemis
|
||||
/// <para>Note: <see cref="IsPropertyInUse" /> is slightly faster but string-based.</para>
|
||||
/// </summary>
|
||||
/// <param name="propertyLambda">
|
||||
/// The path to check per example: <c>IsPropertyInUse(dm => dm.TimeDataModel.CurrentTimeUTC)</c>
|
||||
/// </param>
|
||||
/// <param name="includeChildren">
|
||||
/// If <see langword="true" /> any child of the given path will return true as well; if
|
||||
/// <see langword="false" /> only an exact path match returns <see langword="true" />.
|
||||
/// </param>
|
||||
public bool IsPropertyInUse<TProperty>(Expression<Func<T, TProperty>> propertyLambda, bool includeChildren)
|
||||
{
|
||||
string path = GetMemberPath((MemberExpression) propertyLambda.Body);
|
||||
return IsPropertyInUse(path, includeChildren);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the provided dot-separated path is actively being used by Artemis
|
||||
/// </summary>
|
||||
/// <param name="path">The path to check per example: <c>MyDataModelChild.MyDataModelProperty</c></param>
|
||||
/// <param name="includeChildren">
|
||||
/// If <see langword="true" /> any child of the given path will return true as well; if
|
||||
/// <see langword="false" /> only an exact path match returns <see langword="true" />.
|
||||
/// </param>
|
||||
public bool IsPropertyInUse(string path, bool includeChildren)
|
||||
{
|
||||
return DataModel.IsPropertyInUse(path, includeChildren);
|
||||
}
|
||||
|
||||
internal override void InternalEnable()
|
||||
{
|
||||
DataModel = new T();
|
||||
DataModel.Module = this;
|
||||
DataModel.DataModelDescription = GetDataModelDescription();
|
||||
base.InternalEnable();
|
||||
}
|
||||
|
||||
internal override void InternalDisable()
|
||||
{
|
||||
Deactivate(true);
|
||||
base.InternalDisable();
|
||||
}
|
||||
|
||||
private static string GetMemberPath(MemberExpression? me)
|
||||
{
|
||||
StringBuilder builder = new();
|
||||
while (me != null)
|
||||
{
|
||||
DefaultProfilePaths = new ReadOnlyCollection<(DefaultCategoryName, string)>(_defaultProfilePaths);
|
||||
HiddenProperties = new ReadOnlyCollection<PropertyInfo>(HiddenPropertiesList);
|
||||
builder.Insert(0, me.Member.Name);
|
||||
me = me.Expression as MemberExpression;
|
||||
if (me != null)
|
||||
builder.Insert(0, ".");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a read only collection of default profile paths
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<(DefaultCategoryName, string)> DefaultProfilePaths { get; }
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A list of activation requirements
|
||||
/// <para>
|
||||
/// If this list is not <see langword="null" /> and not empty <see cref="IsAlwaysAvailable" /> becomes
|
||||
/// <see langword="false" /> and the data of this module is only available to profiles specifically targeting it.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public abstract List<IModuleActivationRequirement>? ActivationRequirements { get; }
|
||||
/// <summary>
|
||||
/// For internal use only, please use <see cref="Module{T}" />.
|
||||
/// </summary>
|
||||
public abstract class Module : PluginFeature
|
||||
{
|
||||
private readonly List<(DefaultCategoryName, string)> _defaultProfilePaths = new();
|
||||
private readonly List<(DefaultCategoryName, string)> _pendingDefaultProfilePaths = new();
|
||||
|
||||
/// <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>
|
||||
/// Gets a list of all properties ignored at runtime using <c>IgnoreProperty(x => x.y)</c>
|
||||
/// </summary>
|
||||
protected internal readonly List<PropertyInfo> HiddenPropertiesList = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether this module's activation was due to an override, can only be true if <see cref="IsActivated" /> is
|
||||
/// <see langword="true" />
|
||||
/// </summary>
|
||||
public bool IsActivatedOverride { get; private set; }
|
||||
/// <summary>
|
||||
/// The base constructor of the <see cref="Module" /> class.
|
||||
/// </summary>
|
||||
protected Module()
|
||||
{
|
||||
DefaultProfilePaths = new ReadOnlyCollection<(DefaultCategoryName, string)>(_defaultProfilePaths);
|
||||
HiddenProperties = new ReadOnlyCollection<PropertyInfo>(HiddenPropertiesList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether this module should update while <see cref="IsActivatedOverride" /> is <see langword="true" />. When
|
||||
/// set to <see langword="false" /> <see cref="Update" /> and any timed updates will not get called during an
|
||||
/// activation override.
|
||||
/// <para>Defaults to <see langword="false" /></para>
|
||||
/// </summary>
|
||||
public bool UpdateDuringActivationOverride { get; protected set; }
|
||||
/// <summary>
|
||||
/// Gets a read only collection of default profile paths
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<(DefaultCategoryName, string)> DefaultProfilePaths { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the activation requirement mode, defaults to <see cref="ActivationRequirementType.Any" />
|
||||
/// </summary>
|
||||
public ActivationRequirementType ActivationRequirementMode { get; set; } = ActivationRequirementType.Any;
|
||||
/// <summary>
|
||||
/// A list of activation requirements
|
||||
/// <para>
|
||||
/// If this list is not <see langword="null" /> and not empty <see cref="IsAlwaysAvailable" /> becomes
|
||||
/// <see langword="false" /> and the data of this module is only available to profiles specifically targeting it.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public abstract List<IModuleActivationRequirement>? ActivationRequirements { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether this module is always available to profiles or only to profiles that specifically
|
||||
/// target this module.
|
||||
/// <para>
|
||||
/// Note: <see langword="true" /> if there are any <see cref="ActivationRequirements" />; otherwise
|
||||
/// <see langword="false" />
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public bool IsAlwaysAvailable => ActivationRequirements == null || ActivationRequirements.Count == 0;
|
||||
/// <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>
|
||||
/// Gets whether updating this module is currently allowed
|
||||
/// </summary>
|
||||
public bool IsUpdateAllowed => IsActivated && (UpdateDuringActivationOverride || !IsActivatedOverride);
|
||||
/// <summary>
|
||||
/// Gets whether this module's activation was due to an override, can only be true if <see cref="IsActivated" /> is
|
||||
/// <see langword="true" />
|
||||
/// </summary>
|
||||
public bool IsActivatedOverride { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all properties ignored at runtime using <c>IgnoreProperty(x => x.y)</c>
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<PropertyInfo> HiddenProperties { get; }
|
||||
/// <summary>
|
||||
/// Gets whether this module should update while <see cref="IsActivatedOverride" /> is <see langword="true" />. When
|
||||
/// set to <see langword="false" /> <see cref="Update" /> and any timed updates will not get called during an
|
||||
/// activation override.
|
||||
/// <para>Defaults to <see langword="false" /></para>
|
||||
/// </summary>
|
||||
public bool UpdateDuringActivationOverride { get; protected set; }
|
||||
|
||||
internal DataModel? InternalDataModel { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the activation requirement mode, defaults to <see cref="ActivationRequirementType.Any" />
|
||||
/// </summary>
|
||||
public ActivationRequirementType ActivationRequirementMode { get; set; } = ActivationRequirementType.Any;
|
||||
|
||||
/// <summary>
|
||||
/// Called each frame when the module should update
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">Time in seconds since the last update</param>
|
||||
public abstract void Update(double deltaTime);
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether this module is always available to profiles or only to profiles that specifically
|
||||
/// target this module.
|
||||
/// <para>
|
||||
/// Note: <see langword="true" /> if there are any <see cref="ActivationRequirements" />; otherwise
|
||||
/// <see langword="false" />
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public bool IsAlwaysAvailable => ActivationRequirements == null || ActivationRequirements.Count == 0;
|
||||
|
||||
/// <summary>
|
||||
/// Called when the <see cref="ActivationRequirements" /> are met or during an override
|
||||
/// </summary>
|
||||
/// <param name="isOverride">
|
||||
/// If true, the activation was due to an override. This usually means the module was activated
|
||||
/// by the profile editor
|
||||
/// </param>
|
||||
public virtual void ModuleActivated(bool isOverride)
|
||||
/// <summary>
|
||||
/// Gets whether updating this module is currently allowed
|
||||
/// </summary>
|
||||
public bool IsUpdateAllowed => IsActivated && (UpdateDuringActivationOverride || !IsActivatedOverride);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all properties ignored at runtime using <c>IgnoreProperty(x => x.y)</c>
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<PropertyInfo> HiddenProperties { get; }
|
||||
|
||||
internal DataModel? InternalDataModel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Called each frame when the module should update
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">Time in seconds since the last update</param>
|
||||
public abstract void Update(double deltaTime);
|
||||
|
||||
/// <summary>
|
||||
/// Called when the <see cref="ActivationRequirements" /> are met or during an override
|
||||
/// </summary>
|
||||
/// <param name="isOverride">
|
||||
/// If true, the activation was due to an override. This usually means the module was activated
|
||||
/// by the profile editor
|
||||
/// </param>
|
||||
public virtual void ModuleActivated(bool isOverride)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the <see cref="ActivationRequirements" /> are no longer met or during an override
|
||||
/// </summary>
|
||||
/// <param name="isOverride">
|
||||
/// If true, the deactivation was due to an override. This usually means the module was deactivated
|
||||
/// by the profile editor
|
||||
/// </param>
|
||||
public virtual void ModuleDeactivated(bool isOverride)
|
||||
{
|
||||
}
|
||||
|
||||
/// <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 (IsAlwaysAvailable)
|
||||
return true;
|
||||
if (ActivationRequirementMode == ActivationRequirementType.All)
|
||||
return ActivationRequirements!.All(r => r.Evaluate());
|
||||
if (ActivationRequirementMode == ActivationRequirementType.Any)
|
||||
return ActivationRequirements!.Any(r => r.Evaluate());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <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 = Info.Name, Description = Info.Description};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a default profile by reading it from the file found at the provided path
|
||||
/// </summary>
|
||||
/// <param name="category">The category in which to place the default profile</param>
|
||||
/// <param name="file">A path pointing towards a profile file. May be relative to the plugin directory.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the default profile was added; <see langword="false" /> if it was not because it is
|
||||
/// already in the list.
|
||||
/// </returns>
|
||||
protected bool AddDefaultProfile(DefaultCategoryName category, string file)
|
||||
{
|
||||
// It can be null if the plugin has not loaded yet in which case Plugin.ResolveRelativePath fails
|
||||
if (Plugin == null!)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the <see cref="ActivationRequirements" /> are no longer met or during an override
|
||||
/// </summary>
|
||||
/// <param name="isOverride">
|
||||
/// If true, the deactivation was due to an override. This usually means the module was deactivated
|
||||
/// by the profile editor
|
||||
/// </param>
|
||||
public virtual void ModuleDeactivated(bool isOverride)
|
||||
{
|
||||
}
|
||||
|
||||
/// <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 (IsAlwaysAvailable)
|
||||
return true;
|
||||
if (ActivationRequirementMode == ActivationRequirementType.All)
|
||||
return ActivationRequirements!.All(r => r.Evaluate());
|
||||
if (ActivationRequirementMode == ActivationRequirementType.Any)
|
||||
return ActivationRequirements!.Any(r => r.Evaluate());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <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 = Info.Name, Description = Info.Description};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a default profile by reading it from the file found at the provided path
|
||||
/// </summary>
|
||||
/// <param name="category">The category in which to place the default profile</param>
|
||||
/// <param name="file">A path pointing towards a profile file. May be relative to the plugin directory.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the default profile was added; <see langword="false" /> if it was not because it is
|
||||
/// already in the list.
|
||||
/// </returns>
|
||||
protected bool AddDefaultProfile(DefaultCategoryName category, string file)
|
||||
{
|
||||
// It can be null if the plugin has not loaded yet in which case Plugin.ResolveRelativePath fails
|
||||
if (Plugin == null!)
|
||||
{
|
||||
if (_pendingDefaultProfilePaths.Contains((category, file)))
|
||||
return false;
|
||||
_pendingDefaultProfilePaths.Add((category, file));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Path.IsPathRooted(file))
|
||||
file = Plugin.ResolveRelativePath(file);
|
||||
|
||||
// Ensure the file exists
|
||||
if (!File.Exists(file))
|
||||
throw new ArtemisPluginFeatureException(this, $"Could not find default profile at {file}.");
|
||||
|
||||
if (_defaultProfilePaths.Contains((category, file)))
|
||||
if (_pendingDefaultProfilePaths.Contains((category, file)))
|
||||
return false;
|
||||
_defaultProfilePaths.Add((category, file));
|
||||
|
||||
_pendingDefaultProfilePaths.Add((category, file));
|
||||
return true;
|
||||
}
|
||||
|
||||
internal virtual void InternalUpdate(double deltaTime)
|
||||
{
|
||||
StartUpdateMeasure();
|
||||
if (IsUpdateAllowed)
|
||||
Update(deltaTime);
|
||||
StopUpdateMeasure();
|
||||
}
|
||||
if (!Path.IsPathRooted(file))
|
||||
file = Plugin.ResolveRelativePath(file);
|
||||
|
||||
internal virtual void Activate(bool isOverride)
|
||||
{
|
||||
if (IsActivated)
|
||||
return;
|
||||
// Ensure the file exists
|
||||
if (!File.Exists(file))
|
||||
throw new ArtemisPluginFeatureException(this, $"Could not find default profile at {file}.");
|
||||
|
||||
IsActivatedOverride = isOverride;
|
||||
ModuleActivated(isOverride);
|
||||
IsActivated = true;
|
||||
}
|
||||
if (_defaultProfilePaths.Contains((category, file)))
|
||||
return false;
|
||||
_defaultProfilePaths.Add((category, file));
|
||||
|
||||
internal virtual void Deactivate(bool isOverride)
|
||||
{
|
||||
if (!IsActivated)
|
||||
return;
|
||||
|
||||
IsActivatedOverride = false;
|
||||
IsActivated = false;
|
||||
ModuleDeactivated(isOverride);
|
||||
}
|
||||
|
||||
#region Overrides of PluginFeature
|
||||
|
||||
/// <inheritdoc />
|
||||
internal override void InternalEnable()
|
||||
{
|
||||
foreach ((DefaultCategoryName categoryName, string? path) in _pendingDefaultProfilePaths)
|
||||
AddDefaultProfile(categoryName, path);
|
||||
_pendingDefaultProfilePaths.Clear();
|
||||
|
||||
base.InternalEnable();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal virtual void Reactivate(bool isDeactivateOverride, bool isActivateOverride)
|
||||
{
|
||||
if (!IsActivated)
|
||||
return;
|
||||
|
||||
Deactivate(isDeactivateOverride);
|
||||
Activate(isActivateOverride);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
internal virtual void InternalUpdate(double deltaTime)
|
||||
{
|
||||
StartUpdateMeasure();
|
||||
if (IsUpdateAllowed)
|
||||
Update(deltaTime);
|
||||
StopUpdateMeasure();
|
||||
}
|
||||
|
||||
internal virtual void Activate(bool isOverride)
|
||||
{
|
||||
if (IsActivated)
|
||||
return;
|
||||
|
||||
IsActivatedOverride = isOverride;
|
||||
ModuleActivated(isOverride);
|
||||
IsActivated = true;
|
||||
}
|
||||
|
||||
internal virtual void Deactivate(bool isOverride)
|
||||
{
|
||||
if (!IsActivated)
|
||||
return;
|
||||
|
||||
IsActivatedOverride = false;
|
||||
IsActivated = false;
|
||||
ModuleDeactivated(isOverride);
|
||||
}
|
||||
|
||||
#region Overrides of PluginFeature
|
||||
|
||||
/// <inheritdoc />
|
||||
internal override void InternalEnable()
|
||||
{
|
||||
foreach ((DefaultCategoryName categoryName, string? path) in _pendingDefaultProfilePaths)
|
||||
AddDefaultProfile(categoryName, path);
|
||||
_pendingDefaultProfilePaths.Clear();
|
||||
|
||||
base.InternalEnable();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal virtual void Reactivate(bool isDeactivateOverride, bool isActivateOverride)
|
||||
{
|
||||
if (!IsActivated)
|
||||
return;
|
||||
|
||||
Deactivate(isDeactivateOverride);
|
||||
Activate(isActivateOverride);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// Describes in what way the activation requirements of a module must be met
|
||||
/// All activation requirements must be met for the module to activate
|
||||
/// </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
|
||||
}
|
||||
All
|
||||
}
|
||||
Reference in new issue
Block a user