using GeometryTD.CustomEvent; using GeometryTD.Definition; using GeometryTD.Procedure; using GameFramework.Event; using UnityEngine; using UnityGameFramework.Runtime; namespace GeometryTD.UI { public sealed class NodeMapFormController : UIFormControllerCommonBase { private NodeMapFormUseCase _useCase; protected override UIFormType UIFormTypeId => UIFormType.NodeMapForm; protected override void RefreshUI(NodeMapForm form, NodeMapFormContext context) { form.RefreshUI(context); } protected override void SubscribeCustomEvents() { GameEntry.Event.Subscribe(NodeMapNodeClickEventArgs.EventId, OnNodeClicked); } protected override void UnsubscribeCustomEvents() { GameEntry.Event.Unsubscribe(NodeMapNodeClickEventArgs.EventId, OnNodeClicked); } public override int? OpenUI(object userData = null) { if (userData is NodeMapFormContext context) { return OpenUIInternal(context); } if (userData is NodeMapFormRawData rawDataFromUserData) { return OpenUI(rawDataFromUserData); } if (userData != null) { Log.Warning("NodeMapFormController.OpenUI() userData type is invalid."); return null; } if (_useCase == null) { Log.Error("NodeMapFormController.OpenUI() useCase is null."); return null; } return OpenUI(_useCase.CreateInitialModel()); } public int? OpenUI(NodeMapFormRawData rawData) { return OpenUIInternal(BuildContext(rawData)); } public override void BindUseCase(IUIUseCase useCase) { if (!(useCase is NodeMapFormUseCase nodeMapFormUseCase)) { Log.Error("NodeMapFormController.BindUseCase() useCase is invalid."); return; } _useCase = nodeMapFormUseCase; } private void OnNodeClicked(object sender, GameEventArgs e) { if (!IsEventFromCurrentForm(sender) || !(e is NodeMapNodeClickEventArgs args) || _useCase == null) { return; } if (!_useCase.TryRequestEnterNode(args.SequenceIndex, out NodeMapNodeRawData selectedNode, out NodeMapFormRawData latestRawData)) { if (latestRawData != null) { SetContext(BuildContext(latestRawData)); RefreshCurrentUI(); } return; } if (latestRawData != null) { SetContext(BuildContext(latestRawData)); RefreshCurrentUI(); } if (Form != null && selectedNode != null) { GameEntry.Event.Fire(Form, NodeMapNodeEnterRequestedEventArgs.Create( selectedNode.RunId, selectedNode.NodeId, selectedNode.NodeType, selectedNode.SequenceIndex)); } } private bool IsEventFromCurrentForm(object sender) { if (Form == null) { return false; } if (ReferenceEquals(sender, Form)) { return true; } if (sender is Component component) { NodeMapForm ownerForm = component.GetComponentInParent(); return ownerForm == Form; } return false; } private static NodeMapFormContext BuildContext(NodeMapFormRawData rawData) { NodeItemContext[] nodeItemContexts = System.Array.Empty(); if (rawData?.Nodes != null && rawData.Nodes.Count > 0) { nodeItemContexts = new NodeItemContext[rawData.Nodes.Count]; for (int i = 0; i < rawData.Nodes.Count; i++) { NodeMapNodeRawData node = rawData.Nodes[i]; nodeItemContexts[i] = new NodeItemContext { NodeId = node?.NodeId ?? 0, SequenceIndex = node?.SequenceIndex ?? i, NodeType = node?.NodeType ?? RunNodeType.None, IsLocked = node != null && node.Status == RunNodeStatus.Locked, IsCurrent = node != null && node.IsCurrentNode, IsCompleted = node != null && node.Status == RunNodeStatus.Completed, IsFailed = node != null && node.Status == RunNodeStatus.Failed, CanClick = node != null && node.CanEnter }; } } return new NodeMapFormContext { Title = rawData?.Title ?? "节点地图", ProgressText = rawData?.ProgressText ?? "0 / 0", CurrentNodeText = rawData?.CurrentNodeText ?? "当前节点: 无", IsRunCompleted = rawData != null && rawData.IsRunCompleted, NodeItems = nodeItemContexts }; } } }