diff --git a/src/gg.regression.unity.bots/Runtime/Resources/RegressionGames.exe b/src/gg.regression.unity.bots/Runtime/Resources/RegressionGames.exe index 72f8e6c5..cde23b71 100644 Binary files a/src/gg.regression.unity.bots/Runtime/Resources/RegressionGames.exe and b/src/gg.regression.unity.bots/Runtime/Resources/RegressionGames.exe differ diff --git a/src/gg.regression.unity.bots/Runtime/Scripts/ClientDashboard/RGTcpManager.cs b/src/gg.regression.unity.bots/Runtime/Scripts/ClientDashboard/RGTcpManager.cs index 5d3b9ff9..ece03aaf 100644 --- a/src/gg.regression.unity.bots/Runtime/Scripts/ClientDashboard/RGTcpManager.cs +++ b/src/gg.regression.unity.bots/Runtime/Scripts/ClientDashboard/RGTcpManager.cs @@ -17,7 +17,6 @@ namespace RegressionGames.ClientDashboard { - /// /// Starts and stops RGTcpServer, handles and sends messages to and from connected clients /// @@ -26,10 +25,16 @@ public class RGTcpManager : MonoBehaviour { // the last active sequence that was sent to the client private static BotSegmentsPlaybackController m_botSegmentsPlaybackController; - private static BotSequence m_startPlayingSequence = null; - private static ActiveSequence m_activeSequence = null; private static ReplayToolbarManager m_replayToolbarManager; + private static List m_availableBotSequences = new (); + private static List m_availableBotSegments = new(); + + private static ActiveSequence m_activeSequence = null; + private static BotSequence m_startPlayingSequence = null; + private static BotSegmentList m_startPlayingSegment = null; + private static bool m_shouldStopReplay = false; + public void Start() { @@ -52,6 +57,7 @@ public void Start() RGTcpServer.ProcessClientMessage += ProcessClientMessage; RGTcpServer.Start(); StartCoroutine(RGSequenceManager.ResolveSequenceFiles(ProcessAndSendSequences)); + ProcessAndSendSegments(); } /// @@ -73,17 +79,43 @@ private void Update() SendActiveSequence(); } - // check if we need to start playing a sequence + // check if we need to start playing a sequence or segment if (m_startPlayingSequence != null) { - var botManager = RGBotManager.GetInstance(); - if (botManager != null) + if (activeSequence == null) + { + var botManager = RGBotManager.GetInstance(); + if (botManager != null) + { + botManager.OnBeginPlaying(); + } + m_replayToolbarManager.selectedReplayFilePath = null; + m_startPlayingSequence.Play(); + } + m_startPlayingSequence = null; + m_startPlayingSegment = null; + m_shouldStopReplay = false; + } + else if (m_startPlayingSegment != null) + { + if (activeSequence == null) { - botManager.OnBeginPlaying(); + var botManager = RGBotManager.GetInstance(); + if (botManager != null) + { + botManager.OnBeginPlaying(); + } + m_botSegmentsPlaybackController.SetDataContainer(new BotSegmentsPlaybackContainer(m_startPlayingSegment.segments)); + m_botSegmentsPlaybackController.Play(); } - m_replayToolbarManager.selectedReplayFilePath = null; - m_startPlayingSequence.Play(); m_startPlayingSequence = null; + m_startPlayingSegment = null; + m_shouldStopReplay = false; + } + else if (m_shouldStopReplay) + { + m_replayToolbarManager.StopReplay(); + m_shouldStopReplay = false; } } @@ -120,6 +152,7 @@ private static void DidReloadScripts() var it = RGSequenceManager.ResolveSequenceFiles(ProcessAndSendSequences); while(it.MoveNext()){} + ProcessAndSendSegments(); } /// @@ -170,6 +203,7 @@ private static void OnClientHandshake(TcpClient client) { SendActiveSequence(); SendAvailableSequences(); + SendAvailableSegments(); } /// @@ -185,11 +219,23 @@ private static void ProcessClientMessage(TcpClient client, TcpMessage message) } case TcpMessageType.PlaySequence: { - var playSequenceData = (PlaySequenceTcpMessageData) message.payload; + var playSequenceData = (PlayResourceTcpMessageData) message.payload; var botSequence = BotSequence.LoadSequenceJsonFromPath(playSequenceData.resourcePath); m_startPlayingSequence = botSequence.Item3; break; } + case TcpMessageType.PlaySegment: + { + var playSegmentData = (PlayResourceTcpMessageData) message.payload; + var segmentList = BotSequence.CreateBotSegmentListForPath(playSegmentData.resourcePath, out var sessId); + m_startPlayingSegment = segmentList; + break; + } + case TcpMessageType.StopReplay: + { + m_shouldStopReplay = true; + break; + } } } @@ -207,6 +253,12 @@ private static void ProcessAndSendSequences(IDictionary seg.Item2).ToList(); + SendAvailableSegments(); + } + /// /// Returns the active bot sequence, if there is one /// @@ -261,6 +313,19 @@ private static void SendAvailableSequences([CanBeNull] TcpClient client = null) RGTcpServer.QueueMessage(message, client); } + private static void SendAvailableSegments([CanBeNull] TcpClient client = null) + { + var message = new TcpMessage + { + type = TcpMessageType.AvailableSegments, + payload = new AvailableSegmentsTcpMessageData + { + availableSegments = m_availableBotSegments + } + }; + RGTcpServer.QueueMessage(message, client); + } + private static void SendActiveSequence([CanBeNull] TcpClient client = null) { var message = new TcpMessage diff --git a/src/gg.regression.unity.bots/Runtime/Scripts/ClientDashboard/TcpMessage.cs b/src/gg.regression.unity.bots/Runtime/Scripts/ClientDashboard/TcpMessage.cs index 29bd18cd..8bc7cfc7 100644 --- a/src/gg.regression.unity.bots/Runtime/Scripts/ClientDashboard/TcpMessage.cs +++ b/src/gg.regression.unity.bots/Runtime/Scripts/ClientDashboard/TcpMessage.cs @@ -5,6 +5,7 @@ using RegressionGames.RemoteOrchestration.Models; using RegressionGames.RemoteOrchestration.Types; using RegressionGames.StateRecorder; +using RegressionGames.StateRecorder.BotSegments.Models; using RegressionGames.StateRecorder.JsonConverters; namespace RegressionGames.ClientDashboard @@ -17,8 +18,12 @@ public enum TcpMessageType Ping, - // client requests to play a sequence with the given resourcePath + // client requests to play a resource with the given resourcePath PlaySequence, + PlaySegment, + + // stops any currently-running sequence/segments + StopReplay, // ===================== // server -> client @@ -26,8 +31,9 @@ public enum TcpMessageType Pong, - // info about the available sequences for this game instance + // info about the available file-based resources for this game instance AvailableSequences, + AvailableSegments, // info about the currently-running sequence (or segment) ActiveSequence, @@ -124,7 +130,53 @@ public override string ToString() } [Serializable] - public class PlaySequenceTcpMessageData : ITcpMessageData + public class AvailableSegmentsTcpMessageData : ITcpMessageData + { + public List availableSegments; + + public void WriteToStringBuilder(StringBuilder stringBuilder) + { + stringBuilder.Append("{\"availableSegments\":["); + var availableSegmentsCount = availableSegments.Count; + for (var i = 0; i < availableSegmentsCount; i++) + { + // a lot of the fields on BotSequenceEntry are not written to string builder + // so pick what we need for the dashboard here... + var currentSegment = availableSegments[i]; + + stringBuilder.Append("{\"apiVersion\":"); + IntJsonConverter.WriteToStringBuilder(stringBuilder, currentSegment.apiVersion); + + // not normally serialized + stringBuilder.Append(",\"resourcePath\":"); + StringJsonConverter.WriteToStringBuilder(stringBuilder, currentSegment.resourcePath); + stringBuilder.Append(",\"type\":"); + StringJsonConverter.WriteToStringBuilder(stringBuilder, currentSegment.type.ToString()); + stringBuilder.Append(",\"name\":"); + StringJsonConverter.WriteToStringBuilder(stringBuilder, currentSegment.name); + stringBuilder.Append(",\"description\":"); + StringJsonConverter.WriteToStringBuilder(stringBuilder, currentSegment.description); + + stringBuilder.Append("}"); + + if (i + 1 < availableSegmentsCount) + { + stringBuilder.Append(","); + } + } + stringBuilder.Append("]}"); + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(1000); + WriteToStringBuilder(sb); + return sb.ToString(); + } + } + + [Serializable] + public class PlayResourceTcpMessageData : ITcpMessageData { public string resourcePath; @@ -142,4 +194,5 @@ public override string ToString() return sb.ToString(); } } + } \ No newline at end of file diff --git a/src/gg.regression.unity.bots/Runtime/Scripts/ClientDashboard/TcpMessageDataJsonConverter.cs b/src/gg.regression.unity.bots/Runtime/Scripts/ClientDashboard/TcpMessageDataJsonConverter.cs index b1f32f7a..9d737ae1 100644 --- a/src/gg.regression.unity.bots/Runtime/Scripts/ClientDashboard/TcpMessageDataJsonConverter.cs +++ b/src/gg.regression.unity.bots/Runtime/Scripts/ClientDashboard/TcpMessageDataJsonConverter.cs @@ -22,6 +22,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist { case TcpMessageType.Ping: case TcpMessageType.Pong: + case TcpMessageType.StopReplay: case TcpMessageType.CloseConnection: // these messages have no payload break; @@ -31,8 +32,12 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist case TcpMessageType.AvailableSequences: payload = jObject["payload"].ToObject(serializer); break; + case TcpMessageType.AvailableSegments: + payload = jObject["payload"].ToObject(serializer); + break; case TcpMessageType.PlaySequence: - payload = jObject["payload"].ToObject(serializer); + case TcpMessageType.PlaySegment: + payload = jObject["payload"].ToObject(serializer); break; default: throw new JsonSerializationException($"Unsupported TcpMessage type: '{message.type}'");