├── LICENSE ├── README.md ├── README_ru.md ├── docs └── AUTHORS.rst └── src └── ControllersTree ├── .idea └── .idea.ControllersTree.dir │ └── .idea │ ├── .gitignore │ └── encodings.xml ├── Core.meta ├── Core ├── AssemblyInfo.cs ├── AssemblyInfo.cs.meta ├── Attributes.meta ├── Attributes │ ├── DebugMethodAttribute.cs │ └── DebugMethodAttribute.cs.meta ├── Contracts.meta ├── Contracts │ ├── EmptyControllerArg.cs │ ├── EmptyControllerArg.cs.meta │ ├── EmptyControllerResult.cs │ └── EmptyControllerResult.cs.meta ├── Controllers.meta ├── Controllers │ ├── ControllerBase.Debug.cs │ ├── ControllerBase.Debug.cs.meta │ ├── ControllerBase.Editor.cs │ ├── ControllerBase.Editor.cs.meta │ ├── ControllerBase.Execute.cs │ ├── ControllerBase.Execute.cs.meta │ ├── ControllerBase.ExecuteAndWaitResultAsync.cs │ ├── ControllerBase.ExecuteAndWaitResultAsync.cs.meta │ ├── ControllerBase.Profiler.cs │ ├── ControllerBase.Profiler.cs.meta │ ├── ControllerBase.cs │ ├── ControllerBase.cs.meta │ ├── ControllerBase`1.cs │ ├── ControllerBase`1.cs.meta │ ├── ControllerWithResultBase.cs │ ├── ControllerWithResultBase.cs.meta │ ├── ControllerWithResultBase`1.cs │ ├── ControllerWithResultBase`1.cs.meta │ ├── ControllerWithResultBase`2.Editor.cs │ ├── ControllerWithResultBase`2.Editor.cs.meta │ ├── ControllerWithResultBase`2.cs │ ├── ControllerWithResultBase`2.cs.meta │ ├── RootController.Profiler.cs │ ├── RootController.Profiler.cs.meta │ ├── RootController.cs │ └── RootController.cs.meta ├── Interfaces.meta ├── Interfaces │ ├── IController.cs │ ├── IController.cs.meta │ ├── IControllerDebugInfo.cs │ ├── IControllerDebugInfo.cs.meta │ ├── IControllerFactory.cs │ ├── IControllerFactory.cs.meta │ ├── IControllerWithResult.cs │ └── IControllerWithResult.cs.meta ├── Playtika.Controllers.asmdef ├── Playtika.Controllers.asmdef.meta ├── Profiler.meta ├── Profiler │ ├── FixedString.cs │ ├── FixedString.cs.meta │ ├── Helper.cs │ └── Helper.cs.meta ├── States.meta ├── States │ ├── ControllerState.cs │ ├── ControllerState.cs.meta │ ├── ControllerWithResultState.cs │ └── ControllerWithResultState.cs.meta ├── Utils.meta └── Utils │ ├── ControllerCompositeDisposable.cs │ ├── ControllerCompositeDisposable.cs.meta │ ├── DisposableToken.cs │ └── DisposableToken.cs.meta ├── Editor.meta ├── Editor ├── ControllersHierarchy.meta ├── ControllersHierarchy │ ├── ControllerTabData.cs │ ├── ControllerTabData.cs.meta │ ├── ControllerTreeView.cs │ ├── ControllerTreeView.cs.meta │ ├── ControllersHierarchy.cs │ ├── ControllersHierarchy.cs.meta │ ├── ControllersHierarchyView.cs │ ├── ControllersHierarchyView.cs.meta │ ├── ControllersInfoView.cs │ ├── ControllersInfoView.cs.meta │ ├── ControllersMethodsView.cs │ ├── ControllersMethodsView.cs.meta │ ├── ControllersTabBarDrawer.cs │ ├── ControllersTabBarDrawer.cs.meta │ ├── ControllersTreeHelper.cs │ ├── ControllersTreeHelper.cs.meta │ ├── ControllersTreeViewItem.cs │ ├── ControllersTreeViewItem.cs.meta │ ├── ControllersTreeViewModel.cs │ ├── ControllersTreeViewModel.cs.meta │ ├── FieldsDrawers.meta │ ├── FieldsDrawers │ │ ├── ControllersActionFieldDrawer.cs │ │ ├── ControllersActionFieldDrawer.cs.meta │ │ ├── ControllersBaseFieldDrawer.cs │ │ ├── ControllersBaseFieldDrawer.cs.meta │ │ ├── ControllersBooleanFieldDrawer.cs │ │ ├── ControllersBooleanFieldDrawer.cs.meta │ │ ├── ControllersCollectionFieldDrawer.cs │ │ ├── ControllersCollectionFieldDrawer.cs.meta │ │ ├── ControllersFieldsFactory.cs │ │ ├── ControllersFieldsFactory.cs.meta │ │ ├── ControllersIntegerFieldDrawer.cs │ │ ├── ControllersIntegerFieldDrawer.cs.meta │ │ ├── ControllersLabelFieldDrawer.cs │ │ ├── ControllersLabelFieldDrawer.cs.meta │ │ ├── ControllersParentObjectFieldDrawer.cs │ │ ├── ControllersParentObjectFieldDrawer.cs.meta │ │ ├── ControllersStringFieldDrawer.cs │ │ ├── ControllersStringFieldDrawer.cs.meta │ │ ├── ControllersUnityObjectFieldDrawer.cs │ │ └── ControllersUnityObjectFieldDrawer.cs.meta │ ├── Playtika.Controllers.Editor.asmdef │ └── Playtika.Controllers.Editor.asmdef.meta ├── ControllersProfiler.meta └── ControllersProfiler │ ├── ControllerData.cs │ ├── ControllerData.cs.meta │ ├── ControllerLiveData.cs │ ├── ControllerLiveData.cs.meta │ ├── ControllersProfilerModule.cs │ ├── ControllersProfilerModule.cs.meta │ ├── ControllersProfilerModuleViewController.cs │ ├── ControllersProfilerModuleViewController.cs.meta │ ├── CreatedAndDestroyedControllersListView.cs │ ├── CreatedAndDestroyedControllersListView.cs.meta │ ├── LiveControllersListView.cs │ ├── LiveControllersListView.cs.meta │ ├── Playtika.ControllersProfiler.Editor.asmdef │ └── Playtika.ControllersProfiler.Editor.asmdef.meta ├── Substitute.meta ├── Substitute ├── Runtime.meta ├── Runtime │ ├── Playtika.Controllers.Substitute.asmdef │ ├── Playtika.Controllers.Substitute.asmdef.meta │ ├── SubstituteController.cs │ ├── SubstituteController.cs.meta │ ├── SubstituteControllerFactory.cs │ ├── SubstituteControllerFactory.cs.meta │ ├── SubstituteControllerWithResult.cs │ ├── SubstituteControllerWithResult.cs.meta │ ├── TestRootController.cs │ └── TestRootController.cs.meta ├── Tests.meta └── Tests │ ├── Playtika.Controllers.Substitute.Tests.asmdef │ ├── Playtika.Controllers.Substitute.Tests.asmdef.meta │ ├── SubstituteControllerFactoryTests.cs │ ├── SubstituteControllerFactoryTests.cs.meta │ ├── TestRootControllerWithSubstituteFactoryTests.cs │ ├── TestRootControllerWithSubstituteFactoryTests.cs.meta │ ├── TypesForTest.cs │ └── TypesForTest.cs.meta ├── Tests.meta ├── Tests ├── Controllers.meta ├── Controllers │ ├── ControllersBase.meta │ ├── ControllersBase │ │ ├── ActionModelTestControllerBase.cs │ │ └── ActionModelTestControllerBase.cs.meta │ ├── ControllersWithResult.meta │ └── ControllersWithResult │ │ ├── ActionModelTestControllerWithResult.cs │ │ ├── ActionModelTestControllerWithResult.cs.meta │ │ ├── ActionModelTestControllerWithResult_CompleteAfterOnFlowAsync.cs │ │ ├── ActionModelTestControllerWithResult_CompleteAfterOnFlowAsync.cs.meta │ │ ├── ActionModelTestControllerWithResult_CompleteOnFlowAsync.cs │ │ ├── ActionModelTestControllerWithResult_CompleteOnFlowAsync.cs.meta │ │ ├── ActionModelTestControllerWithResult_CompleteOnStart.cs │ │ ├── ActionModelTestControllerWithResult_CompleteOnStart.cs.meta │ │ ├── ActionModelTestControllerWithResult_FailInDispose.cs │ │ ├── ActionModelTestControllerWithResult_FailInDispose.cs.meta │ │ ├── ActionModelTestControllerWithResult_FailOnFlowAsync.cs │ │ ├── ActionModelTestControllerWithResult_FailOnFlowAsync.cs.meta │ │ ├── ActionModelTestControllerWithResult_FailOnStart.cs │ │ ├── ActionModelTestControllerWithResult_FailOnStart.cs.meta │ │ ├── ActionModelTestControllerWithResult_FailOnStop.cs │ │ ├── ActionModelTestControllerWithResult_FailOnStop.cs.meta │ │ ├── ActionModelTestControllerWithResult_ThrowAfterOnFlowAsync.cs │ │ ├── ActionModelTestControllerWithResult_ThrowAfterOnFlowAsync.cs.meta │ │ ├── Childs.meta │ │ └── Childs │ │ ├── ActionModelTestChildControllerWithResult.cs │ │ ├── ActionModelTestChildControllerWithResult.cs.meta │ │ ├── ActionModelTestControllerWithResultAndChildControllers.cs │ │ ├── ActionModelTestControllerWithResultAndChildControllers.cs.meta │ │ ├── ActionModelTestControllerWithResultAndChildControllers_FailOnFlowAsync.cs │ │ └── ActionModelTestControllerWithResultAndChildControllers_FailOnFlowAsync.cs.meta ├── ControllersBaseTests.cs ├── ControllersBaseTests.cs.meta ├── ControllersWithResultBaseTests.ChildControllers.cs ├── ControllersWithResultBaseTests.ChildControllers.cs.meta ├── ControllersWithResultBaseTests.FlowAsync.cs ├── ControllersWithResultBaseTests.FlowAsync.cs.meta ├── ControllersWithResultBaseTests.cs ├── ControllersWithResultBaseTests.cs.meta ├── Playtika.Controllers.Tests.asmdef ├── Playtika.Controllers.Tests.asmdef.meta ├── TestChildControllerArgs.cs ├── TestChildControllerArgs.cs.meta ├── TestChildControllersActionModel.cs ├── TestChildControllersActionModel.cs.meta ├── TestControllerArgs.cs ├── TestControllerArgs.cs.meta ├── TestControllersActionModel.cs ├── TestControllersActionModel.cs.meta ├── TestControllersException.cs ├── TestControllersException.cs.meta ├── TestControllersMethodsNamesConsts.cs ├── TestControllersMethodsNamesConsts.cs.meta ├── TestControllersUtils.cs ├── TestControllersUtils.cs.meta ├── TestEmptyControllerResult.cs ├── TestEmptyControllerResult.cs.meta ├── TestRootControllerLauncher.cs └── TestRootControllerLauncher.cs.meta ├── package.json └── package.json.meta /docs/AUTHORS.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Project Authors 3 | ============ 4 | We thank the following people for their contributions (in alphabetical order): 5 | 6 | - Aleksei Borisov 7 | - Aleksey Lukoyanichev 8 | - Alex Kniazkin 9 | - Alexey Merzlikin 10 | - Aliaksandr Hurynovich 11 | - Aliaksandr Krauchuk 12 | - Aliaksandr Maisak 13 | - Aliaksandr Shchamialiou 14 | - Andrei Batseka 15 | - Andrei Navoichyk 16 | - Andrew Chaiko 17 | - Andrey Makarevich 18 | - Artem Svirid 19 | - Artur Sushkov 20 | - Daniil Kondrashov 21 | - Dmitry Novitsky 22 | - Dzmitry Chubryk 23 | - Dzmitry Kharko 24 | - Dzmitry Malchykau 25 | - Egor Zhingerovsky 26 | - Eldar Huseinau 27 | - Evgeny Pikta 28 | - Grigory Perepechko 29 | - Igor Perepechenko 30 | - Ivan Kovalchuk 31 | - Ivan Voinyi 32 | - Ivan Zhdanov 33 | - Leonid Hromyko 34 | - Maksim Shabanets 35 | - Maxim Bozbey 36 | - Maxim Gulik 37 | - Mihail Podshivadlov 38 | - Mikhail Gvozdev 39 | - Nikita Markianov 40 | - Nikita Anufriev 41 | - Nikita Barkun 42 | - Nikolai Karnovskii 43 | - Oleg Ilyin 44 | - Polina Freydlina 45 | - Roman Shevchik 46 | - Ruslan Panteleev 47 | - Sergey Efremov 48 | - Sergey Greshnov 49 | - Sergey Khalandachev 50 | - Sergey Ladychin 51 | - Sergey Metlov 52 | - Shilo Olga 53 | - Siarhei Rydkin 54 | - Stepan Shamashov 55 | - Uladzislau Navaselski 56 | - Viachaslau Burlo 57 | - Vitaliy Kaymachnikov 58 | - Vitaly Kolesnikov 59 | - Vlad Larin 60 | - Vyacheslav Alferov 61 | - Yahor Remshanka 62 | - Yaraslau Shabanets 63 | 64 | If you contributed and don't see your name here, please submit a pull request to add yourself! 65 | -------------------------------------------------------------------------------- /src/ControllersTree/.idea/.idea.ControllersTree.dir/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Rider ignored files 5 | /modules.xml 6 | /projectSettingsUpdater.xml 7 | /.idea.ControllersTree.iml 8 | /contentModel.xml 9 | # Editor-based HTTP Client requests 10 | /httpRequests/ 11 | # Datasource local storage ignored files 12 | /dataSources/ 13 | /dataSources.local.xml 14 | -------------------------------------------------------------------------------- /src/ControllersTree/.idea/.idea.ControllersTree.dir/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/ControllersTree/Core.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9bfa0cfab11f63344bf36ef374030d5b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | [assembly: AssemblyTitle("Controllers tree")] 4 | [assembly: AssemblyDescription("Controllers tree base classes.")] 5 | 6 | // internal should be visible to Substitute 7 | [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("DynamicProxyGenAssembly2")] 8 | [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Playtika.Controllers.Editor")] 9 | 10 | [assembly: AssemblyVersion("1.0.0")] 11 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/AssemblyInfo.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dbdd90e2624b748879ec7f05b82bd0a9 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Attributes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d70bab7ded4a435086fa7ddfa8a37648 3 | timeCreated: 1706189464 -------------------------------------------------------------------------------- /src/ControllersTree/Core/Attributes/DebugMethodAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine.Scripting; 3 | 4 | namespace Playtika.Controllers 5 | { 6 | [AttributeUsage(AttributeTargets.Method)] 7 | public sealed class DebugMethodAttribute : 8 | #if UNITY_EDITOR || DEVELOPMENT_BUILD || UNITY_BUILDTYPE_DEV 9 | PreserveAttribute 10 | #else 11 | Attribute 12 | #endif 13 | { 14 | public readonly string Name; 15 | public DebugMethodAttribute() 16 | { 17 | } 18 | 19 | public DebugMethodAttribute(string name) 20 | { 21 | Name = name; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Attributes/DebugMethodAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 01ea8bb24cc2049f1addbb91a9ade90e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Contracts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 09766dab6c294cb2a92961ce3780d829 3 | timeCreated: 1706189503 -------------------------------------------------------------------------------- /src/ControllersTree/Core/Contracts/EmptyControllerArg.cs: -------------------------------------------------------------------------------- 1 | namespace Playtika.Controllers 2 | { 3 | public readonly struct EmptyControllerArg 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /src/ControllersTree/Core/Contracts/EmptyControllerArg.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 99487367fb7994829806d6bd9cf4d6e5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Contracts/EmptyControllerResult.cs: -------------------------------------------------------------------------------- 1 | namespace Playtika.Controllers 2 | { 3 | public readonly struct EmptyControllerResult 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /src/ControllersTree/Core/Contracts/EmptyControllerResult.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c53d574ef7226431b8166d0e31a475a2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: becdf090793f424d9d9f70dd34c709d4 3 | timeCreated: 1706189522 -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerBase.Debug.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine.Pool; 3 | 4 | namespace Playtika.Controllers 5 | { 6 | public partial class ControllerBase 7 | { 8 | /// 9 | /// Generates a string representation of the controller tree. 10 | /// Used for debug or error handling purposes. 11 | /// 12 | /// A string representation of the controller tree. 13 | protected string Dump() 14 | { 15 | using var controllersTreePooledObject = ListPool.Get(out var controllersTree); 16 | ((IController)this).ScanTree(controllersTree, string.Empty); 17 | return string.Join("\n", controllersTree); 18 | } 19 | 20 | void IController.ScanTree(List controllersTree, string prefix) 21 | { 22 | controllersTree.Add($"{prefix}{this}"); 23 | foreach (var child in _childControllers) 24 | { 25 | child.ScanTree(controllersTree, $" {prefix}"); 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerBase.Debug.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5577f91e517834a109f65d113df90b5b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerBase.Editor.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_EDITOR 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Threading; 5 | using UnityEngine; 6 | 7 | namespace Playtika.Controllers 8 | { 9 | public partial class ControllerBase : IControllerDebugInfo 10 | { 11 | IEnumerator IEnumerable.GetEnumerator() 12 | { 13 | return ((IEnumerable)this).GetEnumerator(); 14 | } 15 | 16 | IEnumerator IEnumerable.GetEnumerator() 17 | { 18 | foreach (var childController in _childControllers) 19 | { 20 | yield return (IControllerDebugInfo)childController; 21 | } 22 | } 23 | 24 | string IControllerDebugInfo.ControllerType => ControllerTypeInternal(); 25 | string IControllerDebugInfo.StateName => StateNameInternal(); 26 | Color IControllerDebugInfo.StateColor => StateColorInternal(); 27 | string IControllerDebugInfo.ScopeName => _controllerFactory?.ToString(); 28 | 29 | protected virtual string ControllerTypeInternal() => 30 | nameof(ControllerBase); 31 | 32 | protected virtual string StateNameInternal() => 33 | _state.ToString(); 34 | 35 | protected virtual Color StateColorInternal() => 36 | _state switch 37 | { 38 | ControllerState.Created => new Color(0.09f, 0.52f, 0.87f), 39 | ControllerState.Initialized => new Color(0.07f, 0.84f, 0.85f), 40 | ControllerState.Running => new Color(0.13f, 0.8f, 0f), 41 | ControllerState.Stopped => new Color(1f, 0.86f, 0f), 42 | ControllerState.Disposed => new Color(1f, 0.26f, 0.12f), 43 | _ => Color.magenta 44 | }; 45 | } 46 | } 47 | #endif 48 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerBase.Editor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ac02a3c99bbc747e099c5edef1a1560c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerBase.Execute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Linq; 4 | using System.Runtime.CompilerServices; 5 | using System.Threading; 6 | 7 | namespace Playtika.Controllers 8 | { 9 | public abstract partial class ControllerBase 10 | { 11 | /// 12 | /// Executes a controller of type T. 13 | /// This method creates an instance of the controller and starts it. 14 | /// 15 | /// The type of the controller to execute. Must implement IController. 16 | protected void Execute() 17 | where T : class, IController 18 | { 19 | ThrowIfControllerWithResult(); 20 | ExecuteInternal(null, default); 21 | } 22 | 23 | /// 24 | /// Executes a controller of type T that requires an argument of type TArg. 25 | /// This method creates an instance of the controller, sets the argument, and starts the controller. 26 | /// 27 | /// The type of the controller to execute. Must implement IController and IController<TArg>. 28 | /// The type of the argument required by the controller. 29 | /// The argument to pass to the controller. 30 | protected void Execute(TArg arg) 31 | where T : class, IController, IController 32 | { 33 | ThrowIfControllerWithResult(); 34 | ExecuteInternal(arg, null, default); 35 | } 36 | 37 | /// 38 | /// Executes a controller of type T using a specified controller factory. 39 | /// This method creates an instance of the controller and starts it. 40 | /// 41 | /// The type of the controller to execute. Must implement IController. 42 | /// The factory to use when creating the controller. 43 | protected void Execute(IControllerFactory factory) 44 | where T : class, IController 45 | { 46 | ThrowIfControllerWithResult(); 47 | ExecuteInternal(factory, default); 48 | } 49 | 50 | /// 51 | /// Executes a controller of type T that requires an argument of type TArg using a specified controller factory. 52 | /// This method creates an instance of the controller, sets the argument, and starts the controller. 53 | /// 54 | /// The type of the controller to execute. Must implement IController and IController<TArg>. 55 | /// The type of the argument required by the controller. 56 | /// The argument to pass to the controller. 57 | /// The factory to use when creating the controller. 58 | protected void Execute(TArg arg, 59 | IControllerFactory factory) 60 | where T : class, IController, IController 61 | { 62 | ThrowIfControllerWithResult(); 63 | ExecuteInternal(arg, factory, default); 64 | } 65 | 66 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 67 | private IController ExecuteInternal( 68 | IControllerFactory factory, 69 | CancellationToken cancellationToken) 70 | where T : class, IController 71 | { 72 | cancellationToken.ThrowIfCancellationRequested(); 73 | ThrowIfControllerHasIncorrectState(); 74 | var controller = Create(factory); 75 | Start(controller, cancellationToken); 76 | return controller; 77 | } 78 | 79 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 80 | private IController ExecuteInternal( 81 | TArg arg, 82 | IControllerFactory factory, 83 | CancellationToken cancellationToken) 84 | where T : class, IController, IController 85 | { 86 | cancellationToken.ThrowIfCancellationRequested(); 87 | ThrowIfControllerHasIncorrectState(); 88 | var controller = Create(factory); 89 | ((IController)controller).SetArgInternal(arg); 90 | Start(controller, cancellationToken); 91 | return controller; 92 | } 93 | 94 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 95 | private IController Create(IControllerFactory factory) 96 | where T : class, IController 97 | { 98 | factory ??= _controllerFactory; 99 | var controller = factory.Create(); 100 | return controller; 101 | } 102 | 103 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 104 | private void Start(IController controller, CancellationToken token) 105 | { 106 | controller.Initialize(token, CancellationToken); 107 | 108 | AddChild(controller); 109 | 110 | try 111 | { 112 | controller.Start(); 113 | } 114 | catch (Exception exception) 115 | { 116 | using (controller) 117 | { 118 | controller.Stop(exception); 119 | RemoveChild(controller); 120 | } 121 | 122 | throw; 123 | } 124 | } 125 | 126 | [Conditional("UNITY_EDITOR")] 127 | private static void ThrowIfControllerWithResult() 128 | { 129 | var controllerType = typeof(T); 130 | var controllerWithResultBaseInterface = typeof(IControllerWithResult<>); 131 | var interfaces = controllerType.GetInterfaces(); 132 | if (interfaces.Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == controllerWithResultBaseInterface)) 133 | { 134 | throw new Exception( 135 | $"{controllerType.Name}: ControllerWithResult cannot be started with {nameof(Execute)}"); 136 | } 137 | } 138 | 139 | [Conditional("UNITY_EDITOR")] 140 | private void ThrowIfControllerHasIncorrectState() 141 | { 142 | if (_state != ControllerState.Running) 143 | { 144 | throw new InvalidOperationException($"{Name} Can't Execute from {_state} state."); 145 | } 146 | } 147 | } 148 | } -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerBase.Execute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 31e13c00f1b794ebc9a5628a5ba45da4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerBase.ExecuteAndWaitResultAsync.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e9bda3a0dd00a47ee8c17d96572f2ce3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerBase.Profiler.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_CONTROLLERS_PROFILER 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Threading; 6 | using Unity.Collections; 7 | using UnityEngine.Profiling; 8 | 9 | namespace Playtika.Controllers 10 | { 11 | public partial class ControllerBase 12 | { 13 | protected static int _totalCount; 14 | protected static int _activeCount; 15 | protected static int _createdThisFrameCount; 16 | 17 | internal int _instanceId; 18 | internal long _startTimeMSec; 19 | private readonly Stopwatch _stopwatch = Stopwatch.StartNew(); 20 | 21 | internal List ChildControllers => _childControllers; 22 | internal string ScopeName => _controllerFactory?.ToString(); 23 | 24 | internal long GetLifetime() => _stopwatch.ElapsedMilliseconds; 25 | private HashSet _savedNames = new HashSet(); 26 | 27 | partial void ProfileOnCreated() 28 | { 29 | ++_totalCount; 30 | ++_activeCount; 31 | ++_createdThisFrameCount; 32 | } 33 | 34 | partial void ProfileOnStart() 35 | { 36 | _startTimeMSec = _stopwatch.ElapsedMilliseconds; 37 | PushCreateControllerToProfilerStream(Name, _startTimeMSec); 38 | _stopwatch.Restart(); 39 | } 40 | 41 | partial void ProfileOnStop() 42 | { 43 | --_activeCount; 44 | var elapsedMilliseconds = _stopwatch.ElapsedMilliseconds; 45 | PushStopControllerToProfilerStream(Name, elapsedMilliseconds); 46 | } 47 | 48 | private void PushCreateControllerToProfilerStream( 49 | string name, 50 | long startTimeMSec) 51 | { 52 | if (!Profiler.enabled || string.IsNullOrEmpty(name)) 53 | { 54 | return; 55 | } 56 | 57 | var nameHash = name.GetHashCode(); 58 | var data = new NativeArray(1, Allocator.Persistent); 59 | data[0] = new CreateControllerFrameData() 60 | { 61 | NameHash = nameHash, 62 | StartTimeMSec = startTimeMSec 63 | }; 64 | 65 | Profiler.EmitFrameMetaData(Helper.ControllerProfilerGuid, Helper.ControllerStartTag, data); 66 | data.Dispose(); 67 | 68 | if (_savedNames.Contains(nameHash)) 69 | { 70 | return; 71 | } 72 | 73 | var nameData = new NativeArray(1, Allocator.Persistent); 74 | nameData[0] = new NameSessionData() 75 | { 76 | NameHash = nameHash, 77 | Name = name 78 | }; 79 | Profiler.EmitSessionMetaData(Helper.ControllerProfilerGuid, Helper.ControllerNameTag, nameData); 80 | nameData.Dispose(); 81 | _savedNames.Add(nameHash); 82 | } 83 | 84 | private static void PushStopControllerToProfilerStream(string name, long elapsedMilliseconds) 85 | { 86 | if (!Profiler.enabled || string.IsNullOrEmpty(name)) 87 | { 88 | return; 89 | } 90 | 91 | var data = new NativeArray(1, Allocator.Persistent); 92 | data[0] = new StopControllerFrameData() 93 | { 94 | NameHash = name.GetHashCode(), 95 | ElapsedMilliseconds = elapsedMilliseconds 96 | }; 97 | 98 | Profiler.EmitFrameMetaData(Helper.ControllerProfilerGuid, Helper.ControllerStopTag, data); 99 | data.Dispose(); 100 | } 101 | } 102 | } 103 | #endif 104 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerBase.Profiler.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a8c38b6fa86b9495d8e36f4a95f11791 -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using System.Linq; 5 | using UnityEngine.Pool; 6 | 7 | namespace Playtika.Controllers 8 | { 9 | public abstract partial class ControllerBase : IController, IDisposable 10 | { 11 | private readonly List _childControllers; 12 | private readonly ControllerCompositeDisposable _compositeDisposables = new (); 13 | private readonly IControllerFactory _controllerFactory; 14 | private CancellationToken _lifetimeToken; 15 | private CancellationTokenSource _lifetimeTokenSource; 16 | private ControllerState _state; 17 | 18 | public string Name => GetType().Name; 19 | protected CancellationToken CancellationToken => _lifetimeToken; 20 | 21 | CancellationToken IController.CancellationToken => _lifetimeToken; 22 | 23 | partial void ProfileOnCreated(); 24 | partial void ProfileOnStart(); 25 | partial void ProfileOnStop(); 26 | 27 | protected ControllerBase(IControllerFactory controllerFactory) 28 | { 29 | _controllerFactory = controllerFactory; 30 | _childControllers = ListPool.Get(); 31 | _state = ControllerState.Created; 32 | } 33 | 34 | public void AddDisposable(IDisposable disposable) 35 | { 36 | _compositeDisposables.Add(disposable); 37 | } 38 | 39 | public void AddDisposables(IEnumerable collection) 40 | { 41 | _compositeDisposables.AddRange(collection); 42 | } 43 | 44 | protected virtual void OnStart() 45 | { 46 | } 47 | 48 | protected virtual void OnStop() 49 | { 50 | } 51 | 52 | void IController.Initialize( 53 | CancellationToken externalCancellationToken, 54 | CancellationToken parentCancellationToken) 55 | { 56 | switch (_state) 57 | { 58 | case ControllerState.Created: 59 | { 60 | _lifetimeTokenSource = CancellationTokenSource.CreateLinkedTokenSource(externalCancellationToken, parentCancellationToken); 61 | AddDisposable(_lifetimeTokenSource); 62 | _lifetimeToken = _lifetimeTokenSource.Token; 63 | _lifetimeToken.ThrowIfCancellationRequested(); 64 | _state = ControllerState.Initialized; 65 | ProfileOnCreated(); 66 | break; 67 | } 68 | default: 69 | throw new InvalidOperationException($"{Name} Initialized called from non-'Created' state. Current state: {_state}"); 70 | } 71 | } 72 | 73 | void IController.Start() 74 | { 75 | switch (_state) 76 | { 77 | case ControllerState.Initialized: 78 | { 79 | _state = ControllerState.Running; 80 | OnStart(); 81 | ProfileOnStart(); 82 | break; 83 | } 84 | default: 85 | throw new InvalidOperationException($"{Name} Controller should be initialized before adding. Current state: {_state}"); 86 | } 87 | } 88 | 89 | void IDisposable.Dispose() 90 | { 91 | try 92 | { 93 | ((IController)this).Stop(); 94 | } 95 | finally 96 | { 97 | DisposeInternal(); 98 | } 99 | } 100 | 101 | void IController.Stop() 102 | { 103 | switch (_state) 104 | { 105 | case ControllerState.Created: 106 | case ControllerState.Initialized: 107 | case ControllerState.Running: 108 | StopChildrenAndSelf(); 109 | ProfileOnStop(); 110 | break; 111 | case ControllerState.Stopped: 112 | case ControllerState.Disposed: 113 | break; 114 | default: 115 | throw new InvalidOperationException($"{Name} Controller can not be stopped from current state: {_state}"); 116 | } 117 | } 118 | 119 | void IController.Stop(Exception rootCauseException) 120 | { 121 | try 122 | { 123 | ((IController)this).Stop(); 124 | } 125 | catch (Exception exception) 126 | { 127 | throw new AggregateException(rootCauseException, exception); 128 | } 129 | } 130 | 131 | private void DisposeInternal() 132 | { 133 | switch (_state) 134 | { 135 | case ControllerState.Initialized: 136 | case ControllerState.Running: 137 | case ControllerState.Stopped: 138 | { 139 | _lifetimeTokenSource?.Cancel(); 140 | _compositeDisposables.Dispose(); 141 | ListPool.Release(_childControllers); 142 | _state = ControllerState.Disposed; 143 | break; 144 | } 145 | 146 | case ControllerState.Disposed: 147 | break; 148 | 149 | default: 150 | throw new InvalidOperationException($"{Name} Controller can not be disposed from current state: {_state}"); 151 | } 152 | } 153 | 154 | private void AddChild(IController controller) 155 | { 156 | _childControllers.Add(controller); 157 | } 158 | 159 | private void RemoveChild(IController controller) 160 | { 161 | _childControllers.Remove(controller); 162 | } 163 | 164 | private void StopChildrenAndSelf() 165 | { 166 | using var poolToken = ListPool.Get(out var exceptions); 167 | var childControllers = _childControllers.ToArray(); 168 | foreach (var child in childControllers) 169 | { 170 | try 171 | { 172 | child.Stop(); 173 | } 174 | catch (Exception exception) 175 | { 176 | exceptions.Add(exception); 177 | } 178 | } 179 | 180 | AddDisposables(_childControllers); 181 | _state = ControllerState.Stopped; 182 | 183 | try 184 | { 185 | OnStop(); 186 | } 187 | catch (Exception exception) 188 | { 189 | if (exceptions.Any()) 190 | { 191 | exceptions.Add(exception); 192 | } 193 | else 194 | { 195 | throw; 196 | } 197 | } 198 | 199 | if (exceptions.Any()) 200 | { 201 | throw new AggregateException(exceptions); 202 | } 203 | } 204 | 205 | public override string ToString() 206 | { 207 | return _state switch 208 | { 209 | ControllerState.Running => Name, 210 | _ => $"{Name} : {_state}" 211 | }; 212 | } 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerBase.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ab6a76801e6a39c469cb1d918b84af4f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerBase`1.cs: -------------------------------------------------------------------------------- 1 | namespace Playtika.Controllers 2 | { 3 | public class ControllerBase : ControllerBase, IController 4 | { 5 | protected TArg Args { get; private set; } = default; 6 | 7 | protected ControllerBase(IControllerFactory controllerFactory) 8 | : base(controllerFactory) 9 | { 10 | } 11 | 12 | void IController.SetArgInternal(TArg arg) 13 | { 14 | Args = arg; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerBase`1.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7d7143ae0ea3c4487bf7e04bca18574b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerWithResultBase.cs: -------------------------------------------------------------------------------- 1 | namespace Playtika.Controllers 2 | { 3 | public abstract class ControllerWithResultBase : ControllerWithResultBase 4 | { 5 | protected ControllerWithResultBase(IControllerFactory controllerFactory) 6 | : base(controllerFactory) 7 | { 8 | } 9 | 10 | /// 11 | /// Complete controller with default result. 12 | /// 13 | protected void Complete() 14 | { 15 | Complete(default); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerWithResultBase.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 40de3ed3419927f44af9908eb7674092 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerWithResultBase`1.cs: -------------------------------------------------------------------------------- 1 | namespace Playtika.Controllers 2 | { 3 | public abstract class ControllerWithResultBase : ControllerWithResultBase, IControllerWithResult 4 | { 5 | protected ControllerWithResultBase(IControllerFactory controllerFactory) 6 | : base(controllerFactory) 7 | { 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerWithResultBase`1.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b7b77d4e4b51546649fd0e649c62b4c2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerWithResultBase`2.Editor.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_EDITOR 2 | using UnityEngine; 3 | 4 | namespace Playtika.Controllers 5 | { 6 | public partial class ControllerWithResultBase : ControllerBase, IControllerDebugInfo 7 | { 8 | private bool _inFlowAsyncCompleted; 9 | 10 | protected override string ControllerTypeInternal() => 11 | nameof(ControllerWithResultBase); 12 | 13 | protected override string StateNameInternal() 14 | { 15 | switch (_withResultState) 16 | { 17 | case ControllerWithResultState.WaitForResultAsync: 18 | return _inFlowAsyncCompleted 19 | ? ControllerWithResultState.WaitForResultAsync.ToString() 20 | : "await OnFlowAsync()"; 21 | default: 22 | return base.StateNameInternal(); 23 | } 24 | } 25 | 26 | protected override Color StateColorInternal() 27 | { 28 | switch (_withResultState) 29 | { 30 | case ControllerWithResultState.None: 31 | return Color.white; 32 | case ControllerWithResultState.WaitForResultAsync: 33 | return _inFlowAsyncCompleted 34 | ? new Color(0.25f, 0.65f, 0.75f, 1.0f) 35 | : new Color(1.0f, 0.647f, 0.0f, 1.0f); 36 | case ControllerWithResultState.Completed: 37 | return new Color(0.13f, 0.9f, 0f); 38 | case ControllerWithResultState.Failed: 39 | return Color.red; 40 | default: 41 | return Color.magenta; 42 | } 43 | } 44 | } 45 | } 46 | #endif 47 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerWithResultBase`2.Editor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 014a8fc6ff08142a48aaa67fbd2e459e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerWithResultBase`2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using Cysharp.Threading.Tasks; 4 | 5 | namespace Playtika.Controllers 6 | { 7 | public abstract partial class ControllerWithResultBase : ControllerBase, IControllerWithResult 8 | { 9 | private readonly UniTaskCompletionSource _resultSource = new UniTaskCompletionSource(); 10 | private ControllerWithResultState _withResultState; 11 | 12 | protected ControllerWithResultBase(IControllerFactory controllerFactory) 13 | : base(controllerFactory) 14 | { 15 | } 16 | 17 | async UniTask IControllerWithResult.FlowAsync(CancellationToken cancellationToken) 18 | { 19 | switch (_withResultState) 20 | { 21 | case ControllerWithResultState.None: 22 | { 23 | await OnFlowAsync(cancellationToken); 24 | #if UNITY_EDITOR 25 | _inFlowAsyncCompleted = true; 26 | #endif 27 | break; 28 | } 29 | case ControllerWithResultState.Completed: 30 | case ControllerWithResultState.Failed: 31 | break; 32 | default: 33 | throw new InvalidOperationException( 34 | $"{Name} Flow async called from incorrect state. Current state: {_withResultState}"); 35 | } 36 | } 37 | 38 | async UniTask IControllerWithResult.GetResult(CancellationToken token) 39 | { 40 | switch (_withResultState) 41 | { 42 | case ControllerWithResultState.None: 43 | break; 44 | case ControllerWithResultState.WaitForResultAsync: 45 | throw new InvalidOperationException( 46 | $"{Name} ControllerWithResult awaited from incorrect state: {_withResultState}"); 47 | case ControllerWithResultState.Completed: 48 | case ControllerWithResultState.Failed: 49 | break; 50 | } 51 | 52 | _withResultState = ControllerWithResultState.WaitForResultAsync; 53 | await using (token.Register(Cancel, true)) 54 | { 55 | return await _resultSource.Task; 56 | } 57 | } 58 | 59 | void IControllerWithResult.FailInternal(Exception exception) 60 | { 61 | Fail(exception); 62 | } 63 | 64 | /// 65 | /// Override this for controller async flow. 66 | /// Started automatically after execute controller. 67 | /// 68 | /// Cancellation token. 69 | /// 70 | protected virtual UniTask OnFlowAsync(CancellationToken cancellationToken) 71 | { 72 | return UniTask.CompletedTask; 73 | } 74 | 75 | /// 76 | /// Complete controller with result. 77 | /// 78 | /// Controller result. 79 | protected void Complete(TResult result) 80 | { 81 | _withResultState = ControllerWithResultState.Completed; 82 | _resultSource.TrySetResult(result); 83 | } 84 | 85 | /// 86 | /// Complete controller with result. 87 | /// 88 | /// Exception that caused the controller to stop operating. 89 | protected void Fail(Exception exception) 90 | { 91 | _withResultState = ControllerWithResultState.Failed; 92 | _resultSource.TrySetException(exception); 93 | } 94 | 95 | private void Cancel() 96 | { 97 | _withResultState = ControllerWithResultState.Failed; 98 | _resultSource.TrySetCanceled(); 99 | } 100 | 101 | public override string ToString() 102 | { 103 | return _withResultState switch 104 | { 105 | ControllerWithResultState.WaitForResultAsync => $"{Name} : {_withResultState}", 106 | _ => base.ToString() 107 | }; 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/ControllerWithResultBase`2.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 311fc035b77fb460c97ad2b41478fec0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/RootController.Profiler.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_CONTROLLERS_PROFILER 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Threading; 5 | using Cysharp.Threading.Tasks; 6 | using Unity.Collections; 7 | using Unity.Profiling; 8 | using UnityEngine.Profiling; 9 | 10 | namespace Playtika.Controllers 11 | { 12 | public partial class RootController 13 | { 14 | private static readonly ProfilerCategory ControllerProfilerCategory = ProfilerCategory.Scripts; 15 | 16 | private static readonly ProfilerCounterValue TotalControllersCount = 17 | new ProfilerCounterValue( 18 | ControllerProfilerCategory, Helper.TotalControllersCount, 19 | ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame); 20 | 21 | private static readonly ProfilerCounterValue ActiveControllersCount = 22 | new ProfilerCounterValue( 23 | ControllerProfilerCategory, Helper.ActiveControllersCount, 24 | ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame); 25 | 26 | private static readonly ProfilerCounterValue CreateThisFrameControllersCount = 27 | new ProfilerCounterValue( 28 | ControllerProfilerCategory, Helper.CreateThisFrameControllersCount, 29 | ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame); 30 | private HashSet _savedNames = new HashSet(); 31 | 32 | partial void ProfileOnStart() 33 | { 34 | MadeSnapshot(CancellationToken).Forget(); 35 | } 36 | 37 | private async UniTaskVoid MadeSnapshot(CancellationToken cancellationToken) 38 | { 39 | while (!cancellationToken.IsCancellationRequested) 40 | { 41 | await UniTask.Yield(PlayerLoopTiming.LastUpdate); 42 | PushToProfilerStream(); 43 | } 44 | } 45 | 46 | private void PushToProfilerStream() 47 | { 48 | if (!Profiler.enabled) 49 | { 50 | return; 51 | } 52 | 53 | TotalControllersCount.Value = _totalCount; 54 | ActiveControllersCount.Value = _activeCount; 55 | CreateThisFrameControllersCount.Value = _createdThisFrameCount; 56 | _createdThisFrameCount = 0; 57 | 58 | var count = _activeCount; 59 | var frameData = new NativeArray(count, Allocator.Persistent); 60 | var frameDataIndex = 0; 61 | ProfilerDumpTree((ControllerBase) this, frameData, ref frameDataIndex, 0); 62 | Profiler.EmitFrameMetaData(Helper.ControllerProfilerGuid, Helper.ControllerRunTag, frameData); 63 | frameData.Dispose(); 64 | } 65 | 66 | private void ProfilerDumpTree( 67 | ControllerBase controllerBase, 68 | NativeArray frameData, 69 | ref int frameDataIndex, 70 | int level) 71 | { 72 | var scopeName = controllerBase.ScopeName; 73 | frameData[frameDataIndex] = new RunControllerFrameData() 74 | { 75 | NameHash = controllerBase.Name.GetHashCode(), 76 | ScopeHash = scopeName.GetHashCode(), 77 | InstanceId = controllerBase._instanceId, 78 | Level = level, 79 | StartTimeMSec = controllerBase._startTimeMSec, 80 | ElapsedMilliseconds = controllerBase.GetLifetime(), 81 | }; 82 | 83 | ++frameDataIndex; 84 | 85 | var nameHash = scopeName.GetHashCode(); 86 | if (!_savedNames.Contains(nameHash)) 87 | { 88 | PushScopeNameToStream(scopeName, nameHash); 89 | _savedNames.Add(nameHash); 90 | } 91 | 92 | foreach (var child in controllerBase.ChildControllers) 93 | { 94 | ProfilerDumpTree((ControllerBase) child, frameData, ref frameDataIndex, level + 2); 95 | } 96 | } 97 | 98 | private static void PushScopeNameToStream(string name, int nameHash) 99 | { 100 | var nameData = new NativeArray(1, Allocator.Persistent); 101 | nameData[0] = new NameSessionData() 102 | { 103 | NameHash = nameHash, 104 | Name = name 105 | }; 106 | Profiler.EmitSessionMetaData(Helper.ControllerProfilerGuid, Helper.ScopeNameTag, nameData); 107 | nameData.Dispose(); 108 | } 109 | } 110 | } 111 | #endif 112 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/RootController.Profiler.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: db2b7a8e2d894400cb9af017be93308f -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/RootController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Threading; 4 | 5 | namespace Playtika.Controllers 6 | { 7 | public abstract partial class RootController : ControllerBase 8 | { 9 | protected RootController(IControllerFactory controllerFactory) 10 | : base(controllerFactory) 11 | { 12 | } 13 | 14 | partial void ProfileOnStart(); 15 | 16 | /// 17 | /// Launches the execution of the controller tree. 18 | /// This method initializes the root controller with the provided cancellation token, starts it, and registers a callback to stop the root controller when the cancellation token is cancelled. 19 | /// 20 | /// A cancellation token that can be used to cancel the operation. 21 | public void LaunchTree(CancellationToken cancellationToken) 22 | { 23 | var registration = cancellationToken.Register(StopRootController, true); 24 | AddDisposable(registration); 25 | ((IController)this).Initialize(cancellationToken, CancellationToken.None); 26 | ((IController)this).Start(); 27 | } 28 | 29 | private void StopRootController() 30 | { 31 | ((IDisposable)this).Dispose(); 32 | } 33 | 34 | protected override void OnStart() 35 | { 36 | SetRootController(this); 37 | ProfileOnStart(); 38 | } 39 | 40 | protected override void OnStop() 41 | { 42 | SetRootController(null); 43 | } 44 | 45 | public string DumpControllersTree() 46 | { 47 | return Dump(); 48 | } 49 | 50 | [Conditional("UNITY_EDITOR"), Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_BUILDTYPE_DEV")] 51 | private static void SetRootController(ControllerBase controller) 52 | { 53 | #if UNITY_EDITOR || DEVELOPMENT_BUILD || UNITY_BUILDTYPE_DEV 54 | Instance = controller; 55 | #endif 56 | } 57 | 58 | #if UNITY_EDITOR || DEVELOPMENT_BUILD || UNITY_BUILDTYPE_DEV 59 | public static ControllerBase Instance { get; private set; } 60 | #endif 61 | } 62 | } -------------------------------------------------------------------------------- /src/ControllersTree/Core/Controllers/RootController.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b1826eeb44b304979a6de21b70e9d057 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Interfaces.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b4497a84772143bdb2f4b06a0c085dcd 3 | timeCreated: 1706189428 -------------------------------------------------------------------------------- /src/ControllersTree/Core/Interfaces/IController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | 5 | namespace Playtika.Controllers 6 | { 7 | public interface IController : IDisposable 8 | { 9 | string Name { get; } 10 | internal CancellationToken CancellationToken { get; } 11 | void AddDisposable(IDisposable disposable); 12 | void AddDisposables(IEnumerable collection); 13 | internal void Initialize(CancellationToken externalCancellationToken, CancellationToken parentCancellationToken); 14 | internal void Start(); 15 | internal void Stop(); 16 | internal void Stop(Exception rootCauseException); 17 | internal void ScanTree(List controllersTree, string prefix); 18 | } 19 | 20 | public interface IController 21 | { 22 | internal void SetArgInternal(TArg arg); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Interfaces/IController.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f707ca318eab4550af85ab3e874ab913 3 | timeCreated: 1631522012 -------------------------------------------------------------------------------- /src/ControllersTree/Core/Interfaces/IControllerDebugInfo.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_EDITOR 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Threading; 5 | using UnityEngine; 6 | 7 | namespace Playtika.Controllers 8 | { 9 | internal interface IControllerDebugInfo : IEnumerable 10 | { 11 | internal string ControllerType { get; } 12 | internal string StateName { get; } 13 | internal Color StateColor { get; } 14 | internal string ScopeName { get; } 15 | void AddDisposable(IDisposable disposable); 16 | } 17 | } 18 | #endif 19 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Interfaces/IControllerDebugInfo.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f743a087b4e74810b7087504e1edf1d8 3 | timeCreated: 1711475460 -------------------------------------------------------------------------------- /src/ControllersTree/Core/Interfaces/IControllerFactory.cs: -------------------------------------------------------------------------------- 1 | namespace Playtika.Controllers 2 | { 3 | public interface IControllerFactory 4 | { 5 | IController Create() where T : class, IController; 6 | } 7 | } -------------------------------------------------------------------------------- /src/ControllersTree/Core/Interfaces/IControllerFactory.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0fe30bb0aea44f62a4d6a3a2ec0fa5dc 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Interfaces/IControllerWithResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using Cysharp.Threading.Tasks; 4 | 5 | namespace Playtika.Controllers 6 | { 7 | public interface IControllerWithResult : IController 8 | { 9 | internal UniTask FlowAsync(CancellationToken cancellationToken); 10 | internal UniTask GetResult(CancellationToken token); 11 | internal void FailInternal(Exception exception); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Interfaces/IControllerWithResult.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 718afbf6fb9448dc9eb8753ca7eaf06b 3 | timeCreated: 1631610958 -------------------------------------------------------------------------------- /src/ControllersTree/Core/Playtika.Controllers.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Playtika.Controllers", 3 | "rootNamespace": "", 4 | "references": [ 5 | "UniTask", 6 | "Unity.Profiling.Core" 7 | ], 8 | "includePlatforms": [], 9 | "excludePlatforms": [], 10 | "allowUnsafeCode": true, 11 | "overrideReferences": false, 12 | "precompiledReferences": [], 13 | "autoReferenced": true, 14 | "defineConstraints": [], 15 | "versionDefines": [], 16 | "noEngineReferences": false 17 | } -------------------------------------------------------------------------------- /src/ControllersTree/Core/Playtika.Controllers.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 79674ce12bb9f467aada6ac5d6ba8345 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Profiler.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d1c738452f0be498ead055c104ebb697 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Profiler/FixedString.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_CONTROLLERS_PROFILER 2 | using System; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace Playtika.Controllers 6 | { 7 | [StructLayout(LayoutKind.Sequential)] 8 | public struct FixedString 9 | { 10 | public unsafe fixed byte Data[128]; 11 | 12 | public override unsafe string ToString() 13 | { 14 | fixed (byte* dataPtr = Data) 15 | { 16 | return GetStringFromFixedBytes(dataPtr); 17 | } 18 | } 19 | 20 | private unsafe void Set(string value) 21 | { 22 | fixed (byte* dataPtr = Data) 23 | { 24 | CopyToFixedBytes(value, dataPtr, 128); 25 | } 26 | } 27 | 28 | private static unsafe void CopyToFixedBytes(string source, byte* destination, int maxLength) 29 | { 30 | if (source == null) 31 | { 32 | destination[0] = 0; 33 | return; 34 | } 35 | 36 | var bytes = System.Text.Encoding.UTF8.GetBytes(source); 37 | var bytesToCopy = Math.Min(bytes.Length, maxLength - 1); 38 | 39 | for (int i = 0; i < bytesToCopy; i++) 40 | { 41 | destination[i] = bytes[i]; 42 | } 43 | 44 | destination[bytesToCopy] = 0; 45 | } 46 | 47 | private static unsafe string GetStringFromFixedBytes(byte* source) 48 | { 49 | var byteLength = 0; 50 | while (source[byteLength] != 0) 51 | { 52 | byteLength++; 53 | } 54 | 55 | return System.Text.Encoding.UTF8.GetString(source, byteLength); 56 | } 57 | 58 | public static implicit operator FixedString(string value) 59 | { 60 | var result = new FixedString(); 61 | result.Set(value); 62 | return result; 63 | } 64 | 65 | public static implicit operator string(FixedString value) 66 | { 67 | return value.ToString(); 68 | } 69 | } 70 | } 71 | #endif -------------------------------------------------------------------------------- /src/ControllersTree/Core/Profiler/FixedString.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ec5b5a8e7e364a50bf6786a3cc1bf0ac 3 | timeCreated: 1744622484 -------------------------------------------------------------------------------- /src/ControllersTree/Core/Profiler/Helper.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_CONTROLLERS_PROFILER 2 | using System; 3 | using System.Runtime.InteropServices; 4 | using UnityEngine; 5 | 6 | namespace Playtika.Controllers 7 | { 8 | [StructLayout(LayoutKind.Sequential)] 9 | public struct NameSessionData 10 | { 11 | public int NameHash; 12 | public FixedString Name; 13 | } 14 | 15 | [StructLayout(LayoutKind.Sequential)] 16 | public struct CreateControllerFrameData 17 | { 18 | public int NameHash; 19 | public long StartTimeMSec; 20 | } 21 | 22 | [StructLayout(LayoutKind.Sequential)] 23 | public struct StopControllerFrameData 24 | { 25 | public int NameHash; 26 | public long ElapsedMilliseconds; 27 | } 28 | 29 | [StructLayout(LayoutKind.Sequential)] 30 | public struct RunControllerFrameData 31 | { 32 | public int NameHash; 33 | public int ScopeHash; 34 | public int InstanceId; 35 | public int Level; 36 | public long StartTimeMSec; 37 | public long ElapsedMilliseconds; 38 | } 39 | 40 | public static class Helper 41 | { 42 | public static readonly Guid ControllerProfilerGuid = new Guid("3E26292C-09A6-4DFD-8EC7-9BF7E5E3B837"); 43 | public const int ControllerNameTag = 0; 44 | public const int ControllerStartTag = 1; 45 | public const int ControllerStopTag = 2; 46 | public const int ControllerRunTag = 3; 47 | public const int ScopeNameTag = 4; 48 | 49 | public const string TotalControllersCount = "Total Controllers Count"; 50 | public const string ActiveControllersCount = "Active Controllers Count"; 51 | public const string CreateThisFrameControllersCount = "Create This Frame Controllers Count"; 52 | } 53 | } 54 | #endif 55 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Profiler/Helper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c0bb821e372a46ffa78aa989720102a1 3 | timeCreated: 1743081058 -------------------------------------------------------------------------------- /src/ControllersTree/Core/States.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 15d96f2194aa442eb2701a500f877e3e 3 | timeCreated: 1706189482 -------------------------------------------------------------------------------- /src/ControllersTree/Core/States/ControllerState.cs: -------------------------------------------------------------------------------- 1 | namespace Playtika.Controllers 2 | { 3 | internal enum ControllerState 4 | { 5 | Created, 6 | Initialized, 7 | Running, 8 | Stopped, 9 | Disposed 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/States/ControllerState.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bceb95e723a47694797c3b728e00dc19 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/States/ControllerWithResultState.cs: -------------------------------------------------------------------------------- 1 | namespace Playtika.Controllers 2 | { 3 | internal enum ControllerWithResultState 4 | { 5 | None, 6 | WaitForResultAsync, 7 | Completed, 8 | Failed 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/States/ControllerWithResultState.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e3fc17be28c94e7797ad0ccb8155bfab 3 | timeCreated: 1704819390 -------------------------------------------------------------------------------- /src/ControllersTree/Core/Utils.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 637847f6504343d48e60eb687c5cca56 3 | timeCreated: 1710341916 -------------------------------------------------------------------------------- /src/ControllersTree/Core/Utils/ControllerCompositeDisposable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEngine.Pool; 5 | 6 | namespace Playtika.Controllers 7 | { 8 | /// 9 | /// Component of controller that keeps related disposable object that must be disposed together with the running controller. 10 | /// 11 | public class ControllerCompositeDisposable : IDisposable 12 | { 13 | private readonly List _disposables = ListPool.Get(); 14 | 15 | /// 16 | /// Adds a disposable object to the internal list of disposables. 17 | /// 18 | /// The disposable object to add to the list. 19 | public void Add(IDisposable disposable) 20 | { 21 | _disposables.Add(disposable); 22 | } 23 | 24 | /// 25 | /// Adds a collection of disposable objects to the internal list of disposables. 26 | /// 27 | /// The collection of disposable objects to add to the list. 28 | public void AddRange(IEnumerable collection) 29 | { 30 | _disposables.AddRange(collection); 31 | } 32 | 33 | public void Dispose() 34 | { 35 | using var pooledObject = ListPool.Get(out var exceptionList); 36 | 37 | foreach (var disposable in _disposables) 38 | { 39 | try 40 | { 41 | disposable.Dispose(); 42 | } 43 | catch (Exception e) 44 | { 45 | exceptionList.Add(e); 46 | } 47 | } 48 | 49 | _disposables.Clear(); 50 | 51 | ListPool.Release(_disposables); 52 | 53 | if (exceptionList.Any()) 54 | { 55 | throw new AggregateException(exceptionList); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Utils/ControllerCompositeDisposable.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8d1d3b5672824a1fbf3d2534b352533d 3 | timeCreated: 1710339163 -------------------------------------------------------------------------------- /src/ControllersTree/Core/Utils/DisposableToken.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using JetBrains.Annotations; 3 | 4 | namespace Playtika.Controllers 5 | { 6 | /// 7 | /// Disposable Token for keeping action to be executed on dispose. 8 | /// 9 | public class DisposableToken : IDisposable 10 | { 11 | private readonly Action _disposeAction; 12 | 13 | public DisposableToken([NotNull] Action disposeAction) 14 | { 15 | _disposeAction = disposeAction ?? throw new ArgumentNullException(nameof(disposeAction)); 16 | } 17 | 18 | public void Dispose() 19 | { 20 | _disposeAction.Invoke(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/ControllersTree/Core/Utils/DisposableToken.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bcda0a257ec74610986d22dc2b97f120 3 | timeCreated: 1734556610 -------------------------------------------------------------------------------- /src/ControllersTree/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 91c30646bd904d30a970932115182228 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 729195b0ebc81484bb1a2e1c6ec317a7 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllerTabData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace Playtika.Controllers.Editor 5 | { 6 | public readonly struct ControllerTabData 7 | { 8 | public readonly string TabName; 9 | public readonly GUIContent TabContent; 10 | 11 | public readonly bool IsClosable; 12 | public readonly Action TabDrawCallback; 13 | public readonly Action TabReloadCallback; 14 | public readonly Action TabOnCallback; 15 | public readonly Action TabOffCallback; 16 | 17 | public ControllerTabData( 18 | string tabName, 19 | string tabTooltip, 20 | bool isClosable, 21 | Action tabDrawCallback, 22 | Action tabReloadCallback, 23 | Action tabOnCallback = null, 24 | Action tabOffCallback = null) 25 | { 26 | TabName = tabName; 27 | TabContent = new GUIContent(TabName, tabTooltip); 28 | 29 | IsClosable = isClosable; 30 | TabDrawCallback = tabDrawCallback; 31 | TabReloadCallback = tabReloadCallback; 32 | TabOnCallback = tabOnCallback; 33 | TabOffCallback = tabOffCallback; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllerTabData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e9fc7c13a94c4476a167ff3e2305e00c 3 | timeCreated: 1643136125 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllerTreeView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 76778fe942284e418d3a85fa138b203d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllersHierarchy.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 66e269b1075343b791d569fd24d50ff9 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllersHierarchyView.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace Playtika.Controllers.Editor 5 | { 6 | internal class ControllersHierarchyView 7 | { 8 | private readonly ControllerTreeView _controllerTreeView; 9 | private readonly ControllersTreeViewModel _model; 10 | 11 | private string _searchString; 12 | private Vector3 _scrollPos; 13 | 14 | internal ControllersHierarchyView(ControllerTreeView controllerTreeView, ControllersTreeViewModel model) 15 | { 16 | _model = model; 17 | _controllerTreeView = controllerTreeView; 18 | } 19 | 20 | internal void Draw() 21 | { 22 | using var verticalScope = new GUILayout.VerticalScope(); 23 | using (new GUILayout.HorizontalScope()) 24 | { 25 | using (var vertScope = new EditorGUILayout.VerticalScope( 26 | GUI.skin.box, GUILayout.Width(_model.HierarchyWidth), GUILayout.Height(_model.TopPanelHeight))) 27 | { 28 | using (new GUILayout.HorizontalScope()) 29 | { 30 | GUILayout.Space(4f); 31 | var searchString = GUILayout.TextField(_searchString, _model.SearchStyle, GUILayout.ExpandWidth(true)); 32 | if (searchString != _searchString) 33 | { 34 | _searchString = searchString; 35 | _controllerTreeView.searchString = _searchString; 36 | _controllerTreeView.Reload(); 37 | } 38 | 39 | if (GUILayout.Button("", _model.CancelSearchStyle)) 40 | { 41 | _searchString = null; 42 | _controllerTreeView.searchString = _searchString; 43 | _controllerTreeView.Reload(); 44 | } 45 | 46 | GUILayout.Space(2f); 47 | } 48 | 49 | GUILayout.Space(-36); 50 | 51 | using (var scrollScope = new GUILayout.ScrollViewScope(_scrollPos)) 52 | { 53 | _scrollPos = scrollScope.scrollPosition; 54 | var rect = vertScope.rect; 55 | rect.width -= 8f; 56 | rect.height -= 26f; 57 | _controllerTreeView.OnGUI(rect); 58 | } 59 | } 60 | 61 | if (_model.IsRightPanelVisible) 62 | { 63 | var style = new GUIStyle(GUI.skin.textArea); 64 | style.padding.left = 2; 65 | style.padding.right = 2; 66 | using (var vertScope = new EditorGUILayout.VerticalScope( 67 | style, GUILayout.Width(ControllersTreeViewModel.SEPARATOR_SIZE), GUILayout.ExpandHeight(true))) 68 | { 69 | _model.SetVerticalSeparatorRect(vertScope.rect); 70 | EditorGUI.DrawRect(vertScope.rect, ControllersTreeHelper.DividingLineColor); 71 | } 72 | } 73 | 74 | _controllerTreeView.DrawRightPanel(); 75 | } 76 | 77 | DrawBottom(); 78 | } 79 | 80 | private void DrawBottom() 81 | { 82 | using var verticalScope = new GUILayout.VerticalScope(GUILayout.Height(_model.BottomPanelHeight)); 83 | if (_model.IsBottomPanelVisible) 84 | { 85 | var style = new GUIStyle(GUI.skin.textArea); 86 | style.padding.top = 2; 87 | style.padding.bottom = 2; 88 | using var horizontalScope = new EditorGUILayout.HorizontalScope( 89 | style, GUILayout.Height(ControllersTreeViewModel.SEPARATOR_SIZE), GUILayout.ExpandWidth(true)); 90 | _model.SetHorizontalSeparatorRect(horizontalScope.rect); 91 | EditorGUI.DrawRect(horizontalScope.rect, ControllersTreeHelper.DividingLineColor); 92 | } 93 | 94 | _controllerTreeView.DrawBottomPanel(); 95 | } 96 | 97 | internal void Reload() 98 | { 99 | _controllerTreeView.Reload(); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllersHierarchyView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f88cea12561c4c5383caa9529afe7666 3 | timeCreated: 1643196344 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllersInfoView.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Playtika.Controllers; 3 | using UnityEditor; 4 | using UnityEngine; 5 | 6 | namespace Playtika.Controllers.Editor 7 | { 8 | internal class ControllersInfoView 9 | { 10 | private readonly ControllersTreeViewModel _model; 11 | 12 | private List _staticFields; 13 | private List _otherFields; 14 | private object _target; 15 | private Vector2 _scrollPosition; 16 | 17 | internal ControllersInfoView(ControllersTreeViewModel model) 18 | { 19 | _model = model; 20 | } 21 | 22 | internal void SelectedController(object target) 23 | { 24 | _target = target; 25 | if (target == null) 26 | { 27 | _staticFields = null; 28 | _otherFields = null; 29 | return; 30 | } 31 | 32 | _staticFields = new List(); 33 | _otherFields = new List(); 34 | 35 | var fieldsInfo = ControllersFieldsFactory.GetFields(target); 36 | foreach (var info in fieldsInfo) 37 | { 38 | if (info.IsStatic) 39 | { 40 | _staticFields.Add(ControllersFieldsFactory.CreateFieldDrawer(info, _target)); 41 | } 42 | else 43 | { 44 | _otherFields.Add(ControllersFieldsFactory.CreateFieldDrawer(info, _target)); 45 | } 46 | } 47 | } 48 | 49 | internal void DrawInfos() 50 | { 51 | if (!_model.IsBottomPanelVisible) 52 | { 53 | return; 54 | } 55 | 56 | using var verticalScope = new GUILayout.VerticalScope(GUI.skin.box, GUILayout.Height(_model.BottomPanelHeight)); 57 | using var scrollScope = new GUILayout.ScrollViewScope(_scrollPosition); 58 | _scrollPosition = scrollScope.scrollPosition; 59 | GUILayout.Space(4); 60 | if (_target != null) 61 | { 62 | TryDrawFieldsPart(_staticFields, "Static or Const fields", Color.red, true); 63 | TryDrawFieldsPart(_otherFields, "Simple fields", Color.yellow); 64 | } 65 | else 66 | { 67 | EditorGUILayout.HelpBox("Controller not selected", MessageType.None); 68 | } 69 | } 70 | 71 | private void TryDrawFieldsPart( 72 | List drawers, 73 | string label, 74 | Color color, 75 | bool disabled = false) 76 | { 77 | var backgroundColor = GUI.backgroundColor; 78 | GUI.backgroundColor = color; 79 | using (new EditorGUI.DisabledScope(disabled)) 80 | using (new GUILayout.VerticalScope(GUI.skin.box)) 81 | { 82 | GUI.backgroundColor = backgroundColor; 83 | 84 | GUILayout.Label(label); 85 | if (drawers != null && drawers.Count > 0) 86 | { 87 | drawers.ForEach(f => f.Draw()); 88 | } 89 | else 90 | { 91 | EditorGUILayout.HelpBox("Fields not found", MessageType.None); 92 | } 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllersInfoView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b82abebbe43d49e7bb720bc28b4f2231 3 | timeCreated: 1645778310 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllersMethodsView.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using Playtika.Controllers; 6 | using UnityEditor; 7 | using UnityEngine; 8 | 9 | namespace Playtika.Controllers.Editor 10 | { 11 | internal class ControllersMethodsView 12 | { 13 | private readonly ControllersTreeViewModel _model; 14 | 15 | private List _debugMethods; 16 | private List _simpleMethods; 17 | private List _disabledMethods; 18 | 19 | private Vector2 _scrollPosition; 20 | private object _invokeObject; 21 | 22 | internal ControllersMethodsView(ControllersTreeViewModel model) 23 | { 24 | _model = model; 25 | _debugMethods = new List(); 26 | _simpleMethods = new List(); 27 | _disabledMethods = new List(); 28 | } 29 | 30 | internal void SelectedController(object invokeObject) 31 | { 32 | _debugMethods.Clear(); 33 | _simpleMethods.Clear(); 34 | _disabledMethods.Clear(); 35 | _invokeObject = invokeObject; 36 | 37 | if (_invokeObject == null) 38 | { 39 | return; 40 | } 41 | 42 | var methods = invokeObject.GetType().GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance); 43 | foreach (var method in methods) 44 | { 45 | var attribute = method.GetCustomAttributes(typeof(DebugMethodAttribute), true).SingleOrDefault(); 46 | if (attribute != null) 47 | { 48 | _debugMethods.Add(method); 49 | } 50 | else if (method.GetParameters().Length == 0 && !((IList) _model.IgnoredMethods).Contains(method.Name)) 51 | { 52 | _simpleMethods.Add(method); 53 | } 54 | else 55 | { 56 | _disabledMethods.Add(method); 57 | } 58 | } 59 | } 60 | 61 | internal void DrawMethods() 62 | { 63 | if (_model.IsRightPanelVisible) 64 | { 65 | using (new GUILayout.VerticalScope(GUI.skin.box, GUILayout.Width(_model.RightPanelWidth))) 66 | { 67 | using (var scrollScope = new GUILayout.ScrollViewScope(_scrollPosition)) 68 | { 69 | _scrollPosition = scrollScope.scrollPosition; 70 | GUILayout.Space(4); 71 | DrawMethodsBlock(_debugMethods, "Debug methods:", Color.green); 72 | DrawMethodsBlock(_simpleMethods, "Available methods:", Color.yellow); 73 | DrawMethodsBlock(_disabledMethods, "Disabled methods:", Color.red, true); 74 | } 75 | } 76 | } 77 | } 78 | 79 | private void DrawMethodsBlock( 80 | List methods, 81 | string label, 82 | Color color, 83 | bool disabled = false) 84 | { 85 | var backgroundColor = GUI.backgroundColor; 86 | GUI.backgroundColor = color; 87 | using (new EditorGUI.DisabledScope(disabled)) 88 | using (new GUILayout.VerticalScope(GUI.skin.box)) 89 | { 90 | GUI.backgroundColor = backgroundColor; 91 | 92 | GUILayout.Label(label); 93 | if (methods.Count <= 0) 94 | { 95 | EditorGUILayout.HelpBox("Methods not found", MessageType.None); 96 | return; 97 | } 98 | 99 | foreach (var method in methods) 100 | { 101 | if (GUILayout.Button(method.Name)) 102 | { 103 | method.Invoke(_invokeObject, null); 104 | } 105 | } 106 | } 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllersMethodsView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ebf77e3da4d240f59c42782d5998f331 3 | timeCreated: 1645776674 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllersTabBarDrawer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEditor; 3 | using UnityEngine; 4 | 5 | namespace Playtika.Controllers.Editor 6 | { 7 | public class ControllersTabBarDrawer 8 | { 9 | private readonly ControllersTreeViewModel _model; 10 | 11 | private List _tabData; 12 | private int _index = 0; 13 | private int? _removeIndex; 14 | private Vector2 _scrollPosition; 15 | 16 | public ControllersTabBarDrawer(ControllersTreeViewModel model, ControllerTabData rootTabData) 17 | { 18 | _model = model; 19 | SetData(rootTabData); 20 | } 21 | 22 | private void SetData(ControllerTabData rootTabData) 23 | { 24 | _tabData = new List(); 25 | _tabData.Add(rootTabData); 26 | Select(_index); 27 | } 28 | 29 | public void AddData(ControllerTabData tabData) 30 | { 31 | _tabData.Add(tabData); 32 | } 33 | 34 | private void RemoveData(int index) 35 | { 36 | if (_index >= index) 37 | { 38 | --_index; 39 | } 40 | 41 | _removeIndex = index; 42 | } 43 | 44 | private void Select(int index) 45 | { 46 | _index = Mathf.Clamp(index, 0, _tabData?.Count - 1 ?? 0); 47 | } 48 | 49 | public void Draw() 50 | { 51 | if (_tabData == null || _tabData.Count == 0) 52 | { 53 | return; 54 | } 55 | 56 | using (var changeScope = new EditorGUI.ChangeCheckScope()) 57 | { 58 | var index = _index; 59 | 60 | DrawTabBar(); 61 | 62 | if (changeScope.changed) 63 | { 64 | _tabData[index].TabOffCallback?.Invoke(); 65 | _tabData[_index].TabOnCallback?.Invoke(); 66 | } 67 | 68 | _tabData[_index].TabDrawCallback?.Invoke(); 69 | } 70 | 71 | if (_removeIndex.HasValue) 72 | { 73 | _tabData.RemoveAt(_removeIndex.Value); 74 | _removeIndex = null; 75 | } 76 | } 77 | 78 | public void Reload() 79 | { 80 | if (_tabData == null || _tabData.Count == 0 || _removeIndex.HasValue) 81 | { 82 | return; 83 | } 84 | 85 | _tabData[_index].TabReloadCallback(); 86 | } 87 | 88 | private void DrawTabBar() 89 | { 90 | using var scrollScope = new EditorGUILayout.ScrollViewScope(_scrollPosition, GUIStyle.none, GUIStyle.none, GUILayout.ExpandHeight(false)); 91 | _scrollPosition = scrollScope.scrollPosition; 92 | 93 | using var scope = new EditorGUILayout.HorizontalScope(); 94 | for (int i = 0; i < _tabData.Count; ++i) 95 | { 96 | DrawTabButton(i); 97 | } 98 | } 99 | 100 | private void DrawTabButton(int index) 101 | { 102 | using var scope = new GUILayout.HorizontalScope(GUI.skin.box); 103 | var color = GUI.backgroundColor; 104 | GUI.backgroundColor = Color.clear; 105 | 106 | if (GUILayout.Button(_tabData[index].TabContent, GUI.skin.box, GUILayout.Height(20), GUILayout.Width(128))) 107 | { 108 | _index = index; 109 | } 110 | 111 | GUI.backgroundColor = color; 112 | 113 | if (_tabData[index].IsClosable) 114 | { 115 | using var verticalScope = new GUILayout.VerticalScope(GUILayout.Height(22), GUILayout.Width(20)); 116 | GUILayout.Space(4); 117 | if (GUILayout.Button("", _model.CloseButtonStyle)) 118 | { 119 | RemoveData(index); 120 | } 121 | } 122 | 123 | var colorRect = _index == index 124 | ? ControllersTreeHelper.SelectedColor 125 | : ControllersTreeHelper.UnselectedColor; 126 | var rect = GUILayoutUtility.GetLastRect(); 127 | var lineRect = rect; 128 | lineRect.height = 2; 129 | var center = lineRect.center; 130 | center.y += rect.height; 131 | lineRect.center = center; 132 | 133 | if (rect.Contains(Event.current.mousePosition)) 134 | { 135 | colorRect = ControllersTreeHelper.FocusedColor; 136 | } 137 | 138 | EditorGUI.DrawRect(lineRect, colorRect); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllersTabBarDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ff87ca77c6a84bcc962e4507fe783eaa 3 | timeCreated: 1643130942 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllersTreeHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Playtika.Controllers; 3 | using UnityEditor.Graphs; 4 | using UnityEngine; 5 | 6 | namespace Playtika.Controllers.Editor 7 | { 8 | internal class ControllersTreeHelper 9 | { 10 | internal static readonly Color FocusedColor = new Color(0f, 0.66f, 1f); 11 | internal static readonly Color SelectedColor = new Color(0f, 0.66f, 1f); 12 | internal static readonly Color UnselectedColor = new Color(0.87f, 0.99f, 1f); 13 | internal static readonly Color DividingLineColor = new Color(0.13f, 0.13f, 0.13f, 0.75f); 14 | internal static readonly Color DarkGrayColor = new Color(0.13f, 0.13f, 0.13f, 0.25f); 15 | } 16 | } -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllersTreeHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4c98a4c164b543038abc32999b7407b7 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllersTreeViewItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | using Playtika.Controllers; 5 | using UnityEditor.IMGUI.Controls; 6 | 7 | namespace Playtika.Controllers.Editor 8 | { 9 | internal class ControllersTreeViewItem : TreeViewItem 10 | { 11 | private readonly WeakReference _controllerWeakReference; 12 | 13 | internal IControllerDebugInfo ControllerDebugInfo 14 | { 15 | get 16 | { 17 | if (_controllerWeakReference.IsAlive) 18 | { 19 | return (IControllerDebugInfo)_controllerWeakReference.Target; 20 | } 21 | 22 | return null; 23 | } 24 | } 25 | 26 | internal ControllersTreeViewItem( 27 | int id, 28 | int depth, 29 | IControllerDebugInfo controllerDebugInfo) 30 | : base(id, depth, controllerDebugInfo.ToString()) 31 | { 32 | _controllerWeakReference = new WeakReference(controllerDebugInfo); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllersTreeViewItem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6df563f44a6343cb81b62048f962605a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllersTreeViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Playtika.Controllers; 3 | using UnityEditor; 4 | using UnityEngine; 5 | 6 | namespace Playtika.Controllers.Editor 7 | { 8 | public class ControllersTreeViewModel 9 | { 10 | internal const float SEPARATOR_SIZE = 4f; 11 | 12 | private const float INTERNAL_SEPARATOR_SIZE = SEPARATOR_SIZE * 5; 13 | private const float WINDOW_HEIGHT_ADJUSTMENT = 75; 14 | 15 | internal event Action CreateNewTreeTab; 16 | 17 | internal GUIStyle ToolbarStyle { get; private set; } 18 | internal GUIStyle SearchStyle { get; private set; } 19 | internal GUIStyle CancelSearchStyle { get; private set; } 20 | internal GUIStyle CloseButtonStyle { get; private set; } 21 | 22 | internal bool IsBottomPanelVisible { get; private set; } 23 | internal bool IsRightPanelVisible { get; private set; } 24 | internal float HierarchyWidth => _windowSize.x * _hierarchyPanelWidthPercent; 25 | internal float RightPanelWidth => _windowSize.x * _rightPanelWidthPercent; 26 | internal float TopPanelHeight => _windowSize.y * _topPanelHeightPercent; 27 | internal float BottomPanelHeight => _windowSize.y * _bottomPanelHeightPercent; 28 | internal string[] IgnoredMethods { get; private set; } 29 | 30 | private Vector2 _windowSize; 31 | private bool _isDraggable; 32 | private bool _isHorizontal; 33 | private float _hierarchyPanelWidthPercent; 34 | private float _rightPanelWidthPercent; 35 | private float _topPanelHeightPercent; 36 | private float _bottomPanelHeightPercent; 37 | 38 | internal void LoadGuiSkin() 39 | { 40 | SearchStyle = EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector).FindStyle("ToolbarSearchTextField"); 41 | CancelSearchStyle = EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector).FindStyle("ToolbarSearchCancelButton"); 42 | if (SearchStyle == null || CancelSearchStyle == null) 43 | { 44 | // support for Unity versions with bug 45 | SearchStyle = EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector).FindStyle("ToolbarSeachTextField"); 46 | CancelSearchStyle = EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector).FindStyle("ToolbarSeachCancelButton"); 47 | } 48 | ToolbarStyle = EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector).FindStyle("Toolbar"); 49 | CloseButtonStyle = EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector).FindStyle("WinBtnCloseMac"); 50 | } 51 | 52 | internal void InvokeCreateNewTreeTab(IControllerDebugInfo controller) 53 | { 54 | CreateNewTreeTab?.Invoke(controller); 55 | } 56 | 57 | internal void SwitchRightPanelState() 58 | { 59 | IsRightPanelVisible = !IsRightPanelVisible; 60 | } 61 | 62 | internal void SwitchBottomPanelState() 63 | { 64 | IsBottomPanelVisible = !IsBottomPanelVisible; 65 | } 66 | 67 | internal void SetWindowSize(Vector2 size) 68 | { 69 | _windowSize = size - Vector2.up * WINDOW_HEIGHT_ADJUSTMENT; 70 | if (IsRightPanelVisible) 71 | { 72 | if (RightPanelWidth <= 0) 73 | { 74 | var percent = 0.75f - INTERNAL_SEPARATOR_SIZE / size.x; 75 | _hierarchyPanelWidthPercent = percent; 76 | _rightPanelWidthPercent = 1f - percent; 77 | } 78 | else 79 | { 80 | _hierarchyPanelWidthPercent = 1f - _rightPanelWidthPercent - INTERNAL_SEPARATOR_SIZE / size.x; 81 | } 82 | } 83 | else 84 | { 85 | _hierarchyPanelWidthPercent = 0; 86 | } 87 | 88 | if (IsBottomPanelVisible) 89 | { 90 | if (BottomPanelHeight <= 0) 91 | { 92 | _topPanelHeightPercent = 0.75f; 93 | _bottomPanelHeightPercent = 0.25f; 94 | } 95 | } 96 | else 97 | { 98 | _topPanelHeightPercent = 0; 99 | } 100 | } 101 | 102 | internal void SetVerticalSeparatorRect(Rect verticalSeparatorRect) 103 | { 104 | EditorGUIUtility.AddCursorRect(verticalSeparatorRect, MouseCursor.ResizeHorizontal); 105 | var newMousePosition = Event.current.mousePosition; 106 | 107 | if (Event.current.type == EventType.MouseDown && verticalSeparatorRect.Contains(newMousePosition)) 108 | { 109 | _isDraggable = true; 110 | _isHorizontal = false; 111 | } 112 | 113 | if (_isDraggable && !_isHorizontal) 114 | { 115 | var percent = Mathf.Clamp(Event.current.mousePosition.x / _windowSize.x, 0.25f, 0.75f) - INTERNAL_SEPARATOR_SIZE / _windowSize.x; 116 | _hierarchyPanelWidthPercent = percent; 117 | _rightPanelWidthPercent = 1f - percent; 118 | } 119 | 120 | if (Event.current.type == EventType.MouseUp) 121 | { 122 | _isDraggable = false; 123 | } 124 | } 125 | 126 | internal void SetHorizontalSeparatorRect(Rect horizontalSeparatorRect) 127 | { 128 | EditorGUIUtility.AddCursorRect(horizontalSeparatorRect, MouseCursor.ResizeVertical); 129 | var newMousePosition = Event.current.mousePosition; 130 | 131 | if (Event.current.type == EventType.MouseDown && horizontalSeparatorRect.Contains(newMousePosition)) 132 | { 133 | _isDraggable = true; 134 | _isHorizontal = true; 135 | } 136 | 137 | if (_isDraggable && _isHorizontal) 138 | { 139 | var percent = Mathf.Clamp(Event.current.mousePosition.y / _windowSize.y, 0.25f, 0.75f) - INTERNAL_SEPARATOR_SIZE / _windowSize.y; 140 | _topPanelHeightPercent = percent; 141 | _bottomPanelHeightPercent = 1f - percent; 142 | } 143 | 144 | if (Event.current.type == EventType.MouseUp) 145 | { 146 | _isDraggable = false; 147 | } 148 | } 149 | 150 | internal void SetIgnoredMethods(string[] ignoredMethods) 151 | { 152 | IgnoredMethods = ignoredMethods; 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/ControllersTreeViewModel.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 526e47a4418c4422b9bc1f618d968348 3 | timeCreated: 1643129982 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a815ec5067ae48d885d35ca155913e86 3 | timeCreated: 1646040783 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersActionFieldDrawer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using UnityEngine; 4 | 5 | namespace Playtika.Controllers.Editor 6 | { 7 | public class ControllersActionFieldDrawer : ControllersBaseFieldDrawer 8 | { 9 | public ControllersActionFieldDrawer( 10 | FieldInfo fieldInfo, 11 | object target) 12 | : base(fieldInfo, target) 13 | { 14 | } 15 | 16 | protected override void OnDraw() 17 | { 18 | using (new GUILayout.HorizontalScope()) 19 | { 20 | GUILayout.Label(FieldInfo.Name); 21 | GUILayout.FlexibleSpace(); 22 | if (GUILayout.Button("Invoke")) 23 | { 24 | if (FieldInfo.GetValue(Target) is Action action) 25 | { 26 | action?.Invoke(); 27 | } 28 | } 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersActionFieldDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 142fec94f5504b6d8d580ef832506202 3 | timeCreated: 1646131426 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersBaseFieldDrawer.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using UnityEditor; 3 | using UnityEngine; 4 | 5 | namespace Playtika.Controllers.Editor 6 | { 7 | public abstract class ControllersBaseFieldDrawer 8 | { 9 | protected const string NULL_VALUE = "NULL"; 10 | 11 | protected readonly FieldInfo FieldInfo; 12 | protected readonly object Target; 13 | 14 | protected ControllersBaseFieldDrawer(FieldInfo fieldInfo, object target) 15 | { 16 | FieldInfo = fieldInfo; 17 | Target = target; 18 | } 19 | 20 | public void Draw() 21 | { 22 | try 23 | { 24 | EditorGUI.indentLevel += 1; 25 | var backgroundColor = GUI.backgroundColor; 26 | GUI.backgroundColor = Color.black; 27 | using (new GUILayout.VerticalScope(GUI.skin.box)) 28 | { 29 | GUI.backgroundColor = backgroundColor; 30 | OnDraw(); 31 | } 32 | } 33 | finally 34 | { 35 | EditorGUI.indentLevel -= 1; 36 | } 37 | } 38 | 39 | protected abstract void OnDraw(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersBaseFieldDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 78649b1972244c519b61d621abb43a01 3 | timeCreated: 1646040809 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersBooleanFieldDrawer.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using UnityEditor; 3 | using UnityEngine; 4 | 5 | namespace Playtika.Controllers.Editor 6 | { 7 | public class ControllersBooleanFieldDrawer : ControllersBaseFieldDrawer 8 | { 9 | public ControllersBooleanFieldDrawer( 10 | FieldInfo fieldInfo, 11 | object target) 12 | : base(fieldInfo, target) 13 | { 14 | } 15 | 16 | protected override void OnDraw() 17 | { 18 | using (new GUILayout.HorizontalScope()) 19 | { 20 | GUILayout.Label(FieldInfo.Name); 21 | GUILayout.FlexibleSpace(); 22 | using (var scope = new EditorGUI.ChangeCheckScope()) 23 | { 24 | if (FieldInfo.GetValue(Target) is bool value) 25 | { 26 | value = GUILayout.Toggle(value, ""); 27 | if (scope.changed) 28 | { 29 | FieldInfo.SetValue(Target, value); 30 | } 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersBooleanFieldDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f3854c2d6a8944a0807d6463c37a51ca 3 | timeCreated: 1646133631 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersCollectionFieldDrawer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Reflection; 3 | using UnityEngine; 4 | 5 | namespace Playtika.Controllers.Editor 6 | { 7 | public class ControllersCollectionFieldDrawer : ControllersBaseFieldDrawer 8 | { 9 | private bool _foldout; 10 | 11 | public ControllersCollectionFieldDrawer( 12 | FieldInfo fieldInfo, 13 | object target) 14 | : base(fieldInfo, target) 15 | { 16 | } 17 | 18 | protected override void OnDraw() 19 | { 20 | using (new GUILayout.HorizontalScope()) 21 | { 22 | GUILayout.Label(FieldInfo.Name); 23 | GUILayout.FlexibleSpace(); 24 | GUILayout.Label(FieldInfo.GetValue(Target)?.ToString() ?? NULL_VALUE); 25 | 26 | if (GUILayout.Button(_foldout ? "-" : "+")) 27 | { 28 | _foldout = !_foldout; 29 | } 30 | } 31 | 32 | if (_foldout && FieldInfo.GetValue(Target) is ICollection collection) 33 | { 34 | using (new GUILayout.VerticalScope()) 35 | { 36 | var index = 0; 37 | foreach (var value in collection) 38 | { 39 | using (new GUILayout.HorizontalScope()) 40 | { 41 | GUILayout.Label(index.ToString("D3")); 42 | GUILayout.FlexibleSpace(); 43 | GUILayout.Label(value?.ToString() ?? NULL_VALUE); 44 | ++index; 45 | } 46 | } 47 | } 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersCollectionFieldDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c320ed31153144ad9a2a91ab990a3df5 3 | timeCreated: 1646126641 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersFieldsFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Reflection; 4 | 5 | namespace Playtika.Controllers.Editor 6 | { 7 | public class ControllersFieldsFactory 8 | { 9 | public static FieldInfo[] GetFields(object target) 10 | { 11 | return target.GetType().GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance); 12 | } 13 | 14 | public static ControllersBaseFieldDrawer CreateFieldDrawer(FieldInfo fieldInfo, object target) 15 | { 16 | if (fieldInfo.IsStatic) 17 | { 18 | return new ControllersLabelFieldDrawer(fieldInfo, target); 19 | } 20 | 21 | var value = fieldInfo.GetValue(target); 22 | 23 | switch (value) 24 | { 25 | case string _: 26 | return new ControllersStringFieldDrawer(fieldInfo, target); 27 | case int _: 28 | return new ControllersIntegerFieldDrawer(fieldInfo, target); 29 | case bool _: 30 | return new ControllersBooleanFieldDrawer(fieldInfo, target); 31 | case ICollection _: 32 | return new ControllersCollectionFieldDrawer(fieldInfo, target); 33 | case Action _: 34 | return new ControllersActionFieldDrawer(fieldInfo, target); 35 | case UnityEngine.Object _: 36 | return new ControllersUnityObjectFieldDrawer(fieldInfo, target); 37 | } 38 | 39 | return new ControllersParentObjectFieldDrawer(fieldInfo, target); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersFieldsFactory.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4b5b74fee88f43c1a5fc5884927707b2 3 | timeCreated: 1646048299 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersIntegerFieldDrawer.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using UnityEditor; 3 | using UnityEngine; 4 | 5 | namespace Playtika.Controllers.Editor 6 | { 7 | public class ControllersIntegerFieldDrawer : ControllersBaseFieldDrawer 8 | { 9 | public ControllersIntegerFieldDrawer( 10 | FieldInfo fieldInfo, 11 | object target) 12 | : base(fieldInfo, target) 13 | { 14 | } 15 | 16 | protected override void OnDraw() 17 | { 18 | using (new GUILayout.HorizontalScope()) 19 | { 20 | GUILayout.Label(FieldInfo.Name); 21 | GUILayout.FlexibleSpace(); 22 | using (var scope = new EditorGUI.ChangeCheckScope()) 23 | { 24 | var value = FieldInfo.GetValue(Target) is int 25 | ? (int) FieldInfo.GetValue(Target) 26 | : 0; 27 | value = EditorGUILayout.IntField(value); 28 | if (scope.changed) 29 | { 30 | FieldInfo.SetValue(Target, value); 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersIntegerFieldDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ce073ee5fbaa454788789fa07d647e68 3 | timeCreated: 1646126317 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersLabelFieldDrawer.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using UnityEditor; 3 | using UnityEngine; 4 | 5 | namespace Playtika.Controllers.Editor 6 | { 7 | public class ControllersLabelFieldDrawer : ControllersBaseFieldDrawer 8 | { 9 | public ControllersLabelFieldDrawer( 10 | FieldInfo fieldInfo, 11 | object target) 12 | : base(fieldInfo, target) 13 | { 14 | } 15 | 16 | protected override void OnDraw() 17 | { 18 | using (new GUILayout.HorizontalScope()) 19 | { 20 | GUILayout.Label(FieldInfo.Name); 21 | GUILayout.FlexibleSpace(); 22 | GUILayout.Label(FieldInfo.GetValue(Target)?.ToString() ?? NULL_VALUE); 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersLabelFieldDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8b9b1176ea244b35b192db6d4f1791bd 3 | timeCreated: 1646051705 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersParentObjectFieldDrawer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Reflection; 3 | using UnityEditor; 4 | using UnityEngine; 5 | 6 | namespace Playtika.Controllers.Editor 7 | { 8 | public class ControllersParentObjectFieldDrawer : ControllersBaseFieldDrawer 9 | { 10 | private List _staticChildren; 11 | private List _simpleChildren; 12 | private object _childTarget; 13 | private string _value; 14 | 15 | public ControllersParentObjectFieldDrawer( 16 | FieldInfo fieldInfo, 17 | object target) 18 | : base( 19 | fieldInfo, 20 | target) 21 | { 22 | } 23 | 24 | protected override void OnDraw() 25 | { 26 | using (new GUILayout.HorizontalScope()) 27 | { 28 | _value = FieldInfo.GetValue(Target)?.ToString() ?? NULL_VALUE; 29 | 30 | GUILayout.Label(FieldInfo.Name); 31 | GUILayout.FlexibleSpace(); 32 | GUILayout.Label(_value); 33 | 34 | using (new EditorGUI.DisabledScope(_value == NULL_VALUE)) 35 | { 36 | if (_simpleChildren == null && _staticChildren == null) 37 | { 38 | if (GUILayout.Button("+")) 39 | { 40 | InitializeChildren(); 41 | } 42 | } 43 | else 44 | { 45 | if (GUILayout.Button("-")) 46 | { 47 | RemoveChildren(); 48 | } 49 | } 50 | } 51 | } 52 | 53 | TryDrawChildrenFields(); 54 | } 55 | 56 | private void TryDrawChildrenFields() 57 | { 58 | if (_staticChildren != null) 59 | { 60 | DrawFieldsPart(_staticChildren, "Static or Const fields", Color.red); 61 | } 62 | 63 | if (_simpleChildren != null) 64 | { 65 | DrawFieldsPart(_simpleChildren, "Simple fields", Color.yellow); 66 | } 67 | } 68 | 69 | private void DrawFieldsPart( 70 | List drawers, 71 | string label, 72 | Color color) 73 | { 74 | var backgroundColor = GUI.backgroundColor; 75 | GUI.backgroundColor = color; 76 | using (new GUILayout.VerticalScope(GUI.skin.box)) 77 | { 78 | GUI.backgroundColor = backgroundColor; 79 | 80 | GUILayout.Label(label); 81 | if (drawers.Count > 0) 82 | { 83 | drawers.ForEach(f => f.Draw()); 84 | } 85 | else 86 | { 87 | EditorGUILayout.HelpBox("Fields not found", MessageType.None); 88 | } 89 | } 90 | } 91 | 92 | private void InitializeChildren() 93 | { 94 | _childTarget = FieldInfo.GetValue(Target); 95 | var childInfos = ControllersFieldsFactory.GetFields(_childTarget); 96 | if (childInfos != null) 97 | { 98 | _simpleChildren = new List(); 99 | _staticChildren = new List(); 100 | foreach (var item in childInfos) 101 | { 102 | var fieldInfo = ControllersFieldsFactory.CreateFieldDrawer(item, _childTarget); 103 | if (fieldInfo != null) 104 | { 105 | if (item.IsStatic) 106 | { 107 | _staticChildren.Add(fieldInfo); 108 | } 109 | else 110 | { 111 | _simpleChildren.Add(fieldInfo); 112 | } 113 | } 114 | } 115 | } 116 | } 117 | 118 | private void RemoveChildren() 119 | { 120 | _childTarget = null; 121 | _simpleChildren = null; 122 | _staticChildren = null; 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersParentObjectFieldDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 18521e608dd64d94ae96c0c953505abe 3 | timeCreated: 1646042779 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersStringFieldDrawer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using UnityEditor; 4 | using UnityEngine; 5 | 6 | namespace Playtika.Controllers.Editor 7 | { 8 | public class ControllersStringFieldDrawer : ControllersBaseFieldDrawer 9 | { 10 | public ControllersStringFieldDrawer( 11 | FieldInfo fieldInfo, 12 | object target) 13 | : base(fieldInfo, target) 14 | { 15 | } 16 | 17 | protected override void OnDraw() 18 | { 19 | using (new GUILayout.HorizontalScope()) 20 | { 21 | GUILayout.Label(FieldInfo.Name); 22 | GUILayout.FlexibleSpace(); 23 | using (var scope = new EditorGUI.ChangeCheckScope()) 24 | { 25 | var text = GUILayout.TextArea(FieldInfo.GetValue(Target)?.ToString() ?? NULL_VALUE); 26 | if (scope.changed) 27 | { 28 | FieldInfo.SetValue(Target, text); 29 | } 30 | } 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersStringFieldDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1a8a19df09ee4bc690b5a78bba07d22c 3 | timeCreated: 1646059735 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersUnityObjectFieldDrawer.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using UnityEditor; 3 | using UnityEngine; 4 | 5 | namespace Playtika.Controllers.Editor 6 | { 7 | public class ControllersUnityObjectFieldDrawer: ControllersBaseFieldDrawer 8 | { 9 | public ControllersUnityObjectFieldDrawer( 10 | FieldInfo fieldInfo, 11 | object target) 12 | : base(fieldInfo, target) 13 | { 14 | } 15 | 16 | protected override void OnDraw() 17 | { 18 | using (new GUILayout.HorizontalScope()) 19 | { 20 | GUILayout.Label(FieldInfo.Name); 21 | GUILayout.FlexibleSpace(); 22 | var obj = FieldInfo.GetValue(Target); 23 | if (obj == null) 24 | { 25 | GUILayout.Label(NULL_VALUE); 26 | } 27 | else 28 | { 29 | EditorGUILayout.ObjectField((Object) obj, typeof(Object), true); 30 | } 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/FieldsDrawers/ControllersUnityObjectFieldDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 347f95dc6fd54cdb9f1a25cade9ec4e1 3 | timeCreated: 1647092654 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/Playtika.Controllers.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Playtika.Controllers.Editor", 3 | "references": [ 4 | "Playtika.Controllers" 5 | ], 6 | "optionalUnityReferences": [], 7 | "includePlatforms": [ 8 | "Editor" 9 | ], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": false 12 | } -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersHierarchy/Playtika.Controllers.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b0fee331efa9941619d7591163ee90c7 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersProfiler.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e93af593fe6f245d294b5246fbaa0e6f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersProfiler/ControllerData.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_CONTROLLERS_PROFILER 2 | namespace Modules.Controller.Editor 3 | { 4 | internal sealed class ControllerData 5 | { 6 | public string ControllerName; 7 | public string TimeData; 8 | } 9 | } 10 | #endif -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersProfiler/ControllerData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ee5f7ac6df3345bab739de63878866cd 3 | timeCreated: 1748442516 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersProfiler/ControllerLiveData.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_CONTROLLERS_PROFILER 2 | using UnityEngine; 3 | 4 | namespace Modules.Controller.Editor 5 | { 6 | internal sealed class ControllerLiveData 7 | { 8 | public string ControllerName; 9 | public Color ControllerColor; 10 | public string ScopeName; 11 | public Color ScopeColor; 12 | public long StartTimeMSec; 13 | public long LifeTimeMSec; 14 | } 15 | } 16 | #endif -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersProfiler/ControllerLiveData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c8f905aff9bd4b5ea7038a0fcda0016c 3 | timeCreated: 1748442524 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersProfiler/ControllersProfilerModule.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_CONTROLLERS_PROFILER 2 | using Playtika.Controllers; 3 | using Unity.Profiling; 4 | using Unity.Profiling.Editor; 5 | 6 | namespace Modules.Controller.Editor 7 | { 8 | [System.Serializable] 9 | [ProfilerModuleMetadata("Controllers profiler")] 10 | public class ControllersProfilerModule : ProfilerModule 11 | { 12 | private static readonly ProfilerCounterDescriptor[] Counters = new ProfilerCounterDescriptor[] 13 | { 14 | new ProfilerCounterDescriptor(Helper.ActiveControllersCount, ProfilerCategory.Scripts), 15 | new ProfilerCounterDescriptor(Helper.TotalControllersCount, ProfilerCategory.Scripts), 16 | new ProfilerCounterDescriptor(Helper.CreateThisFrameControllersCount, ProfilerCategory.Scripts), 17 | }; 18 | 19 | public ControllersProfilerModule() 20 | : base(Counters) 21 | { 22 | } 23 | 24 | public override ProfilerModuleViewController CreateDetailsViewController() 25 | { 26 | return new ControllersProfilerModuleViewController(ProfilerWindow); 27 | } 28 | } 29 | } 30 | #endif -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersProfiler/ControllersProfilerModule.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1ab8eaed533094bada3f001bedfe374d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersProfiler/ControllersProfilerModuleViewController.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b7eae78773b514119ba1faeed2fd5ec6 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersProfiler/CreatedAndDestroyedControllersListView.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_CONTROLLERS_PROFILER 2 | using System.Collections.Generic; 3 | using UnityEngine.UIElements; 4 | 5 | namespace Modules.Controller.Editor 6 | { 7 | internal class CreatedAndDestroyedControllersListView : ListView 8 | { 9 | private const float ItemHeight = 16f; 10 | 11 | internal CreatedAndDestroyedControllersListView(List controllers) 12 | : base() 13 | { 14 | itemsSource = controllers; 15 | Setup(); 16 | Rebuild(); 17 | } 18 | 19 | private void Setup() 20 | { 21 | fixedItemHeight = ItemHeight; 22 | makeItem = MakeStartStopListItem; 23 | bindItem = BindItem; 24 | style.flexGrow = 1.0f; 25 | } 26 | 27 | private void BindItem(VisualElement row, int index) 28 | { 29 | if (itemsSource == null || index >= itemsSource.Count) 30 | { 31 | return; 32 | } 33 | 34 | var controllerNameLabel = row[0] as Label; 35 | var timeDataLabel = row[1] as Label; 36 | 37 | var item = itemsSource[index] as ControllerData; 38 | 39 | controllerNameLabel.text = item.ControllerName; 40 | timeDataLabel.text = item.TimeData; 41 | } 42 | 43 | private static VisualElement MakeStartStopListItem() 44 | { 45 | var row = new VisualElement(); 46 | row.style.flexDirection = FlexDirection.Row; 47 | row.style.paddingTop = 2; 48 | row.style.paddingBottom = 2; 49 | 50 | var col1 = new Label(); 51 | col1.style.flexGrow = 1; 52 | col1.style.marginRight = 4; 53 | col1.style.overflow = Overflow.Hidden; 54 | col1.style.whiteSpace = WhiteSpace.NoWrap; 55 | 56 | var col2 = new Label(); 57 | col2.style.width = 60; 58 | col2.style.marginRight = 4; 59 | row.Add(col1); 60 | row.Add(col2); 61 | 62 | return row; 63 | } 64 | } 65 | } 66 | #endif -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersProfiler/CreatedAndDestroyedControllersListView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c23222482baf496ab19990ba6dc65682 3 | timeCreated: 1748442412 -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersProfiler/LiveControllersListView.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_CONTROLLERS_PROFILER 2 | using System; 3 | using System.Collections.Generic; 4 | using UnityEngine.UIElements; 5 | using UnityEngine; 6 | 7 | namespace Modules.Controller.Editor 8 | { 9 | internal class LiveControllersListView : ListView 10 | { 11 | private const float ItemHeight = 16f; 12 | 13 | internal LiveControllersListView(List controllers) 14 | : base() 15 | { 16 | itemsSource = controllers; 17 | Setup(); 18 | Rebuild(); 19 | } 20 | 21 | internal static VisualElement FillLifetimeListHeader() 22 | { 23 | var row = MakeLifetimeListItem(); 24 | row.style.height = ItemHeight * 2; 25 | var controllerNameLabel = row[0] as Label; 26 | var scopeNameLabel = row[1] as Label; 27 | var onStartTimeLabel = row[2] as Label; 28 | var lifetimeLabel = row[3] as Label; 29 | 30 | controllerNameLabel.text = "Controller name"; 31 | ApplyLabelStyle(controllerNameLabel); 32 | scopeNameLabel.text = "Scope name"; 33 | ApplyLabelStyle(scopeNameLabel); 34 | onStartTimeLabel.text = "OnStart\n(MSec)"; 35 | ApplyLabelStyle(onStartTimeLabel); 36 | onStartTimeLabel.style.unityTextAlign = TextAnchor.MiddleLeft; 37 | lifetimeLabel.text = "Lifetime\n(MSec)"; 38 | ApplyLabelStyle(lifetimeLabel); 39 | lifetimeLabel.style.unityTextAlign = TextAnchor.MiddleLeft; 40 | lifetimeLabel.style.width = 74; 41 | 42 | return row; 43 | } 44 | 45 | private void Setup() 46 | { 47 | fixedItemHeight = ItemHeight; 48 | makeItem = MakeLifetimeListItem; 49 | bindItem = BindItem; 50 | style.flexGrow = 1.0f; 51 | } 52 | 53 | private static VisualElement MakeLifetimeListItem() 54 | { 55 | var row = new VisualElement(); 56 | row.style.flexDirection = FlexDirection.Row; 57 | row.style.paddingTop = 2; 58 | row.style.paddingBottom = 2; 59 | 60 | var col1 = new Label(); 61 | col1.style.flexGrow = 1; 62 | col1.style.marginRight = 4; 63 | col1.style.overflow = Overflow.Hidden; 64 | col1.style.whiteSpace = WhiteSpace.NoWrap; 65 | 66 | var col2 = new Label(); 67 | col2.style.width = 150; 68 | col2.style.unityTextAlign = TextAnchor.MiddleCenter; 69 | col2.style.marginRight = 4; 70 | col2.style.overflow = Overflow.Hidden; 71 | col2.style.whiteSpace = WhiteSpace.NoWrap; 72 | 73 | var col3 = new Label(); 74 | col3.style.width = 60; 75 | col3.style.marginRight = 4; 76 | 77 | var col4 = new Label(); 78 | col4.style.width = 60; 79 | 80 | row.Add(col1); 81 | row.Add(col2); 82 | row.Add(col3); 83 | row.Add(col4); 84 | 85 | return row; 86 | } 87 | 88 | private void BindItem(VisualElement row, int index) 89 | { 90 | if (itemsSource == null || index >= itemsSource.Count) 91 | { 92 | return; 93 | } 94 | 95 | var controllerNameLabel = row[0] as Label; 96 | var scopeNameLabel = row[1] as Label; 97 | var onStartTimeLabel = row[2] as Label; 98 | var lifetimeLabel = row[3] as Label; 99 | 100 | var item = itemsSource[index] as ControllerLiveData; 101 | 102 | controllerNameLabel.text = item.ControllerName; 103 | controllerNameLabel.style.color = item.ControllerColor; 104 | 105 | scopeNameLabel.text = item.ScopeName; 106 | scopeNameLabel.style.backgroundColor = item.ScopeColor; 107 | 108 | var startTime = item.StartTimeMSec; 109 | onStartTimeLabel.text = startTime.ToString(); 110 | onStartTimeLabel.style.color = startTime > 0 111 | ? Color.red 112 | : Color.gray; 113 | 114 | lifetimeLabel.text = item.LifeTimeMSec.ToString(); 115 | } 116 | 117 | private static void ApplyLabelStyle(Label label) 118 | { 119 | label.style.color = Color.white; 120 | label.style.unityFontStyleAndWeight = FontStyle.Bold; 121 | label.style.unityTextAlign = TextAnchor.MiddleCenter; 122 | label.style.height = ItemHeight * 2f; 123 | label.style.alignSelf = Align.Center; 124 | label.style.justifyContent = Justify.Center; 125 | } 126 | } 127 | } 128 | #endif 129 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersProfiler/LiveControllersListView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c3b2c0960855640f78116e6b1c566ae9 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersProfiler/Playtika.ControllersProfiler.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Playtika.ControllersProfiler.Editor", 3 | "rootNamespace": "", 4 | "references": [ 5 | "Playtika.Controllers" 6 | ], 7 | "includePlatforms": [ 8 | "Editor" 9 | ], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": false, 12 | "overrideReferences": false, 13 | "precompiledReferences": [], 14 | "autoReferenced": true, 15 | "defineConstraints": [], 16 | "versionDefines": [], 17 | "noEngineReferences": false 18 | } -------------------------------------------------------------------------------- /src/ControllersTree/Editor/ControllersProfiler/Playtika.ControllersProfiler.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2a65724b6c4f446c3b79830c77ccd24e 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /src/ControllersTree/Substitute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ec1f86e2d0dd74811b4056809246fee6 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d2e78271553f84e35880ece99f778081 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Runtime/Playtika.Controllers.Substitute.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Playtika.Controllers.Substitute", 3 | "rootNamespace": "", 4 | "references": [ 5 | "UniTask", 6 | "Playtika.Controllers" 7 | ], 8 | "includePlatforms": [], 9 | "excludePlatforms": [], 10 | "allowUnsafeCode": false, 11 | "overrideReferences": false, 12 | "precompiledReferences": [], 13 | "autoReferenced": true, 14 | "versionDefines": [], 15 | "noEngineReferences": false, 16 | "testAssemblies": true 17 | } -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Runtime/Playtika.Controllers.Substitute.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cfbcd2ac455cc4b8aa305c6452bcdb48 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Runtime/SubstituteController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Playtika.Controllers.Substitute 4 | { 5 | /// 6 | /// Controller Stub for tests. 7 | /// 8 | public class SubstituteController : ControllerBase 9 | { 10 | public SubstituteController() 11 | : base(null) 12 | { 13 | } 14 | } 15 | 16 | /// 17 | /// Generic Controller Stub for tests with ability to define fake behaviour. 18 | /// 19 | /// 20 | public class SubstituteController : ControllerBase 21 | { 22 | private readonly ControllerBehaviour _behaviour; 23 | private readonly Exception _exception; 24 | public SubstituteController(ControllerBehaviour behaviour, Exception exception) 25 | : base(null) 26 | { 27 | _behaviour = behaviour; 28 | _exception = exception; 29 | } 30 | 31 | protected override void OnStart() 32 | { 33 | base.OnStart(); 34 | if (_behaviour == ControllerBehaviour.FailOnStart) 35 | { 36 | throw _exception; 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Runtime/SubstituteController.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5344acf8deef94b59af6ab4fcb2facc0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Runtime/SubstituteControllerFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Playtika.Controllers.Substitute 6 | { 7 | /// 8 | /// Variants of fake controller behavior. 9 | /// 10 | public enum ControllerBehaviour 11 | { 12 | CompleteOnStart, 13 | CompleteOnFlowAsync, 14 | NeverComplete, 15 | FailOnStart, 16 | FailOnFlowAsync, 17 | } 18 | 19 | /// 20 | /// Override controller factory for testing. 21 | /// 22 | public class SubstituteControllerFactory : IControllerFactory 23 | { 24 | private readonly Dictionary _instances = new(); 25 | private readonly Dictionary _results = new(); 26 | private readonly Dictionary _received = new(); 27 | private readonly Dictionary _behaviours = new(); 28 | private readonly Dictionary _exceptions = new(); 29 | 30 | public IController Create() where T : class, IController 31 | { 32 | var type = typeof(T); 33 | if (_instances.TryGetValue(type, out var instance)) 34 | { 35 | WriteReceived(); 36 | return instance; 37 | } 38 | 39 | if (TryCreateStubControllerWithResult(type, out var controllerWithResult)) 40 | { 41 | return controllerWithResult; 42 | } 43 | 44 | if (TryCreateStubControllerBase(type, out var controllerBase)) 45 | { 46 | return controllerBase; 47 | } 48 | 49 | throw new Exception($"Unhandled type {type.Name}"); 50 | } 51 | 52 | public SubstituteControllerFactory AddInstance(T instance) 53 | where T : IController 54 | { 55 | var type = typeof(T); 56 | _instances[type] = instance; 57 | return this; 58 | } 59 | 60 | public SubstituteControllerFactory AddResultFor(object result) 61 | where T : IController 62 | { 63 | var type = typeof(T); 64 | _results[type] = result; 65 | _behaviours[type] = ControllerBehaviour.CompleteOnStart; 66 | return this; 67 | } 68 | 69 | public SubstituteControllerFactory AddExceptionFor(Exception exception) 70 | where T : IController 71 | { 72 | var type = typeof(T); 73 | _exceptions[type] = exception; 74 | _behaviours[type] = ControllerBehaviour.FailOnStart; 75 | return this; 76 | } 77 | 78 | public SubstituteControllerFactory SetBehaviourFor(ControllerBehaviour behaviour) 79 | { 80 | var type = typeof(T); 81 | _behaviours[type] = behaviour; 82 | return this; 83 | } 84 | 85 | public int Received() 86 | { 87 | _received.TryGetValue(typeof(T), out var count); 88 | return count; 89 | } 90 | 91 | private bool TryCreateStubControllerWithResult(Type type, out IController controller) 92 | where T : class, IController 93 | { 94 | controller = null; 95 | var interfaces = type.GetInterfaces(); 96 | var interfaceType = interfaces.FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IControllerWithResult<>)); 97 | 98 | if (interfaceType != null) 99 | { 100 | var argumentType = typeof(EmptyControllerArg); 101 | var interfaceForArgument = interfaces.FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IController<>)); 102 | 103 | if (interfaceForArgument != null) 104 | { 105 | argumentType = interfaceForArgument.GetGenericArguments()[0]; 106 | } 107 | 108 | var resultType = interfaceType.GetGenericArguments()[0]; 109 | var substituteType = typeof(SubstituteControllerWithResult<,>).MakeGenericType(argumentType, resultType); 110 | 111 | WriteReceived(); 112 | 113 | var obj = Activator.CreateInstance(substituteType, GetResult(), GetBehaviour(), GetException()); 114 | controller = obj as IController; 115 | return true; 116 | } 117 | 118 | return false; 119 | } 120 | 121 | private bool TryCreateStubControllerBase(Type type, out IController controller) 122 | where T : class, IController 123 | { 124 | controller = null; 125 | var interfaces = type.GetInterfaces(); 126 | var interfaceType = interfaces.FirstOrDefault(x => x == typeof(IController)); 127 | 128 | if (interfaceType != null) 129 | { 130 | WriteReceived(); 131 | 132 | var interfaceForArgument = interfaces.FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IController<>)); 133 | 134 | if (interfaceForArgument == null) 135 | { 136 | controller = new SubstituteController(); 137 | return true; 138 | } 139 | 140 | var argumentType = interfaceForArgument.GetGenericArguments()[0]; 141 | var substituteType = typeof(SubstituteController<>).MakeGenericType(argumentType); 142 | 143 | var obj = Activator.CreateInstance(substituteType, GetBehaviour(), GetException()); 144 | controller = obj as IController; 145 | return true; 146 | } 147 | 148 | return false; 149 | } 150 | 151 | private object GetResult() 152 | { 153 | _results.TryGetValue(typeof(T), out var result); 154 | return result; 155 | } 156 | 157 | private ControllerBehaviour GetBehaviour() 158 | { 159 | return _behaviours.GetValueOrDefault(typeof(T), ControllerBehaviour.CompleteOnStart); 160 | } 161 | 162 | private Exception GetException() 163 | { 164 | return _exceptions.GetValueOrDefault(typeof(T), new Exception("Mock controller fail")); 165 | } 166 | 167 | private void WriteReceived() 168 | { 169 | var type = typeof(T); 170 | _received.TryAdd(type, 0); 171 | _received[type]++; 172 | } 173 | } 174 | } -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Runtime/SubstituteControllerFactory.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 22cc8dbce4f7b48419acd84b054f70d0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Runtime/SubstituteControllerWithResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using Cysharp.Threading.Tasks; 4 | 5 | namespace Playtika.Controllers.Substitute 6 | { 7 | /// 8 | /// Controller With Result Stub for tests with ability to define fake behaviour. 9 | /// 10 | /// 11 | /// 12 | public class SubstituteControllerWithResult : ControllerWithResultBase 13 | { 14 | private readonly ControllerBehaviour _behaviour; 15 | private readonly TResult _result; 16 | private readonly Exception _exception; 17 | 18 | public SubstituteControllerWithResult(TResult result, ControllerBehaviour behaviour, Exception exception) 19 | : base(null) 20 | { 21 | _result = result; 22 | _behaviour = behaviour; 23 | _exception = exception; 24 | } 25 | 26 | protected override void OnStart() 27 | { 28 | base.OnStart(); 29 | switch (_behaviour) 30 | { 31 | case ControllerBehaviour.CompleteOnStart: 32 | Complete(_result); 33 | break; 34 | case ControllerBehaviour.FailOnStart: 35 | throw _exception; 36 | } 37 | } 38 | 39 | protected override async UniTask OnFlowAsync(CancellationToken cancellationToken) 40 | { 41 | await base.OnFlowAsync(cancellationToken); 42 | cancellationToken.ThrowIfCancellationRequested(); 43 | 44 | await UniTask.Yield(cancellationToken); 45 | cancellationToken.ThrowIfCancellationRequested(); 46 | 47 | switch (_behaviour) 48 | { 49 | case ControllerBehaviour.CompleteOnFlowAsync: 50 | Complete(_result); 51 | break; 52 | case ControllerBehaviour.FailOnFlowAsync: 53 | throw _exception; 54 | } 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Runtime/SubstituteControllerWithResult.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a24256132aa394ad6bdec62a1ff35503 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Runtime/TestRootController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using Cysharp.Threading.Tasks; 3 | 4 | namespace Playtika.Controllers.Substitute 5 | { 6 | /// 7 | /// Root controller for testing. 8 | /// 9 | public sealed class TestRootController : RootController 10 | { 11 | public TestRootController(IControllerFactory controllerFactory) 12 | : base(controllerFactory) 13 | { 14 | } 15 | 16 | public new void Execute() 17 | where T : class, IController 18 | { 19 | base.Execute(); 20 | } 21 | 22 | public new void Execute(TArg arg) 23 | where T : class, IController, IController 24 | { 25 | base.Execute(arg); 26 | } 27 | 28 | public new UniTask ExecuteAndWaitResultAsync( 29 | CancellationToken cancellationToken) 30 | where T : class, IControllerWithResult, IController 31 | { 32 | return base.ExecuteAndWaitResultAsync(cancellationToken); 33 | } 34 | 35 | public new UniTask ExecuteAndWaitResultAsync( 36 | CancellationToken cancellationToken) 37 | where T : class, IControllerWithResult, IController 38 | { 39 | return base.ExecuteAndWaitResultAsync(cancellationToken); 40 | } 41 | 42 | public new UniTask ExecuteAndWaitResultAsync( 43 | TArg arg, 44 | CancellationToken cancellationToken) 45 | where T : class, IControllerWithResult, IController 46 | { 47 | return base.ExecuteAndWaitResultAsync( 48 | arg, 49 | cancellationToken); 50 | } 51 | 52 | public new UniTask ExecuteAndWaitResultAsync( 53 | TArg arg, 54 | CancellationToken cancellationToken) 55 | where T : class, IControllerWithResult, IController 56 | { 57 | return base.ExecuteAndWaitResultAsync( 58 | arg, 59 | cancellationToken); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Runtime/TestRootController.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 551bf98303c3a45a6bd658fe7d817b07 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Tests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dc89fcc6770e14c0da26f877d0599fab 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Tests/Playtika.Controllers.Substitute.Tests.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Playtika.Controllers.Substitute.Tests", 3 | "references": [ 4 | "Playtika.Controllers", 5 | "Playtika.Controllers.Substitute", 6 | "UniTask" 7 | ], 8 | "optionalUnityReferences": [], 9 | "includePlatforms": [ 10 | "Editor" 11 | ], 12 | "excludePlatforms": [], 13 | "allowUnsafeCode": false, 14 | "testAssemblies": true 15 | } -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Tests/Playtika.Controllers.Substitute.Tests.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3827430749b67472cb8bfd06137e11de 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Tests/SubstituteControllerFactoryTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Playtika.Controllers.Substitute.Tests 4 | { 5 | [TestFixture] 6 | public class SubstituteControllerFactoryTests 7 | { 8 | [Test] 9 | public void CreateControllerBaseByInterface_ControllerIsCorrectType() 10 | { 11 | var factory = new SubstituteControllerFactory(); 12 | var controller = factory.Create(); 13 | Assert.That(controller, Is.Not.Null); 14 | Assert.That(controller, Is.TypeOf()); 15 | } 16 | 17 | [Test] 18 | public void CreateControllerBaseByClass_ControllerIsCorrectType() 19 | { 20 | var factory = new SubstituteControllerFactory(); 21 | var controller = factory.Create(); 22 | Assert.That(controller, Is.Not.Null); 23 | Assert.That(controller, Is.TypeOf()); 24 | } 25 | 26 | [Test] 27 | public void CreateControllerBaseWithArgsByInterface_ControllerIsCorrectType() 28 | { 29 | var factory = new SubstituteControllerFactory(); 30 | var controller = factory.Create(); 31 | Assert.That(controller, Is.Not.Null); 32 | Assert.That(controller, Is.TypeOf>()); 33 | } 34 | 35 | [Test] 36 | public void CreateControllerBaseWithArgsByClass_ControllerIsCorrectType() 37 | { 38 | var factory = new SubstituteControllerFactory(); 39 | var controller = factory.Create(); 40 | Assert.That(controller, Is.Not.Null); 41 | Assert.That(controller, Is.TypeOf>()); 42 | } 43 | 44 | [Test] 45 | public void CreateControllerWithResultBaseByInterface_ControllerIsCorrectType() 46 | { 47 | var factory = new SubstituteControllerFactory(); 48 | var controller = factory.Create(); 49 | Assert.That(controller, Is.Not.Null); 50 | Assert.That(controller, Is.TypeOf>()); 51 | } 52 | 53 | [Test] 54 | public void CreateControllerWithResultBaseTByClass_ControllerIsCorrectType() 55 | { 56 | var factory = new SubstituteControllerFactory(); 57 | var controller = factory.Create(); 58 | Assert.That(controller, Is.Not.Null); 59 | Assert.That(controller, Is.TypeOf>()); 60 | } 61 | 62 | [Test] 63 | public void CreateControllerWithResultBaseTByInterface_ControllerIsCorrectType() 64 | { 65 | var factory = new SubstituteControllerFactory(); 66 | var controller = factory.Create(); 67 | Assert.That(controller, Is.Not.Null); 68 | Assert.That(controller, Is.TypeOf>()); 69 | } 70 | 71 | [Test] 72 | public void CreateControllerWithResultBaseByClass_ControllerIsCorrectType() 73 | { 74 | var factory = new SubstituteControllerFactory(); 75 | var controller = factory.Create(); 76 | Assert.That(controller, Is.Not.Null); 77 | Assert.That(controller, Is.TypeOf>()); 78 | } 79 | 80 | [Test] 81 | public void CreateControllerWithResultBaseWithArgsByInterface_ControllerIsCorrectType() 82 | { 83 | var factory = new SubstituteControllerFactory(); 84 | var controller = factory.Create(); 85 | Assert.That(controller, Is.Not.Null); 86 | Assert.That(controller, Is.TypeOf>()); 87 | } 88 | 89 | [Test] 90 | public void CreateControllerWithResultTBaseWithArgsByInterface_ControllerIsCorrectType() 91 | { 92 | var factory = new SubstituteControllerFactory(); 93 | var controller = factory.Create(); 94 | Assert.That(controller, Is.Not.Null); 95 | Assert.That(controller, Is.TypeOf>()); 96 | } 97 | 98 | [Test] 99 | public void CreateControllerWithResultTBaseWithArgsByClass_ControllerIsCorrectType() 100 | { 101 | var factory = new SubstituteControllerFactory(); 102 | var controller = factory.Create(); 103 | Assert.That(controller, Is.Not.Null); 104 | Assert.That(controller, Is.TypeOf>()); 105 | } 106 | 107 | [Test] 108 | public void CreateControllerWithResultBaseGenericByInterface_ControllerIsCorrectType() 109 | { 110 | var factory = new SubstituteControllerFactory(); 111 | var controller = factory.Create>(); 112 | Assert.That(controller, Is.Not.Null); 113 | Assert.That(controller, Is.TypeOf>()); 114 | } 115 | 116 | [Test] 117 | public void CreateControllerWithResultBaseGenericByClass_ControllerIsCorrectType() 118 | { 119 | var factory = new SubstituteControllerFactory(); 120 | var controller = factory.Create>(); 121 | Assert.That(controller, Is.Not.Null); 122 | Assert.That(controller, Is.TypeOf>()); 123 | } 124 | 125 | [Test] 126 | public void CreateControllerWithResultBaseGenericWithArgsGenericByInterface_ControllerIsCorrectType() 127 | { 128 | var factory = new SubstituteControllerFactory(); 129 | var controller = factory.Create>(); 130 | Assert.That(controller, Is.Not.Null); 131 | Assert.That(controller, Is.TypeOf>()); 132 | } 133 | 134 | [Test] 135 | public void CreateControllerWithResultBaseGenericWithArgsGenericByClass_ControllerIsCorrectType() 136 | { 137 | var factory = new SubstituteControllerFactory(); 138 | var controller = factory.Create>(); 139 | Assert.That(controller, Is.Not.Null); 140 | Assert.That(controller, Is.TypeOf>()); 141 | } 142 | 143 | [Test] 144 | public void Create2IdenticalControllers_ControllersAreNotEquals() 145 | { 146 | var factory = new SubstituteControllerFactory(); 147 | var c1 = factory.Create(); 148 | var c2 = factory.Create(); 149 | 150 | Assert.That(c1, Is.Not.SameAs(c2)); 151 | } 152 | } 153 | } -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Tests/SubstituteControllerFactoryTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 93996a419f2064b32810862ba7c41ece 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Tests/TestRootControllerWithSubstituteFactoryTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using NUnit.Framework; 4 | 5 | namespace Playtika.Controllers.Substitute.Tests 6 | { 7 | [TestFixture] 8 | public class TestRootControllerWithSubstituteFactoryTests 9 | { 10 | private interface ITestInstanceController : IController 11 | { 12 | } 13 | 14 | private class TestInstanceController : ControllerBase, ITestInstanceController 15 | { 16 | public bool StartWasCalled; 17 | 18 | public TestInstanceController() 19 | : base(null) 20 | { 21 | } 22 | 23 | protected override void OnStart() 24 | { 25 | base.OnStart(); 26 | StartWasCalled = true; 27 | } 28 | } 29 | 30 | [Test] 31 | public void ExecuteByInterface_NotThrowException() 32 | { 33 | using var cts = new CancellationTokenSource(); 34 | var factory = new SubstituteControllerFactory(); 35 | var rootController = new TestRootController(factory); 36 | rootController.LaunchTree(cts.Token); 37 | 38 | rootController.Execute(); 39 | } 40 | 41 | [Test] 42 | public void ExecuteByClass_NotThrowException() 43 | { 44 | using var cts = new CancellationTokenSource(); 45 | var factory = new SubstituteControllerFactory(); 46 | var rootController = new TestRootController(factory); 47 | rootController.LaunchTree(cts.Token); 48 | 49 | rootController.Execute(); 50 | } 51 | 52 | [Test] 53 | public async Task ExecuteAndWaitResultByInterface_NoThrowException() 54 | { 55 | using var cts = new CancellationTokenSource(); 56 | var factory = new SubstituteControllerFactory(); 57 | var rootController = new TestRootController(factory); 58 | rootController.LaunchTree(cts.Token); 59 | 60 | await rootController.ExecuteAndWaitResultAsync(cts.Token); 61 | } 62 | 63 | [Test] 64 | public async Task ExecuteAndWaitResultByClass_NoThrowException() 65 | { 66 | using var cts = new CancellationTokenSource(); 67 | var factory = new SubstituteControllerFactory(); 68 | var rootController = new TestRootController(factory); 69 | rootController.LaunchTree(cts.Token); 70 | 71 | await rootController.ExecuteAndWaitResultAsync(cts.Token); 72 | } 73 | 74 | [Test] 75 | public async Task ExecuteAndWaitResultGenericWithArgGenericByInterface_DoNotThrowException() 76 | { 77 | using var cts = new CancellationTokenSource(); 78 | var factory = new SubstituteControllerFactory(); 79 | var rootController = new TestRootController(factory); 80 | rootController.LaunchTree(cts.Token); 81 | await rootController.ExecuteAndWaitResultAsync, string, float>( 82 | string.Empty, cts.Token); 83 | } 84 | 85 | [Test] 86 | public async Task CreateAndWaitResultGenericWithArgGenericByClass_DoNotThrowException() 87 | { 88 | using var cts = new CancellationTokenSource(); 89 | var factory = new SubstituteControllerFactory(); 90 | var rootController = new TestRootController(factory); 91 | rootController.LaunchTree(cts.Token); 92 | await rootController.ExecuteAndWaitResultAsync, string, float>( 93 | string.Empty, cts.Token); 94 | } 95 | 96 | [Test] 97 | public void AddInstance_InstanceWasStarted() 98 | { 99 | using var cts = new CancellationTokenSource(); 100 | 101 | var controllerInstance = new TestInstanceController(); 102 | 103 | var factory = new SubstituteControllerFactory() 104 | .AddInstance(controllerInstance); 105 | 106 | var rootController = new TestRootController(factory); 107 | rootController.LaunchTree(cts.Token); 108 | 109 | rootController.Execute(); 110 | 111 | Assert.That(controllerInstance.StartWasCalled, Is.True); 112 | } 113 | 114 | [Test] 115 | public void AddInstanceAsInterface_InstanceWasStarted() 116 | { 117 | using var cts = new CancellationTokenSource(); 118 | 119 | var controllerInstance = new TestInstanceController(); 120 | 121 | var factory = new SubstituteControllerFactory() 122 | .AddInstance(controllerInstance); 123 | 124 | var rootController = new TestRootController(factory); 125 | rootController.LaunchTree(cts.Token); 126 | 127 | rootController.Execute(); 128 | 129 | Assert.That(controllerInstance.StartWasCalled, Is.True); 130 | } 131 | 132 | [Test] 133 | public async Task AddResultFor_ResultIsCorrect() 134 | { 135 | using var cts = new CancellationTokenSource(); 136 | var factory = new SubstituteControllerFactory() 137 | .AddResultFor>(45); 138 | 139 | var rootController = new TestRootController(factory); 140 | rootController.LaunchTree(cts.Token); 141 | var result = await rootController.ExecuteAndWaitResultAsync, float>(cts.Token); 142 | 143 | Assert.That(result, Is.EqualTo(45)); 144 | } 145 | 146 | [Test] 147 | public Task ExecuteOneController_ReceivedReturn1() 148 | { 149 | using var cts = new CancellationTokenSource(); 150 | var factory = new SubstituteControllerFactory(); 151 | 152 | var rootController = new TestRootController(factory); 153 | rootController.LaunchTree(cts.Token); 154 | rootController.Execute(); 155 | 156 | Assert.That(factory.Received(), Is.EqualTo(1)); 157 | return Task.CompletedTask; 158 | } 159 | 160 | [Test] 161 | public Task ExecuteControllerTwice_ReceivedReturn2() 162 | { 163 | using var cts = new CancellationTokenSource(); 164 | var factory = new SubstituteControllerFactory(); 165 | 166 | var rootController = new TestRootController(factory); 167 | rootController.LaunchTree(cts.Token); 168 | rootController.Execute(); 169 | rootController.Execute(); 170 | 171 | Assert.That(factory.Received(), Is.EqualTo(2)); 172 | return Task.CompletedTask; 173 | } 174 | 175 | [Test] 176 | public Task ExecuteTwoController_Received1PerEachController() 177 | { 178 | using var cts = new CancellationTokenSource(); 179 | var factory = new SubstituteControllerFactory(); 180 | 181 | var rootController = new TestRootController(factory); 182 | rootController.LaunchTree(cts.Token); 183 | rootController.Execute(); 184 | rootController.ExecuteAndWaitResultAsync(cts.Token); 185 | 186 | Assert.That(factory.Received(), Is.EqualTo(1)); 187 | Assert.That(factory.Received(), Is.EqualTo(1)); 188 | return Task.CompletedTask; 189 | } 190 | } 191 | } -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Tests/TestRootControllerWithSubstituteFactoryTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e97bda49527674048bd3312dc30706db 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Tests/TypesForTest.cs: -------------------------------------------------------------------------------- 1 | namespace Playtika.Controllers.Substitute.Tests 2 | { 3 | internal class TypesForTest 4 | { 5 | public interface ITestController : IController 6 | { 7 | } 8 | 9 | public interface ITestControllerWithArgs : IController, IController 10 | { 11 | } 12 | 13 | public interface ITestControllerWithResult : IControllerWithResult, IController 14 | { 15 | } 16 | 17 | public interface ITestControllerWithResultWithArgs : IControllerWithResult, IController 18 | { 19 | 20 | } 21 | 22 | public interface ITestControllerWithResultGeneric : IControllerWithResult, IController 23 | { 24 | 25 | } 26 | 27 | public interface ITestControllerWithResultTWithArgs : IControllerWithResult, IController 28 | { 29 | 30 | } 31 | 32 | public interface ITestControllerWithResultGenericWithArgsGeneric : IControllerWithResult, IController 33 | { 34 | 35 | } 36 | 37 | public interface ITestControllerWithResultT : IControllerWithResult 38 | { 39 | } 40 | 41 | public class TestController : ControllerBase 42 | { 43 | public TestController(IControllerFactory controllerFactory) 44 | : base(controllerFactory) 45 | { 46 | } 47 | } 48 | 49 | public class TestControllerWithArgs : ControllerBase 50 | { 51 | public TestControllerWithArgs(IControllerFactory controllerFactory) 52 | : base(controllerFactory) 53 | { 54 | } 55 | } 56 | 57 | public class TestControllerWithResult : ControllerWithResultBase 58 | { 59 | public TestControllerWithResult(IControllerFactory controllerFactory) 60 | : base(controllerFactory) 61 | { 62 | } 63 | } 64 | 65 | public class TestControllerWithResultT : ControllerWithResultBase 66 | { 67 | public TestControllerWithResultT(IControllerFactory controllerFactory) 68 | : base(controllerFactory) 69 | { 70 | } 71 | } 72 | 73 | public class TestControllerWithResultGeneric : ControllerWithResultBase 74 | { 75 | public TestControllerWithResultGeneric(IControllerFactory controllerFactory) 76 | : base(controllerFactory) 77 | { 78 | } 79 | } 80 | 81 | public class TestControllerWithResultWithArg : ControllerWithResultBase 82 | { 83 | public TestControllerWithResultWithArg(IControllerFactory controllerFactory) 84 | : base(controllerFactory) 85 | { 86 | } 87 | } 88 | 89 | public class TestControllerWithResultGenericWithArgsGeneric : ControllerWithResultBase 90 | { 91 | public TestControllerWithResultGenericWithArgsGeneric(IControllerFactory controllerFactory) 92 | : base(controllerFactory) 93 | { 94 | } 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /src/ControllersTree/Substitute/Tests/TypesForTest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 935260ac74ad743139ea6435361d871a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ba4befc67a834995b7edf9eb80ff76b3 3 | timeCreated: 1734555003 -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4d247d315000a4d9391bbfe12b88cc30 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersBase.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3d96a1d58a337418e94b99d40a7a3954 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersBase/ActionModelTestControllerBase.cs: -------------------------------------------------------------------------------- 1 | using Playtika.Controllers; 2 | 3 | namespace UnitTests.Controllers 4 | { 5 | public class ActionModelTestControllerBase : ControllerBase 6 | { 7 | private readonly TestControllersActionModel _testControllersActionModel; 8 | 9 | internal ActionModelTestControllerBase( 10 | IControllerFactory controllerFactory, 11 | TestControllersActionModel testControllersControllersModel) 12 | : base(controllerFactory) 13 | { 14 | _testControllersActionModel = testControllersControllersModel; 15 | } 16 | 17 | protected override void OnStart() 18 | { 19 | base.OnStart(); 20 | AddDisposable(new DisposableToken(() => 21 | { 22 | _testControllersActionModel.TriggerDispose(); 23 | })); 24 | _testControllersActionModel.Args = Args.InputString; 25 | _testControllersActionModel.TriggerStart(); 26 | } 27 | 28 | protected override void OnStop() 29 | { 30 | base.OnStop(); 31 | _testControllersActionModel.TriggerStop(); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersBase/ActionModelTestControllerBase.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9c10f9e8d9b474d4f9eb6de9e3ad313d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 42e0bbb0ad9744967afd243c9c631324 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using Playtika.Controllers; 3 | using Cysharp.Threading.Tasks; 4 | 5 | namespace UnitTests.Controllers 6 | { 7 | internal class ActionModelTestControllerWithResult : ControllerWithResultBase 8 | { 9 | protected readonly TestControllersActionModel TestControllersActionModel; 10 | 11 | internal ActionModelTestControllerWithResult( 12 | IControllerFactory controllerFactory, 13 | TestControllersActionModel testControllersActionModel) 14 | : base(controllerFactory) 15 | { 16 | TestControllersActionModel = testControllersActionModel; 17 | } 18 | 19 | protected override void OnStart() 20 | { 21 | base.OnStart(); 22 | AddDisposable(new DisposableToken(() => 23 | { 24 | TestControllersActionModel.TriggerDispose(); 25 | })); 26 | TestControllersActionModel.Args = Args.InputString; 27 | TestControllersActionModel.TriggerStart(); 28 | } 29 | 30 | protected override async UniTask OnFlowAsync(CancellationToken cancellationToken) 31 | { 32 | base.OnFlowAsync(cancellationToken); 33 | 34 | await UniTask.Delay(10, cancellationToken: cancellationToken); 35 | TestControllersActionModel.TriggerFlow(); 36 | await UniTask.Delay(10, cancellationToken: cancellationToken); 37 | } 38 | 39 | protected override void OnStop() 40 | { 41 | TestControllersActionModel.TriggerStop(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6eca80c908d9438b988305a7ccb6c25d 3 | timeCreated: 1705426757 -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult_CompleteAfterOnFlowAsync.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using Playtika.Controllers; 3 | using Cysharp.Threading.Tasks; 4 | 5 | namespace UnitTests.Controllers 6 | { 7 | internal class ActionModelTestControllerWithResult_CompleteAfterOnFlowAsync : ActionModelTestControllerWithResult 8 | { 9 | internal ActionModelTestControllerWithResult_CompleteAfterOnFlowAsync( 10 | IControllerFactory controllerFactory, 11 | TestControllersActionModel testControllersActionModel) 12 | : base(controllerFactory, testControllersActionModel) 13 | { 14 | } 15 | 16 | protected override async UniTask OnFlowAsync(CancellationToken cancellationToken) 17 | { 18 | await base.OnFlowAsync(cancellationToken); 19 | AfterFlowAsync(cancellationToken).Forget(); 20 | } 21 | 22 | private async UniTask AfterFlowAsync(CancellationToken cancellationToken) 23 | { 24 | await UniTask.Delay(10, cancellationToken: cancellationToken); 25 | Complete(new TestEmptyControllerResult(Args.InputString)); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult_CompleteAfterOnFlowAsync.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d0d8b891dadc4df38ee4e04433932e0c 3 | timeCreated: 1705426715 -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult_CompleteOnFlowAsync.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using Playtika.Controllers; 3 | using Cysharp.Threading.Tasks; 4 | 5 | namespace UnitTests.Controllers 6 | { 7 | internal class ActionModelTestControllerWithResult_CompleteOnFlowAsync : ActionModelTestControllerWithResult 8 | { 9 | public ActionModelTestControllerWithResult_CompleteOnFlowAsync( 10 | IControllerFactory controllerFactory, 11 | TestControllersActionModel testControllersActionModel) 12 | : base(controllerFactory, testControllersActionModel) 13 | { 14 | } 15 | 16 | protected override async UniTask OnFlowAsync(CancellationToken cancellationToken) 17 | { 18 | await base.OnFlowAsync(cancellationToken); 19 | Complete(new TestEmptyControllerResult(Args.InputString)); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult_CompleteOnFlowAsync.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e629ed978239447cbf05c9e8e0e67fb7 3 | timeCreated: 1705426703 -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult_CompleteOnStart.cs: -------------------------------------------------------------------------------- 1 | using Playtika.Controllers; 2 | 3 | namespace UnitTests.Controllers 4 | { 5 | internal class ActionModelTestControllerWithResult_CompleteOnStart : ActionModelTestControllerWithResult 6 | { 7 | internal ActionModelTestControllerWithResult_CompleteOnStart( 8 | IControllerFactory controllerFactory, 9 | TestControllersActionModel testControllersActionModel) 10 | : base(controllerFactory, testControllersActionModel) 11 | { 12 | } 13 | 14 | protected override void OnStart() 15 | { 16 | base.OnStart(); 17 | Complete(new TestEmptyControllerResult(Args.InputString)); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult_CompleteOnStart.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1b6dcda5096644c79f78018703d6badc 3 | timeCreated: 1705426697 -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult_FailInDispose.cs: -------------------------------------------------------------------------------- 1 | using Playtika.Controllers; 2 | 3 | namespace UnitTests.Controllers 4 | { 5 | internal class ActionModelTestControllerWithResult_FailInDispose : ActionModelTestControllerWithResult 6 | { 7 | internal ActionModelTestControllerWithResult_FailInDispose( 8 | IControllerFactory controllerFactory, 9 | TestControllersActionModel testControllersControllersModel) 10 | : base(controllerFactory, testControllersControllersModel) 11 | { 12 | } 13 | 14 | protected override void OnStart() 15 | { 16 | AddDisposable(new DisposableToken(() => 17 | { 18 | Fail(new TestControllersException(TestControllersMethodsNamesConsts.DisposeMethodName)); 19 | })); 20 | TestControllersActionModel.Args = Args.InputString; 21 | TestControllersActionModel.TriggerStart(); 22 | 23 | Complete(new TestEmptyControllerResult(Args.InputString)); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult_FailInDispose.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 656bfdaf5cf0e48938948fce833bcf8d 3 | timeCreated: 1705941216 -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult_FailOnFlowAsync.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using Playtika.Controllers; 3 | using Cysharp.Threading.Tasks; 4 | 5 | namespace UnitTests.Controllers 6 | { 7 | internal class ActionModelTestControllerWithResult_FailOnFlowAsync : ActionModelTestControllerWithResult 8 | { 9 | internal ActionModelTestControllerWithResult_FailOnFlowAsync( 10 | IControllerFactory controllerFactory, 11 | TestControllersActionModel testControllersControllersModel) 12 | : base(controllerFactory, testControllersControllersModel) 13 | { 14 | } 15 | 16 | protected override UniTask OnFlowAsync(CancellationToken cancellationToken) 17 | { 18 | Fail(new TestControllersException(TestControllersMethodsNamesConsts.OnFlowAsyncMethodName)); 19 | return UniTask.CompletedTask; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult_FailOnFlowAsync.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 62c5f36d99feb40ce9434be4c862999a 3 | timeCreated: 1705941216 -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult_FailOnStart.cs: -------------------------------------------------------------------------------- 1 | using Playtika.Controllers; 2 | 3 | namespace UnitTests.Controllers 4 | { 5 | internal class ActionModelTestControllerWithResult_FailOnStart : ActionModelTestControllerWithResult 6 | { 7 | internal ActionModelTestControllerWithResult_FailOnStart( 8 | IControllerFactory controllerFactory, 9 | TestControllersActionModel testControllersControllersModel) 10 | : base(controllerFactory, testControllersControllersModel) 11 | { 12 | } 13 | 14 | protected override void OnStart() 15 | { 16 | base.OnStart(); 17 | Fail(new TestControllersException(TestControllersMethodsNamesConsts.FailMethodName)); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult_FailOnStart.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 290e50c6c8164effb7470cfc66c64139 3 | timeCreated: 1705941216 -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult_FailOnStop.cs: -------------------------------------------------------------------------------- 1 | using Playtika.Controllers; 2 | 3 | namespace UnitTests.Controllers 4 | { 5 | internal class ActionModelTestControllerWithResult_FailOnStop : ActionModelTestControllerWithResult 6 | { 7 | internal ActionModelTestControllerWithResult_FailOnStop( 8 | IControllerFactory controllerFactory, 9 | TestControllersActionModel testControllersControllersModel) 10 | : base(controllerFactory, testControllersControllersModel) 11 | { 12 | } 13 | 14 | protected override void OnStart() 15 | { 16 | base.OnStart(); 17 | Complete(new TestEmptyControllerResult(Args.InputString)); 18 | } 19 | 20 | protected override void OnStop() 21 | { 22 | base.OnStop(); 23 | Fail(new TestControllersException(TestControllersMethodsNamesConsts.FailMethodName)); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult_FailOnStop.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 567ccb5392f5440bfadc805ffa08dbc8 3 | timeCreated: 1705941216 -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult_ThrowAfterOnFlowAsync.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using Playtika.Controllers; 3 | using Cysharp.Threading.Tasks; 4 | 5 | namespace UnitTests.Controllers 6 | { 7 | internal class ActionModelTestControllerWithResult_ThrowAfterOnFlowAsync : ActionModelTestControllerWithResult 8 | { 9 | internal ActionModelTestControllerWithResult_ThrowAfterOnFlowAsync( 10 | IControllerFactory controllerFactory, 11 | TestControllersActionModel testControllersActionModel) 12 | : base(controllerFactory, testControllersActionModel) 13 | { 14 | } 15 | 16 | protected override async UniTask OnFlowAsync(CancellationToken cancellationToken) 17 | { 18 | await base.OnFlowAsync(cancellationToken); 19 | ThrowAfterFlowAsync(cancellationToken).Forget(); 20 | } 21 | 22 | private async UniTask ThrowAfterFlowAsync(CancellationToken cancellationToken) 23 | { 24 | await UniTask.Delay(10, cancellationToken: cancellationToken); 25 | throw new TestControllersException(TestControllersMethodsNamesConsts.CompleteMethodName); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/ActionModelTestControllerWithResult_ThrowAfterOnFlowAsync.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c794687638b04901bb400edad7296168 3 | timeCreated: 1705426751 -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/Childs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1187863d0f10b4c9296c3d13c04eeb28 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/Childs/ActionModelTestChildControllerWithResult.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using Playtika.Controllers; 4 | using Cysharp.Threading.Tasks; 5 | 6 | namespace UnitTests.Controllers 7 | { 8 | internal class ActionModelTestChildControllerWithResult : ControllerWithResultBase 9 | { 10 | protected readonly TestChildControllersActionModel TestChildControllersActionModel; 11 | protected string TestControllerGuid => Args; 12 | 13 | public ActionModelTestChildControllerWithResult( 14 | IControllerFactory controllerFactory, 15 | TestChildControllersActionModel testChildControllersModel) 16 | : base(controllerFactory) 17 | { 18 | TestChildControllersActionModel = testChildControllersModel; 19 | } 20 | 21 | protected override void OnStart() 22 | { 23 | base.OnStart(); 24 | AddDisposable(new DisposableToken(() => 25 | { 26 | TestChildControllersActionModel.TriggerChildDispose(TestControllerGuid); 27 | })); 28 | TestChildControllersActionModel.TriggerChildStart(TestControllerGuid); 29 | } 30 | 31 | protected override async UniTask OnFlowAsync(CancellationToken cancellationToken) 32 | { 33 | base.OnFlowAsync(cancellationToken); 34 | await Task.Delay(50, cancellationToken).ConfigureAwait(false); 35 | 36 | TestChildControllersActionModel.TriggerChildFlow(TestControllerGuid); 37 | 38 | await Task.Delay(50, cancellationToken).ConfigureAwait(false); 39 | 40 | Complete(default); 41 | } 42 | 43 | protected override void OnStop() 44 | { 45 | TestChildControllersActionModel.TriggerChildStop(TestControllerGuid); 46 | } 47 | } 48 | 49 | internal class ActionModelTestChildControllerWithResult1 : ActionModelTestChildControllerWithResult 50 | { 51 | public ActionModelTestChildControllerWithResult1( 52 | IControllerFactory controllerFactory, 53 | TestChildControllersActionModel testChildControllersModel) 54 | : base(controllerFactory, testChildControllersModel) 55 | { 56 | } 57 | } 58 | 59 | internal class ActionModelTestChildControllerWithResult2 : ActionModelTestChildControllerWithResult 60 | { 61 | public ActionModelTestChildControllerWithResult2( 62 | IControllerFactory controllerFactory, 63 | TestChildControllersActionModel testChildControllersModel) 64 | : base(controllerFactory, testChildControllersModel) 65 | { 66 | } 67 | } 68 | internal class ActionModelTestChildControllerWithResult3 : ActionModelTestChildControllerWithResult 69 | { 70 | public ActionModelTestChildControllerWithResult3( 71 | IControllerFactory controllerFactory, 72 | TestChildControllersActionModel testChildControllersModel) 73 | : base(controllerFactory, testChildControllersModel) 74 | { 75 | } 76 | } 77 | internal class ActionModelTestChildControllerWithResult4 : ActionModelTestChildControllerWithResult 78 | { 79 | public ActionModelTestChildControllerWithResult4( 80 | IControllerFactory controllerFactory, 81 | TestChildControllersActionModel testChildControllersModel) 82 | : base(controllerFactory, testChildControllersModel) 83 | { 84 | } 85 | } 86 | internal class ActionModelTestChildControllerWithResult5 : ActionModelTestChildControllerWithResult 87 | { 88 | public ActionModelTestChildControllerWithResult5( 89 | IControllerFactory controllerFactory, 90 | TestChildControllersActionModel testChildControllersModel) 91 | : base(controllerFactory, testChildControllersModel) 92 | { 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/Childs/ActionModelTestChildControllerWithResult.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 23adbfb3f8e6144e790c433c545090f2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/Childs/ActionModelTestControllerWithResultAndChildControllers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using Playtika.Controllers; 5 | using Cysharp.Threading.Tasks; 6 | using UnityEngine.Assertions; 7 | 8 | namespace UnitTests.Controllers 9 | { 10 | internal class ActionModelTestControllerWithResultAndChildControllers : ControllerWithResultBase 11 | { 12 | protected readonly TestControllersActionModel TestControllersActionModel; 13 | 14 | internal ActionModelTestControllerWithResultAndChildControllers( 15 | IControllerFactory controllerFactory, 16 | TestControllersActionModel testControllersActionModel) 17 | : base(controllerFactory) 18 | { 19 | TestControllersActionModel = testControllersActionModel; 20 | } 21 | 22 | protected override void OnStart() 23 | { 24 | base.OnStart(); 25 | AddDisposable(new DisposableToken(() => 26 | { 27 | TestControllersActionModel.TriggerDispose(); 28 | })); 29 | TestControllersActionModel.Args = Args.InputString; 30 | TestControllersActionModel.TriggerStart(); 31 | } 32 | 33 | protected override async UniTask OnFlowAsync(CancellationToken cancellationToken) 34 | { 35 | TestControllersActionModel.TriggerFlow(); 36 | 37 | await StartChildControllersAsync(cancellationToken); 38 | cancellationToken.ThrowIfCancellationRequested(); 39 | 40 | Complete(new TestEmptyControllerResult(Args.InputString)); 41 | } 42 | 43 | protected async UniTask StartChildControllersAsync(CancellationToken cancellationToken) 44 | { 45 | var launchers = GetAsyncLaunchers(); 46 | Assert.AreEqual(Args.ChildControllersGuids.Count, launchers.Count); 47 | var i = 0; 48 | foreach (var childControllerGuid in Args.ChildControllersGuids) 49 | { 50 | var launcher = launchers[i]; 51 | await launcher(childControllerGuid, cancellationToken); 52 | cancellationToken.ThrowIfCancellationRequested(); 53 | i++; 54 | } 55 | } 56 | 57 | protected override void OnStop() 58 | { 59 | TestControllersActionModel.TriggerStop(); 60 | } 61 | 62 | private List> GetAsyncLaunchers() 63 | { 64 | return new List> 65 | { 66 | StartChildControllersAsync1, 67 | StartChildControllersAsync2, 68 | StartChildControllersAsync3, 69 | StartChildControllersAsync4, 70 | StartChildControllersAsync5, 71 | }; 72 | } 73 | 74 | private async UniTask StartChildControllersAsync1(string childControllerGuid, CancellationToken cancellationToken) 75 | { 76 | await ExecuteAndWaitResultAsync(childControllerGuid, cancellationToken); 77 | } 78 | 79 | private async UniTask StartChildControllersAsync2(string childControllerGuid, CancellationToken cancellationToken) 80 | { 81 | await ExecuteAndWaitResultAsync(childControllerGuid, cancellationToken); 82 | } 83 | 84 | private async UniTask StartChildControllersAsync3(string childControllerGuid, CancellationToken cancellationToken) 85 | { 86 | await ExecuteAndWaitResultAsync(childControllerGuid, cancellationToken); 87 | } 88 | 89 | private async UniTask StartChildControllersAsync4(string childControllerGuid, CancellationToken cancellationToken) 90 | { 91 | await ExecuteAndWaitResultAsync(childControllerGuid, cancellationToken); 92 | } 93 | 94 | private async UniTask StartChildControllersAsync5(string childControllerGuid, CancellationToken cancellationToken) 95 | { 96 | await ExecuteAndWaitResultAsync(childControllerGuid, cancellationToken); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/Childs/ActionModelTestControllerWithResultAndChildControllers.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7d5e3ddc08e934d9a8dc86154c0f706d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/Childs/ActionModelTestControllerWithResultAndChildControllers_FailOnFlowAsync.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using Playtika.Controllers; 3 | using Cysharp.Threading.Tasks; 4 | 5 | namespace UnitTests.Controllers 6 | { 7 | internal class ActionModelTestControllerWithResultAndChildControllers_FailOnFlowAsync : ActionModelTestControllerWithResultAndChildControllers 8 | { 9 | internal ActionModelTestControllerWithResultAndChildControllers_FailOnFlowAsync( 10 | IControllerFactory controllerFactory, 11 | TestControllersActionModel testControllersActionModel) 12 | : base(controllerFactory, testControllersActionModel) 13 | { 14 | } 15 | 16 | protected override async UniTask OnFlowAsync(CancellationToken cancellationToken) 17 | { 18 | TestControllersActionModel.TriggerFlow(); 19 | 20 | await StartChildControllersAsync(cancellationToken); 21 | throw new TestControllersException(TestControllersMethodsNamesConsts.OnFlowAsyncMethodName); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Controllers/ControllersWithResult/Childs/ActionModelTestControllerWithResultAndChildControllers_FailOnFlowAsync.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 304b326d630eb485f842129b1492bd9f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/ControllersBaseTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using Playtika.Controllers; 4 | using NUnit.Framework; 5 | using Playtika.Controllers.Substitute; 6 | 7 | namespace UnitTests.Controllers 8 | { 9 | [TestFixture] 10 | public class ControllersBaseTests 11 | { 12 | private IControllerFactory _controllerFactory; 13 | private TestControllersActionModel _testControllersActionModel; 14 | private CancellationTokenSource _cancellationTokenSource; 15 | private CancellationToken CancellationToken => _cancellationTokenSource.Token; 16 | 17 | [SetUp] 18 | public void SetUp() 19 | { 20 | var substituteControllerFactory = new SubstituteControllerFactory(); 21 | _testControllersActionModel = new TestControllersActionModel(); 22 | substituteControllerFactory.AddInstance( 23 | new ActionModelTestControllerBase( 24 | substituteControllerFactory, 25 | _testControllersActionModel)); 26 | 27 | _cancellationTokenSource = new CancellationTokenSource(); 28 | _controllerFactory = substituteControllerFactory; 29 | } 30 | 31 | [TearDown] 32 | public void TearDown() 33 | { 34 | _controllerFactory = null; 35 | _testControllersActionModel = null; 36 | _cancellationTokenSource.Cancel(); 37 | _cancellationTokenSource.Dispose(); 38 | } 39 | 40 | [OneTimeTearDown] 41 | public void OneTimeTearDown() 42 | { 43 | _controllerFactory = null; 44 | _cancellationTokenSource = null; 45 | } 46 | 47 | [Test] 48 | public void ControllerBase_NoFails_CorrectArguments() 49 | { 50 | // Arrange 51 | var startTriggered = false; 52 | var stopTriggered = false; 53 | var disposeTriggered = false; 54 | 55 | var testGuid = TestControllersUtils.GenerateTestGuid(); 56 | var args = new TestControllerArgs(testGuid); 57 | _testControllersActionModel.StartTriggered += () => startTriggered = true; 58 | _testControllersActionModel.StopTriggered += () => stopTriggered = true; 59 | _testControllersActionModel.DisposeTriggered += () => disposeTriggered = true; 60 | 61 | Assert.DoesNotThrow( 62 | () => 63 | { 64 | // Act 65 | TestRootControllerLauncher.Launch( 66 | args, 67 | _controllerFactory, CancellationToken); 68 | 69 | _cancellationTokenSource.Cancel(); 70 | 71 | // Assert 72 | Assert.AreEqual(args.InputString, _testControllersActionModel.Args, "Args are not equal"); 73 | Assert.True(startTriggered, "OnStart is not triggered"); 74 | Assert.True(stopTriggered, "OnStop is not triggered"); 75 | Assert.True(disposeTriggered, "Dispose is not triggered"); 76 | }); 77 | } 78 | 79 | [Test] 80 | public void ControllerBase_OnStartThrowsException_StopAndDisposeAreTriggered() 81 | { 82 | // Arrange 83 | var stopTriggered = false; 84 | var disposeTriggered = false; 85 | 86 | var testGuid = TestControllersUtils.GenerateTestGuid(); 87 | var args = new TestControllerArgs(testGuid); 88 | _testControllersActionModel.StartTriggered += () => throw new TestControllersException(TestControllersMethodsNamesConsts.OnStartMethodName); 89 | _testControllersActionModel.StopTriggered += () => stopTriggered = true; 90 | _testControllersActionModel.DisposeTriggered += () => disposeTriggered = true; 91 | 92 | Assert.Throws( 93 | () => 94 | { 95 | // Act 96 | TestRootControllerLauncher.Launch( 97 | args, 98 | _controllerFactory, CancellationToken); 99 | 100 | _cancellationTokenSource.Cancel(); 101 | }); 102 | 103 | // Assert 104 | Assert.True(stopTriggered, "OnStop is not triggered"); 105 | Assert.True(disposeTriggered, "Dispose is not triggered"); 106 | } 107 | 108 | [Test] 109 | public void ControllerBase_OnStopThrowsException_OnStartAndOnDisposeAreTriggered() 110 | { 111 | var startTriggered = false; 112 | var disposeTriggered = false; 113 | 114 | var testGuid = TestControllersUtils.GenerateTestGuid(); 115 | var args = new TestControllerArgs(testGuid); 116 | _testControllersActionModel.StartTriggered += () => startTriggered = true; 117 | _testControllersActionModel.StopTriggered += () => throw new TestControllersException(TestControllersMethodsNamesConsts.OnStopMethodName); 118 | _testControllersActionModel.DisposeTriggered += () => disposeTriggered = true; 119 | 120 | Assert.Throws( 121 | () => 122 | { 123 | // Act 124 | TestRootControllerLauncher.Launch( 125 | args, 126 | _controllerFactory, CancellationToken); 127 | 128 | _cancellationTokenSource.Cancel(); 129 | }); 130 | 131 | // Assert 132 | Assert.True(startTriggered, "OnStart is not triggered"); 133 | Assert.True(disposeTriggered, "Dispose is not triggered"); 134 | } 135 | 136 | [Test] 137 | public void ControllerBase_OnDisposeThrowsException_OnStartAndOnStopAreTriggered() 138 | { 139 | // Arrange 140 | var startTriggered = false; 141 | var stopTriggered = false; 142 | 143 | var testGuid = TestControllersUtils.GenerateTestGuid(); 144 | var args = new TestControllerArgs(testGuid); 145 | _testControllersActionModel.StartTriggered += () => startTriggered = true; 146 | _testControllersActionModel.StopTriggered += () => stopTriggered = true; 147 | _testControllersActionModel.DisposeTriggered += () => throw new TestControllersException(TestControllersMethodsNamesConsts.DisposeMethodName); 148 | 149 | Assert.Throws( 150 | () => 151 | { 152 | // Act 153 | TestRootControllerLauncher.Launch( 154 | args, 155 | _controllerFactory, CancellationToken); 156 | 157 | _cancellationTokenSource.Cancel(); 158 | }); 159 | 160 | // Assert 161 | Assert.True(startTriggered, "OnStart is not triggered"); 162 | Assert.True(stopTriggered, "OnStop has been triggered"); 163 | } 164 | 165 | [Test] 166 | public void ControllerBase_OnStartTokenCancelled_OnStopAndOnDisposeAreTriggered() 167 | { 168 | // Arrange 169 | var stopTriggered = false; 170 | var disposeTriggered = false; 171 | 172 | var testGuid = TestControllersUtils.GenerateTestGuid(); 173 | var args = new TestControllerArgs(testGuid); 174 | _testControllersActionModel.StartTriggered += () => _cancellationTokenSource.Cancel(); 175 | _testControllersActionModel.StopTriggered += () => stopTriggered = true; 176 | _testControllersActionModel.DisposeTriggered += () => disposeTriggered = true; 177 | 178 | Assert.DoesNotThrow( 179 | () => 180 | { 181 | // Act 182 | TestRootControllerLauncher.Launch( 183 | args, 184 | _controllerFactory, CancellationToken); 185 | 186 | // Assert 187 | Assert.True(stopTriggered, "OnStop is not triggered"); 188 | Assert.True(disposeTriggered, "Dispose is not triggered"); 189 | Assert.True(CancellationToken.IsCancellationRequested, "Cancellation token should be cancelled"); 190 | }); 191 | } 192 | } 193 | } -------------------------------------------------------------------------------- /src/ControllersTree/Tests/ControllersBaseTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ac1f85185945b40f7b73fe43e0cb785c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/ControllersWithResultBaseTests.ChildControllers.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using NUnit.Framework; 5 | 6 | namespace UnitTests.Controllers 7 | { 8 | public partial class ControllersWithResultBaseTests 9 | { 10 | [Test] 11 | public async Task ControllerWithResultBase_Complete_Parent() 12 | { 13 | // Arrange 14 | var testGuid = TestControllersUtils.GenerateTestGuid(); 15 | var childControllersGuids = Enumerable.Range(0, 5) 16 | .Select( number => TestControllersUtils.GenerateTestGuid()) 17 | .ToList(); 18 | 19 | var args = new TestChildControllerArgs(testGuid, childControllersGuids); 20 | 21 | var startTriggeredCallers = new List(); 22 | var flowTriggeredCallers = new List(); 23 | var stopTriggeredCallers = new List(); 24 | var disposeTriggeredCallers = new List(); 25 | 26 | _testChildControllersActionModel.StartTriggered += caller => startTriggeredCallers.Add(caller); 27 | _testChildControllersActionModel.FlowTriggered += caller => flowTriggeredCallers.Add(caller); 28 | _testChildControllersActionModel.StopTriggered += caller => stopTriggeredCallers.Add(caller); 29 | _testChildControllersActionModel.DisposeTriggered += caller => disposeTriggeredCallers.Add(caller); 30 | 31 | var result = await TestRootControllerLauncher 32 | .LaunchAsync( 33 | args, _controllerFactory, CancellationToken); 34 | 35 | // Assert 36 | AssertTriggerCallers(startTriggeredCallers, childControllersGuids, "Expected callers doesn't contain Start caller id"); 37 | AssertTriggerCallers(flowTriggeredCallers, childControllersGuids, "Expected callers doesn't contain Flow caller id"); 38 | AssertTriggerCallers(stopTriggeredCallers, childControllersGuids, "Expected callers doesn't contain Stop caller id"); 39 | AssertTriggerCallers(disposeTriggeredCallers, childControllersGuids, "Expected callers doesn't contain Dispose caller id"); 40 | Assert.IsNotNull(result, "Result shouldn't be null"); 41 | var resultCorrect = string.Equals(args.InputString, result.ResultString); 42 | Assert.True(resultCorrect, "Result is incorrect"); 43 | } 44 | 45 | private void AssertTriggerCallers( 46 | List callers, 47 | List expectedCallers, 48 | string errorMessage) 49 | { 50 | Assert.IsNotEmpty(callers, "Controllers methods callers collection shouldn't be empty"); 51 | Assert.AreEqual(expectedCallers.Count, callers.Count, "Controllers methods callers collection size is incorrect"); 52 | foreach (var caller in callers) 53 | { 54 | Assert.Contains(caller, expectedCallers, errorMessage, errorMessage); 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/ControllersWithResultBaseTests.ChildControllers.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bd388f781a4e54fe29fec5726e5dfbf3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/ControllersWithResultBaseTests.FlowAsync.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 35dd7e7239abe44108d458b82dcc51ce 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/ControllersWithResultBaseTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4930e2f834f74d22af9f7c2d81e1a002 3 | timeCreated: 1704983994 -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Playtika.Controllers.Tests.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Playtika.Controllers.Tests", 3 | "references": [ 4 | "Playtika.Controllers", 5 | "Playtika.Controllers.Substitute", 6 | "UniTask" 7 | ], 8 | "optionalUnityReferences": [], 9 | "includePlatforms": [ 10 | "Editor" 11 | ], 12 | "excludePlatforms": [], 13 | "allowUnsafeCode": false, 14 | "testAssemblies": true 15 | } -------------------------------------------------------------------------------- /src/ControllersTree/Tests/Playtika.Controllers.Tests.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 263051419b854553b99ef74e20764527 3 | timeCreated: 1734555024 -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestChildControllerArgs.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace UnitTests.Controllers 4 | { 5 | internal class TestChildControllerArgs : TestControllerArgs 6 | { 7 | public readonly IReadOnlyCollection ChildControllersGuids; 8 | 9 | public TestChildControllerArgs( 10 | string inputString, 11 | IReadOnlyCollection childControllersGuids) 12 | : base(inputString) 13 | { 14 | ChildControllersGuids = childControllersGuids; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestChildControllerArgs.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2e757706c19bf4813b7e959d0e663b69 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestChildControllersActionModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnitTests.Controllers 4 | { 5 | internal class TestChildControllersActionModel 6 | { 7 | public string Args; 8 | 9 | public event Action StartTriggered; 10 | public event Action FlowTriggered; 11 | public event Action StopTriggered; 12 | public event Action DisposeTriggered; 13 | 14 | public void TriggerChildStart(string childControllerName) 15 | { 16 | StartTriggered?.Invoke(childControllerName); 17 | } 18 | 19 | public void TriggerChildFlow(string childControllerName) 20 | { 21 | FlowTriggered?.Invoke(childControllerName); 22 | } 23 | 24 | public void TriggerChildStop(string childControllerName) 25 | { 26 | StopTriggered?.Invoke(childControllerName); 27 | } 28 | 29 | public void TriggerChildDispose(string childControllerName) 30 | { 31 | DisposeTriggered?.Invoke(childControllerName); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestChildControllersActionModel.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5fd75c53179e24df5a6ca55e20bb016e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestControllerArgs.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTests.Controllers 2 | { 3 | public class TestControllerArgs 4 | { 5 | public readonly string InputString; 6 | 7 | public TestControllerArgs(string inputString) 8 | { 9 | InputString = inputString; 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestControllerArgs.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7a67a2329169a443da6fef56ab2f7f68 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestControllersActionModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnitTests.Controllers 4 | { 5 | public class TestControllersActionModel 6 | { 7 | public string Args; 8 | public event Action StartTriggered; 9 | public event Action FlowTriggered; 10 | public event Action StopTriggered; 11 | public event Action DisposeTriggered; 12 | 13 | public void TriggerStart() => StartTriggered?.Invoke(); 14 | public void TriggerStop() => StopTriggered?.Invoke(); 15 | public void TriggerFlow() => FlowTriggered?.Invoke(); 16 | public void TriggerDispose() => DisposeTriggered?.Invoke(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestControllersActionModel.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4c0bc1c3108e4a7d91f87233bed316f2 3 | timeCreated: 1705507522 -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestControllersException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnitTests.Controllers 4 | { 5 | public class TestControllersException : Exception 6 | { 7 | public readonly string ThrowerCallerName; 8 | 9 | public TestControllersException(string throwerCallerName) 10 | { 11 | ThrowerCallerName = throwerCallerName; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestControllersException.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bc867e28314b44c7eb90049337db8640 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestControllersMethodsNamesConsts.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTests.Controllers 2 | { 3 | public static class TestControllersMethodsNamesConsts 4 | { 5 | public const string OnStartMethodName = "OnStart"; 6 | public const string OnFlowAsyncMethodName = "OnFlowAsync"; 7 | public const string CompleteMethodName = "Complete"; 8 | public const string OnStopMethodName = "OnStop"; 9 | public const string DisposeMethodName = "Dispose"; 10 | public const string FailMethodName = "Fail"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestControllersMethodsNamesConsts.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 416770c5057074dadb038ba41d1ff5f2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestControllersUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnitTests.Controllers 4 | { 5 | public static class TestControllersUtils 6 | { 7 | public static string GenerateTestGuid() 8 | { 9 | return Guid.NewGuid() 10 | .ToString(); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestControllersUtils.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3f1fde4ecdc0d4750b1baaaf745ec16b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestEmptyControllerResult.cs: -------------------------------------------------------------------------------- 1 | namespace UnitTests.Controllers 2 | { 3 | public class TestEmptyControllerResult 4 | { 5 | public readonly string ResultString; 6 | 7 | public TestEmptyControllerResult(string resultString) 8 | { 9 | ResultString = resultString; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestEmptyControllerResult.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b9cd38c0ba272429d85caf6032ff6881 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestRootControllerLauncher.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using Playtika.Controllers; 3 | using Cysharp.Threading.Tasks; 4 | using Playtika.Controllers.Substitute; 5 | 6 | namespace UnitTests.Controllers 7 | { 8 | public static class TestRootControllerLauncher 9 | { 10 | public static TestRootController Launch(IControllerFactory controllerFactory, 11 | CancellationToken cancellationToken) 12 | { 13 | var testRootController = new TestRootController(controllerFactory); 14 | testRootController.LaunchTree(cancellationToken); 15 | 16 | return testRootController; 17 | } 18 | 19 | public static void Launch( 20 | TArg arg, 21 | IControllerFactory controllerFactory, 22 | CancellationToken cancellationToken) 23 | where T : class, IController, IController 24 | { 25 | var testRootController = new TestRootController(controllerFactory); 26 | testRootController.LaunchTree(cancellationToken); 27 | 28 | testRootController.Execute(arg); 29 | } 30 | 31 | public static UniTask LaunchAsync( 32 | IControllerFactory controllerFactory, 33 | CancellationToken cancellationToken) 34 | where T : class, IControllerWithResult, IController 35 | { 36 | var testRootController = new TestRootController(controllerFactory); 37 | testRootController.LaunchTree(cancellationToken); 38 | 39 | return testRootController.ExecuteAndWaitResultAsync(cancellationToken); 40 | } 41 | 42 | public static void Launch( 43 | IControllerFactory controllerFactory, 44 | TArg arg, 45 | CancellationToken cancellationToken) 46 | where T : class, IController, IController 47 | { 48 | var testRootController = new TestRootController(controllerFactory); 49 | testRootController.LaunchTree(cancellationToken); 50 | 51 | testRootController.Execute(arg); 52 | } 53 | 54 | public static UniTask LaunchAsync( 55 | TArg arg, 56 | IControllerFactory controllerFactory, 57 | CancellationToken cancellationToken) 58 | where T : class, IControllerWithResult, IController 59 | { 60 | var testRootController = new TestRootController(controllerFactory); 61 | testRootController.LaunchTree(cancellationToken); 62 | 63 | return testRootController.ExecuteAndWaitResultAsync(arg, cancellationToken); 64 | } 65 | 66 | public static UniTask LaunchAsync( 67 | TArg arg, 68 | IControllerFactory controllerFactory, 69 | CancellationToken cancellationToken) 70 | where T : class, IControllerWithResult, IController 71 | { 72 | var testRootController = new TestRootController(controllerFactory); 73 | testRootController.LaunchTree(cancellationToken); 74 | 75 | return testRootController.ExecuteAndWaitResultAsync(arg, cancellationToken); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /src/ControllersTree/Tests/TestRootControllerLauncher.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7e3d018d248042e6b0e625073827a104 3 | timeCreated: 1734556934 -------------------------------------------------------------------------------- /src/ControllersTree/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.playtika.controllers-tree", 3 | "displayName": "ControllersTree", 4 | "version": "1.0.0", 5 | "unity": "2018.3", 6 | "description": "Framework for organising game logic into scalable, maintainable hierarchies of controllers.", 7 | "keywords": ["Unity", "HMVC", "controllers-tree", "Hierarchy of controllers", "Unity controllers"], 8 | "documentationUrl": "https://github.com/PlaytikaOSS/controllers-tree/blob/main/README.md" 9 | } -------------------------------------------------------------------------------- /src/ControllersTree/package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eed75e7819021ff4a926bcb3049bf980 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------