diff --git a/Runtime/AgentDispatcher.cs b/Runtime/AgentDispatcher.cs index 3046046..fb00ab6 100644 --- a/Runtime/AgentDispatcher.cs +++ b/Runtime/AgentDispatcher.cs @@ -1,6 +1,7 @@ // Copyright (c) 2023 DeNA Co., Ltd. // This software is released under the MIT License. +using System; using DeNA.Anjin.Agents; using DeNA.Anjin.Settings; using DeNA.Anjin.Utilities; @@ -88,17 +89,17 @@ public void DispatchByScene(Scene scene) agent = _settings.fallbackAgent; } - DispatchAgent(agent); + DispatchAgent(agent).Forget(); if (_settings.observerAgent != null) { - DispatchAgent(_settings.observerAgent); + DispatchAgent(_settings.observerAgent).Forget(); // Note: The ObserverAgent is not made to DontDestroyOnLoad, to start every time. // Because it is a source of bugs to force the implementation of DontDestroyOnLoad to the descendants of the Composite. } } - private void DispatchAgent(AbstractAgent agent) + private async UniTask DispatchAgent(AbstractAgent agent) { var agentName = agent.name; var gameObject = new GameObject(agentName); @@ -106,9 +107,19 @@ private void DispatchAgent(AbstractAgent agent) agent.Logger = _logger; agent.Random = _randomFactory.CreateRandom(); - agent.Run(token).Forget(); - - _logger.Log($"Agent {agentName} dispatched!"); + + try + { + agent.Run(token).Forget(); + _logger.Log($"Agent {agentName} dispatched!"); + } + catch (Exception e) + { + // XXX: Wait 1 frame to fix https://github.com/DeNA/Anjin/issues/20 + await UniTask.DelayFrame(1, cancellationToken: token); + Debug.LogException(e); + _logger.Log($"Agent {agentName} dispatched but immediately threw an error!"); + } } } } diff --git a/Runtime/Autopilot.cs b/Runtime/Autopilot.cs index 7bf1ac7..6cbb190 100644 --- a/Runtime/Autopilot.cs +++ b/Runtime/Autopilot.cs @@ -62,15 +62,18 @@ private void Start() _randomFactory = new RandomFactory(seed); _logger.Log($"Random seed is {seed}"); + + // NOTE: Registering logMessageReceived must be placed before DispatchByScene. + // Because some agent can throw an error immediately, so reporter can miss the error if + // registering logMessageReceived is placed after DispatchByScene. + _reporter = new SlackReporter(_settings, new SlackAPI()); + _logMessageHandler = new LogMessageHandler(_settings, _reporter); + Application.logMessageReceived += _logMessageHandler.HandleLog; _dispatcher = new AgentDispatcher(_settings, _logger, _randomFactory); _dispatcher.DispatchByScene(SceneManager.GetActiveScene()); SceneManager.activeSceneChanged += _dispatcher.DispatchByScene; - _reporter = new SlackReporter(_settings, new SlackAPI()); - _logMessageHandler = new LogMessageHandler(_settings, _reporter); - Application.logMessageReceived += _logMessageHandler.HandleLog; - if (_settings.lifespanSec > 0) { StartCoroutine(Lifespan(_settings.lifespanSec)); diff --git a/Tests/Runtime/TestDoubles/StubClickAgent.cs b/Tests/Runtime/TestDoubles/StubClickAgent.cs index d384def..e03b57e 100644 --- a/Tests/Runtime/TestDoubles/StubClickAgent.cs +++ b/Tests/Runtime/TestDoubles/StubClickAgent.cs @@ -9,10 +9,18 @@ namespace DeNA.Anjin.TestDoubles { + /// + /// A test double for agent. This agent immediately click game objects that have the name specified + /// public class StubClickAgent : AbstractAgent { + /// + /// A name of game objects to click + /// [SerializeField] public string targetName; + + /// public override UniTask Run(CancellationToken token) { foreach (var obj in FindObjectsByType(FindObjectsSortMode.None)) @@ -33,6 +41,7 @@ public override UniTask Run(CancellationToken token) handler.OnPointerClick(new PointerEventData(EventSystem.current)); } + return UniTask.CompletedTask; } }