Merge branch 'implement_task_UI' into feature/task-emote
This commit is contained in:
@@ -754,7 +754,25 @@ namespace BrewMonster.Scripts.Task
|
||||
m_ulDynTasksDataSize = 0;
|
||||
}
|
||||
}
|
||||
// void OnStorageData(TaskInterface* pTask, const void* data);
|
||||
|
||||
// 处理存储任务数据 // Handle storage task data
|
||||
public void OnStorageData(TaskInterface pTask, byte[] data)
|
||||
{
|
||||
// Copy data directly to the storage buffer (equivalent to C++ memcpy operations)
|
||||
// 直接将数据复制到存储缓冲区(等同于C++的memcpy操作)
|
||||
if (pTask is CECTaskInterface cecTask)
|
||||
{
|
||||
cecTask.SetStorageTaskListBuffer(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: read into struct (but won't persist without writing back)
|
||||
// 后备方案:读取到结构体(但不写回则不会持久化)
|
||||
StorageTaskList pLst = pTask.GetStorageTaskList();
|
||||
pLst.ReadByte(data);
|
||||
}
|
||||
}
|
||||
|
||||
// void OnSpecialAward(const special_award* p,TaskInterface* pTask);
|
||||
// void VerifyDynTasksPack(const char* szPath);
|
||||
// const special_award* GetSpecialAward() const { return &m_SpecialAward; }
|
||||
@@ -902,7 +920,9 @@ namespace BrewMonster.Scripts.Task
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header.pack_size != data_size)
|
||||
// Only check pack_size when reading full data, not when header_only is true
|
||||
// When header_only is true, we only read the header, so pack_size will be larger than data_size
|
||||
if (!header_only && header.pack_size != data_size)
|
||||
{
|
||||
// TaskInterface::WriteLog(0, 0, 0, "UnmarshalDynTasks, wrong header");
|
||||
BMLogger.LogError($" [ATaskTemplMan] UnmarshalDynTasks, wrong header: pack_size {header.pack_size} != data_size {data_size}");
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Runtime.InteropServices;
|
||||
using BrewMonster.UI;
|
||||
using CSNetwork;
|
||||
using UnityEngine;
|
||||
using System;
|
||||
|
||||
namespace BrewMonster.Scripts.Task
|
||||
{
|
||||
@@ -1292,8 +1293,7 @@ namespace BrewMonster.Scripts.Task
|
||||
ActiveTaskList pLst = GetActiveTaskList();
|
||||
uint ulCurTime = GetCurTime(); // 当前时间 // current time
|
||||
ATaskTempl pTempl = null;
|
||||
ActiveTaskEntry foundEntry = default;
|
||||
bool hasFoundEntry = false;
|
||||
int foundEntryIndex = -1; // Keep track of entry index like C++ code does
|
||||
|
||||
if (bActiveTask)
|
||||
{
|
||||
@@ -1304,8 +1304,7 @@ namespace BrewMonster.Scripts.Task
|
||||
if (CurEntry.m_ID != ulTaskId || CurEntry.m_ulTemplAddr == 0) continue;
|
||||
|
||||
pTempl = CurEntry.GetTempl();
|
||||
foundEntry = CurEntry;
|
||||
hasFoundEntry = true;
|
||||
foundEntryIndex = i; // Store index to access entry later
|
||||
|
||||
// 检查任务是否可以完成 // Check if task can be completed
|
||||
if (pTempl != null && pTempl.CanFinishTask(this, CurEntry, ulCurTime))
|
||||
@@ -1380,9 +1379,11 @@ namespace BrewMonster.Scripts.Task
|
||||
pInfo.m_MonsterWanted[ulMonsterCount].m_ulMonsterId = mw.m_ulMonsterTemplId;
|
||||
pInfo.m_MonsterWanted[ulMonsterCount].m_ulMonstersToKill = mw.m_ulMonsterNum;
|
||||
|
||||
if (bActiveTask && hasFoundEntry)
|
||||
// Access the entry directly from the list using stored index, like C++ code does
|
||||
if (bActiveTask && foundEntryIndex >= 0)
|
||||
{
|
||||
pInfo.m_MonsterWanted[ulMonsterCount].m_ulMonstersKilled = foundEntry.m_wMonsterNum[j];
|
||||
ActiveTaskEntry CurEntry = pLst.m_TaskEntries[foundEntryIndex];
|
||||
pInfo.m_MonsterWanted[ulMonsterCount].m_ulMonstersKilled = CurEntry.m_wMonsterNum[j];
|
||||
}
|
||||
|
||||
ulMonsterCount++;
|
||||
@@ -1409,9 +1410,11 @@ namespace BrewMonster.Scripts.Task
|
||||
{
|
||||
pInfo.m_PlayerWanted[ulPlayerCount].m_ulPlayersToKill = pw.m_ulPlayerNum;
|
||||
|
||||
if (bActiveTask && hasFoundEntry)
|
||||
// Access the entry directly from the list using stored index, like C++ code does
|
||||
if (bActiveTask && foundEntryIndex >= 0)
|
||||
{
|
||||
pInfo.m_PlayerWanted[ulPlayerCount].m_ulPlayersKilled = foundEntry.m_wMonsterNum[j];
|
||||
ActiveTaskEntry CurEntry = pLst.m_TaskEntries[foundEntryIndex];
|
||||
pInfo.m_PlayerWanted[ulPlayerCount].m_ulPlayersKilled = CurEntry.m_wMonsterNum[j];
|
||||
}
|
||||
|
||||
pInfo.m_PlayerWanted[ulPlayerCount].m_Requirements = pw.m_Requirements;
|
||||
@@ -1564,7 +1567,16 @@ namespace BrewMonster.Scripts.Task
|
||||
public StorageTaskList GetStorageTaskList()
|
||||
{
|
||||
StorageTaskList ret = new StorageTaskList();
|
||||
ret.ReadByte(m_pStorageTaskListBuf);
|
||||
// Initialize arrays before use
|
||||
ret.EnsureInitialized();
|
||||
|
||||
// Check if buffer is initialized before reading
|
||||
if (m_pStorageTaskListBuf != null)
|
||||
{
|
||||
ret.ReadByte(m_pStorageTaskListBuf);
|
||||
}
|
||||
// If buffer is null, return empty/default StorageTaskList
|
||||
// This can happen if Init() hasn't been called yet or failed
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1670,6 +1682,21 @@ namespace BrewMonster.Scripts.Task
|
||||
ret.ReadFromBytes(m_pFinishedListBuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 记录任务完成/失败到已完成列表(用于前置任务/可重复接任务判断)
|
||||
// English: Record task finish/fail into FinishedTaskList (used by prerequisite checks)
|
||||
public void RecordFinishedTask(uint taskId, bool success)
|
||||
{
|
||||
if (m_pFinishedListBuf == null) return;
|
||||
FinishedTaskList lst = new FinishedTaskList();
|
||||
lst.ReadFromBytes(m_pFinishedListBuf);
|
||||
lst.AddOneTask(taskId, success);
|
||||
// Persist back into buffer
|
||||
if (lst.m_Buf != null && lst.m_Buf.Length == m_pFinishedListBuf.Length)
|
||||
{
|
||||
global::System.Buffer.BlockCopy(lst.m_Buf, 0, m_pFinishedListBuf, 0, m_pFinishedListBuf.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public int GetPlayerId()
|
||||
{
|
||||
|
||||
@@ -383,18 +383,15 @@ namespace BrewMonster.Scripts.Task
|
||||
// Handle storage data notification
|
||||
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_STORAGE)
|
||||
{
|
||||
// TODO: StorageTaskList struct not defined; need to define or use alternative
|
||||
// if (sz != Marshal.SizeOf<task_notify_base>() + Marshal.SizeOf<StorageTaskList>()) return;
|
||||
// TODO: OnStorageData method not found in ATaskTemplMan; implement if needed
|
||||
// ATaskTemplMan pMan = GetTaskTemplMan(pTask);
|
||||
// if (pMan != null)
|
||||
// {
|
||||
// byte[] storageData = new byte[Marshal.SizeOf<StorageTaskList>()];
|
||||
// Array.Copy(pBuf, Marshal.SizeOf<task_notify_base>(), storageData, 0, storageData.Length);
|
||||
// pMan.OnStorageData(pTask, storageData);
|
||||
// }
|
||||
// TODO: UpdateTaskUI static method not found; implement UI update if needed
|
||||
// TaskInterface.UpdateTaskUI(pNotify.task, pNotify.reason);
|
||||
if (sz != Marshal.SizeOf<task_notify_base>() + Marshal.SizeOf<StorageTaskList>()) return;
|
||||
ATaskTemplMan pMan = GetTaskTemplMan();
|
||||
if (pMan != null)
|
||||
{
|
||||
byte[] storageData = new byte[Marshal.SizeOf<StorageTaskList>()];
|
||||
Array.Copy(pBuf, Marshal.SizeOf<task_notify_base>(), storageData, 0, storageData.Length);
|
||||
pMan.OnStorageData(pTask, storageData);
|
||||
}
|
||||
pTask.UpdateTaskUI(pNotify.task, pNotify.reason);
|
||||
return;
|
||||
}
|
||||
// Handle special award notification
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
using BrewMonster.Network;
|
||||
using BrewMonster.Scripts.Task;
|
||||
using CSNetwork.GPDataType;
|
||||
@@ -394,6 +395,28 @@ namespace BrewMonster.Scripts.Task
|
||||
}
|
||||
}
|
||||
// bool CanShowInExclusiveUI (TaskInterface* pTask, unsigned long ulCurTime) const;
|
||||
#if !TASK_TEMPL_EDITOR
|
||||
// RecursiveCheckPunchMonster(const ATaskTempl* pTempl)
|
||||
// 递归检查“沙包怪”并弹提示 // English: Recursively check "punch bag" monster and show prompt
|
||||
// NOTE: The original C++ checks monster essence switches (MCS_SUMMONER_ATTACK_ONLY + MCS_RECORD_DPS_RANK)
|
||||
// and calls ShowPunchBagMessage(). The Unity port doesn't currently expose elementdataman/monster essence,
|
||||
// so this is a safe no-op placeholder that preserves call sites and recursion shape.
|
||||
private static void RecursiveCheckPunchMonster(ATaskTempl pTempl)
|
||||
{
|
||||
if (pTempl == null) return;
|
||||
|
||||
// TODO: Port elementdataman lookup + MONSTER_ESSENCE combined_switch checks and call:
|
||||
// pTask.ShowPunchBagMessage(false,false,monsterId,0,0);
|
||||
|
||||
var child = pTempl.m_pFirstChild;
|
||||
while (child != null)
|
||||
{
|
||||
RecursiveCheckPunchMonster(child);
|
||||
child = child.m_pNextSibling;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public void OnServerNotify(
|
||||
TaskInterface pTask,
|
||||
ActiveTaskEntry pEntry,
|
||||
@@ -424,7 +447,7 @@ namespace BrewMonster.Scripts.Task
|
||||
int iIndex = pKilledPlayer.index;
|
||||
if (iIndex < TaskInterfaceConstants.MAX_MONSTER_WANTED)
|
||||
{
|
||||
pEntry.m_wMonsterNum[iIndex] = pKilledPlayer.player_num;
|
||||
pEntry.SetMonsterNum(iIndex, pKilledPlayer.player_num);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -447,7 +470,7 @@ namespace BrewMonster.Scripts.Task
|
||||
|
||||
if (mw.m_ulMonsterTemplId == pKilled.monster_id)
|
||||
{
|
||||
pEntry.m_wMonsterNum[i] = pKilled.monster_num;
|
||||
pEntry.SetMonsterNum((int)i, pKilled.monster_num);
|
||||
|
||||
if (pKilled.dps > 0 && pKilled.dph > 0)
|
||||
{
|
||||
@@ -459,12 +482,60 @@ namespace BrewMonster.Scripts.Task
|
||||
|
||||
break;
|
||||
case TaskTemplConstants.TASK_SVR_NOTIFY_NEW:
|
||||
var svr_new_task = GPDataTypeHelper.FromBytes<svr_new_task>(pBuf);
|
||||
if (svr_new_task.valid_size((int)sz))
|
||||
// Follow C++ logic: valid_size checks the buffer size before deserializing
|
||||
// In C++, pNotify is a pointer to the structure, so valid_size can read sub_tags.sz directly
|
||||
// In C#, we need to read sub_tags.sz from the buffer first, then validate
|
||||
|
||||
// Calculate base size: task_notify_base (3) + cur_time (4) + cap_task (4) = 11
|
||||
int baseSzNew = Marshal.SizeOf<task_notify_base>() + 8;
|
||||
if (sz <= (uint)baseSzNew)
|
||||
{
|
||||
BMLogger.LogError($" [TASK_SVR_NOTIFY_NEW] the size of byte not meet !!!");
|
||||
Debug.Log($" [ATaskTempl] TASK_SVR_NOTIFY_NEW: buffer too small, need more than {baseSzNew} bytes, got {sz}");
|
||||
break;
|
||||
}
|
||||
|
||||
// Read sub_tags.sz from buffer to validate size (matching C++ valid_size logic)
|
||||
// Offset to sub_tags: baseSzNew = 11
|
||||
// sub_tags layout: sub_task/state (2 bytes) + sz (1 byte) = 3 bytes minimum
|
||||
if ((int)sz < baseSzNew + 3)
|
||||
{
|
||||
Debug.Log($" [ATaskTempl] TASK_SVR_NOTIFY_NEW: buffer too small to read sub_tags.sz");
|
||||
break;
|
||||
}
|
||||
|
||||
byte subTagsSzNew = pBuf[baseSzNew + 2]; // Read sz field from sub_tags (after sub_task/state which is 2 bytes)
|
||||
|
||||
// Manually implement valid_size check (matching C++ logic)
|
||||
// C++: return sub_tags.valid_size(sz - base_sz);
|
||||
// sub_tags.valid_size checks: get_size() == _sz, where get_size() = sz + 3
|
||||
int subTagsSize = subTagsSzNew + 3; // get_size() = sz + 3
|
||||
if (subTagsSize != (int)sz - baseSzNew)
|
||||
{
|
||||
Debug.Log($" [TASK_SVR_NOTIFY_NEW] the size of byte not meet !!! expected sub_tags size {subTagsSize}, got {sz - baseSzNew}");
|
||||
break;
|
||||
}
|
||||
|
||||
// Now safe to deserialize - buffer size matches expected size
|
||||
// Marshal.SizeOf returns size with full MAX_SUB_TAGS array, but actual data is smaller
|
||||
int fixedSizeNew = Marshal.SizeOf<svr_new_task>();
|
||||
svr_new_task svr_new_task;
|
||||
|
||||
if (sz < (uint)fixedSizeNew)
|
||||
{
|
||||
// Buffer is smaller than fixed structure size, create padded buffer for safe deserialization
|
||||
byte[] paddedBufNew = new byte[fixedSizeNew];
|
||||
Array.Copy(pBuf, paddedBufNew, (int)sz);
|
||||
// Zero-fill the rest (tags array will be zero-filled, which is safe)
|
||||
|
||||
svr_new_task = GPDataTypeHelper.FromBytes<svr_new_task>(paddedBufNew);
|
||||
// Restore the original sub_tags.sz value since padding might have corrupted it
|
||||
svr_new_task.sub_tags.sz = subTagsSzNew;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Buffer is large enough for fixed structure size
|
||||
svr_new_task = GPDataTypeHelper.FromBytes<svr_new_task>(pBuf);
|
||||
}
|
||||
pLst = pTask.GetActiveTaskList();
|
||||
svr_new_task.get_data(
|
||||
ref ulTime,
|
||||
@@ -472,7 +543,9 @@ namespace BrewMonster.Scripts.Task
|
||||
ref sub_tags
|
||||
);
|
||||
|
||||
GetTaskTemplMan().RemoveActiveStorageTask(pStorage, m_FixedData.m_ID);
|
||||
// NOTE: Disabled for now due to an ambiguous call error being reported by the Unity compiler in this project setup.
|
||||
// TODO: Re-enable once the underlying duplicate/assembly ambiguity is resolved.
|
||||
// GetTaskTemplMan().RemoveActiveStorageTask(pStorage, m_FixedData.m_ID);
|
||||
|
||||
if (sub_tags.sub_task > 0)
|
||||
{
|
||||
@@ -494,7 +567,7 @@ namespace BrewMonster.Scripts.Task
|
||||
pSub,
|
||||
ref sub_tags,
|
||||
new TaskGlobalData(),
|
||||
0);
|
||||
0xFF);
|
||||
|
||||
if (m_FixedData.m_lAvailFrequency != (int)TaskAwardFreq.enumTAFNormal &&
|
||||
!m_FixedData.m_bAccountTaskLimit && !m_FixedData.m_bRoleTaskLimit)
|
||||
@@ -526,8 +599,60 @@ namespace BrewMonster.Scripts.Task
|
||||
|
||||
break;
|
||||
case TaskTemplConstants.TASK_SVR_NOTIFY_COMPLETE:
|
||||
var svr_task_complete = GPDataTypeHelper.FromBytes<svr_task_complete>(pBuf);
|
||||
if (svr_task_complete.valid_size((int)sz)) break;
|
||||
// Follow C++ logic: valid_size checks the buffer size before deserializing
|
||||
// In C++, pNotify is a pointer to the structure, so valid_size can read sub_tags.sz directly
|
||||
// In C#, we need to read sub_tags.sz from the buffer first, then validate
|
||||
|
||||
// Calculate base size: task_notify_base (3) + cur_time (4) = 7
|
||||
int baseSz = Marshal.SizeOf<task_notify_base>() + 4;
|
||||
if (sz <= (uint)baseSz)
|
||||
{
|
||||
Debug.Log($" [ATaskTempl] TASK_SVR_NOTIFY_COMPLETE: buffer too small, need more than {baseSz} bytes, got {sz}");
|
||||
break;
|
||||
}
|
||||
|
||||
// Read sub_tags.sz from buffer to validate size (matching C++ valid_size logic)
|
||||
// Offset to sub_tags: baseSz = 7
|
||||
// sub_tags layout: sub_task/state (2 bytes) + sz (1 byte) = 3 bytes minimum
|
||||
if ((int)sz < baseSz + 3)
|
||||
{
|
||||
Debug.Log($" [ATaskTempl] TASK_SVR_NOTIFY_COMPLETE: buffer too small to read sub_tags.sz");
|
||||
break;
|
||||
}
|
||||
|
||||
byte subTagsSz = pBuf[baseSz + 2]; // Read sz field from sub_tags (after sub_task/state which is 2 bytes)
|
||||
|
||||
// Manually implement valid_size check (matching C++ logic)
|
||||
// C++: return sub_tags.valid_size(sz - base_sz);
|
||||
// sub_tags.valid_size checks: get_size() == _sz, where get_size() = sz + 3
|
||||
int subTagsSizeComplete = subTagsSz + 3; // get_size() = sz + 3
|
||||
if (subTagsSizeComplete != (int)sz - baseSz)
|
||||
{
|
||||
Debug.Log($" [TASK_SVR_NOTIFY_COMPLETE] the size of byte not meet !!! expected sub_tags size {subTagsSizeComplete}, got {sz - baseSz}");
|
||||
break;
|
||||
}
|
||||
|
||||
// Now safe to deserialize - buffer size matches expected size
|
||||
// Marshal.SizeOf returns size with full MAX_SUB_TAGS array, but actual data is smaller
|
||||
int fixedSize = Marshal.SizeOf<svr_task_complete>();
|
||||
svr_task_complete svr_task_complete;
|
||||
|
||||
if (sz < (uint)fixedSize)
|
||||
{
|
||||
// Buffer is smaller than fixed structure size, create padded buffer for safe deserialization
|
||||
byte[] paddedBuf = new byte[fixedSize];
|
||||
Array.Copy(pBuf, paddedBuf, (int)sz);
|
||||
// Zero-fill the rest (tags array will be zero-filled, which is safe)
|
||||
|
||||
svr_task_complete = GPDataTypeHelper.FromBytes<svr_task_complete>(paddedBuf);
|
||||
// Restore the original sub_tags.sz value since padding might have corrupted it
|
||||
svr_task_complete.sub_tags.sz = subTagsSz;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Buffer is large enough for fixed structure size
|
||||
svr_task_complete = GPDataTypeHelper.FromBytes<svr_task_complete>(pBuf);
|
||||
}
|
||||
svr_task_complete.get_data(
|
||||
ref ulTime,
|
||||
ref sub_tags
|
||||
@@ -537,7 +662,7 @@ namespace BrewMonster.Scripts.Task
|
||||
|
||||
if (!pEntry.IsSuccess())
|
||||
{
|
||||
#if TASK_TEMPL_EDITOR
|
||||
#if !TASK_TEMPL_EDITOR
|
||||
RecursiveCheckPunchMonster(this);
|
||||
#endif
|
||||
}
|
||||
@@ -573,7 +698,8 @@ namespace BrewMonster.Scripts.Task
|
||||
break;
|
||||
case TaskTemplConstants.TASK_SVR_NOTIFY_GIVE_UP:
|
||||
pLst = pTask.GetActiveTaskList();
|
||||
pLst.ClearTask(pTask, pEntry, false);
|
||||
// Use simplified removal to keep list consistent in the managed port
|
||||
pLst.RemoveEntry(pEntry);
|
||||
|
||||
// TODO: Log task give up
|
||||
// if (m_bDisplayInTitleTaskUI) TaskInterface::UpdateTitleUI(m_ID);
|
||||
@@ -805,9 +931,9 @@ namespace BrewMonster.Scripts.Task
|
||||
// ����ﵽ����
|
||||
bool bReachLimit = false;
|
||||
if (m_bHidden)
|
||||
bReachLimit = pList.m_uTopHideTaskCount >= TASK_HIDDEN_COUNT;
|
||||
bReachLimit = pList.m_uTopHideTaskCount >= TASK_.TASK_HIDDEN_COUNT;
|
||||
else if (m_bDisplayInTitleTaskUI)
|
||||
bReachLimit = bReachLimit || pList.m_uTitleTaskCount >= TASK_TITLE_TASK_COUNT;
|
||||
bReachLimit = bReachLimit || pList.m_uTitleTaskCount >= TASK_.TASK_TITLE_TASK_COUNT;
|
||||
else
|
||||
bReachLimit = bReachLimit || pList.m_uTopShowTaskCount >= pList.GetMaxSimultaneousCount();
|
||||
|
||||
@@ -1591,8 +1717,54 @@ namespace BrewMonster.Scripts.Task
|
||||
TaskGlobalData pGlobal,
|
||||
byte uParentIndex)
|
||||
{
|
||||
// TODO: implement full logic when ActiveTaskList/ActiveTaskEntry and TaskInterface APIs are available
|
||||
return null;
|
||||
// 最小实现:保证接任务/放弃任务会真实改变 ActiveTaskList,从而驱动任务面板刷新
|
||||
// English: Minimal implementation: make NEW/GIVEUP actually mutate ActiveTaskList so UI can refresh.
|
||||
if (pTask == null || pList == null) return null;
|
||||
|
||||
// Already has task
|
||||
var existed = pList.GetEntry(m_FixedData.m_ID);
|
||||
if (existed != null && existed.m_ID != 0) return existed;
|
||||
|
||||
if (pList.m_uTaskCount >= TaskInterfaceConstants.TASK_ACTIVE_LIST_MAX_LEN) return null;
|
||||
|
||||
int insertIndex = pList.m_uTaskCount;
|
||||
ActiveTaskEntry entry = pEntry ?? new ActiveTaskEntry();
|
||||
|
||||
// Fill fixed data (top-level by default)
|
||||
entry.m_ID = (ushort)m_FixedData.m_ID;
|
||||
entry.m_ulTemplAddr = m_FixedData.m_ID; // non-zero marker; template is resolved by ID in GetTempl()
|
||||
entry.m_ulTaskTime = ulCurTime;
|
||||
|
||||
entry.m_ParentIndex = (char)0xff;
|
||||
entry.m_PrevSblIndex = (char)0xff;
|
||||
entry.m_NextSblIndex = (char)0xff;
|
||||
entry.m_ChildIndex = (char)0xff;
|
||||
|
||||
entry.m_uState = (char)0;
|
||||
entry.SetSuccess(); // default success, may be cleared by later checks
|
||||
|
||||
if (ulCaptainTask != 0)
|
||||
{
|
||||
entry.m_uCapTaskId = (ushort)ulCaptainTask;
|
||||
entry.m_ulCapTemplAddr = ulCaptainTask; // marker only
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.m_uCapTaskId = 0;
|
||||
entry.m_ulCapTemplAddr = 0;
|
||||
}
|
||||
|
||||
// Clear union buffer
|
||||
if (entry.m_BufData != null)
|
||||
Array.Clear(entry.m_BufData, 0, entry.m_BufData.Length);
|
||||
|
||||
// Insert and update list count
|
||||
pList.m_TaskEntries[insertIndex] = entry;
|
||||
pList.m_uTaskCount = (byte)(insertIndex + 1);
|
||||
|
||||
// Recount for UI and budget checks
|
||||
pList.RecountTaskCounters();
|
||||
return entry;
|
||||
|
||||
/*ActiveTaskEntry* aEntries = pList->m_TaskEntries;
|
||||
if (!pEntry) pEntry = aEntries + pList->m_uTaskCount;
|
||||
@@ -1814,6 +1986,29 @@ namespace BrewMonster.Scripts.Task
|
||||
int nChoice,
|
||||
ref task_sub_tags pSubTag)
|
||||
{
|
||||
// 最小实现(客户端):
|
||||
// - 记录到 FinishedTaskList(用于前置任务/可重复接判断)
|
||||
// - 从 ActiveTaskList 移除该任务条目,从而驱动任务面板刷新
|
||||
// English minimal client port:
|
||||
// - Record into FinishedTaskList (prerequisites/redo checks)
|
||||
// - Remove entry from ActiveTaskList to refresh UI lists
|
||||
if (pTask == null || pList == null || pEntry == null) return;
|
||||
|
||||
bool success = pEntry.IsSuccess() && !pEntry.IsGiveUp();
|
||||
|
||||
// Only record on top-level templates (same as C++: !m_pParent && m_bNeedRecord)
|
||||
if (m_pParent == null && m_FixedData.m_bNeedRecord)
|
||||
{
|
||||
if (pTask is CECTaskInterface cec)
|
||||
{
|
||||
cec.RecordFinishedTask(m_FixedData.m_ID, success);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from active list (C++ RecursiveAward clears children + removes current entry)
|
||||
pList.RemoveEntry(pEntry);
|
||||
return;
|
||||
|
||||
// TODO : implement full logic when ActiveTaskList/ActiveTaskEntry and TaskInterface APIs are available
|
||||
/*{
|
||||
char log[1024];
|
||||
|
||||
@@ -100,8 +100,23 @@ namespace BrewMonster.Scripts.Task
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.TASK_STORAGE_COUNT)]
|
||||
public byte[] m_StoragesReceivePerDay;
|
||||
|
||||
// Initialize arrays if they are null
|
||||
// In C++, arrays are automatically allocated on the stack, but in C# they need explicit initialization
|
||||
public void EnsureInitialized()
|
||||
{
|
||||
if (m_Storages == null)
|
||||
m_Storages = new ushort[TaskTemplConstants.TASK_STORAGE_COUNT * TaskTemplConstants.TASK_STORAGE_LEN];
|
||||
if (m_StoragesTaskSetCount == null)
|
||||
m_StoragesTaskSetCount = new ushort[TaskTemplConstants.TASK_STORAGE_COUNT];
|
||||
if (m_StoragesRefreshTime == null)
|
||||
m_StoragesRefreshTime = new uint[TaskTemplConstants.TASK_STORAGE_COUNT];
|
||||
if (m_StoragesReceivePerDay == null)
|
||||
m_StoragesReceivePerDay = new byte[TaskTemplConstants.TASK_STORAGE_COUNT];
|
||||
}
|
||||
|
||||
public void RemoveAll()
|
||||
{
|
||||
EnsureInitialized();
|
||||
for (int i = 0; i < TaskTemplConstants.TASK_STORAGE_COUNT; i++)
|
||||
{
|
||||
for (int j = 0; j < TaskTemplConstants.TASK_STORAGE_LEN; j++)
|
||||
@@ -117,6 +132,11 @@ namespace BrewMonster.Scripts.Task
|
||||
|
||||
public void ReadByte(byte[] data)
|
||||
{
|
||||
if (data == null)
|
||||
return;
|
||||
|
||||
EnsureInitialized();
|
||||
|
||||
int offset = 0;
|
||||
for (int i=0; i < TaskTemplConstants.TASK_STORAGE_COUNT; i++)
|
||||
{
|
||||
@@ -436,8 +456,58 @@ namespace BrewMonster.Scripts.Task
|
||||
|
||||
public void AddOneTask(uint ulID, bool bSuccess)
|
||||
{
|
||||
// TODO: Implement logic to add one task (for future use)
|
||||
//throw new NotImplementedException();
|
||||
// 将任务写入已完成列表(按任务ID有序) // English: Insert/update into finished list (sorted by task id)
|
||||
if (m_Buf == null || m_Buf.Length != TaskInterfaceConstants.TASK_FINISHED_LIST_BUF_SIZE)
|
||||
{
|
||||
m_Buf = new byte[TaskInterfaceConstants.TASK_FINISHED_LIST_BUF_SIZE];
|
||||
}
|
||||
|
||||
var header = m_FnshHeader;
|
||||
ushort count = header.m_uTaskCount;
|
||||
if (count >= TaskInterfaceConstants.TASK_FINISHED_LIST_MAX_LEN) return;
|
||||
|
||||
int entrySize = Marshal.SizeOf<FnshedTaskEntry>(); // should be 4
|
||||
int pos = GetTaskPos(ulID);
|
||||
|
||||
byte mask = (byte)(bSuccess ? 0 : 1);
|
||||
|
||||
if (pos >= 0)
|
||||
{
|
||||
// Update existing entry
|
||||
int start = 4 + pos * entrySize;
|
||||
// m_uTaskId
|
||||
Array.Copy(BitConverter.GetBytes((ushort)ulID), 0, m_Buf, start, 2);
|
||||
// m_Buf (mask + reserved bits)
|
||||
m_Buf[start + 2] = (byte)((m_Buf[start + 2] & 0xFE) | (mask & 0x1));
|
||||
// m_FnshedCount: keep at least 1
|
||||
if (m_Buf[start + 3] == 0) m_Buf[start + 3] = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Find insertion index to keep sorted order
|
||||
int insert = 0;
|
||||
for (; insert < count; insert++)
|
||||
{
|
||||
ushort existingId = BitConverter.ToUInt16(m_Buf, 4 + insert * entrySize);
|
||||
if (ulID < existingId) break;
|
||||
}
|
||||
|
||||
// Shift bytes to make room
|
||||
int srcStart = 4 + insert * entrySize;
|
||||
int bytesToMove = (count - insert) * entrySize;
|
||||
if (bytesToMove > 0)
|
||||
{
|
||||
Buffer.BlockCopy(m_Buf, srcStart, m_Buf, srcStart + entrySize, bytesToMove);
|
||||
}
|
||||
|
||||
// Write new entry
|
||||
int dst = 4 + insert * entrySize;
|
||||
Array.Copy(BitConverter.GetBytes((ushort)ulID), 0, m_Buf, dst, 2);
|
||||
m_Buf[dst + 2] = (byte)(mask & 0x1); // reserved bits 0
|
||||
m_Buf[dst + 3] = 1; // finish count
|
||||
|
||||
header.m_uTaskCount = (ushort)(count + 1);
|
||||
m_FnshHeader = header;
|
||||
}
|
||||
|
||||
public void RemoveTask(uint ulID)
|
||||
@@ -461,22 +531,34 @@ namespace BrewMonster.Scripts.Task
|
||||
|
||||
public byte SearchTaskFinishCount(ulong ulID)
|
||||
{
|
||||
// TODO: Implement logic to search task finish count
|
||||
//throw new NotImplementedException();
|
||||
|
||||
return 0;
|
||||
int pos = GetTaskPos((uint)ulID);
|
||||
if (pos < 0) return 0;
|
||||
int entrySize = Marshal.SizeOf<FnshedTaskEntry>();
|
||||
int start = 4 + pos * entrySize;
|
||||
return m_Buf[start + 3]; // m_FnshedCount
|
||||
}
|
||||
|
||||
public void ResetFinishCount(ulong ulID)
|
||||
{
|
||||
// TODO: Implement logic to reset finish count
|
||||
//throw new NotImplementedException();
|
||||
int pos = GetTaskPos((uint)ulID);
|
||||
if (pos < 0) return;
|
||||
int entrySize = Marshal.SizeOf<FnshedTaskEntry>();
|
||||
int start = 4 + pos * entrySize;
|
||||
m_Buf[start + 3] = 0;
|
||||
}
|
||||
|
||||
public void AddForFinishCount(ulong ulID, bool bSuccess)
|
||||
{
|
||||
// TODO: Implement logic to add for finish count
|
||||
//throw new NotImplementedException();
|
||||
// 只用于计数:如果不存在则插入;如果存在则递增 m_FnshedCount
|
||||
// English: Finish-count bookkeeping: insert if missing; otherwise increment m_FnshedCount.
|
||||
AddOneTask((uint)ulID, bSuccess);
|
||||
|
||||
int pos = GetTaskPos((uint)ulID);
|
||||
if (pos < 0) return;
|
||||
int entrySize = Marshal.SizeOf<FnshedTaskEntry>();
|
||||
int start = 4 + pos * entrySize;
|
||||
byte cur = m_Buf[start + 3];
|
||||
if (cur < byte.MaxValue) m_Buf[start + 3] = (byte)(cur + 1);
|
||||
}
|
||||
|
||||
public void RemoveAll()
|
||||
|
||||
@@ -404,10 +404,12 @@ namespace BrewMonster.Scripts.Task.UI
|
||||
// void RefreshTaskTrace();
|
||||
public bool UpdateTask(int idTask = -1)
|
||||
{
|
||||
// if( m_szName != "Win_Quest" || m_iType != 0)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// Only rebuild the list if viewing "Have Quest" (m_iType == 0)
|
||||
// But always allow updating specific task details regardless of view type
|
||||
if (idTask < 0 && m_iType != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// ATaskTemplMan *pMan = GetGame()->GetTaskTemplateMan();
|
||||
ATaskTemplMan pMan = EC_Game.GetTaskTemplateMan();
|
||||
@@ -440,6 +442,7 @@ namespace BrewMonster.Scripts.Task.UI
|
||||
ATaskTempl pTemp = pMan.GetTaskTemplByID((uint)idTask);
|
||||
if (pTemp != null)
|
||||
{
|
||||
// Only update description and name if task changed
|
||||
if( idTask != m_idLastTask )
|
||||
{
|
||||
_nameTaskText.SetText(EC_Utility.FormatForTextMeshPro(GetTaskNameWithColor(pTemp)));
|
||||
@@ -452,9 +455,11 @@ namespace BrewMonster.Scripts.Task.UI
|
||||
|
||||
m_pBtn_Abandon.interactable = pMan.CanGiveUpTask((uint)idTask);
|
||||
|
||||
// Get info
|
||||
// Always refresh task state info to get latest progress data
|
||||
// This ensures real-time updates when task progress changes
|
||||
// When viewing "Have Quest" (m_iType == 0), tasks are active, so pass true to read kill counts
|
||||
Task_State_info tsi = new Task_State_info();
|
||||
pTask.GetTaskStateInfo((uint)idTask, ref tsi, false);
|
||||
pTask.GetTaskStateInfo((uint)idTask, ref tsi, m_iType == 0);
|
||||
|
||||
// Clear first
|
||||
strNewTextItem = "";
|
||||
@@ -466,19 +471,19 @@ namespace BrewMonster.Scripts.Task.UI
|
||||
int nANPC = (int)pTemp.GetAwardNPC();
|
||||
UpdateAwardNPC(ref strNewTextItem, nANPC);
|
||||
|
||||
// Complete condition
|
||||
// Complete condition - always refresh to show updated progress
|
||||
UpdateCompleteCondition(ref strNewTextItem, ref strNewHintItem, tsi);
|
||||
|
||||
// Wanted Item
|
||||
// Wanted Item - always refresh to show updated item counts
|
||||
UpdateItemWanted(ref strNewTextItem, tsi, idTask);
|
||||
|
||||
// Treasure Map
|
||||
UpdateTreasureMap(ref strNewTextItem);
|
||||
|
||||
// Task Confirm
|
||||
// Task Confirm - always refresh to update button state
|
||||
UpdateTaskConfirm(idTask, pTemp.m_FixedData.m_enumFinishType == (uint)TaskFinishType.enumTFTConfirm);
|
||||
|
||||
// Award
|
||||
// Award - always refresh to show updated award preview
|
||||
Task_Award_Preview award = default;
|
||||
pTask.GetTaskAwardPreview((uint)idTask, ref award);
|
||||
|
||||
@@ -526,6 +531,8 @@ namespace BrewMonster.Scripts.Task.UI
|
||||
// Guard: only handle search list when current UI type is 1 (search)
|
||||
public bool SearchForTask(int idTask = -1)
|
||||
{
|
||||
// Only process search list when in search view (m_iType == 1)
|
||||
// This prevents clearing the wrong list when updating
|
||||
if (m_iType != 1)
|
||||
{
|
||||
return true;
|
||||
@@ -647,10 +654,49 @@ namespace BrewMonster.Scripts.Task.UI
|
||||
return true;
|
||||
}
|
||||
//
|
||||
// //�������������б��������ɽ�������ѽ����� zhangyitian
|
||||
// //�������������б��������ɽ�������ѽ�������ѽ����� zhangyitian
|
||||
// When task updates, the available task list also needs to be updated, otherwise the available task list won't update
|
||||
public bool UpdateQuestView()
|
||||
{
|
||||
return UpdateTask() && SearchForTask();
|
||||
// Refresh the list for the current view type
|
||||
// This ensures that when tasks are taken/completed/abandoned, the visible list is updated
|
||||
bool result = true;
|
||||
|
||||
if (m_iType == 0)
|
||||
{
|
||||
// Refresh "Have Quest" list (taken tasks)
|
||||
result = UpdateTask(-1);
|
||||
}
|
||||
else if (m_iType == 1)
|
||||
{
|
||||
// Refresh "Search Quest" list (available tasks)
|
||||
result = SearchForTask(-1);
|
||||
}
|
||||
|
||||
// Refresh the currently selected task details if one is selected
|
||||
// This ensures task progress updates are reflected in real-time
|
||||
var pTree = m_pTv_Quest;
|
||||
var pItem = pTree?.GetSelectedItem();
|
||||
|
||||
if (pItem != null && pTree.transform != pItem.transform.parent)
|
||||
{
|
||||
uint selectedTaskId = pTree.GetItemData(pItem);
|
||||
if (selectedTaskId > 0)
|
||||
{
|
||||
if (m_iType == 0)
|
||||
{
|
||||
// Refresh the selected task's details to show updated progress
|
||||
UpdateTask((int)selectedTaskId);
|
||||
}
|
||||
else if (m_iType == 1)
|
||||
{
|
||||
// For search view, refresh the selected task
|
||||
SearchForTask((int)selectedTaskId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// bool IsPQTaskOrSubTask(int idTask);
|
||||
|
||||
Reference in New Issue
Block a user