mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 19:36:28 +00:00
Profile editor - Continue updating datamodel in editor
Display conditions - Added setting to display current values while selecting condition targets
This commit is contained in:
1 parent
8ca671fa84
commit
c5dbe73000
26 files changed
+382
-93
No files matched your search
@@ -25,6 +25,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
||||
{
|
||||
Parent = parent;
|
||||
DisplayConditionPredicateEntity = entity;
|
||||
PredicateType = (PredicateType) entity.PredicateType;
|
||||
}
|
||||
|
||||
public DisplayConditionPredicateEntity DisplayConditionPredicateEntity { get; set; }
|
||||
@@ -124,6 +125,9 @@ namespace Artemis.Core.Models.Profile.Conditions
|
||||
StaticConditionLambda = null;
|
||||
CompiledStaticConditionLambda = null;
|
||||
|
||||
if (Operator == null)
|
||||
return;
|
||||
|
||||
// If the operator does not support a right side, create a static expression because the right side will simply be null
|
||||
if (PredicateType == PredicateType.Dynamic && Operator.SupportsRightSide)
|
||||
CreateDynamicExpression();
|
||||
@@ -133,6 +137,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
||||
|
||||
internal override void ApplyToEntity()
|
||||
{
|
||||
DisplayConditionPredicateEntity.PredicateType = (int)PredicateType;
|
||||
DisplayConditionPredicateEntity.LeftDataModelGuid = LeftDataModel?.PluginInfo?.Guid;
|
||||
DisplayConditionPredicateEntity.LeftPropertyPath = LeftPropertyPath;
|
||||
|
||||
@@ -173,14 +178,14 @@ namespace Artemis.Core.Models.Profile.Conditions
|
||||
}
|
||||
|
||||
// Right side dynamic
|
||||
if (DisplayConditionPredicateEntity.RightDataModelGuid != null)
|
||||
if (PredicateType == PredicateType.Dynamic && DisplayConditionPredicateEntity.RightDataModelGuid != null)
|
||||
{
|
||||
var dataModel = dataModelService.GetPluginDataModelByGuid(DisplayConditionPredicateEntity.RightDataModelGuid.Value);
|
||||
if (dataModel != null && dataModel.ContainsPath(DisplayConditionPredicateEntity.RightPropertyPath))
|
||||
UpdateRightSide(dataModel, DisplayConditionPredicateEntity.RightPropertyPath);
|
||||
}
|
||||
// Right side static
|
||||
else if (DisplayConditionPredicateEntity.RightStaticValue != null)
|
||||
else if (PredicateType == PredicateType.Static && DisplayConditionPredicateEntity.RightStaticValue != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -188,7 +193,20 @@ namespace Artemis.Core.Models.Profile.Conditions
|
||||
{
|
||||
// Use the left side type so JSON.NET has a better idea what to do
|
||||
var leftSideType = LeftDataModel.GetTypeAtPath(LeftPropertyPath);
|
||||
UpdateRightSide(JsonConvert.DeserializeObject(DisplayConditionPredicateEntity.RightStaticValue, leftSideType));
|
||||
object rightSideValue;
|
||||
|
||||
try
|
||||
{
|
||||
rightSideValue = JsonConvert.DeserializeObject(DisplayConditionPredicateEntity.RightStaticValue, leftSideType);
|
||||
}
|
||||
// If deserialization fails, use the type's default
|
||||
catch (JsonSerializationException e)
|
||||
{
|
||||
dataModelService.LogDeserializationFailure(this, e);
|
||||
rightSideValue = Activator.CreateInstance(leftSideType);
|
||||
}
|
||||
|
||||
UpdateRightSide(rightSideValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -265,7 +283,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
||||
|
||||
private void CreateDynamicExpression()
|
||||
{
|
||||
if (LeftDataModel == null || RightDataModel == null)
|
||||
if (LeftDataModel == null || RightDataModel == null || Operator == null)
|
||||
return;
|
||||
|
||||
var leftSideParameter = Expression.Parameter(typeof(DataModel), "leftDataModel");
|
||||
@@ -306,8 +324,8 @@ namespace Artemis.Core.Models.Profile.Conditions
|
||||
return;
|
||||
|
||||
// If the right side value is null, the constant type cannot be inferred and must be provided manually
|
||||
var rightSideConstant = RightStaticValue != null
|
||||
? Expression.Constant(RightStaticValue)
|
||||
var rightSideConstant = RightStaticValue != null
|
||||
? Expression.Constant(RightStaticValue)
|
||||
: Expression.Constant(null, leftSideAccessor.Type);
|
||||
|
||||
var conditionExpression = Operator.CreateExpression(leftSideAccessor, rightSideConstant);
|
||||
@@ -315,6 +333,13 @@ namespace Artemis.Core.Models.Profile.Conditions
|
||||
StaticConditionLambda = Expression.Lambda<Func<DataModel, bool>>(conditionExpression, leftSideParameter);
|
||||
CompiledStaticConditionLambda = StaticConditionLambda.Compile();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (PredicateType == PredicateType.Dynamic)
|
||||
return $"[Dynamic] {LeftPropertyPath} {Operator.Description} {RightPropertyPath}";
|
||||
return $"[Static] {LeftPropertyPath} {Operator.Description} {RightStaticValue}";
|
||||
}
|
||||
}
|
||||
|
||||
public enum PredicateType
|
||||
|
||||
@@ -223,12 +223,14 @@ namespace Artemis.Core.Models.Profile
|
||||
// Ensure the layer must still be displayed
|
||||
UpdateDisplayCondition();
|
||||
|
||||
// TODO: No point updating further than this if the layer is not going to be rendered
|
||||
|
||||
// Update the layer timeline, this will give us a new delta time which could be negative in case the main segment wrapped back
|
||||
// to it's start
|
||||
UpdateTimeline(deltaTime);
|
||||
|
||||
// No point updating further than this if the layer is not going to be rendered
|
||||
if (TimelinePosition > TimelineLength)
|
||||
return;
|
||||
|
||||
General.Update();
|
||||
Transform.Update();
|
||||
LayerBrush.BaseProperties?.Update();
|
||||
@@ -285,7 +287,7 @@ namespace Artemis.Core.Models.Profile
|
||||
/// <inheritdoc />
|
||||
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo)
|
||||
{
|
||||
if (!Enabled)
|
||||
if (!Enabled || TimelinePosition > TimelineLength)
|
||||
return;
|
||||
|
||||
// Ensure the layer is ready
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Artemis.Core.Plugins.Abstract.DataModels;
|
||||
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
|
||||
using Artemis.Core.Utilities;
|
||||
|
||||
namespace Artemis.Core.Plugins.Abstract
|
||||
{
|
||||
@@ -18,6 +24,27 @@ namespace Artemis.Core.Plugins.Abstract
|
||||
internal set => InternalDataModel = value;
|
||||
}
|
||||
|
||||
/// <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>();
|
||||
@@ -39,6 +66,13 @@ namespace Artemis.Core.Plugins.Abstract
|
||||
/// </summary>
|
||||
public abstract class BaseDataModelExpansion : Plugin
|
||||
{
|
||||
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();
|
||||
|
||||
internal DataModel InternalDataModel { get; set; }
|
||||
public abstract void Update(double deltaTime);
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reflection;
|
||||
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
|
||||
using Artemis.Core.Plugins.Models;
|
||||
|
||||
@@ -51,5 +54,19 @@ namespace Artemis.Core.Plugins.Abstract.DataModels
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a read-only list of all properties in this datamodel that are to be ignored
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ReadOnlyCollection<PropertyInfo> GetHiddenProperties()
|
||||
{
|
||||
if (PluginInfo.Instance is ProfileModule profileModule)
|
||||
return profileModule.HiddenProperties;
|
||||
if (PluginInfo.Instance is BaseDataModelExpansion dataModelExpansion)
|
||||
return dataModelExpansion.HiddenProperties;
|
||||
|
||||
return new List<PropertyInfo>().AsReadOnly();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,7 @@ namespace Artemis.Core.Plugins.Abstract
|
||||
/// <summary>
|
||||
/// Called each frame when the module must update
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">Time since the last update</param>
|
||||
/// <param name="deltaTime">Time in seconds since the last update</param>
|
||||
public abstract void Update(double deltaTime);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Artemis.Core.Exceptions;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Models.Surface;
|
||||
using Artemis.Core.Plugins.Abstract.DataModels;
|
||||
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
|
||||
using Artemis.Core.Plugins.Models;
|
||||
using Artemis.Core.Utilities;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core.Plugins.Abstract
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows you to add support for new games/applications while utilizing Artemis' profile engine and your own data model
|
||||
/// 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
|
||||
{
|
||||
@@ -45,7 +51,29 @@ namespace Artemis.Core.Plugins.Abstract
|
||||
{
|
||||
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>();
|
||||
@@ -66,15 +94,28 @@ namespace Artemis.Core.Plugins.Abstract
|
||||
/// </summary>
|
||||
public abstract class ProfileModule : Module
|
||||
{
|
||||
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)
|
||||
{
|
||||
// Update the profile
|
||||
ActiveProfile?.Update(deltaTime);
|
||||
if (!IsProfileUpdatingDisabled)
|
||||
ActiveProfile?.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,14 +2,25 @@
|
||||
|
||||
namespace Artemis.Core.Plugins.Abstract.ViewModels
|
||||
{
|
||||
/// <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; }
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,6 @@ namespace Artemis.Core.Services
|
||||
}
|
||||
|
||||
public TimeSpan FrameTime { get; private set; }
|
||||
public bool PluginUpdatingDisabled { get; set; }
|
||||
public bool ModuleRenderingDisabled { get; set; }
|
||||
public List<string> StartupArguments { get; set; }
|
||||
|
||||
@@ -140,21 +139,18 @@ namespace Artemis.Core.Services
|
||||
try
|
||||
{
|
||||
_frameStopWatch.Restart();
|
||||
if (!PluginUpdatingDisabled)
|
||||
lock (_dataModelExpansions)
|
||||
{
|
||||
lock (_dataModelExpansions)
|
||||
{
|
||||
// Update all active modules
|
||||
foreach (var dataModelExpansion in _dataModelExpansions)
|
||||
dataModelExpansion.Update(args.DeltaTime);
|
||||
}
|
||||
// Update all active modules
|
||||
foreach (var dataModelExpansion in _dataModelExpansions)
|
||||
dataModelExpansion.Update(args.DeltaTime);
|
||||
}
|
||||
|
||||
lock (_modules)
|
||||
{
|
||||
// Update all active modules
|
||||
foreach (var module in _modules)
|
||||
module.Update(args.DeltaTime);
|
||||
}
|
||||
lock (_modules)
|
||||
{
|
||||
// Update all active modules
|
||||
foreach (var module in _modules)
|
||||
module.Update(args.DeltaTime);
|
||||
}
|
||||
|
||||
// If there is no ready bitmap brush, skip the frame
|
||||
|
||||
@@ -12,6 +12,8 @@ using Artemis.Core.Plugins.Abstract.DataModels;
|
||||
using Artemis.Core.Plugins.Exceptions;
|
||||
using Artemis.Core.Plugins.Models;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
|
||||
namespace Artemis.Core.Services
|
||||
{
|
||||
@@ -22,11 +24,13 @@ namespace Artemis.Core.Services
|
||||
{
|
||||
private readonly List<DataModel> _dataModelExpansions;
|
||||
private readonly IPluginService _pluginService;
|
||||
private readonly ILogger _logger;
|
||||
private readonly List<DisplayConditionOperator> _registeredConditionOperators;
|
||||
|
||||
internal DataModelService(IPluginService pluginService)
|
||||
internal DataModelService(IPluginService pluginService, ILogger logger)
|
||||
{
|
||||
_pluginService = pluginService;
|
||||
_logger = logger;
|
||||
_dataModelExpansions = new List<DataModel>();
|
||||
_registeredConditionOperators = new List<DisplayConditionOperator>();
|
||||
|
||||
@@ -174,6 +178,11 @@ namespace Artemis.Core.Services
|
||||
return RegisteredConditionOperators.FirstOrDefault(o => o.PluginInfo.Guid == operatorPluginGuid && o.GetType().Name == operatorType);
|
||||
}
|
||||
|
||||
public void LogDeserializationFailure(DisplayConditionPredicate displayConditionPredicate, JsonSerializationException exception)
|
||||
{
|
||||
_logger.Warning(exception, "Failed to deserialize display condition predicate {predicate}", displayConditionPredicate);
|
||||
}
|
||||
|
||||
private void RegisterBuiltInConditionOperators()
|
||||
{
|
||||
// General usage for any type
|
||||
|
||||
@@ -15,12 +15,7 @@ namespace Artemis.Core.Services.Interfaces
|
||||
/// The time the last frame took to render
|
||||
/// </summary>
|
||||
TimeSpan FrameTime { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether modules are updated each frame by calling their Update method
|
||||
/// </summary>
|
||||
bool PluginUpdatingDisabled { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether modules are rendered each frame by calling their Render method
|
||||
/// </summary>
|
||||
|
||||
@@ -5,6 +5,7 @@ using Artemis.Core.Models.Profile.Conditions;
|
||||
using Artemis.Core.Plugins.Abstract;
|
||||
using Artemis.Core.Plugins.Abstract.DataModels;
|
||||
using Artemis.Core.Plugins.Models;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Artemis.Core.Services.Interfaces
|
||||
{
|
||||
@@ -59,5 +60,6 @@ namespace Artemis.Core.Services.Interfaces
|
||||
|
||||
List<DisplayConditionOperator> GetCompatibleConditionOperators(Type type);
|
||||
DisplayConditionOperator GetConditionOperator(Guid operatorPluginGuid, string operatorType);
|
||||
void LogDeserializationFailure(DisplayConditionPredicate displayConditionPredicate, JsonSerializationException exception);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Artemis.Core.Utilities
|
||||
{
|
||||
public static class ReflectionUtilities
|
||||
{
|
||||
public static PropertyInfo GetPropertyInfo<TSource, TProperty>(TSource source, Expression<Func<TSource, TProperty>> propertyLambda)
|
||||
{
|
||||
var type = typeof(TSource);
|
||||
|
||||
var member = propertyLambda.Body as MemberExpression;
|
||||
if (member == null)
|
||||
throw new ArgumentException(string.Format("Expression '{0}' refers to a method, not a property.", propertyLambda));
|
||||
|
||||
var propInfo = member.Member as PropertyInfo;
|
||||
if (propInfo == null)
|
||||
throw new ArgumentException(string.Format("Expression '{0}' refers to a field, not a property.", propertyLambda));
|
||||
|
||||
return propInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user