diff --git a/src/Artemis.Core/Models/Profile/Conditions/EventCondition.cs b/src/Artemis.Core/Models/Profile/Conditions/EventCondition.cs index 9b51e0fcc..3923733fe 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/EventCondition.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/EventCondition.cs @@ -1,35 +1,35 @@ using System; using System.Linq; using Artemis.Core.Internal; +using Artemis.Storage.Entities.Profile.Abstract; using Artemis.Storage.Entities.Profile.Conditions; namespace Artemis.Core { - public class EventCondition : CorePropertyChanged, IDisposable, IStorageModel + public class EventCondition : CorePropertyChanged, INodeScriptCondition { private readonly string _displayName; - private readonly object? _context; - private DateTime _lastProcessedTrigger; + private readonly EventConditionEntity _entity; + private EventDefaultNode _eventNode; + private TimeLineEventOverlapMode _eventOverlapMode; private DataModelPath? _eventPath; + private DateTime _lastProcessedTrigger; - internal EventCondition(string displayName, object? context) + public EventCondition(ProfileElement profileElement) { - _displayName = displayName; - _context = context; + _entity = new EventConditionEntity(); + _displayName = profileElement.GetType().Name; - Entity = new EventConditionEntity(); - Script = new NodeScript($"Activate {displayName}", $"Whether or not the event should activate the {displayName}", context); - UpdateEventNode(); + ProfileElement = profileElement; + Script = new NodeScript($"Activate {_displayName}", $"Whether or not the event should activate the {_displayName}", profileElement.Profile); } - internal EventCondition(EventConditionEntity entity, string displayName, object? context) + internal EventCondition(EventConditionEntity entity, ProfileElement profileElement) { - _displayName = displayName; - _context = context; - - Entity = entity; - Script = null!; + _entity = entity; + _displayName = profileElement.GetType().Name; + ProfileElement = profileElement; Load(); } @@ -47,22 +47,104 @@ namespace Artemis.Core get => _eventPath; } - internal EventConditionEntity Entity { get; } - internal bool Evaluate() + /// + /// Gets or sets how the condition behaves when events trigger before the timeline finishes + /// + public TimeLineEventOverlapMode EventOverlapMode + { + get => _eventOverlapMode; + set => SetAndNotify(ref _eventOverlapMode, value); + } + + /// + /// Updates the event node, applying the selected event + /// + public void UpdateEventNode() + { + if (EventPath?.GetValue() is not IDataModelEvent dataModelEvent) + return; + + if (Script.Nodes.FirstOrDefault(n => n is EventDefaultNode) is EventDefaultNode existing) + { + existing.UpdateDataModelEvent(dataModelEvent); + _eventNode = existing; + } + else + { + _eventNode = new EventDefaultNode(); + _eventNode.UpdateDataModelEvent(dataModelEvent); + } + + if (_eventNode.Pins.Any() && !Script.Nodes.Contains(_eventNode)) + Script.AddNode(_eventNode); + else + Script.RemoveNode(_eventNode); + } + + private bool Evaluate() { if (EventPath?.GetValue() is not IDataModelEvent dataModelEvent || dataModelEvent.LastTrigger <= _lastProcessedTrigger) return false; - // TODO: Place dataModelEvent.LastEventArgumentsUntyped; in the start node - Script.Run(); - _lastProcessedTrigger = dataModelEvent.LastTrigger; + if (!Script.ExitNodeConnected) + return true; + Script.Run(); return Script.Result; } - #region IDisposable + /// + public IConditionEntity Entity => _entity; + + /// + public ProfileElement ProfileElement { get; } + + /// + public bool IsMet { get; private set; } + + /// + public void Update() + { + if (EventOverlapMode == TimeLineEventOverlapMode.Toggle) + { + if (Evaluate()) + IsMet = !IsMet; + } + else + { + IsMet = Evaluate(); + } + } + + /// + public void ApplyToTimeline(bool isMet, bool wasMet, Timeline timeline) + { + if (!isMet) + { + if (EventOverlapMode == TimeLineEventOverlapMode.Toggle) + timeline.JumpToEnd(); + return; + } + + // Event overlap mode doesn't apply in this case + if (timeline.IsFinished) + { + timeline.JumpToStart(); + return; + } + + // If the timeline was already running, look at the event overlap mode + if (EventOverlapMode == TimeLineEventOverlapMode.Restart) + timeline.JumpToStart(); + else if (EventOverlapMode == TimeLineEventOverlapMode.Copy) + timeline.AddExtraTimeline(); + else if (EventOverlapMode == TimeLineEventOverlapMode.Toggle && !wasMet) + timeline.JumpToStart(); + + // The remaining overlap mode is 'ignore' which requires no further action + } /// public void Dispose() @@ -71,49 +153,32 @@ namespace Artemis.Core EventPath?.Dispose(); } - #endregion - - internal void LoadNodeScript() - { - Script.Load(); - UpdateEventNode(); - } - - /// - /// Updates the event node, applying the selected event - /// - public void UpdateEventNode() - { - if (EventPath?.GetValue() is not IDataModelEvent dataModelEvent) - return; - - if (Script.Nodes.FirstOrDefault(n => n is EventStartNode) is EventStartNode existing) - existing.UpdateDataModelEvent(dataModelEvent); - else - { - EventStartNode node = new(); - node.UpdateDataModelEvent(dataModelEvent); - Script.AddNode(node); - } - } - - #region Implementation of IStorageModel + #region Storage /// public void Load() { - EventPath = new DataModelPath(null, Entity.EventPath); - Script = new NodeScript($"Activate {_displayName}", $"Whether or not the event should activate the {_displayName}", Entity.Script, _context); - UpdateEventNode(); + EventOverlapMode = (TimeLineEventOverlapMode) _entity.EventOverlapMode; + Script = new NodeScript($"Activate {_displayName}", $"Whether or not the event should activate the {_displayName}", _entity.Script, ProfileElement.Profile); + EventPath = new DataModelPath(_entity.EventPath); } /// public void Save() { - EventPath?.Save(); - Entity.EventPath = EventPath?.Entity; + _entity.EventOverlapMode = (int) EventOverlapMode; Script.Save(); - Entity.Script = Script.Entity; + _entity.Script = Script.Entity; + EventPath?.Save(); + _entity.EventPath = EventPath?.Entity; + } + + /// + public void LoadNodeScript() + { + Script.Load(); + UpdateEventNode(); + Script.LoadConnections(); } #endregion diff --git a/src/Artemis.Core/Models/Profile/Conditions/EventsCondition.cs b/src/Artemis.Core/Models/Profile/Conditions/EventsCondition.cs deleted file mode 100644 index 86edae3e0..000000000 --- a/src/Artemis.Core/Models/Profile/Conditions/EventsCondition.cs +++ /dev/null @@ -1,175 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using Artemis.Storage.Entities.Profile.Abstract; -using Artemis.Storage.Entities.Profile.Conditions; - -namespace Artemis.Core -{ - public class EventsCondition : CorePropertyChanged, INodeScriptCondition - { - private readonly EventsConditionEntity _entity; - private readonly List _eventsList; - private TimeLineEventOverlapMode _eventOverlapMode; - - public EventsCondition(ProfileElement profileElement) - { - _entity = new EventsConditionEntity(); - _eventsList = new List(); - - ProfileElement = profileElement; - Events = new ReadOnlyCollection(_eventsList); - } - - internal EventsCondition(EventsConditionEntity entity, ProfileElement profileElement) - { - _entity = entity; - _eventsList = new List(); - - ProfileElement = profileElement; - Events = new ReadOnlyCollection(_eventsList); - - Load(); - } - - /// - /// Gets a list of events this condition reacts to - /// - public IReadOnlyCollection Events { get; } - - /// - /// Gets or sets how the condition behaves when events trigger before the timeline finishes - /// - public TimeLineEventOverlapMode EventOverlapMode - { - get => _eventOverlapMode; - set => SetAndNotify(ref _eventOverlapMode, value); - } - - /// - public IConditionEntity Entity => _entity; - - /// - public ProfileElement ProfileElement { get; } - - /// - public bool IsMet { get; private set; } - - /// - /// Adds a new event condition - /// - /// The newly created event condition - public EventCondition AddEventCondition() - { - EventCondition eventCondition = new(ProfileElement.GetType().Name.ToLower(), ProfileElement.Profile); - lock (_eventsList) - { - _eventsList.Add(eventCondition); - } - - return eventCondition; - } - - /// - /// Removes the provided event condition - /// - /// The event condition to remove - public void RemoveEventCondition(EventCondition eventCondition) - { - lock (_eventsList) - { - _eventsList.Remove(eventCondition); - } - } - - /// - public void Update() - { - lock (_eventsList) - { - if (EventOverlapMode == TimeLineEventOverlapMode.Toggle) - { - if (_eventsList.Any(c => c.Evaluate())) - IsMet = !IsMet; - } - else - { - IsMet = _eventsList.Any(c => c.Evaluate()); - } - } - } - - /// - public void ApplyToTimeline(bool isMet, bool wasMet, Timeline timeline) - { - if (!isMet) - return; - - // Event overlap mode doesn't apply in this case - if (timeline.IsFinished) - { - timeline.JumpToStart(); - return; - } - - // If the timeline was already running, look at the event overlap mode - if (EventOverlapMode == TimeLineEventOverlapMode.Restart) - timeline.JumpToStart(); - else if (EventOverlapMode == TimeLineEventOverlapMode.Copy) - timeline.AddExtraTimeline(); - else if (EventOverlapMode == TimeLineEventOverlapMode.Toggle && !wasMet) - timeline.JumpToStart(); - - // The remaining overlap mode is 'ignore' which requires no further action - } - - /// - public void Dispose() - { - foreach (EventCondition eventCondition in Events) - eventCondition.Dispose(); - } - - #region Storage - - /// - public void Load() - { - EventOverlapMode = (TimeLineEventOverlapMode) _entity.EventOverlapMode; - lock (_eventsList) - { - _eventsList.Clear(); - foreach (EventConditionEntity eventCondition in _entity.Events) - _eventsList.Add(new EventCondition(eventCondition, ProfileElement.GetType().Name.ToLower(), ProfileElement.Profile)); - } - } - - /// - public void Save() - { - _entity.EventOverlapMode = (int) EventOverlapMode; - _entity.Events.Clear(); - lock (_eventsList) - { - foreach (EventCondition eventCondition in _eventsList) - { - eventCondition.Save(); - _entity.Events.Add(eventCondition.Entity); - } - } - } - - /// - public void LoadNodeScript() - { - lock (_eventsList) - { - foreach (EventCondition eventCondition in _eventsList) - eventCondition.LoadNodeScript(); - } - } - - #endregion - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/Conditions/StaticCondition.cs b/src/Artemis.Core/Models/Profile/Conditions/StaticCondition.cs index f0a8d9e0b..4e4b41874 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/StaticCondition.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/StaticCondition.cs @@ -1,6 +1,4 @@ -using System; -using System.Linq; -using Artemis.Storage.Entities.Profile.Abstract; +using Artemis.Storage.Entities.Profile.Abstract; using Artemis.Storage.Entities.Profile.Conditions; namespace Artemis.Core @@ -8,19 +6,21 @@ namespace Artemis.Core public class StaticCondition : CorePropertyChanged, INodeScriptCondition { private readonly StaticConditionEntity _entity; + private readonly string _displayName; public StaticCondition(ProfileElement profileElement) { _entity = new StaticConditionEntity(); - + _displayName = profileElement.GetType().Name; + ProfileElement = profileElement; - string typeDisplayName = profileElement.GetType().Name.ToLower(); - Script = new NodeScript($"Activate {typeDisplayName}", $"Whether or not this {typeDisplayName} should be active", profileElement.Profile); + Script = new NodeScript($"Activate {_displayName}", $"Whether or not this {_displayName} should be active", profileElement.Profile); } internal StaticCondition(StaticConditionEntity entity, ProfileElement profileElement) { _entity = entity; + _displayName = profileElement.GetType().Name; ProfileElement = profileElement; Script = null!; @@ -45,7 +45,7 @@ namespace Artemis.Core /// public void Update() { - if (!Script.HasNodes) + if (!Script.ExitNodeConnected) { IsMet = true; return; @@ -64,23 +64,18 @@ namespace Artemis.Core timeline.JumpToEndSegment(); } - #region IDisposable - /// public void Dispose() { Script.Dispose(); } - #endregion - #region Storage /// public void Load() { - string typeDisplayName = ProfileElement.GetType().Name.ToLower(); - Script = new NodeScript($"Activate {typeDisplayName}", $"Whether or not this {typeDisplayName} should be active", _entity.Script, ProfileElement.Profile); + Script = new NodeScript($"Activate {_displayName}", $"Whether or not this {_displayName} should be active", _entity.Script, ProfileElement.Profile); } /// diff --git a/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs index 2b67187f6..daeb72650 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs @@ -12,13 +12,14 @@ namespace Artemis.Core private readonly List _properties = new(); private bool _disposed; private bool _isEnabled; + private DataBindingNodeScript _script; internal DataBinding(LayerProperty layerProperty) { LayerProperty = layerProperty; Entity = new DataBindingEntity(); - Script = new DataBindingNodeScript(GetScriptName(), "The value to put into the data binding", this, LayerProperty.ProfileElement.Profile); + _script = new DataBindingNodeScript(GetScriptName(), "The value to put into the data binding", this, LayerProperty.ProfileElement.Profile); Save(); } @@ -28,7 +29,7 @@ namespace Artemis.Core LayerProperty = layerProperty; Entity = entity; - Script = new DataBindingNodeScript(GetScriptName(), "The value to put into the data binding", this, LayerProperty.ProfileElement.Profile); + _script = new DataBindingNodeScript(GetScriptName(), "The value to put into the data binding", this, LayerProperty.ProfileElement.Profile); // Load will add children so be initialized before that Load(); @@ -42,7 +43,7 @@ namespace Artemis.Core /// /// Gets the script used to populate the data binding /// - public DataBindingNodeScript Script { get; private set; } + public INodeScript Script => _script; /// /// Gets the data binding entity this data binding uses for persistent storage @@ -183,7 +184,7 @@ namespace Artemis.Core if (!IsEnabled) return; - Script.DataBindingExitNode.ApplyToDataBinding(); + _script.DataBindingExitNode.ApplyToDataBinding(); } /// @@ -220,8 +221,8 @@ namespace Artemis.Core /// public void LoadNodeScript() { - Script.Dispose(); - Script = Entity.NodeScript != null + _script.Dispose(); + _script = Entity.NodeScript != null ? new DataBindingNodeScript(GetScriptName(), "The value to put into the data binding", this, Entity.NodeScript, LayerProperty.ProfileElement.Profile) : new DataBindingNodeScript(GetScriptName(), "The value to put into the data binding", this, LayerProperty.ProfileElement.Profile); } @@ -232,9 +233,9 @@ namespace Artemis.Core if (_disposed) throw new ObjectDisposedException("DataBinding"); - Script.Save(); + _script.Save(); Entity.IsEnabled = IsEnabled; - Entity.NodeScript = Script.Entity.Nodes.Any() ? Script.Entity : null; + Entity.NodeScript = _script.Entity.Nodes.Any() ? _script.Entity : null; } #endregion diff --git a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs index 92ec6eaec..c6ee7ce90 100644 --- a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs +++ b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs @@ -75,11 +75,9 @@ namespace Artemis.Core /// /// Creates a new instance of the class based on a /// - /// /// - public DataModelPath(DataModel? target, DataModelPathEntity entity) + public DataModelPath(DataModelPathEntity entity) { - Target = target; Path = entity.Path; Entity = entity; diff --git a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs index dbe3f785c..e33de9fc7 100644 --- a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs +++ b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs @@ -7,6 +7,7 @@ using Artemis.Core.LayerEffects.Placeholder; using Artemis.Core.Properties; using Artemis.Storage.Entities.Profile; using Artemis.Storage.Entities.Profile.Abstract; +using Artemis.Storage.Entities.Profile.Conditions; using SkiaSharp; namespace Artemis.Core @@ -72,6 +73,13 @@ namespace Artemis.Core ? new Timeline(RenderElementEntity.Timeline) : new Timeline(); + DisplayCondition = RenderElementEntity.DisplayCondition switch + { + StaticConditionEntity staticConditionEntity => new StaticCondition(staticConditionEntity, this), + EventConditionEntity eventConditionEntity => new EventCondition(eventConditionEntity, this), + _ => DisplayCondition + }; + ActivateEffects(); } @@ -130,10 +138,10 @@ namespace Artemis.Core /// public void UpdateTimeline(double deltaTime) { + // TODO: Move to conditions + // The play mode dictates whether to stick to the main segment unless the display conditions contains events - bool stickToMainSegment = (Timeline.PlayMode == TimelinePlayMode.Repeat || Timeline.EventOverlapMode == TimeLineEventOverlapMode.Toggle) && DisplayConditionMet; - // if (DisplayCondition != null && DisplayCondition.ContainsEvents && Timeline.EventOverlapMode != TimeLineEventOverlapMode.Toggle) - // stickToMainSegment = false; + bool stickToMainSegment = Timeline.PlayMode == TimelinePlayMode.Repeat && DisplayConditionMet; Timeline.Update(TimeSpan.FromSeconds(deltaTime), stickToMainSegment); } diff --git a/src/Artemis.Core/Models/Profile/Timeline.cs b/src/Artemis.Core/Models/Profile/Timeline.cs index 5e29dc86e..139b5a8c0 100644 --- a/src/Artemis.Core/Models/Profile/Timeline.cs +++ b/src/Artemis.Core/Models/Profile/Timeline.cs @@ -13,7 +13,7 @@ namespace Artemis.Core public class Timeline : CorePropertyChanged, IStorageModel { private const int MaxExtraTimelines = 15; - private readonly object _lock = new (); + private readonly object _lock = new(); /// /// Creates a new instance of the class @@ -24,7 +24,7 @@ namespace Artemis.Core MainSegmentLength = TimeSpan.FromSeconds(5); _extraTimelines = new List(); - ExtraTimelines = new(_extraTimelines); + ExtraTimelines = new ReadOnlyCollection(_extraTimelines); Save(); } @@ -33,7 +33,7 @@ namespace Artemis.Core { Entity = entity; _extraTimelines = new List(); - ExtraTimelines = new(_extraTimelines); + ExtraTimelines = new ReadOnlyCollection(_extraTimelines); Load(); } @@ -47,7 +47,7 @@ namespace Artemis.Core EndSegmentLength = Parent.EndSegmentLength; _extraTimelines = new List(); - ExtraTimelines = new(_extraTimelines); + ExtraTimelines = new ReadOnlyCollection(_extraTimelines); } /// @@ -139,17 +139,7 @@ namespace Artemis.Core get => _stopMode; set => SetAndNotify(ref _stopMode, value); } - - /// - /// Gets or sets the mode in which the render element responds to display condition events being fired before the - /// timeline finished - /// - public TimeLineEventOverlapMode EventOverlapMode - { - get => _eventOverlapMode; - set => SetAndNotify(ref _eventOverlapMode, value); - } - + /// /// Gets a list of extra copies of the timeline applied to this timeline /// @@ -326,7 +316,7 @@ namespace Artemis.Core IsOverridden = false; _lastOverridePosition = Position; - + if (stickToMainSegment && Position > MainSegmentEndPosition) { // If the main segment has no length, simply stick to the start of the segment @@ -445,7 +435,8 @@ namespace Artemis.Core EndSegmentLength = Entity.EndSegmentLength; PlayMode = (TimelinePlayMode) Entity.PlayMode; StopMode = (TimelineStopMode) Entity.StopMode; - EventOverlapMode = (TimeLineEventOverlapMode) Entity.EventOverlapMode; + + JumpToEnd(); } /// @@ -456,7 +447,6 @@ namespace Artemis.Core Entity.EndSegmentLength = EndSegmentLength; Entity.PlayMode = (int) PlayMode; Entity.StopMode = (int) StopMode; - Entity.EventOverlapMode = (int) EventOverlapMode; } #endregion diff --git a/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs b/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs index 20ba2ddc3..7ddc0f5f5 100644 --- a/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs +++ b/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs @@ -171,7 +171,7 @@ namespace Artemis.Core if (_disposed) throw new ObjectDisposedException("ProfileConfiguration"); - if (!ActivationCondition.HasNodes) + if (!ActivationCondition.ExitNodeConnected) ActivationConditionMet = true; else { diff --git a/src/Artemis.Core/VisualScripting/DataBindingNodeScript.cs b/src/Artemis.Core/VisualScripting/DataBindingNodeScript.cs index 0fafe87d6..40858933f 100644 --- a/src/Artemis.Core/VisualScripting/DataBindingNodeScript.cs +++ b/src/Artemis.Core/VisualScripting/DataBindingNodeScript.cs @@ -1,15 +1,19 @@ using System; +using System.Linq; using Artemis.Core.Internal; using Artemis.Storage.Entities.Profile.Nodes; namespace Artemis.Core { - public class DataBindingNodeScript : NodeScript + internal class DataBindingNodeScript : NodeScript { #region Properties & Fields internal DataBindingExitNode DataBindingExitNode { get; } + /// + public override bool ExitNodeConnected => DataBindingExitNode.Pins.Any(p => p.ConnectedTo.Any()); + /// public override Type ResultType => typeof(object); diff --git a/src/Artemis.Core/VisualScripting/Interfaces/INodeScript.cs b/src/Artemis.Core/VisualScripting/Interfaces/INodeScript.cs index 10c80548d..2a299743c 100644 --- a/src/Artemis.Core/VisualScripting/Interfaces/INodeScript.cs +++ b/src/Artemis.Core/VisualScripting/Interfaces/INodeScript.cs @@ -9,8 +9,7 @@ namespace Artemis.Core { string Name { get; } string Description { get; } - bool HasNodes { get; } - + IEnumerable Nodes { get; } Type ResultType { get; } diff --git a/src/Artemis.Core/VisualScripting/Internal/EventStartNode.cs b/src/Artemis.Core/VisualScripting/Internal/EventDefaultNode.cs similarity index 79% rename from src/Artemis.Core/VisualScripting/Internal/EventStartNode.cs rename to src/Artemis.Core/VisualScripting/Internal/EventDefaultNode.cs index c6fc57242..b5ee6e227 100644 --- a/src/Artemis.Core/VisualScripting/Internal/EventStartNode.cs +++ b/src/Artemis.Core/VisualScripting/Internal/EventDefaultNode.cs @@ -1,20 +1,23 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using Artemis.Core.Modules; using Humanizer; namespace Artemis.Core.Internal { - internal class EventStartNode : Node + internal class EventDefaultNode : Node { - private IDataModelEvent? _dataModelEvent; private readonly Dictionary _propertyPins; + private IDataModelEvent? _dataModelEvent; - public EventStartNode() : base("Event Arguments", "Contains the event arguments that triggered the evaluation") + public EventDefaultNode() : base("Event Arguments", "Contains the event arguments that triggered the evaluation") { _propertyPins = new Dictionary(); } + public override bool IsDefaultNode => true; + public void UpdateDataModelEvent(IDataModelEvent dataModelEvent) { if (_dataModelEvent == dataModelEvent) @@ -25,13 +28,11 @@ namespace Artemis.Core.Internal _propertyPins.Clear(); _dataModelEvent = dataModelEvent; - 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, CreateOutputPin(propertyInfo.PropertyType, propertyInfo.Name.Humanize())); } - #region Overrides of Node - - /// public override void Evaluate() { if (_dataModelEvent?.LastEventArgumentsUntyped == null) @@ -43,7 +44,5 @@ namespace Artemis.Core.Internal outputPin.Value = propertyInfo.GetValue(_dataModelEvent.LastEventArgumentsUntyped) ?? outputPin.Type.GetDefault()!; } } - - #endregion } } \ No newline at end of file diff --git a/src/Artemis.Core/VisualScripting/NodeScript.cs b/src/Artemis.Core/VisualScripting/NodeScript.cs index 30d227a86..8f5263fa6 100644 --- a/src/Artemis.Core/VisualScripting/NodeScript.cs +++ b/src/Artemis.Core/VisualScripting/NodeScript.cs @@ -25,12 +25,12 @@ namespace Artemis.Core public string Name { get; } public string Description { get; } - public bool HasNodes => _nodes.Count > 1; private readonly List _nodes = new(); public IEnumerable Nodes => new ReadOnlyCollection(_nodes); protected INode ExitNode { get; set; } + public abstract bool ExitNodeConnected { get; } public abstract Type ResultType { get; } public object? Context { get; set; } @@ -149,7 +149,7 @@ namespace Artemis.Core { IPinCollection? collection = node.PinCollections.FirstOrDefault(c => c.Name == entityNodePinCollection.Name && c.Type.Name == entityNodePinCollection.Type && - (int)c.Direction == entityNodePinCollection.Direction); + (int) c.Direction == entityNodePinCollection.Direction); if (collection == null) continue; @@ -231,7 +231,7 @@ namespace Artemis.Core { Name = nodePinCollection.Name, Type = nodePinCollection.Type.Name, - Direction = (int)nodePinCollection.Direction, + Direction = (int) nodePinCollection.Direction, Amount = nodePinCollection.Count() }); } @@ -301,8 +301,9 @@ namespace Artemis.Core { #region Properties & Fields - public T Result => ((ExitNode)ExitNode).Value; + public T Result => ((ExitNode) ExitNode).Value; + public override bool ExitNodeConnected => ((ExitNode) ExitNode).Input.ConnectedTo.Any(); public override Type ResultType => typeof(T); #endregion diff --git a/src/Artemis.Storage/Entities/Profile/Conditions/EventsConditionEntity.cs b/src/Artemis.Storage/Entities/Profile/Conditions/EventConditionEntity.cs similarity index 51% rename from src/Artemis.Storage/Entities/Profile/Conditions/EventsConditionEntity.cs rename to src/Artemis.Storage/Entities/Profile/Conditions/EventConditionEntity.cs index 05404882d..19b9587dc 100644 --- a/src/Artemis.Storage/Entities/Profile/Conditions/EventsConditionEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/Conditions/EventConditionEntity.cs @@ -1,17 +1,11 @@ -using System.Collections.Generic; -using Artemis.Storage.Entities.Profile.Abstract; +using Artemis.Storage.Entities.Profile.Abstract; using Artemis.Storage.Entities.Profile.Nodes; namespace Artemis.Storage.Entities.Profile.Conditions { - public class EventsConditionEntity : IConditionEntity + public class EventConditionEntity : IConditionEntity { public int EventOverlapMode { get; set; } - public List Events { get; set; } = new(); - } - - public class EventConditionEntity - { public DataModelPathEntity EventPath { get; set; } public NodeScriptEntity Script { get; set; } } diff --git a/src/Artemis.Storage/Entities/Profile/TimelineEntity.cs b/src/Artemis.Storage/Entities/Profile/TimelineEntity.cs index 6d17188c6..46dd7984b 100644 --- a/src/Artemis.Storage/Entities/Profile/TimelineEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/TimelineEntity.cs @@ -10,6 +10,5 @@ namespace Artemis.Storage.Entities.Profile public int PlayMode { get; set; } public int StopMode { get; set; } - public int EventOverlapMode { get; set; } } } \ No newline at end of file diff --git a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs index bc46e929a..dfd2a6b42 100644 --- a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs +++ b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs @@ -97,7 +97,6 @@ namespace Artemis.UI.Ninject.Factories public interface IConditionVmFactory : IVmFactory { StaticConditionViewModel StaticConditionViewModel(StaticCondition staticCondition); - EventsConditionViewModel EventsConditionViewModel(EventsCondition eventsCondition); EventConditionViewModel EventConditionViewModel(EventCondition eventCondition); } diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml index 9d5962688..acf304468 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml @@ -81,13 +81,13 @@ - A condition that checks whenever one or more events fire and acts in a configurable way + A condition triggers on a selectable event - EVENTS + EVENT diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs index 699ea3340..134025bf3 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs @@ -50,7 +50,7 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions if (DisplayConditionType == DisplayConditionType.Static) _profileEditorService.SelectedProfileElement.ChangeDisplayCondition(new StaticCondition(_profileEditorService.SelectedProfileElement)); else if (DisplayConditionType == DisplayConditionType.Events) - _profileEditorService.SelectedProfileElement.ChangeDisplayCondition(new EventsCondition(_profileEditorService.SelectedProfileElement)); + _profileEditorService.SelectedProfileElement.ChangeDisplayCondition(new EventCondition(_profileEditorService.SelectedProfileElement)); else _profileEditorService.SelectedProfileElement.ChangeDisplayCondition(null); @@ -71,9 +71,9 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions ActiveItem = _conditionVmFactory.StaticConditionViewModel(staticCondition); _displayConditionType = DisplayConditionType.Static; } - else if (renderProfileElement.DisplayCondition is EventsCondition eventsCondition) + else if (renderProfileElement.DisplayCondition is EventCondition eventsCondition) { - ActiveItem = _conditionVmFactory.EventsConditionViewModel(eventsCondition); + ActiveItem = _conditionVmFactory.EventConditionViewModel(eventsCondition); _displayConditionType = DisplayConditionType.Events; } else diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/Event/EventConditionView.xaml b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/Event/EventConditionView.xaml index 1ebd5faf6..b27aef128 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/Event/EventConditionView.xaml +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/Event/EventConditionView.xaml @@ -4,78 +4,163 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor.DisplayConditions.Event" + xmlns:converters="clr-namespace:Artemis.UI.Converters" xmlns:s="https://github.com/canton7/Stylet" xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls;assembly=Artemis.VisualScripting" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" - xmlns:shared="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared" + xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core" + xmlns:controls1="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance {x:Type local:EventConditionViewModel}}"> + + + - - - - - + + - - - - \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/Event/EventsConditionViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/Event/EventsConditionViewModel.cs deleted file mode 100644 index 5828abb04..000000000 --- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/Event/EventsConditionViewModel.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Linq; -using Artemis.Core; -using Artemis.UI.Ninject.Factories; -using Artemis.UI.Shared.Services; -using Stylet; - -namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions.Event -{ - public class EventsConditionViewModel : Conductor.Collection.OneActive - { - private readonly IConditionVmFactory _conditionVmFactory; - private readonly IProfileEditorService _profileEditorService; - - public EventsConditionViewModel(EventsCondition eventsCondition, IConditionVmFactory conditionVmFactory, IProfileEditorService profileEditorService) - { - _conditionVmFactory = conditionVmFactory; - _profileEditorService = profileEditorService; - EventsCondition = eventsCondition; - } - - public EventsCondition EventsCondition { get; } - - public TimeLineEventOverlapMode EventOverlapMode - { - get => EventsCondition.EventOverlapMode; - set - { - if (EventsCondition.EventOverlapMode == value) return; - EventsCondition.EventOverlapMode = value; - _profileEditorService.SaveSelectedProfileElement(); - } - } - - public void AddEvent() - { - EventCondition eventCondition = EventsCondition.AddEventCondition(); - Items.Add(_conditionVmFactory.EventConditionViewModel(eventCondition)); - - _profileEditorService.SaveSelectedProfileElement(); - } - - public void DeleteEvent(EventConditionViewModel eventConditionViewModel) - { - EventsCondition.RemoveEventCondition(eventConditionViewModel.EventCondition); - Items.Remove(eventConditionViewModel); - - _profileEditorService.SaveSelectedProfileElement(); - } - - #region Overrides of Screen - - /// - protected override void OnInitialActivate() - { - if (!EventsCondition.Events.Any()) - EventsCondition.AddEventCondition(); - - foreach (EventCondition eventCondition in EventsCondition.Events) - Items.Add(_conditionVmFactory.EventConditionViewModel(eventCondition)); - base.OnInitialActivate(); - } - - #endregion - } -} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/Static/StaticConditionView.xaml b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/Static/StaticConditionView.xaml index 396404858..21a143354 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/Static/StaticConditionView.xaml +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/Static/StaticConditionView.xaml @@ -49,16 +49,17 @@ - - - - - - + + + Click to edit script + + + + + Scripts with nothing connected to their end-node are always true. - - + diff --git a/src/Artemis.VisualScripting/Nodes/DataModelEventNode.cs b/src/Artemis.VisualScripting/Nodes/DataModelEventNode.cs index 26c981864..89e6afe8a 100644 --- a/src/Artemis.VisualScripting/Nodes/DataModelEventNode.cs +++ b/src/Artemis.VisualScripting/Nodes/DataModelEventNode.cs @@ -31,7 +31,7 @@ namespace Artemis.VisualScripting.Nodes if (Storage is not DataModelPathEntity pathEntity) return; - DataModelPath = new DataModelPath(null, pathEntity); + DataModelPath = new DataModelPath(pathEntity); DataModelPath.PathValidated += DataModelPathOnPathValidated; } diff --git a/src/Artemis.VisualScripting/Nodes/DataModelNode.cs b/src/Artemis.VisualScripting/Nodes/DataModelNode.cs index 155420fc4..44869c711 100644 --- a/src/Artemis.VisualScripting/Nodes/DataModelNode.cs +++ b/src/Artemis.VisualScripting/Nodes/DataModelNode.cs @@ -32,7 +32,7 @@ namespace Artemis.VisualScripting.Nodes if (Storage is not DataModelPathEntity pathEntity) return; - DataModelPath = new DataModelPath(null, pathEntity); + DataModelPath = new DataModelPath(pathEntity); DataModelPath.PathValidated += DataModelPathOnPathValidated; UpdateOutputPin(false);