diff --git a/src/Artemis.Core/Plugins/Modules/DataModel.cs b/src/Artemis.Core/Plugins/Modules/DataModel.cs index 2fabac52f..880fffc4a 100644 --- a/src/Artemis.Core/Plugins/Modules/DataModel.cs +++ b/src/Artemis.Core/Plugins/Modules/DataModel.cs @@ -345,8 +345,8 @@ public abstract class DataModel { lock (_activePaths) { - if (_activePaths.Contains(path)) - return; + if (_activePaths.Any(p => ReferenceEquals(p, path))) + throw new ArtemisCoreException("Path already present on this data model, initialization done twice?"); _activePaths.Add(path); diff --git a/src/Artemis.Core/Services/NodeService.cs b/src/Artemis.Core/Services/NodeService.cs index 867fe8cb3..5ebe8cc80 100644 --- a/src/Artemis.Core/Services/NodeService.cs +++ b/src/Artemis.Core/Services/NodeService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Security.Cryptography; using System.Text; @@ -37,6 +38,12 @@ internal class NodeService : INodeService #region Methods + /// + public List GetRegisteredTypes() + { + return NodeTypeStore.GetColors().Select(c => c.Type).Distinct().ToList(); + } + /// public TypeColorRegistration GetTypeColorRegistration(Type type) { @@ -132,6 +139,12 @@ public interface INodeService : IArtemisService /// IEnumerable AvailableNodes { get; } + /// + /// Gets all currently available node pin types. + /// + /// A of containing the currently available node pin types. + List GetRegisteredTypes(); + /// /// Gets the best matching registration for the provided type /// diff --git a/src/Artemis.Core/Stores/NodeTypeStore.cs b/src/Artemis.Core/Stores/NodeTypeStore.cs index fb96f2794..052cac84c 100644 --- a/src/Artemis.Core/Stores/NodeTypeStore.cs +++ b/src/Artemis.Core/Stores/NodeTypeStore.cs @@ -96,6 +96,14 @@ internal class NodeTypeStore } } + public static List GetColors() + { + lock (ColorRegistrations) + { + return new List(ColorRegistrations); + } + } + public static TypeColorRegistration? GetColor(Type type) { lock (ColorRegistrations) diff --git a/src/Artemis.UI/Screens/Debugger/Tabs/DataModel/DataModelDebugViewModel.cs b/src/Artemis.UI/Screens/Debugger/Tabs/DataModel/DataModelDebugViewModel.cs index eae701ef3..a0f9586dc 100644 --- a/src/Artemis.UI/Screens/Debugger/Tabs/DataModel/DataModelDebugViewModel.cs +++ b/src/Artemis.UI/Screens/Debugger/Tabs/DataModel/DataModelDebugViewModel.cs @@ -48,7 +48,12 @@ public class DataModelDebugViewModel : ActivatableViewModelBase GetDataModel(); _updateTimer.Start(); - Disposable.Create(() => _updateTimer.Stop()).DisposeWith(disposables); + Disposable.Create(() => + { + _updateTimer.Stop(); + MainDataModel?.Dispose(); + MainDataModel = null; + }).DisposeWith(disposables); }); } diff --git a/src/Artemis.VisualScripting/Nodes/DataModel/DataModelEventNode.cs b/src/Artemis.VisualScripting/Nodes/DataModel/DataModelEventNode.cs index c38af35c2..054977e8b 100644 --- a/src/Artemis.VisualScripting/Nodes/DataModel/DataModelEventNode.cs +++ b/src/Artemis.VisualScripting/Nodes/DataModel/DataModelEventNode.cs @@ -14,7 +14,12 @@ public class DataModelEventNode : Node, OutputPin> _propertyPins; private DataModelPath? _dataModelPath; private IDataModelEvent? _dataModelEvent; - + private OutputPin? _oldValuePin; + private OutputPin? _newValuePin; + private DateTime _lastTrigger; + private object? _lastValue; + private int _valueChangeCount; + public DataModelEventNode() : base("Data Model-Event", "Outputs the latest values of a data model event.") { _propertyPins = new Dictionary, OutputPin>(); @@ -43,18 +48,40 @@ public class DataModelEventNode : Node propertyAccessor, OutputPin outputPin) in _propertyPins) + // If the path is a data model event, evaluate the event + if (pathValue is IDataModelEvent dataModelEvent) { - if (!outputPin.ConnectedTo.Any()) - continue; - object value = dataModelEvent.LastEventArgumentsUntyped != null ? propertyAccessor(dataModelEvent.LastEventArgumentsUntyped) : outputPin.Type.GetDefault()!; - outputPin.Value = outputPin.IsNumeric ? new Numeric(value) : value; + TimeSinceLastTrigger.Value = dataModelEvent.TimeSinceLastTrigger.TotalMilliseconds; + TriggerCount.Value = dataModelEvent.TriggerCount; + + 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; + } + } + // If the path is a regular value, evaluate the current value + else if (_oldValuePin != null && _newValuePin != null) + { + if (Equals(_lastValue, pathValue)) + { + TimeSinceLastTrigger.Value = (DateTime.Now - _lastTrigger).TotalMilliseconds; + return; + } + + _valueChangeCount++; + _lastTrigger = DateTime.Now; + + _oldValuePin.Value = _lastValue; + _newValuePin.Value = pathValue; + + _lastValue = pathValue; + + TimeSinceLastTrigger.Value = 0; + TriggerCount.Value = _valueChangeCount; } } @@ -78,23 +105,18 @@ public class DataModelEventNode : Node pins = Pins.Skip(2).ToList(); - while (pins.Any()) - RemovePin((Pin) pins.First()); - _propertyPins.Clear(); - + + ClearPins(); _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)))) { @@ -112,6 +134,31 @@ public class DataModelEventNode : Node pins = Pins.Skip(2).ToList(); + foreach (IPin pin in pins) + RemovePin((Pin) pin); + + _propertyPins.Clear(); + _oldValuePin = null; + _newValuePin = null; + } private void DataModelPathOnPathValidated(object? sender, EventArgs e) { diff --git a/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelEventNodeCustomView.axaml b/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelEventNodeCustomView.axaml index 5f988e54a..a73713e3c 100644 --- a/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelEventNodeCustomView.axaml +++ b/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelEventNodeCustomView.axaml @@ -12,7 +12,7 @@ Modules="{CompiledBinding Modules}" ShowDataModelValues="{CompiledBinding ShowDataModelValues.Value}" ShowFullPath="{CompiledBinding ShowFullPaths.Value}" - FilterTypes="{CompiledBinding FilterTypes}" + FilterTypes="{CompiledBinding NodePinTypes}" IsEventPicker="True" VerticalAlignment="Top" MaxWidth="300"/> diff --git a/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelEventNodeCustomViewModel.cs b/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelEventNodeCustomViewModel.cs index c3ec5b539..9fe7d1058 100644 --- a/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelEventNodeCustomViewModel.cs +++ b/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelEventNodeCustomViewModel.cs @@ -19,7 +19,8 @@ public class DataModelEventNodeCustomViewModel : CustomNodeViewModel private ObservableCollection? _modules; private bool _updating; - public DataModelEventNodeCustomViewModel(DataModelEventNode node, INodeScript script, ISettingsService settingsService, INodeEditorService nodeEditorService) : base(node, script) + public DataModelEventNodeCustomViewModel(DataModelEventNode node, INodeScript script, ISettingsService settingsService, INodeEditorService nodeEditorService, INodeService nodeService) + : base(node, script) { _node = node; _nodeEditorService = nodeEditorService; @@ -28,6 +29,11 @@ public class DataModelEventNodeCustomViewModel : CustomNodeViewModel ShowDataModelValues = settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false); Modules = new ObservableCollection(); + List nodePinTypes = nodeService.GetRegisteredTypes(); + nodePinTypes.AddRange(Constants.NumberTypes); + nodePinTypes.Add(typeof(IDataModelEvent)); + NodePinTypes = new ObservableCollection(nodePinTypes); + this.WhenActivated(d => { // Set up extra modules @@ -50,6 +56,7 @@ public class DataModelEventNodeCustomViewModel : CustomNodeViewModel public PluginSetting ShowFullPaths { get; } public PluginSetting ShowDataModelValues { get; } + public ObservableCollection NodePinTypes { get; } public ObservableCollection? Modules { @@ -63,8 +70,6 @@ public class DataModelEventNodeCustomViewModel : CustomNodeViewModel set => this.RaiseAndSetIfChanged(ref _dataModelPath, value); } - public List FilterTypes => new() {typeof(IDataModelEvent)}; - private void UpdateDataModelPath(DataModelPathEntity? entity) { try diff --git a/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelNodeCustomView.axaml b/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelNodeCustomView.axaml index 376e79962..cef80d0ae 100644 --- a/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelNodeCustomView.axaml +++ b/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelNodeCustomView.axaml @@ -12,5 +12,6 @@ Modules="{CompiledBinding Modules}" ShowDataModelValues="{CompiledBinding ShowDataModelValues.Value}" ShowFullPath="{CompiledBinding ShowFullPaths.Value}" + FilterTypes="{CompiledBinding NodePinTypes}" MaxWidth="300"/> \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelNodeCustomViewModel.cs b/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelNodeCustomViewModel.cs index af5f1ffe2..55b4d6dd2 100644 --- a/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelNodeCustomViewModel.cs +++ b/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelNodeCustomViewModel.cs @@ -19,7 +19,7 @@ public class DataModelNodeCustomViewModel : CustomNodeViewModel private ObservableCollection? _modules; private bool _updating; - public DataModelNodeCustomViewModel(DataModelNode node, INodeScript script, ISettingsService settingsService, INodeEditorService nodeEditorService) : base(node, script) + public DataModelNodeCustomViewModel(DataModelNode node, INodeScript script, ISettingsService settingsService, INodeEditorService nodeEditorService, INodeService nodeService) : base(node, script) { _node = node; _nodeEditorService = nodeEditorService; @@ -27,6 +27,10 @@ public class DataModelNodeCustomViewModel : CustomNodeViewModel ShowFullPaths = settingsService.GetSetting("ProfileEditor.ShowFullPaths", true); ShowDataModelValues = settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false); + List nodePinTypes = nodeService.GetRegisteredTypes(); + nodePinTypes.AddRange(Constants.NumberTypes); + NodePinTypes = new ObservableCollection(nodePinTypes); + this.WhenActivated(d => { // Set up extra modules @@ -49,7 +53,8 @@ public class DataModelNodeCustomViewModel : CustomNodeViewModel public PluginSetting ShowFullPaths { get; } public PluginSetting ShowDataModelValues { get; } - + public ObservableCollection NodePinTypes { get; } + public ObservableCollection? Modules { get => _modules;