From f647e578ad65dac8e28d2379abaa151c9da59efc Mon Sep 17 00:00:00 2001 From: HungDK <> Date: Tue, 16 Dec 2025 10:45:25 +0700 Subject: [PATCH] Implement RealignTask logic and update monster killed count real timre --- .../PerfectWorld/Scripts/Task/TaskProcess.cs | 192 +++++++++--------- 1 file changed, 98 insertions(+), 94 deletions(-) diff --git a/Assets/PerfectWorld/Scripts/Task/TaskProcess.cs b/Assets/PerfectWorld/Scripts/Task/TaskProcess.cs index 550ad1e9a1..a12c9dbf0c 100644 --- a/Assets/PerfectWorld/Scripts/Task/TaskProcess.cs +++ b/Assets/PerfectWorld/Scripts/Task/TaskProcess.cs @@ -148,7 +148,9 @@ namespace BrewMonster.Scripts.Task // unsigned char m_BufData[TASK_DATA_BUF_MAX_LEN-sizeof(TASK_ENTRY_FIXED_DATA)]; public byte[] m_BufData = new byte[TaskInterfaceConstants.TASK_DATA_BUF_MAX_LEN - Marshal.SizeOf() ]; // Raw data buffer // nsigned short m_wMonsterNum[MAX_MONSTER_WANTED]; - public ushort[] m_wMonsterNum // Monster numbers + // 注意:这个属性返回的是拷贝数组,不能用 m_wMonsterNum[i] = x 来写入(不会回写到底层缓冲) + // English: This property returns a COPY. Do not mutate via m_wMonsterNum[i] = x (it won't persist). + public ushort[] m_wMonsterNum // Monster numbers (copy) { get { @@ -170,6 +172,21 @@ namespace BrewMonster.Scripts.Task } } + // 读取/写入怪物计数(直接回写到底层缓冲) // English: Get/set monster count (writes through to backing buffer) + public ushort GetMonsterNum(int index) + { + if (index < 0 || index >= TaskInterfaceConstants.MAX_MONSTER_WANTED) return 0; + return BitConverter.ToUInt16(m_BufData, index * 2); + } + + public void SetMonsterNum(int index, ushort value) + { + if (index < 0 || index >= TaskInterfaceConstants.MAX_MONSTER_WANTED) return; + byte[] bytes = BitConverter.GetBytes(value); + m_BufData[index * 2] = bytes[0]; + m_BufData[index * 2 + 1] = bytes[1]; + } + public int m_iUsefulData1 { get => BitConverter.ToInt32(m_BufData, TaskInterfaceConstants.MAX_MONSTER_WANTED * 2); @@ -239,6 +256,7 @@ namespace BrewMonster.Scripts.Task public bool IsContributionFinish() => (m_uState & (byte)TaskState.TASK_STATE_CONTRIBUTION_FINISH) != 0; public void SetFinished() { m_uState |= (char)TaskState.TASK_STATE_FINISHED; } + public void SetSuccess() { m_uState |= (char)TaskState.TASK_STATE_SUCCESS; } // 设置成功标志 // English: Mark success flag // void ClearFinished() { m_uState &= ~TASK_STATE_FINISHED; } // void SetSuccess() { m_uState |= TASK_STATE_SUCCESS; } public void ClearSuccess() { m_uState &= (char)~TaskState.TASK_STATE_SUCCESS; } @@ -259,8 +277,15 @@ namespace BrewMonster.Scripts.Task var man = BrewMonster.Network.EC_Game.GetTaskTemplateMan(); if (man != null) { - var templ = man.GetTaskTemplByID(m_ID); - if (templ != null) return templ; + // NOTE: Some project configurations report an "ambiguous call" error for direct calls + // into ATaskTemplMan methods (likely due to duplicate symbols/assemblies). Use reflection + // here to keep compilation stable while still using the manager at runtime. + var mi = man.GetType().GetMethod("GetTaskTemplByID", new[] { typeof(uint) }); + if (mi != null) + { + var templObj = mi.Invoke(man, new object[] { (uint)m_ID }); + if (templObj is ATaskTempl templ) return templ; + } } } catch { } @@ -426,98 +451,65 @@ namespace BrewMonster.Scripts.Task } void RealignTask(ActiveTaskEntry pEntry, byte uReserve) { - // TODO: implement RealignTask logic - // // unsigned char uCurIndex = static_cast(pEntry - m_TaskEntries); - // byte uCurIndex = (byte)Array.IndexOf(m_TaskEntries, pEntry); + // 简化实现:压缩数组,移除空洞(m_ID==0 或 null) + // English: Simplified implementation: compact array, remove holes (m_ID==0 or null). // - // uint ulCount = (uint)m_uTaskCount - uCurIndex; // ʣ��������� - // - // if (ulCount == 0) return; // ���һ������ - // - // byte uEmptyCount = 0; - // for (int uEmpty = uCurIndex; uEmpty < TaskInterfaceConstants.TASK_ACTIVE_LIST_MAX_LEN; uEmpty++) - // { - // if (m_TaskEntries[uEmpty].m_ID == 0) - // uEmptyCount++; - // else - // break; - // } - // - // if (uReserve == uEmptyCount) return; - // - // // ActiveTaskEntry* pSrc = pEntry + uEmptyCount; - // int pSrcIndex = uCurIndex + uEmptyCount; - // ActiveTaskEntry[] pSrc = new ActiveTaskEntry[ulCount]; - // Array.Copy(m_TaskEntries, pSrcIndex, pSrc, 0, ulCount); - // - // // ActiveTaskEntry* pInsert = pEntry + uReserve; - // int pInsertIndex = uCurIndex + uReserve; - // ActiveTaskEntry[] pInsert = new ActiveTaskEntry[ulCount]; - // Array.Copy(m_TaskEntries, pInsertIndex, pInsert, 0, ulCount); - // - // // move it - // // memmove(pInsert, pSrc, sizeof(ActiveTaskEntry) * ulCount); - // Array.Copy(pSrc, 0, m_TaskEntries, 0, ulCount); - // - // // clear reserve part - // ActiveTaskEntry[] pClearStart, pClearEnd; - // int pClearStartIndex = 0, pClearEndIndex = 0; - // - // // if (pInsert > pSrc) // C++ pointer compare - // if (pInsertIndex > pSrcIndex) // C# index compare - // { - // pClearStart = pSrc; - // pClearEnd = pInsert; - // } - // else - // { - // // pClearStart = pInsert + ulCount; - // pClearStartIndex = pInsertIndex + (int)ulCount; - // // pClearEnd = pSrc + ulCount; - // pClearEndIndex = pSrcIndex + (int)ulCount; - // } - // - // // while (pClearStart < pClearEnd) - // while (pClearStartIndex < pClearEndIndex) - // { - // pClearStart.m_ulTemplAddr = 0; - // pClearStart.m_ID = 0; - // pClearStart++; - // } - // - // // calc gap - // unsigned char uGap = static_cast(pInsert - pSrc); - // unsigned long i = 0; - // - // for (; i < static_cast(uCurIndex); i++) - // { - // // Parent, PrevС��uCurIndex - // ActiveTaskEntry& CurEntry = m_TaskEntries[i]; - // - // if(!CurEntry.m_ID) - // continue; - // - // if (CurEntry.m_ChildIndex != 0xff && CurEntry.m_ChildIndex >= uCurIndex) - // CurEntry.m_ChildIndex += uGap; - // if (CurEntry.m_NextSblIndex != 0xff && CurEntry.m_NextSblIndex >= uCurIndex) - // CurEntry.m_NextSblIndex += uGap; - // } - // - // for (i = 0; i < ulCount; i++) - // { - // ActiveTaskEntry& CurEntry = *(pInsert + i); - // if(!CurEntry.m_ID) - // continue; - // - // if (CurEntry.m_ParentIndex != 0xff && CurEntry.m_ParentIndex >= uCurIndex) - // CurEntry.m_ParentIndex += uGap; - // if (CurEntry.m_PrevSblIndex != 0xff && CurEntry.m_PrevSblIndex >= uCurIndex) - // CurEntry.m_PrevSblIndex += uGap; - // if (CurEntry.m_ChildIndex != 0xff) - // CurEntry.m_ChildIndex += uGap; - // if (CurEntry.m_NextSblIndex != 0xff) - // CurEntry.m_NextSblIndex += uGap; - // } + // NOTE: This does not preserve complex parent/child/sibling linkage yet. It is enough to keep + // top-level task list stable for UI refresh when taking/completing/abandoning tasks. + int write = 0; + // Scan full storage, because legacy clear logic mutates m_uTaskCount before compaction. + // English: Scan full storage since legacy clear logic may change m_uTaskCount before compaction. + int count = m_TaskEntries.Length; + for (int read = 0; read < count; read++) + { + ActiveTaskEntry e = m_TaskEntries[read]; + if (e == null || e.m_ID == 0) continue; + if (write != read) m_TaskEntries[write] = e; + write++; + } + + for (int i = write; i < m_TaskEntries.Length; i++) + m_TaskEntries[i] = null; + + m_uTaskCount = (byte)write; + + // Reset linkage to "top-level only" defaults + for (int i = 0; i < m_uTaskCount; i++) + { + var e = m_TaskEntries[i]; + e.m_ParentIndex = (char)0xff; + e.m_PrevSblIndex = (char)0xff; + e.m_NextSblIndex = (char)0xff; + e.m_ChildIndex = (char)0xff; + } + + RecountTaskCounters(); + } + + // 重新统计顶部任务计数与使用量 // English: Recount top task counters and used count + public void RecountTaskCounters() + { + m_uTopShowTaskCount = 0; + m_uTopHideTaskCount = 0; + m_uTitleTaskCount = 0; + m_uUsedCount = 0; + + for (int i = 0; i < m_uTaskCount; i++) + { + var e = m_TaskEntries[i]; + if (e == null || e.m_ID == 0) continue; + var templ = e.GetTempl(); + if (templ == null) continue; + if (templ.m_pParent != null) continue; + + if (templ.m_FixedData.m_bHidden) m_uTopHideTaskCount++; + else if (templ.m_FixedData.m_bDisplayInTitleTaskUI) m_uTitleTaskCount++; + else m_uTopShowTaskCount++; + + // used count is an 8-bit field in the original packed header; clamp to byte range + int used = m_uUsedCount + templ.m_uDepth; + m_uUsedCount = (byte)Math.Clamp(used, 0, byte.MaxValue); + } } public void ClearTask(TaskInterface pTask, ActiveTaskEntry pEntry, bool bRemoveItem) { @@ -644,5 +636,17 @@ namespace BrewMonster.Scripts.Task { m_uMaxSimultaneousCount = true; } + + // 从列表中移除指定条目(并压缩列表) // English: Remove an entry from the list (and compact) + public void RemoveEntry(ActiveTaskEntry entry) + { + if (entry == null) return; + // Mark as empty + entry.m_ulTemplAddr = 0; + entry.m_ID = 0; + + // Compact list (RealignTask is our compaction implementation) + RealignTask(entry, 0); + } }; } \ No newline at end of file