diff --git a/src/Artemis.Core/Artemis.Core.csproj.DotSettings b/src/Artemis.Core/Artemis.Core.csproj.DotSettings
index 7d6c52363..5a6e7bef3 100644
--- a/src/Artemis.Core/Artemis.Core.csproj.DotSettings
+++ b/src/Artemis.Core/Artemis.Core.csproj.DotSettings
@@ -68,6 +68,7 @@
True
True
True
+ True
True
True
True
diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionEvent.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionEvent.cs
index 49a2a0072..8ae6d5411 100644
--- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionEvent.cs
+++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionEvent.cs
@@ -11,9 +11,8 @@ namespace Artemis.Core
public class DataModelConditionEvent : DataModelConditionPart
{
private bool _disposed;
- private IDataModelEvent? _event;
- private bool _eventTriggered;
private bool _reinitializing;
+ private DateTime _lastTrigger;
///
/// Creates a new instance of the class
@@ -53,22 +52,21 @@ namespace Artemis.Core
if (_disposed)
throw new ObjectDisposedException("DataModelConditionEvent");
- // Ensure the event has not been replaced
- if (EventPath?.GetValue() is IDataModelEvent dataModelEvent && _event != dataModelEvent)
- SubscribeToDataModelEvent(dataModelEvent);
-
- // Only evaluate to true once every time the event has been triggered
- if (!_eventTriggered)
+ if (EventPath?.GetValue() is not IDataModelEvent dataModelEvent)
+ return false;
+ // Only evaluate to true once every time the event has been triggered since the last evaluation
+ if (dataModelEvent.LastTrigger <= _lastTrigger)
return false;
- _eventTriggered = false;
+ _lastTrigger = DateTime.Now;
// If there is a child (root group), it must evaluate to true whenever the event triggered
if (Children.Any())
- return Children[0].EvaluateObject(_event?.LastEventArgumentsUntyped);
+ return Children[0].EvaluateObject(dataModelEvent.LastEventArgumentsUntyped);
// If there are no children, we always evaluate to true whenever the event triggered
return true;
+
}
///
@@ -132,7 +130,7 @@ namespace Artemis.Core
// Target list
EventPath?.Save();
Entity.EventPath = EventPath?.Entity;
-
+
// Children
Entity.Children.Clear();
Entity.Children.AddRange(Children.Select(c => c.GetEntity()));
@@ -172,16 +170,9 @@ namespace Artemis.Core
Entity.Children.Clear();
AddChild(new DataModelConditionGroup(this));
}
- }
- private void SubscribeToDataModelEvent(IDataModelEvent dataModelEvent)
- {
- if (_event != null)
- _event.EventTriggered -= OnEventTriggered;
-
- _event = dataModelEvent;
- if (_event != null)
- _event.EventTriggered += OnEventTriggered;
+ if (EventPath?.GetValue() is IDataModelEvent dataModelEvent)
+ _lastTrigger = dataModelEvent.LastTrigger;
}
private Type? GetEventArgumentType()
@@ -212,11 +203,6 @@ namespace Artemis.Core
#region Event handlers
- private void OnEventTriggered(object? sender, EventArgs e)
- {
- _eventTriggered = true;
- }
-
private void EventPathOnPathValidated(object? sender, EventArgs e)
{
if (_reinitializing)
diff --git a/src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs b/src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs
new file mode 100644
index 000000000..30532aa2b
--- /dev/null
+++ b/src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs
@@ -0,0 +1,71 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Artemis.Core.DataModelExpansions;
+using Artemis.Core.Modules;
+using EmbedIO;
+using Newtonsoft.Json;
+
+namespace Artemis.Core.Services
+{
+ ///
+ /// Represents a plugin web endpoint receiving an object of type and returning any
+ /// or .
+ /// Note: Both will be deserialized and serialized respectively using JSON.
+ ///
+ public class DataModelJsonPluginEndPoint : PluginEndPoint where T : DataModel
+ {
+ private readonly Module? _module;
+ private readonly DataModelExpansion? _dataModelExpansion;
+
+ internal DataModelJsonPluginEndPoint(Module module, string name, PluginsModule pluginsModule) : base(module, name, pluginsModule)
+ {
+ _module = module ?? throw new ArgumentNullException(nameof(module));
+
+ ThrowOnFail = true;
+ Accepts = MimeType.Json;
+ }
+
+ internal DataModelJsonPluginEndPoint(DataModelExpansion dataModelExpansion, string name, PluginsModule pluginsModule) : base(dataModelExpansion, name, pluginsModule)
+ {
+ _dataModelExpansion = dataModelExpansion ?? throw new ArgumentNullException(nameof(dataModelExpansion));
+
+ ThrowOnFail = true;
+ Accepts = MimeType.Json;
+ }
+
+ ///
+ /// Whether or not the end point should throw an exception if deserializing the received JSON fails.
+ /// If set to malformed JSON is silently ignored; if set to malformed
+ /// JSON throws a .
+ ///
+ public bool ThrowOnFail { get; set; }
+
+ #region Overrides of PluginEndPoint
+
+ ///
+ protected override async Task ProcessRequest(IHttpContext context)
+ {
+ if (context.Request.HttpVerb != HttpVerbs.Post && context.Request.HttpVerb != HttpVerbs.Put)
+ throw HttpException.MethodNotAllowed("This end point only accepts POST and PUT calls");
+
+ context.Response.ContentType = MimeType.Json;
+
+ using TextReader reader = context.OpenRequestText();
+ try
+ {
+ if (_module != null)
+ JsonConvert.PopulateObject(await reader.ReadToEndAsync(), _module.DataModel);
+ else
+ JsonConvert.PopulateObject(await reader.ReadToEndAsync(), _dataModelExpansion!.DataModel);
+ }
+ catch (JsonException)
+ {
+ if (ThrowOnFail)
+ throw;
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/WebServer/EndPoints/EndpointExceptionEventArgs.cs b/src/Artemis.Core/Services/WebServer/EndPoints/EventArgs/EndpointExceptionEventArgs.cs
similarity index 100%
rename from src/Artemis.Core/Services/WebServer/EndPoints/EndpointExceptionEventArgs.cs
rename to src/Artemis.Core/Services/WebServer/EndPoints/EventArgs/EndpointExceptionEventArgs.cs
diff --git a/src/Artemis.Core/Services/WebServer/EndPoints/EventArgs/EndpointRequestEventArgs.cs b/src/Artemis.Core/Services/WebServer/EndPoints/EventArgs/EndpointRequestEventArgs.cs
new file mode 100644
index 000000000..6b483cc06
--- /dev/null
+++ b/src/Artemis.Core/Services/WebServer/EndPoints/EventArgs/EndpointRequestEventArgs.cs
@@ -0,0 +1,21 @@
+using System;
+using EmbedIO;
+
+namespace Artemis.Core.Services
+{
+ ///
+ /// Provides data about endpoint request related events
+ ///
+ public class EndpointRequestEventArgs : EventArgs
+ {
+ internal EndpointRequestEventArgs(IHttpContext context)
+ {
+ Context = context;
+ }
+
+ ///
+ /// Gets the HTTP context of the request
+ ///
+ public IHttpContext Context { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/WebServer/EndPoints/PluginEndPoint.cs b/src/Artemis.Core/Services/WebServer/EndPoints/PluginEndPoint.cs
index 504fd0eff..c62c41fe3 100644
--- a/src/Artemis.Core/Services/WebServer/EndPoints/PluginEndPoint.cs
+++ b/src/Artemis.Core/Services/WebServer/EndPoints/PluginEndPoint.cs
@@ -57,6 +57,16 @@ namespace Artemis.Core.Services
///
public event EventHandler? RequestException;
+ ///
+ /// Occurs whenever a request is about to be processed
+ ///
+ public event EventHandler? ProcessingRequest;
+
+ ///
+ /// Occurs whenever a request was processed
+ ///
+ public event EventHandler? ProcessedRequest;
+
///
/// Called whenever the end point has to process a request
///
@@ -72,11 +82,29 @@ namespace Artemis.Core.Services
RequestException?.Invoke(this, new EndpointExceptionEventArgs(e));
}
+ ///
+ /// Invokes the event
+ ///
+ protected virtual void OnProcessingRequest(IHttpContext context)
+ {
+ ProcessingRequest?.Invoke(this, new EndpointRequestEventArgs(context));
+ }
+
+ ///
+ /// Invokes the event
+ ///
+ protected virtual void OnProcessedRequest(IHttpContext context)
+ {
+ ProcessedRequest?.Invoke(this, new EndpointRequestEventArgs(context));
+ }
+
internal async Task InternalProcessRequest(IHttpContext context)
{
try
{
+ OnProcessingRequest(context);
await ProcessRequest(context);
+ OnProcessedRequest(context);
}
catch (Exception e)
{
diff --git a/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs b/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs
index 704a4a19c..ef98d3fa0 100644
--- a/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs
+++ b/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs
@@ -1,5 +1,7 @@
using System;
using System.Threading.Tasks;
+using Artemis.Core.DataModelExpansions;
+using Artemis.Core.Modules;
using EmbedIO;
using EmbedIO.WebApi;
@@ -43,6 +45,24 @@ namespace Artemis.Core.Services
/// The resulting end point
JsonPluginEndPoint AddResponsiveJsonEndPoint(PluginFeature feature, string endPointName, Func requestHandler);
+ ///
+ /// Adds a new endpoint that directly maps received JSON to the data model of the provided .
+ ///
+ /// The data model type of the module
+ /// The module whose datamodel to apply the received JSON to
+ /// The name of the end point, must be unique
+ /// The resulting end point
+ DataModelJsonPluginEndPoint AddDataModelJsonEndPoint(Module module, string endPointName) where T : DataModel;
+
+ ///
+ /// Adds a new endpoint that directly maps received JSON to the data model of the provided .
+ ///
+ /// The data model type of the module
+ /// The data model expansion whose datamodel to apply the received JSON to
+ /// The name of the end point, must be unique
+ /// The resulting end point
+ DataModelJsonPluginEndPoint AddDataModelJsonEndPoint(DataModelExpansion dataModelExpansion, string endPointName) where T : DataModel;
+
///
/// Adds a new endpoint for the given plugin feature receiving an a .
///
diff --git a/src/Artemis.Core/Services/WebServer/WebServerService.cs b/src/Artemis.Core/Services/WebServer/WebServerService.cs
index e19e6a4a9..8de5ce9e4 100644
--- a/src/Artemis.Core/Services/WebServer/WebServerService.cs
+++ b/src/Artemis.Core/Services/WebServer/WebServerService.cs
@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
+using Artemis.Core.DataModelExpansions;
+using Artemis.Core.Modules;
using EmbedIO;
using EmbedIO.WebApi;
using Newtonsoft.Json;
@@ -125,6 +127,29 @@ namespace Artemis.Core.Services
return endPoint;
}
+ public DataModelJsonPluginEndPoint AddDataModelJsonEndPoint(Module module, string endPointName) where T : DataModel
+ {
+ if (module == null) throw new ArgumentNullException(nameof(module));
+ if (endPointName == null) throw new ArgumentNullException(nameof(endPointName));
+ DataModelJsonPluginEndPoint endPoint = new(module, endPointName, PluginsModule);
+ PluginsModule.AddPluginEndPoint(endPoint);
+ return endPoint;
+ }
+
+ public DataModelJsonPluginEndPoint AddDataModelJsonEndPoint(DataModelExpansion dataModelExpansion, string endPointName) where T : DataModel
+ {
+ if (dataModelExpansion == null) throw new ArgumentNullException(nameof(dataModelExpansion));
+ if (endPointName == null) throw new ArgumentNullException(nameof(endPointName));
+ DataModelJsonPluginEndPoint endPoint = new(dataModelExpansion, endPointName, PluginsModule);
+ PluginsModule.AddPluginEndPoint(endPoint);
+ return endPoint;
+ }
+
+ private void HandleDataModelRequest(Module module, T value) where T : DataModel
+ {
+
+ }
+
public void RemovePluginEndPoint(PluginEndPoint endPoint)
{
PluginsModule.RemovePluginEndPoint(endPoint);
diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml
index cc49f3d59..05c33df00 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml
+++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml
@@ -200,7 +200,7 @@
+ IsChecked="{Binding Path=EventOverlapMode, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Restart}}">
RESTART
@@ -215,7 +215,7 @@
+ IsChecked="{Binding Path=EventOverlapMode, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Ignore}}">
IGNORE
@@ -230,7 +230,7 @@
+ IsChecked="{Binding Path=EventOverlapMode, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Copy}}">
COPY
diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs
index a04d3d563..3f79b19e3 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs
@@ -38,7 +38,13 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
public RenderProfileElement RenderProfileElement
{
get => _renderProfileElement;
- set => SetAndNotify(ref _renderProfileElement, value);
+ set
+ {
+ if (!SetAndNotify(ref _renderProfileElement, value)) return;
+ NotifyOfPropertyChange(nameof(DisplayContinuously));
+ NotifyOfPropertyChange(nameof(AlwaysFinishTimeline));
+ NotifyOfPropertyChange(nameof(EventOverlapMode));
+ }
}
public bool DisplayContinuously
@@ -65,6 +71,17 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
}
}
+ public TimeLineEventOverlapMode EventOverlapMode
+ {
+ get => RenderProfileElement?.Timeline.EventOverlapMode ?? TimeLineEventOverlapMode.Restart;
+ set
+ {
+ if (RenderProfileElement == null || RenderProfileElement?.Timeline.EventOverlapMode == value) return;
+ RenderProfileElement.Timeline.EventOverlapMode = value;
+ _profileEditorService.UpdateSelectedProfileElement();
+ }
+ }
+
public bool ConditionBehaviourEnabled => RenderProfileElement != null;
protected override void OnInitialActivate()
@@ -119,5 +136,10 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
DisplayStartHint = !RenderProfileElement.DisplayCondition.Children.Any();
IsEventCondition = RenderProfileElement.DisplayCondition.Children.Any(c => c is DataModelConditionEvent);
}
+
+ public void EventTriggerModeSelected()
+ {
+ _profileEditorService.UpdateSelectedProfileElement();
+ }
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugViewModel.cs b/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugViewModel.cs
index e2b83d7d0..0e0e97656 100644
--- a/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugViewModel.cs
@@ -127,7 +127,7 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
lock (MainDataModel)
{
- MainDataModel.Update(_dataModelUIService, null);
+ MainDataModel.Update(_dataModelUIService, new DataModelUpdateConfiguration(true));
}
}