mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Data model nodes - Only allow picking data model entries of types supported by nodes
Data models - Fixed path registration not registering two paths pointing to the same property twice (fixes data model-reliant node scripts that stop updating)
This commit is contained in:
parent
3836fae37a
commit
94b91bfc31
@ -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);
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<Type> GetRegisteredTypes()
|
||||
{
|
||||
return NodeTypeStore.GetColors().Select(c => c.Type).Distinct().ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public TypeColorRegistration GetTypeColorRegistration(Type type)
|
||||
{
|
||||
@ -132,6 +139,12 @@ public interface INodeService : IArtemisService
|
||||
/// </summary>
|
||||
IEnumerable<NodeData> AvailableNodes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets all currently available node pin types.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="List{T}"/> of <see cref="Type"/> containing the currently available node pin types.</returns>
|
||||
List<Type> GetRegisteredTypes();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the best matching registration for the provided type
|
||||
/// </summary>
|
||||
|
||||
@ -96,6 +96,14 @@ internal class NodeTypeStore
|
||||
}
|
||||
}
|
||||
|
||||
public static List<TypeColorRegistration> GetColors()
|
||||
{
|
||||
lock (ColorRegistrations)
|
||||
{
|
||||
return new List<TypeColorRegistration>(ColorRegistrations);
|
||||
}
|
||||
}
|
||||
|
||||
public static TypeColorRegistration? GetColor(Type type)
|
||||
{
|
||||
lock (ColorRegistrations)
|
||||
|
||||
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -14,7 +14,12 @@ public class DataModelEventNode : Node<DataModelPathEntity, DataModelEventNodeCu
|
||||
private readonly Dictionary<Func<DataModelEventArgs, object>, 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<Func<DataModelEventArgs, object>, OutputPin>();
|
||||
@ -43,18 +48,40 @@ public class DataModelEventNode : Node<DataModelPathEntity, DataModelEventNodeCu
|
||||
public override void Evaluate()
|
||||
{
|
||||
object? pathValue = _dataModelPath?.GetValue();
|
||||
if (pathValue is not IDataModelEvent dataModelEvent)
|
||||
return;
|
||||
|
||||
TimeSinceLastTrigger.Value = new Numeric(dataModelEvent.TimeSinceLastTrigger.TotalMilliseconds);
|
||||
TriggerCount.Value = new Numeric(dataModelEvent.TriggerCount);
|
||||
|
||||
foreach ((Func<DataModelEventArgs, object> 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<DataModelEventArgs, object> 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<DataModelPathEntity, DataModelEventNodeCu
|
||||
{
|
||||
object? pathValue = _dataModelPath?.GetValue();
|
||||
if (pathValue is IDataModelEvent dataModelEvent)
|
||||
CreatePins(dataModelEvent);
|
||||
CreateEventPins(dataModelEvent);
|
||||
else
|
||||
CreateValuePins();
|
||||
}
|
||||
|
||||
private void CreatePins(IDataModelEvent? dataModelEvent)
|
||||
|
||||
private void CreateEventPins(IDataModelEvent dataModelEvent)
|
||||
{
|
||||
if (_dataModelEvent == dataModelEvent)
|
||||
return;
|
||||
|
||||
List<IPin> 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<DataModelPathEntity, DataModelEventNodeCu
|
||||
_propertyPins.Add(expression, CreateOrAddOutputPin(propertyInfo.PropertyType, propertyInfo.Name.Humanize()));
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateValuePins()
|
||||
{
|
||||
ClearPins();
|
||||
|
||||
Type? propertyType = _dataModelPath?.GetPropertyType();
|
||||
if (propertyType == null)
|
||||
return;
|
||||
|
||||
_oldValuePin = CreateOrAddOutputPin(propertyType, "Old value");
|
||||
_newValuePin = CreateOrAddOutputPin(propertyType, "New value");
|
||||
_lastValue = null;
|
||||
_valueChangeCount = 0;
|
||||
}
|
||||
|
||||
private void ClearPins()
|
||||
{
|
||||
List<IPin> 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)
|
||||
{
|
||||
|
||||
@ -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"/>
|
||||
|
||||
@ -19,7 +19,8 @@ public class DataModelEventNodeCustomViewModel : CustomNodeViewModel
|
||||
private ObservableCollection<Module>? _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<Module>();
|
||||
|
||||
List<Type> nodePinTypes = nodeService.GetRegisteredTypes();
|
||||
nodePinTypes.AddRange(Constants.NumberTypes);
|
||||
nodePinTypes.Add(typeof(IDataModelEvent));
|
||||
NodePinTypes = new ObservableCollection<Type>(nodePinTypes);
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
// Set up extra modules
|
||||
@ -50,6 +56,7 @@ public class DataModelEventNodeCustomViewModel : CustomNodeViewModel
|
||||
|
||||
public PluginSetting<bool> ShowFullPaths { get; }
|
||||
public PluginSetting<bool> ShowDataModelValues { get; }
|
||||
public ObservableCollection<Type> NodePinTypes { get; }
|
||||
|
||||
public ObservableCollection<Module>? Modules
|
||||
{
|
||||
@ -63,8 +70,6 @@ public class DataModelEventNodeCustomViewModel : CustomNodeViewModel
|
||||
set => this.RaiseAndSetIfChanged(ref _dataModelPath, value);
|
||||
}
|
||||
|
||||
public List<Type> FilterTypes => new() {typeof(IDataModelEvent)};
|
||||
|
||||
private void UpdateDataModelPath(DataModelPathEntity? entity)
|
||||
{
|
||||
try
|
||||
|
||||
@ -12,5 +12,6 @@
|
||||
Modules="{CompiledBinding Modules}"
|
||||
ShowDataModelValues="{CompiledBinding ShowDataModelValues.Value}"
|
||||
ShowFullPath="{CompiledBinding ShowFullPaths.Value}"
|
||||
FilterTypes="{CompiledBinding NodePinTypes}"
|
||||
MaxWidth="300"/>
|
||||
</UserControl>
|
||||
@ -19,7 +19,7 @@ public class DataModelNodeCustomViewModel : CustomNodeViewModel
|
||||
private ObservableCollection<Module>? _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<Type> nodePinTypes = nodeService.GetRegisteredTypes();
|
||||
nodePinTypes.AddRange(Constants.NumberTypes);
|
||||
NodePinTypes = new ObservableCollection<Type>(nodePinTypes);
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
// Set up extra modules
|
||||
@ -49,7 +53,8 @@ public class DataModelNodeCustomViewModel : CustomNodeViewModel
|
||||
|
||||
public PluginSetting<bool> ShowFullPaths { get; }
|
||||
public PluginSetting<bool> ShowDataModelValues { get; }
|
||||
|
||||
public ObservableCollection<Type> NodePinTypes { get; }
|
||||
|
||||
public ObservableCollection<Module>? Modules
|
||||
{
|
||||
get => _modules;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user