using System; using System.Collections.Generic; using Cysharp.Threading.Tasks; using SepCore.Definition; using SepCore.UI; using UnityEngine; using UnityGameFramework.Runtime; namespace SepCore.UIRouter { public class UIRouterComponent : GameFrameworkComponent { [Serializable] public class ControllerBinding { [SerializeField] private UIFormType _uiFormType = UIFormType.Undefined; [SerializeField] private string _controllerTypeName; public UIFormType UIFormType => _uiFormType; public string ControllerTypeName => _controllerTypeName; } [SerializeField] private List _controllerBindings = new(); private readonly Dictionary _routeControllers = new(); private readonly Dictionary> _controllerFactories = new(); protected override void Awake() { base.Awake(); RegisterSerializedBindings(); } public void RegisterController(UIFormType uiFormType, Func controllerFactory) { if (controllerFactory == null) { Log.Error("UIRouterComponent.RegisterController() controllerFactory is invalid."); return; } if (_routeControllers.TryGetValue(uiFormType, out IUIController controller)) { controller.CloseUIAsync().Forget(); _routeControllers.Remove(uiFormType); } _controllerFactories[uiFormType] = controllerFactory; } public void RegisterController(UIFormType uiFormType) where TController : IUIController, new() { RegisterController(uiFormType, () => new TController()); } public void BindUIUseCase(UIFormType uiFormType, IUIUseCase useCase) { IUIController controller = GetOrCreateController(uiFormType); if (controller == null) { return; } controller.BindUseCase(useCase); } public UniTask OpenUIAsync(UIFormType uiFormType, object userData = null, float timeout = 30f) { IUIController controller = GetOrCreateController(uiFormType); if (controller == null) { return default; } return controller.OpenUIAsync(userData, timeout); } public UniTask CloseUIAsync(UIFormType uiFormType, object userData = null, float timeout = 30f) { IUIController controller = GetOrCreateController(uiFormType); if (controller == null) { return UniTask.CompletedTask; } return controller.CloseUIAsync(userData, timeout); } private IUIController GetOrCreateController(UIFormType uiFormType) { if (_routeControllers.TryGetValue(uiFormType, out IUIController controller)) { return controller; } if (!_controllerFactories.TryGetValue(uiFormType, out Func controllerFactory)) { Log.Error("UIRouterComponent requires a controller binding for '{0}'.", uiFormType.ToString()); return null; } controller = controllerFactory(); if (controller == null) { Log.Error("UIRouterComponent controller factory for '{0}' returned null.", uiFormType.ToString()); return null; } _routeControllers.Add(uiFormType, controller); return controller; } private void RegisterSerializedBindings() { if (_controllerBindings == null || _controllerBindings.Count == 0) { return; } HashSet seen = new(); foreach (ControllerBinding binding in _controllerBindings) { if (binding == null || binding.UIFormType == UIFormType.Undefined || string.IsNullOrWhiteSpace(binding.ControllerTypeName)) { continue; } if (!seen.Add(binding.UIFormType)) { Log.Warning("UIRouter duplicate binding for '{0}', later one overrides earlier one.", binding.UIFormType.ToString()); } Type controllerType = Type.GetType(binding.ControllerTypeName); if (controllerType == null) { Log.Warning("UIRouter binding type not found: {0}", binding.ControllerTypeName); continue; } if (!typeof(IUIController).IsAssignableFrom(controllerType)) { Log.Warning("UIRouter binding type '{0}' does not implement IUIFormController.", binding.ControllerTypeName); continue; } RegisterController(binding.UIFormType, () => CreateController(controllerType)); } } private static IUIController CreateController(Type controllerType) { object instance = Activator.CreateInstance(controllerType); if (instance is IUIController controller) { return controller; } return null; } private void OnDestroy() { foreach (KeyValuePair pair in _routeControllers) { pair.Value.CloseUIAsync().Forget(); } _routeControllers.Clear(); } } }