diff --git a/src/Artemis.Core/Models/Profile/Conditions/EventCondition.cs b/src/Artemis.Core/Models/Profile/Conditions/EventCondition.cs
index d39a0f7f5..cc342e12c 100644
--- a/src/Artemis.Core/Models/Profile/Conditions/EventCondition.cs
+++ b/src/Artemis.Core/Models/Profile/Conditions/EventCondition.cs
@@ -1,7 +1,6 @@
using System;
using System.Linq;
using Artemis.Core.Internal;
-using Artemis.Core.VisualScripting.Internal;
using Artemis.Storage.Entities.Profile.Abstract;
using Artemis.Storage.Entities.Profile.Conditions;
diff --git a/src/Artemis.Core/VisualScripting/Internal/DefaultNode.cs b/src/Artemis.Core/VisualScripting/DefaultNode.cs
similarity index 60%
rename from src/Artemis.Core/VisualScripting/Internal/DefaultNode.cs
rename to src/Artemis.Core/VisualScripting/DefaultNode.cs
index 103aa4e12..733b4e97b 100644
--- a/src/Artemis.Core/VisualScripting/Internal/DefaultNode.cs
+++ b/src/Artemis.Core/VisualScripting/DefaultNode.cs
@@ -1,18 +1,11 @@
using System;
-namespace Artemis.Core.Internal;
-
-///
-/// Represents a kind of node that cannot be deleted inside a .
-///
-public interface IDefaultNode : INode
-{
-}
+namespace Artemis.Core;
///
/// Represents a kind of node that cannot be deleted inside a .
///
-public abstract class DefaultNode : Node, IDefaultNode
+public abstract class DefaultNode : Node
{
#region Constructors
@@ -20,8 +13,6 @@ public abstract class DefaultNode : Node, IDefaultNode
protected DefaultNode(Guid id, string name, string description = "") : base(name, description)
{
Id = id;
- Name = name;
- Description = description;
}
#endregion
diff --git a/src/Artemis.Core/VisualScripting/Internal/EventConditionEventStartNode.cs b/src/Artemis.Core/VisualScripting/Internal/EventConditionEventStartNode.cs
index 21a264caa..7ceadc837 100644
--- a/src/Artemis.Core/VisualScripting/Internal/EventConditionEventStartNode.cs
+++ b/src/Artemis.Core/VisualScripting/Internal/EventConditionEventStartNode.cs
@@ -1,23 +1,16 @@
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;
-using Humanizer;
namespace Artemis.Core.Internal;
internal class EventConditionEventStartNode : DefaultNode, IEventConditionNode
{
internal static readonly Guid NodeId = new("278735FE-69E9-4A73-A6B8-59E83EE19305");
- private readonly Dictionary, OutputPin> _propertyPins;
+ private readonly ObjectOutputPins _objectOutputPins;
private IDataModelEvent? _dataModelEvent;
public EventConditionEventStartNode() : base(NodeId, "Event Arguments", "Contains the event arguments that triggered the evaluation")
{
- _propertyPins = new Dictionary, OutputPin>();
+ _objectOutputPins = new ObjectOutputPins(this);
}
public void CreatePins(IDataModelEvent? dataModelEvent)
@@ -25,30 +18,8 @@ internal class EventConditionEventStartNode : DefaultNode, IEventConditionNode
if (_dataModelEvent == dataModelEvent)
return;
- while (Pins.Any())
- RemovePin((Pin) Pins.First());
- _propertyPins.Clear();
-
_dataModelEvent = dataModelEvent;
- if (dataModelEvent == null)
- return;
-
- foreach (PropertyInfo propertyInfo in dataModelEvent.ArgumentsType.GetProperties(BindingFlags.Instance | BindingFlags.Public)
- .Where(p => p.CustomAttributes.All(a => a.AttributeType != typeof(DataModelIgnoreAttribute))))
- {
- // 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 expression = Expression.Lambda>(objectCast, eventParameter).Compile();
-
- _propertyPins.Add(expression, CreateOrAddOutputPin(propertyInfo.PropertyType, propertyInfo.Name.Humanize()));
- }
+ _objectOutputPins.ChangeType(dataModelEvent?.ArgumentsType);
}
public override void Evaluate()
@@ -56,12 +27,6 @@ internal class EventConditionEventStartNode : DefaultNode, IEventConditionNode
if (_dataModelEvent?.LastEventArgumentsUntyped == null)
return;
- foreach ((Func propertyAccessor, OutputPin outputPin) in _propertyPins)
- {
- if (!outputPin.ConnectedTo.Any())
- continue;
- object value = _dataModelEvent.LastEventArgumentsUntyped != null ? propertyAccessor(_dataModelEvent.LastEventArgumentsUntyped) : outputPin.Type.GetDefault()!;
- outputPin.Value = outputPin.IsNumeric ? new Numeric(value) : value;
- }
+ _objectOutputPins.SetCurrentValue(_dataModelEvent.LastEventArgumentsUntyped);
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/VisualScripting/Internal/EventConditionValueChangedStartNode.cs b/src/Artemis.Core/VisualScripting/Internal/EventConditionValueChangedStartNode.cs
index abf571979..2b98acbf6 100644
--- a/src/Artemis.Core/VisualScripting/Internal/EventConditionValueChangedStartNode.cs
+++ b/src/Artemis.Core/VisualScripting/Internal/EventConditionValueChangedStartNode.cs
@@ -1,5 +1,4 @@
using System;
-using Artemis.Core.VisualScripting.Internal;
namespace Artemis.Core.Internal;
diff --git a/src/Artemis.Core/VisualScripting/Internal/IEventConditionNode.cs b/src/Artemis.Core/VisualScripting/Internal/IEventConditionNode.cs
index e47ad33a7..87d45f50a 100644
--- a/src/Artemis.Core/VisualScripting/Internal/IEventConditionNode.cs
+++ b/src/Artemis.Core/VisualScripting/Internal/IEventConditionNode.cs
@@ -1,4 +1,4 @@
-namespace Artemis.Core.VisualScripting.Internal;
+namespace Artemis.Core.Internal;
internal interface IEventConditionNode : INode
{
diff --git a/src/Artemis.Core/VisualScripting/Node.cs b/src/Artemis.Core/VisualScripting/Node.cs
index 7e2161580..70e02fa12 100644
--- a/src/Artemis.Core/VisualScripting/Node.cs
+++ b/src/Artemis.Core/VisualScripting/Node.cs
@@ -132,7 +132,7 @@ public abstract class Node : BreakableModel, INode
/// The name of the pin
/// The type of value the pin will hold
/// The newly created pin
- protected InputPin CreateInputPin(string name = "")
+ public InputPin CreateInputPin(string name = "")
{
InputPin pin = new(this, name);
_pins.Add(pin);
@@ -146,7 +146,7 @@ public abstract class Node : BreakableModel, INode
/// The type of value the pin will hold
/// The name of the pin
/// The newly created pin
- protected InputPin CreateInputPin(Type type, string name = "")
+ public InputPin CreateInputPin(Type type, string name = "")
{
InputPin pin = new(this, type, name);
_pins.Add(pin);
@@ -160,7 +160,7 @@ public abstract class Node : BreakableModel, INode
/// The name of the pin
/// The type of value the pin will hold
/// The newly created pin
- protected OutputPin CreateOutputPin(string name = "")
+ public OutputPin CreateOutputPin(string name = "")
{
OutputPin pin = new(this, name);
_pins.Add(pin);
@@ -174,7 +174,7 @@ public abstract class Node : BreakableModel, INode
/// The type of value the pin will hold
/// The name of the pin
/// The newly created pin
- protected OutputPin CreateOutputPin(Type type, string name = "")
+ public OutputPin CreateOutputPin(Type type, string name = "")
{
OutputPin pin = new(this, type, name);
_pins.Add(pin);
@@ -187,7 +187,7 @@ public abstract class Node : BreakableModel, INode
/// 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.
///
- protected OutputPin CreateOrAddOutputPin(Type valueType, string displayName)
+ public 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));
@@ -217,7 +217,7 @@ public abstract class Node : BreakableModel, INode
/// 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.
///
- protected InputPin CreateOrAddInputPin(Type valueType, string displayName)
+ public 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));
@@ -247,7 +247,7 @@ public abstract class Node : BreakableModel, INode
///
/// The pin to remove
/// if the pin was removed; otherwise .
- protected bool RemovePin(Pin pin)
+ public bool RemovePin(Pin pin)
{
bool isRemoved = _pins.Remove(pin);
if (isRemoved)
@@ -263,7 +263,7 @@ public abstract class Node : BreakableModel, INode
/// Adds an existing to the collection.
///
/// The pin to add
- protected void AddPin(Pin pin)
+ public void AddPin(Pin pin)
{
if (pin.Node != this)
throw new ArtemisCoreException("Can't add a pin to a node that belongs to a different node than the one it's being added to.");
@@ -281,7 +281,7 @@ public abstract class Node : BreakableModel, INode
/// The name of the pin collection
/// The amount of pins to initially add to the collection
/// The resulting input pin collection
- protected InputPinCollection CreateInputPinCollection(string name = "", int initialCount = 1)
+ public InputPinCollection CreateInputPinCollection(string name = "", int initialCount = 1)
{
InputPinCollection pin = new(this, name, initialCount);
_pinCollections.Add(pin);
@@ -296,7 +296,7 @@ public abstract class Node : BreakableModel, INode
/// The name of the pin collection
/// The amount of pins to initially add to the collection
/// The resulting input pin collection
- protected InputPinCollection CreateInputPinCollection(Type type, string name = "", int initialCount = 1)
+ public InputPinCollection CreateInputPinCollection(Type type, string name = "", int initialCount = 1)
{
InputPinCollection pin = new(this, type, name, initialCount);
_pinCollections.Add(pin);
@@ -311,7 +311,7 @@ public abstract class Node : BreakableModel, INode
/// The name of the pin collection
/// The amount of pins to initially add to the collection
/// The resulting output pin collection
- protected OutputPinCollection CreateOutputPinCollection(string name = "", int initialCount = 1)
+ public OutputPinCollection CreateOutputPinCollection(string name = "", int initialCount = 1)
{
OutputPinCollection pin = new(this, name, initialCount);
_pinCollections.Add(pin);
@@ -325,7 +325,7 @@ public abstract class Node : BreakableModel, INode
///
/// The pin collection to remove
/// if the pin collection was removed; otherwise .
- protected bool RemovePinCollection(PinCollection pinCollection)
+ public bool RemovePinCollection(PinCollection pinCollection)
{
bool isRemoved = _pinCollections.Remove(pinCollection);
if (isRemoved)
diff --git a/src/Artemis.Core/VisualScripting/NodeScript.cs b/src/Artemis.Core/VisualScripting/NodeScript.cs
index 1c77626f8..e98dafcf3 100644
--- a/src/Artemis.Core/VisualScripting/NodeScript.cs
+++ b/src/Artemis.Core/VisualScripting/NodeScript.cs
@@ -35,7 +35,10 @@ public abstract class NodeScript : CorePropertyChanged, INodeScript
#region Properties & Fields
- internal NodeScriptEntity Entity { get; private set; }
+ ///
+ /// Gets the entity used to store this script.
+ ///
+ public NodeScriptEntity Entity { get; private set; }
///
public string Name { get; }
@@ -410,7 +413,8 @@ public class NodeScript : NodeScript, INodeScript
#region Constructors
- internal NodeScript(string name, string description, NodeScriptEntity entity, object? context = null)
+ ///
+ public NodeScript(string name, string description, NodeScriptEntity entity, object? context = null)
: base(name, description, entity, context)
{
ExitNode = new ExitNode(name, description);
diff --git a/src/Artemis.Core/VisualScripting/ObjectOutputPins.cs b/src/Artemis.Core/VisualScripting/ObjectOutputPins.cs
new file mode 100644
index 000000000..fb9c874f7
--- /dev/null
+++ b/src/Artemis.Core/VisualScripting/ObjectOutputPins.cs
@@ -0,0 +1,142 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using Artemis.Core.Modules;
+using Humanizer;
+
+namespace Artemis.Core;
+
+///
+/// Represents a collection of output pins for a node capable of outputting the properties of an object or value type.
+///
+public class ObjectOutputPins
+{
+ private readonly Dictionary, OutputPin> _propertyPins;
+ private OutputPin? _valueTypePin;
+
+ ///
+ /// Creates an instance of the class.
+ ///
+ /// The node the object output was created for.
+ public ObjectOutputPins(Node node)
+ {
+ Node = node;
+ _propertyPins = new Dictionary, OutputPin>();
+ }
+
+ ///
+ /// Gets the node the object output was created for.
+ ///
+ public Node Node { get; }
+
+ ///
+ /// Gets the current type the node's pins are set up for.
+ ///
+ public Type? CurrentType { get; private set; }
+
+ ///
+ /// Gets a read only collection of the pins outputting the object of this object node.
+ ///
+ public ReadOnlyCollection Pins => _valueTypePin != null ? new ReadOnlyCollection(new List {_valueTypePin}) : _propertyPins.Values.ToList().AsReadOnly();
+
+ ///
+ /// Change the current type and create pins on the node to reflect this.
+ ///
+ /// The type to change the collection to.
+ public void ChangeType(Type? type)
+ {
+ if (type == CurrentType)
+ return;
+ CurrentType = type;
+
+ // Remove current pins
+ foreach ((Func