diff --git a/src/gg.regression.unity.bots/Runtime/Scripts/RGOverlay/RGSegmentEntry.cs b/src/gg.regression.unity.bots/Runtime/Scripts/RGOverlay/RGSegmentEntry.cs
index 0e4b98b1..cdf60adf 100644
--- a/src/gg.regression.unity.bots/Runtime/Scripts/RGOverlay/RGSegmentEntry.cs
+++ b/src/gg.regression.unity.bots/Runtime/Scripts/RGOverlay/RGSegmentEntry.cs
@@ -31,7 +31,7 @@ public class RGSegmentEntry : MonoBehaviour
* Indicates whether the Segment or Segment List is overridden by a local file.
*/
public bool isOverride;
-
+
/**
* UI component fields
*/
@@ -49,7 +49,7 @@ public class RGSegmentEntry : MonoBehaviour
[SerializeField]
public GameObject segmentListIndicatorComponent;
-
+
[SerializeField]
public GameObject overrideIndicator;
@@ -84,8 +84,8 @@ public void Start()
resourcePathComponent.gameObject.SetActive(false);
}
}
-
- // set indicator that this Segment is being overriden by a local file, within a build
+
+ // set indicator that this Segment is being overriden by a local file, within a build
overrideIndicator.gameObject.SetActive(isOverride);
// assign values to the UI components
@@ -141,7 +141,8 @@ private void OnPlay()
}
// play the segment
- playbackController.SetDataContainer(new BotSegmentsPlaybackContainer(segmentList.segments, new List(), sessionId));
+ playbackController.SetDataContainer(new BotSegmentsPlaybackContainer(new List() {segmentList}, new List(), sessionId));
+
playbackController.Play();
}
}
diff --git a/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/BotSegmentZipParser.cs b/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/BotSegmentZipParser.cs
index b8551942..827ca1fa 100644
--- a/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/BotSegmentZipParser.cs
+++ b/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/BotSegmentZipParser.cs
@@ -4,9 +4,7 @@
using System.IO.Compression;
using System.Linq;
using Newtonsoft.Json;
-using RegressionGames.StateRecorder.BotSegments.JsonConverters;
using RegressionGames.StateRecorder.BotSegments.Models;
-using StateRecorder.BotSegments;
namespace RegressionGames.StateRecorder.BotSegments
{
@@ -66,9 +64,9 @@ public static IOrderedEnumerable OrderZipJsonEntries(IEnumerabl
return entries;
}
- public static List ParseBotSegmentZipFromSystemPath(string zipFilePath, out string sessionId)
+ public static List ParseBotSegmentZipFromSystemPath(string zipFilePath, out string sessionId)
{
- List results = new();
+ List results = new();
sessionId = null;
@@ -100,17 +98,7 @@ public static List ParseBotSegmentZipFromSystemPath(string zipFilePa
break;
}
- foreach (var botSegment in botSegmentList.segments)
- {
- botSegment.Replay_SegmentNumber = replayNumber++;
-
- if (sessionId == null)
- {
- sessionId = botSegment.sessionId;
- }
-
- results.Add(botSegment);
- }
+ results.Add(botSegmentList);
}
catch (Exception)
{
@@ -132,7 +120,16 @@ public static List ParseBotSegmentZipFromSystemPath(string zipFilePa
sessionId = frameData.sessionId;
}
- results.Add(frameData);
+ results.Add(new BotSegmentList()
+ {
+ segments = new List()
+ {
+ frameData
+ },
+ name = "BotSegmentList for BotSegment - " + frameData.name,
+ description = "BotSegmentList for BotSegment - " + frameData.description,
+ validations = new()
+ });
}
catch (Exception ex)
{
diff --git a/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/BotSegmentsPlaybackContainer.cs b/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/BotSegmentsPlaybackContainer.cs
index 8a3201e4..7dadb2e0 100644
--- a/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/BotSegmentsPlaybackContainer.cs
+++ b/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/BotSegmentsPlaybackContainer.cs
@@ -8,9 +8,11 @@ namespace RegressionGames.StateRecorder.BotSegments
public class BotSegmentsPlaybackContainer
{
- private readonly List _botSegments;
+
+ private readonly List _botSegmentLists;
+ private int _botSegmentListIndex = 0;
private int _botSegmentIndex = 0;
-
+
/**
* A top-level set of validations to run for an entire sequence of segments
*/
@@ -18,51 +20,59 @@ public class BotSegmentsPlaybackContainer
public readonly string SessionId;
- public BotSegmentsPlaybackContainer(IEnumerable segments, IEnumerable validations, string sessionId = null)
+ public BotSegmentsPlaybackContainer(IEnumerable segmentLists, IEnumerable validations, string sessionId = null)
{
var replayNumber = 1; // 1 to align with the actual numbers in the recording
- _botSegments = new(segments);
+ _botSegmentLists = new(segmentLists);
+ _botSegmentLists.ForEach(a => a.segments.ForEach(b => b.Replay_SegmentNumber = replayNumber++));
Validations = new(validations);
- _botSegments.ForEach(a => a.Replay_SegmentNumber = replayNumber++);
this.SessionId = sessionId ?? Guid.NewGuid().ToString("n");
}
public void Reset()
{
// sets indexes back to 0
- _botSegmentIndex = 0;
+ _botSegmentListIndex = 0;
- // reset all the tracking flags
- foreach (var botSegment in _botSegments)
+ // reset all the tracking flags in the segmentlists / segments
+ _botSegmentLists.ForEach(a =>
{
- botSegment.ReplayReset();
- }
-
+ a.segments.ForEach(b => b.ReplayReset());
+ a.validations.ForEach(b => b.ReplayReset());
+ });
+
// reset all the top-level validations
foreach (var validation in Validations)
{
validation.ReplayReset();
}
- }
- public BotSegment DequeueBotSegment()
- {
- if (_botSegmentIndex < _botSegments.Count)
- {
- return _botSegments[_botSegmentIndex++];
- }
-
- return null;
}
- public BotSegment PeekBotSegment()
+ /**
+ * Returns the next bot segment to evaluate and also provides the current segmentList level validations
+ */
+ public BotSegment DequeueBotSegment(out List segmentListValidations)
{
- if (_botSegmentIndex < _botSegments.Count)
+ while (_botSegmentListIndex < _botSegmentLists.Count)
{
- // do not update index
- return _botSegments[_botSegmentIndex];
+ var segmentList = _botSegmentLists[_botSegmentListIndex];
+ if (_botSegmentIndex < segmentList.segments.Count)
+ {
+ var segment = segmentList.segments[_botSegmentIndex++];
+ segmentListValidations = segmentList.validations;
+ return segment;
+ }
+ else
+ {
+ // move to the next segmentlist starting on the 0th segment in that list
+ _botSegmentIndex = 0;
+ ++_botSegmentListIndex;
+ }
+
}
+ segmentListValidations = new List();
return null;
}
}
diff --git a/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/BotSegmentsPlaybackController.cs b/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/BotSegmentsPlaybackController.cs
index 631225bb..cb65809a 100644
--- a/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/BotSegmentsPlaybackController.cs
+++ b/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/BotSegmentsPlaybackController.cs
@@ -51,6 +51,8 @@ public class BotSegmentsPlaybackController : MonoBehaviour
// This is done this way to allow situations like when loading screens (UI) are changing while game objects are loading in the background and the process is not consistent/deterministic between the 2
private readonly List _nextBotSegments = new();
+ private List _botSegmentListValidations = new();
+
// helps indicate if we made it through the full replay successfully
private bool? _replaySuccessful;
@@ -108,6 +110,21 @@ private void ProcessBotSegments()
ProcessBotSegmentAction(nextBotSegment, transformStatuses, entityStatuses);
}
+ // Run (and potentially end) the validations for this segment
+ nextBotSegment.ProcessValidation();
+
+ // Also run the validations for the botsegmentList if they exist
+ foreach (var validation in _botSegmentListValidations)
+ {
+ validation.ProcessValidation(nextBotSegment.Replay_SegmentNumber);
+ }
+
+ // Also run the validations for the entire list of segments if they exist
+ foreach (var validation in _dataPlaybackContainer.Validations)
+ {
+ validation.ProcessValidation(nextBotSegment.Replay_SegmentNumber);
+ }
+
var matched = nextBotSegment.Replay_Matched || nextBotSegment.endCriteria == null || nextBotSegment.endCriteria.Count == 0 || KeyFrameEvaluator.Evaluator.Matched(
nextBotSegmentIndex == 0,
nextBotSegment.Replay_SegmentNumber,
@@ -192,7 +209,7 @@ private void ProcessBotSegments()
{
if (_nextBotSegments.Count < 2)
{
- var next = _dataPlaybackContainer.DequeueBotSegment();
+ var next = _dataPlaybackContainer.DequeueBotSegment(out _botSegmentListValidations);
if (next != null)
{
_lastTimeLoggedKeyFrameConditions = now;
@@ -207,7 +224,7 @@ private void ProcessBotSegments()
else
{
// segment list empty.. dequeue another
- var next = _dataPlaybackContainer.DequeueBotSegment();
+ var next = _dataPlaybackContainer.DequeueBotSegment(out _botSegmentListValidations);
if (next != null)
{
_lastTimeLoggedKeyFrameConditions = now;
@@ -282,21 +299,21 @@ private void ProcessBotSegments()
* Thus an exploration action can be invoked in between any 2 passes of the main action when an error occurs. With that concept of update to update interleaving, it should be obvious why actions implementing IKeyMomentExploration must be
* written to expect to be interrupted at any point.
*/
- private void ProcessBotSegmentAction(BotSegment firstActionSegment, Dictionary transformStatuses, Dictionary entityStatuses)
+ private void ProcessBotSegmentAction(BotSegment actionSegment, Dictionary transformStatuses, Dictionary entityStatuses)
{
var now = Time.unscaledTime;
- string logPrefix = $"({firstActionSegment.Replay_SegmentNumber}) - Bot Segment - ";
+ string logPrefix = $"({actionSegment.Replay_SegmentNumber}) - Bot Segment - ";
try
{
- if (firstActionSegment.botAction?.IsCompleted == false)
+ if (actionSegment.botAction?.IsCompleted == false)
{
// allow the main action to retry between every exploratory action
- var didAction = firstActionSegment.ProcessAction(transformStatuses, entityStatuses, out var error);
+ var didAction = actionSegment.ProcessAction(transformStatuses, entityStatuses, out var error);
if (error == null)
{
// we're going to 'pause' exploring, but not reset the exploration state quite yet until this action fully finishes
- _explorationDriver.PauseExploring(firstActionSegment.Replay_SegmentNumber);
+ _explorationDriver.PauseExploring(actionSegment.Replay_SegmentNumber);
if (didAction && _explorationDriver.ExplorationState == ExplorationState.STOPPED)
{
// for every non error action, reset the timer
@@ -312,7 +329,7 @@ private void ProcessBotSegmentAction(BotSegment firstActionSegment, Dictionary()?.SetKeyFrameWarningText(null);
- _explorationDriver.StopExploring(firstActionSegment.Replay_SegmentNumber);
- _explorationDriver.ReportPreviouslyCompletedAction(firstActionSegment.botAction.data);
- }
-
- // Run (and potentially end) the validations for this segment
- firstActionSegment.ProcessValidation();
-
- // Also run the validations for the entire list of segments if they exist
- foreach (var validation in _dataPlaybackContainer.Validations)
- {
- validation.ProcessValidation(-1);
+ _explorationDriver.StopExploring(actionSegment.Replay_SegmentNumber);
+ _explorationDriver.ReportPreviouslyCompletedAction(actionSegment.botAction.data);
}
-
+
}
catch (Exception ex)
{
@@ -393,13 +401,14 @@ public void LateUpdate()
{
if (_dataPlaybackContainer != null)
{
-
+ var currentSegmentNumber = _nextBotSegments.Count > 0 ? _nextBotSegments[0].Replay_SegmentNumber : -1;
+
// If there are top-level validations running, let's make sure those are prepared before we
// process the segments.
var validationsReady = true;
foreach (var validation in _dataPlaybackContainer.Validations)
{
- if (!validation.ProcessValidation(-1))
+ if (!validation.ProcessValidation(currentSegmentNumber))
{
validationsReady = false;
break;
@@ -575,16 +584,18 @@ public void Pause()
{
_playState = PlayState.Paused;
+ var currentSegmentNumber = _nextBotSegments.Count > 0 ? _nextBotSegments[0].Replay_SegmentNumber : -1;
+
foreach (var nextBotSegment in _nextBotSegments)
{
nextBotSegment.PauseAction();
nextBotSegment.PauseValidations();
}
-
+
// Also pause the top-level validations
foreach (var validation in _dataPlaybackContainer.Validations)
{
- validation.PauseValidation(-1);
+ validation.PauseValidation(currentSegmentNumber);
}
}
}
@@ -606,16 +617,18 @@ public void Play()
// resume
_playState = PlayState.Playing;
+ var currentSegmentNumber = _nextBotSegments.Count > 0 ? _nextBotSegments[0].Replay_SegmentNumber : -1;
+
foreach (var nextBotSegment in _nextBotSegments)
{
nextBotSegment.UnPauseAction();
nextBotSegment.UnPauseValidations();
}
-
+
// Also unpause the top-level validations
foreach (var validation in _dataPlaybackContainer.Validations)
{
- validation.UnPauseValidation(-1);
+ validation.UnPauseValidation(currentSegmentNumber);
}
}
}
@@ -647,13 +660,15 @@ public void UnloadSegmentsAndReset()
nextBotSegment.StopValidations();
}
}
-
+
+ var currentSegmentNumber = _nextBotSegments.Count > 0 ? _nextBotSegments[0].Replay_SegmentNumber : -1;
+
// Also wrap up the top-level validations if they exist
if (_dataPlaybackContainer != null)
{
foreach (var validation in _dataPlaybackContainer.Validations)
{
- validation.StopValidation(-1);
+ validation.StopValidation(currentSegmentNumber);
}
}
@@ -687,16 +702,18 @@ public void UnloadSegmentsAndReset()
public void Stop()
{
-
+
+ var currentSegmentNumber = _nextBotSegments.Count > 0 ? _nextBotSegments[0].Replay_SegmentNumber : -1;
+
// Make sure to stop any running validations
if (_dataPlaybackContainer != null)
{
foreach (var validation in _dataPlaybackContainer.Validations)
{
- validation.StopValidation(-1);
+ validation.StopValidation(currentSegmentNumber);
}
}
-
+
_nextBotSegments.Clear();
_playState = PlayState.Stopped;
_loopCount = -1;
@@ -784,7 +801,7 @@ public void Update()
#endif
RGUtils.ConfigureInputSettings();
_playState = PlayState.Playing;
- _nextBotSegments.Add(_dataPlaybackContainer.DequeueBotSegment());
+ _nextBotSegments.Add(_dataPlaybackContainer.DequeueBotSegment(out _botSegmentListValidations));
// if starting to play, or on loop 1.. start recording
if (_loopCount < 2)
{
diff --git a/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/Models/BotSequence.cs b/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/Models/BotSequence.cs
index 11f1b23f..824f7bda 100644
--- a/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/Models/BotSequence.cs
+++ b/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/Models/BotSequence.cs
@@ -30,7 +30,7 @@ public class BotSequence
* A set of top-level validations to run on a sequence of segments
*/
public List validations = new();
-
+
/**
* Define the name of this sequence that will be seen in user interfaces and runtime summaries. This SHOULD NOT be null.
*/
@@ -497,7 +497,7 @@ public void Play()
}
sessionId ??= Guid.NewGuid().ToString();
- playbackController.SetDataContainer(new BotSegmentsPlaybackContainer(_segmentsToProcess.SelectMany(a => a.segments), validations, sessionId));
+ playbackController.SetDataContainer(new BotSegmentsPlaybackContainer(_segmentsToProcess, validations, sessionId));
ActiveBotSequence = this; // SetDataContainer clears this, so set it here before starting
playbackController.Play();
}
diff --git a/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/Models/IRGSegmentValidationData.cs b/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/Models/IRGSegmentValidationData.cs
index 708bfeea..2a6a832c 100644
--- a/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/Models/IRGSegmentValidationData.cs
+++ b/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/Models/IRGSegmentValidationData.cs
@@ -5,7 +5,7 @@ namespace StateRecorder.BotSegments.Models
{
public interface IRGSegmentValidationData
{
-
+
/**
* Attempts to conduct any preparation needed for validation. Returns true if the validations
* are ready to be run, and false otherwise. Implementors should make sure that this method
@@ -51,10 +51,10 @@ public interface IRGSegmentValidationData
* result.
*/
public SegmentValidationResultSetContainer GetResults();
-
+
public void WriteToStringBuilder(StringBuilder stringBuilder);
-
- public int EffectiveApiVersion();
-
+
+ public int EffectiveApiVersion();
+
}
-}
\ No newline at end of file
+}
diff --git a/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/Models/SegmentValidation.cs b/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/Models/SegmentValidation.cs
index e1983757..b4b9fbf1 100644
--- a/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/Models/SegmentValidation.cs
+++ b/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/BotSegments/Models/SegmentValidation.cs
@@ -89,4 +89,4 @@ public override string ToString()
}
}
-}
\ No newline at end of file
+}
diff --git a/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/ReplayToolbarManager.cs b/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/ReplayToolbarManager.cs
index e9a666da..e33b1a54 100644
--- a/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/ReplayToolbarManager.cs
+++ b/src/gg.regression.unity.bots/Runtime/Scripts/StateRecorder/ReplayToolbarManager.cs
@@ -237,8 +237,9 @@ private void ProcessDataContainerZipAndSetup(String filePath)
{
try
{
+ var botSegmentLists = BotSegmentZipParser.ParseBotSegmentZipFromSystemPath(filePath, out var sessionId);
// do this on background thread
- var dataContainer = new BotSegmentsPlaybackContainer(BotSegmentZipParser.ParseBotSegmentZipFromSystemPath(filePath, out var sessionId), new List(), sessionId);
+ var dataContainer = new BotSegmentsPlaybackContainer(botSegmentLists, new List(), sessionId);
_playbackContainer = dataContainer;
}
catch (Exception e)
diff --git a/src/gg.regression.unity.bots/Tests/TestFramework/Scripts/RGTestUtils.cs b/src/gg.regression.unity.bots/Tests/TestFramework/Scripts/RGTestUtils.cs
index 072bbd08..ff603643 100644
--- a/src/gg.regression.unity.bots/Tests/TestFramework/Scripts/RGTestUtils.cs
+++ b/src/gg.regression.unity.bots/Tests/TestFramework/Scripts/RGTestUtils.cs
@@ -130,7 +130,11 @@ public static IEnumerator StartPlaybackFromDirectory(string recordingPath, Actio
{
RGDebug.LogInfo("Loading and starting playback recording from " + recordingPath);
var playbackController = Object.FindObjectOfType();
- var botSegments = BotSegmentDirectoryParser.ParseBotSegmentSystemDirectory(recordingPath, out var sessionId);
+ var botSegments = BotSegmentDirectoryParser.ParseBotSegmentSystemDirectory(recordingPath, out var sessionId).Select(a=>new BotSegmentList("BotSegmentList for BotSegment - " + a.name, new List() {a})
+ {
+ description = "BotSegmentList for BotSegment - " + a.description,
+ validations = new()
+ });
var replayData = new BotSegmentsPlaybackContainer(botSegments, new List(), sessionId);
playbackController.SetDataContainer(replayData);
playbackController.Play();
@@ -317,7 +321,11 @@ public static IEnumerator StartBotSegment(BotSegment botSegment, Action();
- playbackController.SetDataContainer(new BotSegmentsPlaybackContainer(new[] { botSegment }, validations ?? new List()));
+ playbackController.SetDataContainer(new BotSegmentsPlaybackContainer(new List() {new BotSegmentList("BotSegmentList for BotSegment - " + botSegment.name, new List() {botSegment})
+ {
+ description = "BotSegmentList for BotSegment - " + botSegment.description,
+ validations = new()
+ }}, validations ?? new List()));
playbackController.Play();
@@ -363,7 +371,7 @@ public static IEnumerator StartBotSegmentList(BotSegmentList botSegmentList, Act
var playbackController = Object.FindObjectOfType();
- playbackController.SetDataContainer(new BotSegmentsPlaybackContainer(botSegmentList.segments, validations ?? new List()));
+ playbackController.SetDataContainer(new BotSegmentsPlaybackContainer(new List() {botSegmentList}, validations ?? new List()));
playbackController.Play();