diff --git a/Assets/PerfectWorld/Prefab/Task/TaskTrace/DlgTaskTrace.prefab b/Assets/PerfectWorld/Prefab/Task/TaskTrace/DlgTaskTrace.prefab index f0695daa74..16656ee90f 100644 --- a/Assets/PerfectWorld/Prefab/Task/TaskTrace/DlgTaskTrace.prefab +++ b/Assets/PerfectWorld/Prefab/Task/TaskTrace/DlgTaskTrace.prefab @@ -38,7 +38,7 @@ RectTransform: m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} m_AnchoredPosition: {x: 161.25, y: 0} - m_SizeDelta: {x: 322.5, y: 0} + m_SizeDelta: {x: 322.5, y: 300} m_Pivot: {x: 0.5, y: 1} --- !u!222 &9154858122360570458 CanvasRenderer: @@ -372,6 +372,8 @@ MonoBehaviour: m_pTxt_Desc: {fileID: 2531022629832384091} m_pBtnFinishTaskByContribution: {fileID: 0} m_pBtnContributionTaskHelp: {fileID: 0} + m_pToggleReceived: {fileID: 3754705535557026321} + m_pToggleNotReceived: {fileID: 6274674518893574845} --- !u!1 &2291589776560736050 GameObject: m_ObjectHideFlags: 0 @@ -449,7 +451,7 @@ MonoBehaviour: m_PressedTrigger: Pressed m_SelectedTrigger: Selected m_DisabledTrigger: Disabled - m_Interactable: 0 + m_Interactable: 1 m_TargetGraphic: {fileID: 8307833885626771741} toggleTransition: 1 graphic: {fileID: 1446671815119800730} diff --git a/Assets/PerfectWorld/Scripts/Task/TaskClient.cs b/Assets/PerfectWorld/Scripts/Task/TaskClient.cs index 398cdd7b3a..4cf1a68d30 100644 --- a/Assets/PerfectWorld/Scripts/Task/TaskClient.cs +++ b/Assets/PerfectWorld/Scripts/Task/TaskClient.cs @@ -587,6 +587,14 @@ namespace BrewMonster.Scripts.Task pTempl.ClearValidCount(); // OnServerNotify method signature may need adjustment for C# (ref/out parameters) pTempl.OnServerNotify(pTask, pEntry, pNotify, sz, pBuf); + + // TASK_SVR_NOTIFY_COMPLETE (reason 2): re-expand trace for this quest line (subtask chain advance). + // TASK_SVR_NOTIFY_COMPLETE(reason=2):子任务推进后重新挂接追踪链。 + if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_COMPLETE) + { + var gameUi = EC_Game.GetGameRun()?.GetUIManager()?.GetInGameUIMan() as CECGameUIMan; + gameUi?.RetraceTaskAfterServerNotifyComplete(pNotify.task); + } } // Helper method to get task template manager diff --git a/Assets/PerfectWorld/Scripts/Task/UI/DlgTask.cs b/Assets/PerfectWorld/Scripts/Task/UI/DlgTask.cs index eb0113d668..67909fd581 100644 --- a/Assets/PerfectWorld/Scripts/Task/UI/DlgTask.cs +++ b/Assets/PerfectWorld/Scripts/Task/UI/DlgTask.cs @@ -122,6 +122,7 @@ namespace BrewMonster.Scripts.Task.UI // private: private static List m_vecTasksUnFinish = new List(); private static List m_vecTasksCanFinish = new List(); + private static List m_vecTasksCanGet = new List(); // [中文] 目标坐标集合 // [English] Target coordinates collection @@ -378,6 +379,7 @@ namespace BrewMonster.Scripts.Task.UI m_pBtn_SearchQuest.interactable = true; m_pBtn_HaveQuest.interactable = false; UpdateTask(); + RefreshVecTasksCanGet(); } public void OnCommand_showtrace(string szCommand,bool state) { m_bShowTrace = state; @@ -401,6 +403,7 @@ namespace BrewMonster.Scripts.Task.UI vec_task.Remove((int)idTask); } } + Debug.Log($"[DlgTask] TraceTask: idTask={idTask}, task name={pTask.GetTaskTemplMan().GetTaskTemplByID((uint)idTask).GetName()}"); //get the position of idTask in pLst int position = pTask.GetFirstSubTaskPosition(idTask); while(position != -1) @@ -410,6 +413,60 @@ namespace BrewMonster.Scripts.Task.UI } ShowTraceDialog(); } + + /// + /// Add task to trace lists if traceable (no toggle). Used when seeding trace after TASK_DATA init; mirrors TraceTask minus remove/toggle. + /// 若可追踪则加入追踪列表(无切换)。在 TASK_DATA 初始化后填充追踪时用;逻辑对齐 TraceTask 但不移除/切换。 + /// + private void AddTaskToTraceListsNonToggle(uint idTask) + { + if (IsPQTaskOrSubTask((int)idTask)) + return; + CECTaskInterface pTask = GetHostPlayer()?.GetTaskInterface(); + if (pTask == null) + return; + bool bFinishedTask = pTask.CanFinishTask(idTask); + List vec_task = bFinishedTask ? m_vecTasksCanFinish : m_vecTasksUnFinish; + if (IsTaskTraceable(idTask)) + { + if (!vec_task.Contains((int)idTask)) + vec_task.Add((int)idTask); + } + int position = pTask.GetFirstSubTaskPosition(idTask); + while (position != -1) + { + int idSub = pTask.GetNextSub(ref position); + AddTaskToTraceListsNonToggle((uint)idSub); + } + } + + /// + /// After server task pack and templates are loaded (CECTaskInterface.Init finished), apply trace like USER_LAYOUT from server: + /// SyncTrace with a full dwTraceMask for the first 32 top-level slots, then add any further top-level tasks (mask is only 32 bits). + /// 服务端任务包与模板加载完成后调用:用满掩码对前 32 个顶层槽位 SyncTrace,再为更多顶层任务补充追踪(掩码仅 32 位)。 + /// + public void SyncTraceAfterTaskDataInit(CECTaskInterface pTask) + { + if (pTask == null || GetHostPlayer()?.GetTaskInterface() != pTask) + return; + + var ul = new USER_LAYOUT { bTraceAll = true }; + int n = (int)pTask.GetTaskCount(); + if (n > 0) + { + int bits = Mathf.Min(n, 32); + ul.dwTraceMask = bits >= 32 ? uint.MaxValue : ((1u << bits) - 1u); + } + + SyncTrace(ul, true); + + for (int i = 32; i < n; i++) + AddTaskToTraceListsNonToggle(pTask.GetTaskId((uint)i)); + + RefreshVecTasksCanGet(pTask); + RefreshTaskTrace(ul.bTraceAll); + } + public void ShowTraceDialog() { Debug.Log($"[DlgTask] ShowTraceDialog: m_bShowTrace={m_bShowTrace}"); @@ -422,6 +479,28 @@ namespace BrewMonster.Scripts.Task.UI EventBus.Publish(new UIEvent(UIEventType.HideTrace)); } } + + /// + /// TASK_SVR_NOTIFY_COMPLETE (reason 2): re-expand the quest trace from the top task (add-only, same subchain walk as TraceTask). + /// Using TraceTask() here would toggle entries off/on incorrectly; this re-seeds the active subtask chain after server advance. + /// 服务端 reason=2 任务推进/完成后,从顶层任务重新挂接追踪子链(与 TraceTask 同 walk,但只添加不切换)。 + /// + public void RetraceAfterTaskServerNotifyComplete(uint notifyTaskId, bool bShowTrace) + { + var pIface = GetHostPlayer()?.GetTaskInterface(); + if (pIface == null) + return; + ATaskTemplMan pMan = EC_Game.GetTaskTemplateMan(); + ATaskTempl t = pMan?.GetTaskTemplByID(notifyTaskId); + if (t == null) + return; + uint rootId = t.GetTopTask().GetID(); + if (rootId == 0) + return; + if (pIface.HasTask(rootId)) + AddTaskToTraceListsNonToggle(rootId); + RefreshTaskTrace(bShowTrace); + } public void OnCommand_focus(string szCommand="") { var pTree = m_pTv_Quest; var pItem = pTree?.GetSelectedItem(); @@ -506,6 +585,7 @@ namespace BrewMonster.Scripts.Task.UI int taskIdInt = (int)topTaskId; m_vecTasksCanFinish.Remove(taskIdInt); m_vecTasksUnFinish.Remove(taskIdInt); + RefreshVecTasksCanGet(); // Send notification to server to abandon the currently selected task TaskClient._notify_svr(pTask, (byte)ClientNotificationConstants.TASK_CLT_NOTIFY_CHECK_GIVEUP, (ushort)topTaskId); @@ -788,48 +868,62 @@ namespace BrewMonster.Scripts.Task.UI { CECHostPlayer host = GetHostPlayer(); CECTaskInterface pTask = host.GetTaskInterface(); - if( m_vecTasksCanFinish.Count > 0 ) - { - for(int i = 0; i < m_vecTasksCanFinish.Count; i++ ) - { - int idTask = m_vecTasksCanFinish[i]; - bool bCanFinish = pTask.CanFinishTask((uint)idTask); - bool bHasTask = pTask.HasTask((uint)idTask); - if(!bHasTask || !bCanFinish) - { - // 任务未完成,状态变化要删除 - m_vecTasksCanFinish.RemoveAt(i); - i--; - if (bHasTask && !bCanFinish) { - if (!m_vecTasksUnFinish.Contains(idTask)) - m_vecTasksUnFinish.Add(idTask); - } - } - } - } - if( m_vecTasksUnFinish.Count > 0 ) - { - for(int i = 0; i < m_vecTasksUnFinish.Count; i++ ) - { - int idTask = m_vecTasksUnFinish[i]; - bool bCanFinish = pTask.CanFinishTask((uint)idTask); - bool bHasTask = pTask.HasTask((uint)idTask); - if(!bHasTask || bCanFinish) - { - // �������û���ˣ�����״̬�仯Ҫ�Ƴ����� - m_vecTasksUnFinish.RemoveAt(i); - i--; - if (bHasTask && bCanFinish) { - if (!m_vecTasksCanFinish.Contains(idTask)) - m_vecTasksCanFinish.Add(idTask); - } - } - } - } + ShowType2 showType2 = pDlgTaskTrace.GetShowType2(); List tasks = new List(); - tasks.Capacity = m_vecTasksCanFinish.Count + m_vecTasksUnFinish.Count; - tasks.AddRange(m_vecTasksCanFinish); - tasks.AddRange(m_vecTasksUnFinish); + if(showType2 == ShowType2.ST_RECIEVED) + { + if( m_vecTasksCanFinish.Count > 0 ) + { + for(int i = 0; i < m_vecTasksCanFinish.Count; i++ ) + { + int idTask = m_vecTasksCanFinish[i]; + bool bCanFinish = pTask.CanFinishTask((uint)idTask); + bool bHasTask = pTask.HasTask((uint)idTask); + if(!bHasTask || !bCanFinish) + { + // 任务未完成,状态变化要删除 + m_vecTasksCanFinish.RemoveAt(i); + i--; + if (bHasTask && !bCanFinish) { + if (!m_vecTasksUnFinish.Contains(idTask)) + m_vecTasksUnFinish.Add(idTask); + } + } + } + } + if( m_vecTasksUnFinish.Count > 0 ) + { + for(int i = 0; i < m_vecTasksUnFinish.Count; i++ ) + { + int idTask = m_vecTasksUnFinish[i]; + bool bCanFinish = pTask.CanFinishTask((uint)idTask); + bool bHasTask = pTask.HasTask((uint)idTask); + if(!bHasTask || bCanFinish) + { + // �������û���ˣ�����״̬�仯Ҫ�Ƴ����� + m_vecTasksUnFinish.RemoveAt(i); + i--; + if (bHasTask && bCanFinish) { + if (!m_vecTasksCanFinish.Contains(idTask)) + m_vecTasksCanFinish.Add(idTask); + } + } + } + } + + tasks.Capacity = m_vecTasksCanFinish.Count + m_vecTasksUnFinish.Count; + tasks.AddRange(m_vecTasksCanFinish); + tasks.AddRange(m_vecTasksUnFinish); + } + else if(showType2 == ShowType2.ST_NOT_RECIEVED) + { + // Re-run GetAvailableTasks every trace refresh; m_vecTasksCanGet was only filled on quest UI events and stayed stale. + // 每次追踪刷新重新计算可接任务;原先仅在任务界面事件里更新列表,游戏中会一直停留在开局数据。 + RefreshVecTasksCanGet(pTask); + tasks.Capacity = m_vecTasksCanGet.Count; + tasks.AddRange(m_vecTasksCanGet); + } + List titlle_list = new List(); List titletask_list = new List(); //Dictionary title_map = new Dictionary(); @@ -1129,6 +1223,11 @@ namespace BrewMonster.Scripts.Task.UI // TaskTemplLst ttl; List ttl = new List(); // TaskTemplLst -> List pMan.GetAvailableTasks(pTask, ttl); + // Mirror available-to-accept IDs for trace / other systems (same set as tree nodes). + // 与可接任务树节点一致,填充可接任务 ID 列表供追踪等系统使用。 + m_vecTasksCanGet.Clear(); + for (int j = 0; j < ttl.Count; j++) + m_vecTasksCanGet.Add((int)ttl[j].GetID()); if( ttl.Count <= 0 ) return true; for(int i = 0; i < ttl.Count; i++ ) @@ -1198,6 +1297,11 @@ namespace BrewMonster.Scripts.Task.UI } } } + + // Search view already rebuilt m_vecTasksCanGet inside SearchForTask(-1). + // 搜索页在 SearchForTask 内已更新 m_vecTasksCanGet。 + if (m_iType == 0) + RefreshVecTasksCanGet(); return result; } @@ -1227,6 +1331,7 @@ namespace BrewMonster.Scripts.Task.UI // store m_bShowTrace flag instead of bTraceAll flag m_bShowTrace = pul.bTraceAll; + RefreshVecTasksCanGet(); } else { @@ -1303,6 +1408,23 @@ namespace BrewMonster.Scripts.Task.UI #region PRIVATE METHODS + /// + /// Rebuild m_vecTasksCanGet from ATaskTemplMan.GetAvailableTasks (same source as Search quest tree). + /// 用 GetAvailableTasks 重建可接任务 ID 列表,与可接任务搜索树数据源一致。 + /// + private void RefreshVecTasksCanGet(CECTaskInterface pTaskIfKnown = null) + { + m_vecTasksCanGet.Clear(); + CECTaskInterface pTask = pTaskIfKnown ?? GetHostPlayer()?.GetTaskInterface(); + if (pTask == null) return; + ATaskTemplMan pMan = EC_Game.GetTaskTemplateMan(); + if (pMan == null) return; + List ttl = new List(); + pMan.GetAvailableTasks(pTask, ttl); + for (int i = 0; i < ttl.Count; i++) + m_vecTasksCanGet.Add((int)ttl[i].GetID()); + } + private bool OnInitDialog() { // m_pTxt_QuestNO = (PAUILABEL)GetDlgItem("Txt_QuestNO"); diff --git a/Assets/PerfectWorld/Scripts/Task/UI/DlgTaskTrace.cs b/Assets/PerfectWorld/Scripts/Task/UI/DlgTaskTrace.cs index 428960e24e..02be1aa6f4 100644 --- a/Assets/PerfectWorld/Scripts/Task/UI/DlgTaskTrace.cs +++ b/Assets/PerfectWorld/Scripts/Task/UI/DlgTaskTrace.cs @@ -20,6 +20,13 @@ namespace BrewMonster.Scripts.Task.UI ST_TITLE, // ��ʾ�ѽӳƺ����� ST_CONTRIBUTION, // ��ʾ���������ѵĹ��׶����� } + //New show type in Unity version + public enum ShowType2 + { + ST_NONE, + ST_RECIEVED, + ST_NOT_RECIEVED, + } public class DlgTaskTrace : DlgNameLink { static string COLOR_YELLOW = ""; @@ -34,8 +41,11 @@ namespace BrewMonster.Scripts.Task.UI // [SerializeField] protected Button m_pBtnChat; [SerializeField] protected Button m_pBtnFinishTaskByContribution; [SerializeField] protected Button m_pBtnContributionTaskHelp; + [SerializeField] protected Toggle m_pToggleReceived; + [SerializeField] protected Toggle m_pToggleNotReceived; protected int m_nLastTracedTasks; // ����ʾ���ݶ�Ӧ��׷��������������ijЩ����������������б����л��� protected ShowType m_nLastShowType; // ����ʾ���ݶ�Ӧ���б����� + protected ShowType2 m_nLastShowType2; protected int m_nTraceWorldID; // ����ʾ��Ϣ��׷����Ϣ��Ӧ�ĵ�ͼID protected int m_iContributionCurrentPage; protected int m_iContributionTotalPage; @@ -69,13 +79,29 @@ namespace BrewMonster.Scripts.Task.UI } public override void Show(bool value) { + // RefreshTaskTrace calls Show(true) every tick while visible; do not reset filter or re-wire toggles then. + // RefreshTaskTrace 每帧对已显示窗口调用 Show(true);勿重置“已接/可接”筛选,也勿重复注册 Toggle。 + bool wasActive = gameObject.activeSelf; gameObject.SetActive(value); m_bShow = value; + if (value && !wasActive) + m_nLastShowType2 = ShowType2.ST_RECIEVED; + // Remove-before-Add in OnShowDialogue keeps this safe when RefreshTaskTrace calls Show(true) every frame. OnShowDialogue(); } public override void OnShowDialogue() { base.OnShowDialogue(); + if (m_pToggleReceived != null && m_pToggleNotReceived != null) + { + m_pToggleReceived.onValueChanged.RemoveListener(OnToggleReceivedValueChanged); + m_pToggleNotReceived.onValueChanged.RemoveListener(OnToggleNotReceivedValueChanged); + if (m_bShow) + { + m_pToggleReceived.onValueChanged.AddListener(OnToggleReceivedValueChanged); + m_pToggleNotReceived.onValueChanged.AddListener(OnToggleNotReceivedValueChanged); + } + } //m_pTxt_Desc = dynamic_cast(GetDlgItem("Txt_Link_Trace")); //if(m_pTxt_Desc) m_pTxt_Desc->SetForceRenderScroll(false); //m_pChk_Collapse = dynamic_cast(GetDlgItem("Chk_Collapse")); @@ -96,6 +122,20 @@ namespace BrewMonster.Scripts.Task.UI // ); // ����׷�ٽ�����ʾĬ���б� } + public void OnToggleReceivedValueChanged(bool value) + { + if(value) + { + m_nLastShowType2 = ShowType2.ST_RECIEVED; + } + } + public void OnToggleNotReceivedValueChanged(bool value) + { + if(value) + { + m_nLastShowType2 = ShowType2.ST_NOT_RECIEVED; + } + } public void OnShowDialog() { GameObject pObjRadio = transform.Find("Rdo_Quest3").gameObject; @@ -316,6 +356,10 @@ namespace BrewMonster.Scripts.Task.UI { return m_nLastShowType; } + public ShowType2 GetShowType2() + { + return m_nLastShowType2; + } void PrepareRebuildTaskTrace(){ m_Buffer = new StringRef(); m_Buffer.Value = ""; @@ -541,6 +585,10 @@ namespace BrewMonster.Scripts.Task.UI var pTempl = pTaskMan.GetTaskTemplByID((uint)id); var pEntry = pActiveLst.GetEntry((uint)id); if (pTempl != null) { + // 任务名与描述都为空时不显示(数据缺失或损坏) / Hide when both name and description are empty (missing or corrupt data) + if (string.IsNullOrWhiteSpace(pTempl.GetName()) && string.IsNullOrWhiteSpace(pTempl.GetDescription())) + return; + int contribution = 0; // �������׶ȵ�����ֻ�ڶ���������ʾ����ֵ if (hasContributionAward) { @@ -635,17 +683,15 @@ namespace BrewMonster.Scripts.Task.UI if (withName) { AppendText(strIndentIn); - string strNum = index.ToString(); - strNum = string.Format("{0}", index); string strName = pTemp.GetName(); DeleteColorStr(strName); - strName = strNum + " " + strName; + strName = " " + strName; TaskNameHoverCommand cmd = new TaskNameHoverCommand(m_Buffer, strName, idTask, tsi.m_ulErrCode != 0, bCanContributionFinish); BindLinkCommand(m_pTxt_Desc.tmp, strName, cmd); if (contribution != 0) { int colorIndex = contribution > 0 ? 11288 : 11291; - strNum = string.Format(" {0} {1}", GetStringFromTable(colorIndex), contribution); - AppendText(strNum); + strName = string.Format(" {0} {1}", GetStringFromTable(colorIndex), contribution); + AppendText(strName); } AppendText("\n"); } diff --git a/Assets/PerfectWorld/Scripts/UI/GamePlay/EC_GameUIMan.cs b/Assets/PerfectWorld/Scripts/UI/GamePlay/EC_GameUIMan.cs index 6107162c18..62074575da 100644 --- a/Assets/PerfectWorld/Scripts/UI/GamePlay/EC_GameUIMan.cs +++ b/Assets/PerfectWorld/Scripts/UI/GamePlay/EC_GameUIMan.cs @@ -193,6 +193,18 @@ namespace BrewMonster.UI return m_pDlgTask.UpdateQuestView(); } } + + /// + /// Call after CECTaskInterface.Init completes (TASK_DATA). Restores/applies quest trace via DlgTask.SyncTrace and refreshes minimion. + /// 在 CECTaskInterface.Init(TASK_DATA)完成后调用,通过 DlgTask.SyncTrace 应用任务追踪并刷新小窗。 + /// + public void OnHostTaskDataInitialized(CECTaskInterface pTask) + { + if (m_pDlgTask == null || pTask == null) + return; + m_pDlgTask.SyncTraceAfterTaskDataInit(pTask); + } + public DialogScriptTableObject GetDialogResource() { return m_dialogResouce; @@ -406,6 +418,18 @@ namespace BrewMonster.UI } } + /// + /// TASK_SVR_NOTIFY_COMPLETE (reason 2): refresh quest trace after server advances subtasks. + /// 服务端任务完成/推进通知后刷新任务追踪。 + /// + public void RetraceTaskAfterServerNotifyComplete(ushort taskId) + { + if (m_pDlgTask == null) + return; + bool showTrace = IsDialogShow("Win_QuestMinion"); + m_pDlgTask.RetraceAfterTaskServerNotifyComplete((uint)taskId, showTrace); + } + public void ShowErrorMsg(string pszMsg, string pszName) { diff --git a/Assets/Scripts/CECHostPlayer.Task.cs b/Assets/Scripts/CECHostPlayer.Task.cs index dcc5169bb0..0a13f07447 100644 --- a/Assets/Scripts/CECHostPlayer.Task.cs +++ b/Assets/Scripts/CECHostPlayer.Task.cs @@ -107,6 +107,11 @@ namespace BrewMonster // GET_ALL_DATA end flag tasks were here in C++ (LoadConfigData), omitted in C# UnityGameSession.LoadConfigData(); + // Quest trace lists + minimion: apply SyncTrace once active tasks and templates are ready. + // 任务追踪:在任务数据与模板就绪后调用 SyncTrace 同步追踪列表与小窗。 + var pGameUI = EC_Game.GetGameRun()?.GetUIManager()?.GetInGameUIMan(); + pGameUI?.OnHostTaskDataInitialized(m_pTaskInterface); + // if (UpdateEquipSkills()) UpdateEquipSkillCoolDown(); // methods not ported yet } else if (header == CommandID.TASK_VAR_DATA)