Files
test/Assets/PerfectWorld/Scripts/Task/TaskProcess.cs
T

544 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Runtime.InteropServices;
using BrewMonster.Scripts.Task;
using UnityEngine;
namespace BrewMonster.Scripts.Task
{
public class TaskProcess
{
}
[Flags]
public enum TaskState : byte
{
TASK_STATE_FINISHED = 0x01, // Is finished
TASK_STATE_SUCCESS = 0x02, // Is successful
TASK_STATE_GIVEUP = 0x04, // Is given up
TASK_STATE_ERR_REPORTED = 0x08, // Error has been reported to client
TASK_STATE_AWARD_NOTIFY_TEAM = 0x10, // Award has been notified to team
TASK_STATE_CONTRIBUTION_FINISH = 0x20 // Contribution finished
}
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
// Cur Size 21 bytes
public class TASK_ENTRY_FIXED_DATA
{
public ushort m_ID; // ID
public char m_ParentIndex; // Parent node index
public char m_PrevSblIndex; // Previous sibling node index
public char m_NextSblIndex; // Next sibling node index
public char m_ChildIndex; // Child node index
public char m_uState; // Task state
public uint m_ulTaskTime; // Timestamp
public ushort m_uCapTaskId; // Captain task ID
public uint m_ulTemplAddr; // Template address -> In C++ this is a pointer, here we use uint to store the ID of the template
public uint m_ulCapTemplAddr; // Captain task template address
};
// ´óСΪTASK_DATA_BUF_MAX_LEN
public class ActiveTaskEntry : TASK_ENTRY_FIXED_DATA
{
// Buffer union simplified (C# does not support union directly)
// 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
{
get
{
ushort[] monsterNums = new ushort[TaskInterfaceConstants.MAX_MONSTER_WANTED];
for (int i = 0; i < TaskInterfaceConstants.MAX_MONSTER_WANTED; i++)
{
monsterNums[i] = BitConverter.ToUInt16(m_BufData, i * 2);
}
return monsterNums;
}
set
{
for (int i = 0; i < TaskInterfaceConstants.MAX_MONSTER_WANTED; i++)
{
byte[] bytes = BitConverter.GetBytes(value[i]);
m_BufData[i * 2] = bytes[0];
m_BufData[i * 2 + 1] = bytes[1];
}
}
}
public int m_iUsefulData1
{
get => BitConverter.ToInt32(m_BufData, TaskInterfaceConstants.MAX_MONSTER_WANTED * 2);
set
{
byte[] bytes = BitConverter.GetBytes(value);
Array.Copy(bytes, 0, m_BufData, TaskInterfaceConstants.MAX_MONSTER_WANTED * 2, 4);
}
}
public byte m_iUsefulData2 // char in C++, but using byte here for simplicity
{
get => m_BufData[TaskInterfaceConstants.MAX_MONSTER_WANTED * 2 + 4];
set => m_BufData[TaskInterfaceConstants.MAX_MONSTER_WANTED * 2 + 4] = value;
}
public void ReadFromBuffer(byte[] buffer, ref int offset)
{
m_ID = BitConverter.ToUInt16(buffer, offset);
offset += 2;
m_ParentIndex = (char)buffer[offset++];
m_PrevSblIndex = (char)buffer[offset++];
m_NextSblIndex = (char)buffer[offset++];
m_ChildIndex = (char)buffer[offset++];
m_uState = (char)buffer[offset++];
m_ulTaskTime = BitConverter.ToUInt32(buffer, offset);
offset += 4;
m_uCapTaskId = BitConverter.ToUInt16(buffer, offset);
offset += 2;
m_ulTemplAddr = BitConverter.ToUInt32(buffer, offset);
offset += 4;
m_ulCapTemplAddr = BitConverter.ToUInt32(buffer, offset);
offset += 4;
// int localOffset = offset; // store current offset for reading additional fields from union
// Read remaining buffer data
Array.Copy(buffer, offset, m_BufData, 0, m_BufData.Length);
offset += m_BufData.Length; // in C++ have union, so we dont plus offset here
// // Additional fields can be read here as needed
// m_wMonsterNum = new ushort[TaskInterfaceConstants.MAX_MONSTER_WANTED];
// for (int i = 0; i < TaskInterfaceConstants.MAX_MONSTER_WANTED; i++)
// {
// m_wMonsterNum[i] = BitConverter.ToUInt16(buffer, localOffset);
// localOffset += 2; // in C++ have union, so we dont plus offset here
// }
//
// m_iUsefulData1 = BitConverter.ToInt32(buffer, localOffset);
// localOffset += 4; // in C++ have union, so we dont plus offset here
//
// m_iUsefulData2 = buffer[localOffset++]; // in C++ have union, so we dont plus offset here
}
// bool IsFinished() const { return (m_uState & TASK_STATE_FINISHED) != 0; }
// bool IsErrReported() const { return (m_uState & TASK_STATE_ERR_REPORTED) != 0; }
// bool IsAwardNotifyTeam() const { return (m_uState & TASK_STATE_AWARD_NOTIFY_TEAM) != 0; }
// bool IsContributionFinish() const { return (m_uState & TASK_STATE_CONTRIBUTION_FINISH) != 0; }
// --- State check methods ---
public bool IsFinished() => (m_uState & (byte)TaskState.TASK_STATE_FINISHED) != 0;
public bool IsSuccess() => (m_uState & (byte)TaskState.TASK_STATE_SUCCESS) != 0;
public bool IsGiveUp() => (m_uState & (byte)TaskState.TASK_STATE_GIVEUP) != 0;
public bool IsErrReported() => (m_uState & (byte)TaskState.TASK_STATE_ERR_REPORTED) != 0;
public bool IsAwardNotifyTeam() => (m_uState & (byte)TaskState.TASK_STATE_AWARD_NOTIFY_TEAM) != 0;
public bool IsContributionFinish() => (m_uState & (byte)TaskState.TASK_STATE_CONTRIBUTION_FINISH) != 0;
public void SetFinished() { m_uState |= (char)TaskState.TASK_STATE_FINISHED; }
// void ClearFinished() { m_uState &= ~TASK_STATE_FINISHED; }
// void SetSuccess() { m_uState |= TASK_STATE_SUCCESS; }
public void ClearSuccess() { m_uState &= (char)~TaskState.TASK_STATE_SUCCESS; }
public void SetGiveUp() { m_uState |= (char)TaskState.TASK_STATE_GIVEUP; }
// void ClearGiveUp() { m_uState &= ~TASK_STATE_GIVEUP; }
// void SetErrReported() { m_uState |= TASK_STATE_ERR_REPORTED; }
// void ClearErrReported() { m_uState &= ~TASK_STATE_ERR_REPORTED; }
// void SetAwardNotifyTeam() { m_uState |= TASK_STATE_AWARD_NOTIFY_TEAM; }
// void ClearAwardNotifyTeam() { m_uState &= ~TASK_STATE_AWARD_NOTIFY_TEAM; }
// void SetContributionFinish() { m_uState |= TASK_STATE_CONTRIBUTION_FINISH; }
// void ClearContributionFinish() { m_uState &= ~TASK_STATE_CONTRIBUTION_FINISH; }
//
public ATaskTempl GetTempl()
{
// Managed fallback: resolve via template manager by ID
try
{
var man = BrewMonster.Network.EC_Game.GetTaskTemplateMan();
if (man != null)
{
var templ = man.GetTaskTemplByID(m_ID);
if (templ != null) return templ;
}
}
catch { }
// Legacy pointer path (likely unused in managed port)
if (m_ulTemplAddr != 0)
{
try
{
return Marshal.PtrToStructure<ATaskTempl>(new IntPtr(unchecked((long)m_ulTemplAddr)));
}
catch { }
}
return null;
}
// const ATaskTempl* GetCap() const { return reinterpret_cast<const ATaskTempl*>(m_ulCapTemplAddr); }
// const ATaskTempl* GetCapOrSelf() const
// {
// if (m_ulCapTemplAddr) return GetCap();
// else return GetTempl();
// }
// bool HasParent() const { return m_ParentIndex != 0xff; }
// bool HasChildren() const { return m_ChildIndex != 0xff; }
public bool IsValid(char uIndex, char uMaxCount)
{
if (m_ParentIndex != 0xff)
{
if (m_ParentIndex >= uIndex || m_ParentIndex >= uMaxCount)
return false;
}
if (m_PrevSblIndex != 0xff)
{
if (m_PrevSblIndex >= uIndex || m_PrevSblIndex >= uMaxCount)
return false;
}
if (m_NextSblIndex != 0xff)
{
if (m_NextSblIndex <= uIndex || m_NextSblIndex >= uMaxCount)
return false;
}
if (m_ChildIndex != 0xff)
{
if (m_ChildIndex <= uIndex || m_ChildIndex >= uMaxCount)
return false;
}
return true;
}
};
public class ActiveTaskList
{
// --- Header Fields ---
// NOTE: union
public byte[] header = new byte[TaskInterfaceConstants.TASK_ACTIVE_LIST_HEADER_LEN];
public byte m_uTaskCount // number of tasks
{
get => header[0];
set => header[0] = value;
}
public byte m_uUsedCount // used count
{
get => header[1];
set => header[1] = value;
}
public ushort m_Version // version
{
get => BitConverter.ToUInt16(header, 2);
set
{
byte[] bytes = BitConverter.GetBytes(value);
header[2] = bytes[0];
header[3] = bytes[1];
}
}
public byte m_uTopShowTaskCount // top show task count
{
get => header[4];
set => header[4] = value;
}
public byte m_uListState // list state
{
get => header[5];
set => header[5] = value;
}
public byte m_uTopHideTaskCount // top hide task count
{
get => header[6];
set => header[6] = value;
}
private byte _flags // simulate bitfield (1 bit + 7 bits)
{
get => header[7];
set => header[7] = value;
}
public bool m_uMaxSimultaneousCount
{
get => (_flags & 0x01) != 0;
set
{
if (value) _flags |= 0x01;
else _flags &= unchecked((byte)~0x01);
}
}
public byte m_uTitleTaskCount
{
get => (byte)((_flags & 0xFE) >> 1);
set => _flags = (byte)((_flags & 0x01) | ((value & 0x7F) << 1));
}
// ActiveTaskEntry m_TaskEntries[TASK_ACTIVE_LIST_MAX_LEN];
public ActiveTaskEntry[] m_TaskEntries = new ActiveTaskEntry[TaskInterfaceConstants.TASK_ACTIVE_LIST_MAX_LEN];
// --- Methods ---
public void ReadFromBuffer(byte[] buffer)
{
// NOTE: union
// cause C++ use union here, header use same data slot with the rest of properties like m_uTaskCount etc.
// so, we dont need to read other properties again, just copy the header part
int offset = 0;
Array.Copy(buffer, offset, header, 0, header.Length);
offset += header.Length;
// m_uTaskCount = buffer[offset++];
// m_uUsedCount = buffer[offset++];
// m_Version = BitConverter.ToUInt16(buffer, offset);
// offset += 2;
// m_uTopShowTaskCount = buffer[offset++];
// m_uListState = buffer[offset++];
// m_uTopHideTaskCount = buffer[offset++];
// _flags = buffer[offset++];
for (int i = 0; i < m_uTaskCount; i++)
{
ActiveTaskEntry entry = new ActiveTaskEntry();
entry.ReadFromBuffer(buffer, ref offset);
m_TaskEntries[i] = entry;
}
}
// void UpdateTaskMask(unsigned long& ulMask) const;
public void UpdateUsedCount()
{
m_uUsedCount = 0;
for (int i = 0; i < m_uTaskCount; i++)
{
ATaskTempl pTempl = m_TaskEntries[i].GetTempl();
if (pTempl == null) continue;
if (pTempl.m_pParent != null) continue;
m_uUsedCount += pTempl.m_uDepth;
}
}
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);
//
// 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;
// }
}
public void ClearTask(TaskInterface pTask, ActiveTaskEntry pEntry, bool bRemoveItem)
{
RecursiveClearTask(pTask, pEntry, bRemoveItem, true, true);
RealignTask(pEntry, 0);
}
void RecursiveClearTask(
TaskInterface pTask,
ActiveTaskEntry pEntry,
bool bRemoveItem,
bool bRemoveAcquired,
bool bClearTask)
{
while (pEntry.m_ChildIndex != 0xff)
{
RecursiveClearTask(
pTask,
m_TaskEntries[pEntry.m_ChildIndex],
bRemoveItem,
bRemoveAcquired,
bClearTask);
}
ATaskTempl pTempl = pEntry.GetTempl();
// ȥõƷ
#if !_TASK_CLIENT
if (bRemoveItem && pTempl != null)
{
if (bRemoveAcquired || pTempl.m_FixedData.m_bClearAcquired) pTempl.RemoveAcquiredItem(pTask, bClearTask, false);
pTempl.TakeAwayGivenItems(pTask);
}
#endif
ushort uTaskId = pEntry.m_ID;
pEntry.m_ulTemplAddr = 0;
pEntry.m_ID = 0;
if (m_uTaskCount > 0)
m_uTaskCount--;
else
// TaskInterface::WriteLog(pTask->GetPlayerId(), uTaskId, 0, "ClearTask, TaskCount == 0");
if (pEntry.m_ParentIndex != 0xff)
{
if (pEntry.m_PrevSblIndex != 0xff)
m_TaskEntries[pEntry.m_PrevSblIndex].m_NextSblIndex = pEntry.m_NextSblIndex;
else
m_TaskEntries[pEntry.m_ParentIndex].m_ChildIndex = pEntry.m_NextSblIndex;
if (pEntry.m_NextSblIndex != 0xff) m_TaskEntries[pEntry.m_NextSblIndex].m_PrevSblIndex = pEntry.m_PrevSblIndex;
}
else
{
if (pTempl != null)
{
if (pTempl.m_FixedData.m_bHidden)
{
if (m_uTopHideTaskCount > 0)
m_uTopHideTaskCount--;
}
else if(pTempl.m_FixedData.m_bDisplayInTitleTaskUI)
{
if (m_uTitleTaskCount > 0)
m_uTitleTaskCount--;
}
else
{
if (m_uTopShowTaskCount > 0)
m_uTopShowTaskCount--;
}
if (m_uUsedCount >= pTempl.m_uDepth)
m_uUsedCount -= pTempl.m_uDepth;
else
{
// TaskInterface::WriteLog(pTask->GetPlayerId(), uTaskId, 0, "ClearTask, No Enough Used Count");
m_uUsedCount = 0;
}
}
}
}
public ActiveTaskEntry GetEntry(uint ulId)
{
for (int i = 0; i < m_uTaskCount; i++)
if (m_TaskEntries[i].m_ID == ulId)
return m_TaskEntries[i];
return null;
}
// void ClearChildrenOf(TaskInterface* pTask, ActiveTaskEntry* pParent, bool bRemoveItem = true);
// ActiveTaskEntry* GetEntry(unsigned long ulId)
// {
// for (unsigned char i = 0; i < m_uTaskCount; i++)
// if (m_TaskEntries[i].m_ID == ulId)
// return &m_TaskEntries[i];
//
// return NULL;
// }
public void RemoveAll()
{
ushort version = m_Version; // Preserve the version
Array.Clear(header, 0, header.Length); // Clear the header array
m_Version = version; // Restore the version
m_uTaskCount = 0; // Reset task count
m_uUsedCount = 0; // Reset used count
m_uTopShowTaskCount = 0; // Reset top show task count
m_uTopHideTaskCount = 0; // Reset top hide task count
m_uTitleTaskCount = 0; // Reset title task count
for (int i = 0; i < m_TaskEntries.Length; i++) // Clear all task entries
{
m_TaskEntries[i] = null;
}
}
public bool IsValid() { return m_uTaskCount <= TaskInterfaceConstants.TASK_ACTIVE_LIST_MAX_LEN; }
// bool IsTimeMarkUpdate() const { return (m_uListState & TLIST_STATE_UPDATE_TIME_MARK) != 0; }
// void SetTimeMarkUpdate() { m_uListState |= TLIST_STATE_UPDATE_TIME_MARK; }
// void ClearTimeMarkUpdate() { m_uListState &= ~TLIST_STATE_UPDATE_TIME_MARK; }
public int GetMaxSimultaneousCount() {return m_uMaxSimultaneousCount ? TaskTemplConstants.TASK_MAX_SIMULTANEOUS_COUT : TaskTemplConstants.TASK_DEFAULT_MAX_SIMULTANEOUS_COUT;}
public void ExpandMaxSimultaneousCount()
{
m_uMaxSimultaneousCount = true;
}
};
}