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:
Robert committed 2022-08-23 20:35:25 +02:00
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();
}
+15
View File
@@ -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;
}
}
}
+64
View File
@@ -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