Core - Only let event conditions react to what happens after they start watching

- A trigger from before the condition watched its event, for example
  long before the profile was activated, counted as new and played the
  element once. Triggers now count from the moment the condition starts
  watching its path.
- A condition on a plain value treated the first value it saw as a
  change and played the element on the first frame. The first value is
  now taken as the starting value.
This commit is contained in:
RobertBeekman committed 2026-10-20 09:28:57 +02:00
1 parent edc7ec7705
commit 3f4c69cae2
2 files changed
+40 -10

No files matched your search

@@ -79,16 +79,24 @@ public class EventConditionTests : RenderTestBase
} }
[Fact] [Fact]
public void Play_EventTriggeredBeforeTheConditionExisted_StillPlaysTheLayer() public void Play_EventTriggeredBeforeTheConditionExisted_DoesNotPlayTheLayer()
{ {
DataModel.Event.Trigger(); DataModel.Event.Trigger();
(Layer layer, _) = AddLayer(); (Layer layer, _) = AddLayer();
using RenderFrame frame = Render(layer.Profile); using RenderFrame frame = Render(layer.Profile);
// Pinned as-is: the condition starts out having seen no triggers at all, so a trigger from before it was created ShouldBeOff(frame);
// (for example long before the profile was activated) still counts as new and plays the layer once. Looks like }
// the condition should only react to triggers that happen after it started watching.
[Fact]
public void Play_EventTriggeredAfterTheConditionExisted_PlaysTheLayer_EvenBeforeTheFirstFrame()
{
(Layer layer, _) = AddLayer();
DataModel.Event.Trigger();
using RenderFrame frame = Render(layer.Profile);
ShouldBeOn(frame); ShouldBeOn(frame);
} }
@@ -416,15 +424,14 @@ public class EventConditionTests : RenderTestBase
} }
[Fact] [Fact]
public void PathToAValue_PlaysOnTheFirstFrame() public void PathToAValue_DoesNotPlayOnTheFirstFrame()
{ {
(Layer layer, _) = AddLayer(eventPath: "Integer"); (Layer layer, _) = AddLayer(eventPath: "Integer");
using RenderFrame frame = Render(layer.Profile); using RenderFrame frame = Render(layer.Profile);
// Pinned as-is: the last seen value starts out empty, so the first frame always sees the value as changed (0 is // The first frame only learns the starting value, nothing changed yet
// not empty) and plays the layer even though nothing changed. ShouldBeOff(frame);
ShouldBeOn(frame);
} }
[Fact] [Fact]
@@ -17,8 +17,10 @@ public class EventCondition : CorePropertyChanged, INodeScriptCondition
private NodeScript<bool> _script; private NodeScript<bool> _script;
private DefaultNode _startNode; private DefaultNode _startNode;
private DataModelPath? _eventPath; private DataModelPath? _eventPath;
private DateTime _lastProcessedTrigger; // Only what happens after the condition starts watching its path counts, see StartWatching
private DateTime _lastProcessedTrigger = DateTime.Now;
private object? _lastProcessedValue; private object? _lastProcessedValue;
private bool _hasProcessedValue;
private EventOverlapMode _overlapMode; private EventOverlapMode _overlapMode;
private EventToggleOffMode _toggleOffMode; private EventToggleOffMode _toggleOffMode;
private EventTriggerMode _triggerMode; private EventTriggerMode _triggerMode;
@@ -64,7 +66,11 @@ public class EventCondition : CorePropertyChanged, INodeScriptCondition
public DataModelPath? EventPath public DataModelPath? EventPath
{ {
get => _eventPath; get => _eventPath;
set => SetAndNotify(ref _eventPath, value); set
{
if (SetAndNotify(ref _eventPath, value))
StartWatching();
}
} }
/// <summary> /// <summary>
@@ -243,6 +249,15 @@ public class EventCondition : CorePropertyChanged, INodeScriptCondition
Script.AddNode(newStartNode); Script.AddNode(newStartNode);
} }
private void StartWatching()
{
// Triggers and values from before the condition watched the path don't count, otherwise for example an event that
// triggered long before the profile was activated would still play the element once
_lastProcessedTrigger = DateTime.Now;
_lastProcessedValue = null;
_hasProcessedValue = false;
}
private bool Evaluate() private bool Evaluate()
{ {
if (EventPath == null) if (EventPath == null)
@@ -258,6 +273,14 @@ public class EventCondition : CorePropertyChanged, INodeScriptCondition
} }
else if (_startNode is EventConditionValueChangedStartNode valueChangedNode) else if (_startNode is EventConditionValueChangedStartNode valueChangedNode)
{ {
// The first value seen is where the value starts, not a change
if (!_hasProcessedValue)
{
_lastProcessedValue = value;
_hasProcessedValue = true;
return false;
}
if (Equals(value, _lastProcessedValue)) if (Equals(value, _lastProcessedValue))
return false; return false;