Implement RealignTask logic and update monster killed count real timre

This commit is contained in:
HungDK
2025-12-16 10:45:25 +07:00
parent 8822775d6a
commit f647e578ad
+98 -94
View File
@@ -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<TASK_ENTRY_FIXED_DATA>() ]; // 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<unsigned char>(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<unsigned char>(pInsert - pSrc);
// unsigned long i = 0;
//
// for (; i < static_cast<unsigned long>(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);
}
};
}