mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 11:26:27 +00:00
Nodes - Fixed string format node not outputting numerics
Data model event node - Renamed to Data Model-Event Value Cycle Data model event node - Added new data model event node that outputs the latest event data Event conditions - Performance improvements
This commit is contained in:
1 parent
3efb97eedd
commit
d2e0607622
15 files changed
+488
-160
No files matched your search
@@ -146,6 +146,8 @@ public class EventCondition : CorePropertyChanged, INodeScriptCondition
|
||||
valueChangedNode.UpdateOutputPins(EventPath);
|
||||
}
|
||||
|
||||
if (!Script.Nodes.Contains(_startNode))
|
||||
Script.AddNode(_startNode);
|
||||
Script.Save();
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,14 @@ public readonly struct Numeric : IComparable<Numeric>, IConvertible
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="Numeric" /> from a <see cref="long" />
|
||||
/// </summary>
|
||||
public Numeric(long value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="Numeric" /> from an <see cref="object" />
|
||||
@@ -60,6 +68,7 @@ public readonly struct Numeric : IComparable<Numeric>, IConvertible
|
||||
int value => value,
|
||||
double value => (float) value,
|
||||
byte value => value,
|
||||
long value => value,
|
||||
Numeric value => value,
|
||||
_ => ParseFloatOrDefault(pathValue?.ToString())
|
||||
};
|
||||
@@ -150,6 +159,11 @@ public readonly struct Numeric : IComparable<Numeric>, IConvertible
|
||||
{
|
||||
return (byte) Math.Clamp(p._value, 0, 255);
|
||||
}
|
||||
|
||||
public static implicit operator long(Numeric p)
|
||||
{
|
||||
return (long) p._value;
|
||||
}
|
||||
|
||||
public static bool operator >(Numeric a, Numeric b)
|
||||
{
|
||||
@@ -264,6 +278,7 @@ public readonly struct Numeric : IComparable<Numeric>, IConvertible
|
||||
type == typeof(float) ||
|
||||
type == typeof(double) ||
|
||||
type == typeof(int) ||
|
||||
type == typeof(long) ||
|
||||
type == typeof(byte);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Core.VisualScripting.Internal;
|
||||
@@ -11,13 +12,12 @@ namespace Artemis.Core.Internal;
|
||||
internal class EventConditionEventStartNode : DefaultNode, IEventConditionNode
|
||||
{
|
||||
internal static readonly Guid NodeId = new("278735FE-69E9-4A73-A6B8-59E83EE19305");
|
||||
private readonly List<OutputPin> _pinBucket = new();
|
||||
private readonly Dictionary<PropertyInfo, OutputPin> _propertyPins;
|
||||
private readonly Dictionary<Func<DataModelEventArgs, object>, OutputPin> _propertyPins;
|
||||
private IDataModelEvent? _dataModelEvent;
|
||||
|
||||
public EventConditionEventStartNode() : base(NodeId, "Event Arguments", "Contains the event arguments that triggered the evaluation")
|
||||
{
|
||||
_propertyPins = new Dictionary<PropertyInfo, OutputPin>();
|
||||
_propertyPins = new Dictionary<Func<DataModelEventArgs, object>, OutputPin>();
|
||||
}
|
||||
|
||||
public void CreatePins(IDataModelEvent? dataModelEvent)
|
||||
@@ -33,40 +33,22 @@ internal class EventConditionEventStartNode : DefaultNode, IEventConditionNode
|
||||
if (dataModelEvent == null)
|
||||
return;
|
||||
|
||||
foreach (PropertyInfo propertyInfo in dataModelEvent.ArgumentsType
|
||||
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||
foreach (PropertyInfo propertyInfo in dataModelEvent.ArgumentsType.GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||
.Where(p => p.CustomAttributes.All(a => a.AttributeType != typeof(DataModelIgnoreAttribute))))
|
||||
_propertyPins.Add(propertyInfo, CreateOrAddOutputPin(propertyInfo.PropertyType, propertyInfo.Name.Humanize()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates or adds an input pin to the node using a bucket.
|
||||
/// The bucket might grow a bit over time as the user edits the node but pins won't get lost, enabling undo/redo in the
|
||||
/// editor.
|
||||
/// </summary>
|
||||
private OutputPin CreateOrAddOutputPin(Type valueType, string displayName)
|
||||
{
|
||||
// Grab the first pin from the bucket that isn't on the node yet
|
||||
OutputPin? pin = _pinBucket.FirstOrDefault(p => !Pins.Contains(p));
|
||||
|
||||
if (Numeric.IsTypeCompatible(valueType))
|
||||
valueType = typeof(Numeric);
|
||||
|
||||
// If there is none, create a new one and add it to the bucket
|
||||
if (pin == null)
|
||||
{
|
||||
pin = CreateOutputPin(valueType, displayName);
|
||||
_pinBucket.Add(pin);
|
||||
}
|
||||
// If there was a pin in the bucket, update it's type and display name and reuse it
|
||||
else
|
||||
{
|
||||
pin.ChangeType(valueType);
|
||||
pin.Name = displayName;
|
||||
AddPin(pin);
|
||||
}
|
||||
// Expect an IDataModelEvent
|
||||
ParameterExpression eventParameter = Expression.Parameter(typeof(DataModelEventArgs), "event");
|
||||
// Cast it to the actual event type
|
||||
UnaryExpression eventCast = Expression.Convert(eventParameter, propertyInfo.DeclaringType!);
|
||||
// Access the property
|
||||
MemberExpression accessor = Expression.Property(eventCast, propertyInfo);
|
||||
// Cast the property to an object (sadly boxing)
|
||||
UnaryExpression objectCast = Expression.Convert(accessor, typeof(object));
|
||||
// Compile the resulting expression
|
||||
Func<DataModelEventArgs, object> expression = Expression.Lambda<Func<DataModelEventArgs, object>>(objectCast, eventParameter).Compile();
|
||||
|
||||
return pin;
|
||||
_propertyPins.Add(expression, CreateOrAddOutputPin(propertyInfo.PropertyType, propertyInfo.Name.Humanize()));
|
||||
}
|
||||
}
|
||||
|
||||
public override void Evaluate()
|
||||
@@ -74,13 +56,12 @@ internal class EventConditionEventStartNode : DefaultNode, IEventConditionNode
|
||||
if (_dataModelEvent?.LastEventArgumentsUntyped == null)
|
||||
return;
|
||||
|
||||
foreach ((PropertyInfo propertyInfo, OutputPin outputPin) in _propertyPins)
|
||||
foreach ((Func<DataModelEventArgs, object> propertyAccessor, OutputPin outputPin) in _propertyPins)
|
||||
{
|
||||
if (outputPin.ConnectedTo.Any())
|
||||
{
|
||||
object value = propertyInfo.GetValue(_dataModelEvent.LastEventArgumentsUntyped) ?? outputPin.Type.GetDefault()!;
|
||||
outputPin.Value = outputPin.IsNumeric ? new Numeric(value) : value;
|
||||
}
|
||||
if (!outputPin.ConnectedTo.Any())
|
||||
continue;
|
||||
object value = _dataModelEvent.LastEventArgumentsUntyped != null ? propertyAccessor(_dataModelEvent.LastEventArgumentsUntyped) : outputPin.Type.GetDefault()!;
|
||||
outputPin.Value = outputPin.IsNumeric ? new Numeric(value) : value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Ninject;
|
||||
using Ninject.Parameters;
|
||||
|
||||
@@ -15,6 +16,9 @@ public abstract class Node : CorePropertyChanged, INode
|
||||
public event EventHandler? Resetting;
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
private readonly List<OutputPin> _outputPinBucket = new();
|
||||
private readonly List<InputPin> _inputPinBucket = new();
|
||||
|
||||
private Guid _id;
|
||||
|
||||
@@ -160,6 +164,66 @@ public abstract class Node : CorePropertyChanged, INode
|
||||
OnPropertyChanged(nameof(Pins));
|
||||
return pin;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates or adds an output pin to the node using a bucket.
|
||||
/// The bucket might grow a bit over time as the user edits the node but pins won't get lost, enabling undo/redo in the
|
||||
/// editor.
|
||||
/// </summary>
|
||||
protected OutputPin CreateOrAddOutputPin(Type valueType, string displayName)
|
||||
{
|
||||
// Grab the first pin from the bucket that isn't on the node yet
|
||||
OutputPin? pin = _outputPinBucket.FirstOrDefault(p => !Pins.Contains(p));
|
||||
|
||||
if (Numeric.IsTypeCompatible(valueType))
|
||||
valueType = typeof(Numeric);
|
||||
|
||||
// If there is none, create a new one and add it to the bucket
|
||||
if (pin == null)
|
||||
{
|
||||
pin = CreateOutputPin(valueType, displayName);
|
||||
_outputPinBucket.Add(pin);
|
||||
}
|
||||
// If there was a pin in the bucket, update it's type and display name and reuse it
|
||||
else
|
||||
{
|
||||
pin.ChangeType(valueType);
|
||||
pin.Name = displayName;
|
||||
AddPin(pin);
|
||||
}
|
||||
|
||||
return pin;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates or adds an input pin to the node using a bucket.
|
||||
/// The bucket might grow a bit over time as the user edits the node but pins won't get lost, enabling undo/redo in the
|
||||
/// editor.
|
||||
/// </summary>
|
||||
protected InputPin CreateOrAddInputPin(Type valueType, string displayName)
|
||||
{
|
||||
// Grab the first pin from the bucket that isn't on the node yet
|
||||
InputPin? pin = _inputPinBucket.FirstOrDefault(p => !Pins.Contains(p));
|
||||
|
||||
if (Numeric.IsTypeCompatible(valueType))
|
||||
valueType = typeof(Numeric);
|
||||
|
||||
// If there is none, create a new one and add it to the bucket
|
||||
if (pin == null)
|
||||
{
|
||||
pin = CreateInputPin(valueType, displayName);
|
||||
_inputPinBucket.Add(pin);
|
||||
}
|
||||
// If there was a pin in the bucket, update it's type and display name and reuse it
|
||||
else
|
||||
{
|
||||
pin.ChangeType(valueType);
|
||||
pin.Name = displayName;
|
||||
AddPin(pin);
|
||||
}
|
||||
|
||||
return pin;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the provided <paramref name="pin" /> from the node and it's <see cref="Pins" /> collection
|
||||
|
||||
Reference in new issue
Block a user