From fa6c0dc370825c3c967befb780257958e89a4d23 Mon Sep 17 00:00:00 2001 From: Koji Hasegawa Date: Tue, 17 Sep 2024 10:17:06 +0900 Subject: [PATCH] Add support calling async method to InitializeOnLaunchAutopilotAttribute --- Editor/UI/Settings/AutopilotSettingsEditor.cs | 2 +- Runtime/Launcher.cs | 22 ++++++++-- .../Settings/AutopilotSettingsEditorTest.cs | 17 ------- Tests/Runtime/LauncherTest.cs | 44 ++++++++++++++++++- .../SpyInitializeOnLaunchAutopilot.cs | 20 +++++++++ 5 files changed, 82 insertions(+), 23 deletions(-) diff --git a/Editor/UI/Settings/AutopilotSettingsEditor.cs b/Editor/UI/Settings/AutopilotSettingsEditor.cs index 2596290..b71d6fb 100644 --- a/Editor/UI/Settings/AutopilotSettingsEditor.cs +++ b/Editor/UI/Settings/AutopilotSettingsEditor.cs @@ -185,7 +185,7 @@ internal void Launch(AutopilotState state) if (EditorApplication.isPlaying) { state.launchFrom = LaunchType.EditorPlayMode; - Launcher.Run(); + Launcher.Run().Forget(); } else { diff --git a/Runtime/Launcher.cs b/Runtime/Launcher.cs index e694e96..65343de 100644 --- a/Runtime/Launcher.cs +++ b/Runtime/Launcher.cs @@ -5,6 +5,8 @@ using System; using System.Linq; +using System.Threading.Tasks; +using Cysharp.Threading.Tasks; using DeNA.Anjin.Attributes; using DeNA.Anjin.Settings; using DeNA.Anjin.Utilities; @@ -33,7 +35,8 @@ internal static void ResetEventHandlers() /// Run autopilot /// [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)] - public static void Run() + // ReSharper disable once Unity.IncorrectMethodSignature + public static async UniTask Run() { var state = AutopilotState.Instance; if (!state.IsRunning) @@ -48,20 +51,31 @@ public static void Run() ScreenshotStore.CleanDirectories(); - CallAttachedInitializeOnLaunchAutopilotAttributeMethods(); + await CallAttachedInitializeOnLaunchAutopilotAttributeMethods(); var autopilot = new GameObject(nameof(Autopilot)).AddComponent(); Object.DontDestroyOnLoad(autopilot); } - private static void CallAttachedInitializeOnLaunchAutopilotAttributeMethods() + private static async UniTask CallAttachedInitializeOnLaunchAutopilotAttributeMethods() { foreach (var methodInfo in AppDomain.CurrentDomain.GetAssemblies() .SelectMany(x => x.GetTypes()) .SelectMany(x => x.GetMethods()) .Where(x => x.GetCustomAttributes(typeof(InitializeOnLaunchAutopilotAttribute), false).Any())) { - methodInfo.Invoke(null, null); // static method only + switch (methodInfo.ReturnType.Name) + { + case nameof(Task): + await (Task)methodInfo.Invoke(null, null); + break; + case nameof(UniTask): + await (UniTask)methodInfo.Invoke(null, null); + break; + default: + methodInfo.Invoke(null, null); // static method only + break; + } } } diff --git a/Tests/Editor/UI/Settings/AutopilotSettingsEditorTest.cs b/Tests/Editor/UI/Settings/AutopilotSettingsEditorTest.cs index 0edad55..39b0bb2 100644 --- a/Tests/Editor/UI/Settings/AutopilotSettingsEditorTest.cs +++ b/Tests/Editor/UI/Settings/AutopilotSettingsEditorTest.cs @@ -4,7 +4,6 @@ using System.Collections; using System.Diagnostics.CodeAnalysis; using DeNA.Anjin.Settings; -using DeNA.Anjin.TestDoubles; using NUnit.Framework; using UnityEditor; using UnityEngine; @@ -66,21 +65,5 @@ public IEnumerator Launch_OnEditMode_RunAutopilotOnPlayMode() var autopilot = Object.FindObjectOfType(); Assert.That((bool)autopilot.gameObject, Is.True, "Autopilot object is alive"); } - - [UnityTest] - public IEnumerator Launch_CallMethodWithInitializeOnLaunchAutopilotAttribute() - { - SpyInitializeOnLaunchAutopilot.Reset(); - - var testSettings = AssetDatabase.LoadAssetAtPath( - "Packages/com.dena.anjin/Tests/TestAssets/AutopilotSettingsForTests.asset"); - var editor = (AutopilotSettingsEditor)UnityEditor.Editor.CreateEditor(testSettings); - var state = AutopilotState.Instance; - editor.Launch(state); // Note: Can not call editor.OnInspectorGUI() and GUILayout.Button() - - yield return new WaitForDomainReload(); // Wait for domain reloading by switching play mode - - Assert.That(SpyInitializeOnLaunchAutopilot.IsCallInitializeOnLaunchAutopilotMethod, Is.True); - } } } diff --git a/Tests/Runtime/LauncherTest.cs b/Tests/Runtime/LauncherTest.cs index 155affe..18a5d6f 100644 --- a/Tests/Runtime/LauncherTest.cs +++ b/Tests/Runtime/LauncherTest.cs @@ -1,10 +1,12 @@ // Copyright (c) 2023 DeNA Co., Ltd. // This software is released under the MIT License. +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using DeNA.Anjin.Editor.UI.Settings; using DeNA.Anjin.Settings; +using DeNA.Anjin.TestDoubles; using NUnit.Framework; using UnityEditor; using UnityEngine; @@ -55,7 +57,7 @@ public async Task Launch_StopAutopilotThatRunInPlayMode_KeepPlayMode() var state = AutopilotState.Instance; editor.Launch(state); - await Task.Delay(2200); // 2sec+overhead + await Task.Delay(5000); // 2sec+overhead Assert.That(state.IsRunning, Is.False, "AutopilotState is terminated"); Assert.That(EditorApplication.isPlaying, Is.True, "Keep play mode"); @@ -69,6 +71,7 @@ public async Task Stop_TerminateAutopilotAndKeepPlayMode() var editor = (AutopilotSettingsEditor)UnityEditor.Editor.CreateEditor(testSettings); var state = AutopilotState.Instance; editor.Launch(state); + await Task.Delay(2000); await editor.Stop(); // Note: If Autopilot stops for life before Stop, a NullReference exception is raised here. @@ -76,5 +79,44 @@ public async Task Stop_TerminateAutopilotAndKeepPlayMode() Assert.That(state.IsRunning, Is.False, "AutopilotState is terminated"); Assert.That(EditorApplication.isPlaying, Is.True, "Keep play mode"); } + + [Test] + public async Task Launch_InitializeOnLaunchAutopilotAttribute_Called() + { + SpyInitializeOnLaunchAutopilot.Reset(); + + var settings = ScriptableObject.CreateInstance(typeof(AutopilotSettings)) as AutopilotSettings; + settings.sceneAgentMaps = new List(); + settings.lifespanSec = 1; + await LauncherFromTest.AutopilotAsync(settings); // TODO: Renamed in another PR + + Assert.That(SpyInitializeOnLaunchAutopilot.IsCallInitializeOnLaunchAutopilotMethod, Is.True); + } + + [Test] + public async Task Launch_InitializeOnLaunchAutopilotAttributeAttachToAsyncMethod_Called() + { + SpyInitializeOnLaunchAutopilot.Reset(); + + var settings = ScriptableObject.CreateInstance(typeof(AutopilotSettings)) as AutopilotSettings; + settings.sceneAgentMaps = new List(); + settings.lifespanSec = 1; + await LauncherFromTest.AutopilotAsync(settings); // TODO: Renamed in another PR + + Assert.That(SpyInitializeOnLaunchAutopilot.IsCallInitializeOnLaunchAutopilotMethodAsync, Is.True); + } + + [Test] + public async Task Launch_InitializeOnLaunchAutopilotAttributeAttachToUniTaskAsyncMethod_Called() + { + SpyInitializeOnLaunchAutopilot.Reset(); + + var settings = ScriptableObject.CreateInstance(typeof(AutopilotSettings)) as AutopilotSettings; + settings.sceneAgentMaps = new List(); + settings.lifespanSec = 1; + await LauncherFromTest.AutopilotAsync(settings); // TODO: Renamed in another PR + + Assert.That(SpyInitializeOnLaunchAutopilot.IsCallInitializeOnLaunchAutopilotMethodUniTaskAsync, Is.True); + } } } diff --git a/Tests/Runtime/TestDoubles/SpyInitializeOnLaunchAutopilot.cs b/Tests/Runtime/TestDoubles/SpyInitializeOnLaunchAutopilot.cs index f87f1a9..f361494 100644 --- a/Tests/Runtime/TestDoubles/SpyInitializeOnLaunchAutopilot.cs +++ b/Tests/Runtime/TestDoubles/SpyInitializeOnLaunchAutopilot.cs @@ -1,6 +1,8 @@ // Copyright (c) 2023 DeNA Co., Ltd. // This software is released under the MIT License. +using System.Threading.Tasks; +using Cysharp.Threading.Tasks; using DeNA.Anjin.Attributes; namespace DeNA.Anjin.TestDoubles @@ -8,10 +10,14 @@ namespace DeNA.Anjin.TestDoubles public static class SpyInitializeOnLaunchAutopilot { public static bool IsCallInitializeOnLaunchAutopilotMethod { get; private set; } + public static bool IsCallInitializeOnLaunchAutopilotMethodAsync { get; private set; } + public static bool IsCallInitializeOnLaunchAutopilotMethodUniTaskAsync { get; private set; } public static void Reset() { IsCallInitializeOnLaunchAutopilotMethod = false; + IsCallInitializeOnLaunchAutopilotMethodAsync = false; + IsCallInitializeOnLaunchAutopilotMethodUniTaskAsync = false; } [InitializeOnLaunchAutopilot] @@ -19,5 +25,19 @@ public static void InitializeOnLaunchAutopilotMethod() { IsCallInitializeOnLaunchAutopilotMethod = true; } + + [InitializeOnLaunchAutopilot] + public static async Task InitializeOnLaunchAutopilotMethodAsync() + { + await Task.Delay(0); + IsCallInitializeOnLaunchAutopilotMethodAsync = true; + } + + [InitializeOnLaunchAutopilot] + public static async UniTask InitializeOnLaunchAutopilotMethodUniTaskAsync() + { + await UniTask.Delay(0); + IsCallInitializeOnLaunchAutopilotMethodUniTaskAsync = true; + } } }