464 lines
13 KiB
C#
464 lines
13 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using CSNetwork.GPDataType;
|
|
|
|
namespace BrewMonster.Scripts.Task
|
|
{
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
public struct task_sub_tags
|
|
{
|
|
// private const int MAX_SUB_TAGS = 32;
|
|
|
|
// union
|
|
// {
|
|
// unsigned short sub_task;
|
|
// unsigned char state;
|
|
// };
|
|
// IMPORTANT: union
|
|
public ushort sub_task;
|
|
|
|
public byte state
|
|
{
|
|
get { return (byte)(sub_task & 0xFF); }
|
|
set { sub_task = (ushort)((sub_task & 0xFF00) | value); }
|
|
}
|
|
|
|
public byte sz;
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_SUB_TAGS)]
|
|
public byte[] tags;
|
|
public byte cur_index; // for temporary use, dont take into account
|
|
|
|
public int get_size() { return sz + 3; }
|
|
public bool valid_size(int _sz)
|
|
{
|
|
if (_sz < 3) return false;
|
|
return get_size() == _sz;
|
|
}
|
|
};
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
public struct task_notify_base
|
|
{
|
|
public byte reason;
|
|
public ushort task;
|
|
};
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
public struct svr_monster_killed
|
|
{
|
|
public task_notify_base baseObj;
|
|
public uint monster_id;
|
|
public ushort monster_num;
|
|
public int dps;
|
|
public int dph;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
public struct svr_player_killed
|
|
{
|
|
public task_notify_base baseObj;
|
|
public ushort index;
|
|
public ushort player_num;
|
|
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
public struct svr_task_err_code
|
|
{
|
|
public task_notify_base baseObj;
|
|
public uint err_code;
|
|
|
|
};
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
public struct StorageTaskList
|
|
{
|
|
// unsigned short m_Storages[TASK_STORAGE_COUNT][TASK_STORAGE_LEN];
|
|
// NOTE: 2D array flattened
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.TASK_STORAGE_COUNT * TaskTemplConstants.TASK_STORAGE_LEN)]
|
|
public ushort[] m_Storages;
|
|
|
|
// union {
|
|
// unsigned short m_StoragesTaskSetCount[TASK_STORAGE_COUNT];
|
|
// unsigned short m_StoragesRefreshCount[TASK_STORAGE_COUNT];
|
|
// };
|
|
// NOTE: union
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.TASK_STORAGE_COUNT)]
|
|
public ushort[] m_StoragesTaskSetCount;
|
|
|
|
// [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.TASK_STORAGE_COUNT)]
|
|
public ushort[] m_StoragesRefreshCount
|
|
{
|
|
get => m_StoragesTaskSetCount;
|
|
set { m_StoragesTaskSetCount = value; }
|
|
}
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.TASK_STORAGE_COUNT)]
|
|
public uint[] m_StoragesRefreshTime;
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.TASK_STORAGE_COUNT)]
|
|
public byte[] m_StoragesReceivePerDay;
|
|
|
|
public void RemoveAll()
|
|
{
|
|
for (int i = 0; i < TaskTemplConstants.TASK_STORAGE_COUNT; i++)
|
|
{
|
|
for (int j = 0; j < TaskTemplConstants.TASK_STORAGE_LEN; j++)
|
|
{
|
|
m_Storages[i * TaskTemplConstants.TASK_STORAGE_LEN + j] = 0;
|
|
}
|
|
m_StoragesTaskSetCount[i] = 0;
|
|
m_StoragesRefreshCount[i] = 0;
|
|
m_StoragesRefreshTime[i] = 0;
|
|
m_StoragesReceivePerDay[i] = 0;
|
|
}
|
|
}
|
|
|
|
public void ReadByte(byte[] data)
|
|
{
|
|
int offset = 0;
|
|
for (int i=0; i < TaskTemplConstants.TASK_STORAGE_COUNT; i++)
|
|
{
|
|
for (int j=0; j < TaskTemplConstants.TASK_STORAGE_LEN; j++)
|
|
{
|
|
m_Storages[i * TaskTemplConstants.TASK_STORAGE_LEN + j] = BitConverter.ToUInt16(data, (i * TaskTemplConstants.TASK_STORAGE_LEN + j) * 2);
|
|
}
|
|
}
|
|
|
|
offset += TaskTemplConstants.TASK_STORAGE_COUNT * TaskTemplConstants.TASK_STORAGE_LEN * 2;
|
|
|
|
// union
|
|
for (int i=0; i < TaskTemplConstants.TASK_STORAGE_COUNT; i++)
|
|
{
|
|
m_StoragesTaskSetCount[i] = BitConverter.ToUInt16(data, offset + i * 2);
|
|
// m_StoragesRefreshCount[i] = BitConverter.ToUInt16(data, offset + i * 2);
|
|
}
|
|
offset += TaskTemplConstants.TASK_STORAGE_COUNT * 2;
|
|
|
|
for (int i=0; i < TaskTemplConstants.TASK_STORAGE_COUNT; i++)
|
|
{
|
|
m_StoragesRefreshTime[i] = BitConverter.ToUInt32(data, offset + i * 4);
|
|
}
|
|
offset += TaskTemplConstants.TASK_STORAGE_COUNT * 4;
|
|
|
|
for (int i=0; i < TaskTemplConstants.TASK_STORAGE_COUNT; i++)
|
|
{
|
|
m_StoragesReceivePerDay[i] = data[offset + i];
|
|
}
|
|
}
|
|
}
|
|
|
|
[ StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
public struct svr_new_task
|
|
{
|
|
public task_notify_base baseObj;
|
|
public uint cur_time;
|
|
public uint cap_task; // In C++ use to store ActiveTaskEntry pointer's address -> In C#, we just store the task ID
|
|
public task_sub_tags sub_tags;
|
|
|
|
// public ActiveTaskEntry cap_task_entry; //
|
|
|
|
public void set_data(
|
|
uint _cur_time,
|
|
uint _cap_task,
|
|
task_sub_tags _sub_tags)
|
|
{
|
|
cur_time = _cur_time;
|
|
cap_task = _cap_task;
|
|
// memcpy(&sub_tags, &_sub_tags, _sub_tags.get_size());
|
|
sub_tags = _sub_tags;
|
|
}
|
|
|
|
public void get_data(
|
|
ref uint _cur_time,
|
|
ref uint _cap_task,
|
|
ref task_sub_tags _sub_tags)
|
|
{
|
|
_cur_time = cur_time;
|
|
_cap_task = cap_task;
|
|
// memcpy(&_sub_tags, &sub_tags, sub_tags.get_size());
|
|
_sub_tags = sub_tags;
|
|
}
|
|
|
|
// inline size_t get_size() const { return sizeof(task_notify_base) + 8 + sub_tags.get_size(); }
|
|
public int get_size() { return Marshal.SizeOf<task_notify_base>() + 8 + sub_tags.get_size(); }
|
|
|
|
public bool valid_size(int sz)
|
|
{
|
|
int base_sz = Marshal.SizeOf<task_notify_base>() + 8;
|
|
if (sz <= base_sz) return false;
|
|
return sub_tags.valid_size(sz - base_sz);
|
|
}
|
|
}
|
|
|
|
[ StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
public struct svr_treasure_map
|
|
{
|
|
public task_notify_base baseObj;
|
|
public int treasure_index;
|
|
|
|
}
|
|
|
|
struct tm {
|
|
int tm_sec; /* seconds after the minute [0-60] */
|
|
int tm_min; /* minutes after the hour [0-59] */
|
|
int tm_hour; /* hours since midnight [0-23] */
|
|
int tm_mday; /* day of the month [1-31] */
|
|
int tm_mon; /* months since January [0-11] */
|
|
int tm_year; /* years since 1900 */
|
|
int tm_wday; /* days since Sunday [0-6] */
|
|
int tm_yday; /* days since January 1 [0-365] */
|
|
int tm_isdst; /* Daylight Savings Time flag */
|
|
long tm_gmtoff; /* offset from UTC in seconds */
|
|
byte tm_zone; /* timezone abbreviation */
|
|
};
|
|
|
|
[StructLayout(LayoutKind.Explicit)]
|
|
public struct TaskGlobalData
|
|
{
|
|
[FieldOffset(0)]
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_GLOBAL_DATA_SIZE)]
|
|
public byte[] buf;
|
|
|
|
[FieldOffset(0)]
|
|
public ulong m_ulReceiverNum;
|
|
|
|
[FieldOffset(8)]
|
|
public ulong m_ulRcvUpdateTime;
|
|
|
|
void AddRevNum() { m_ulReceiverNum++; }
|
|
|
|
void CheckRcvUpdateTime(uint ulCurTime, int nFrequency)
|
|
{
|
|
// TODO: implement time-based receiver number reset logic
|
|
// if (nFrequency == TaskCompletionMethod.enumTAFNormal || m_ulRcvUpdateTime == 0)
|
|
// return;
|
|
//
|
|
// tm tmCur = *localtime((time_t*)&ulCurTime);
|
|
// tm tmRcv = *localtime((time_t*)&m_ulRcvUpdateTime);
|
|
//
|
|
// if (nFrequency == enumTAFEachDay)
|
|
// {
|
|
// if (tmCur.tm_year != tmRcv.tm_year || tmCur.tm_yday != tmRcv.tm_yday)
|
|
// m_ulReceiverNum = 0;
|
|
// }
|
|
// else if (nFrequency == enumTAFEachWeek)
|
|
// {
|
|
// if (!_is_same_week(&tmCur, &tmRcv, ulCurTime, m_ulRcvUpdateTime))
|
|
// m_ulReceiverNum = 0;
|
|
// }
|
|
// else if (nFrequency == enumTAFEachMonth)
|
|
// {
|
|
// if (tmCur.tm_year != tmRcv.tm_year || tmCur.tm_mon != tmRcv.tm_mon)
|
|
// m_ulReceiverNum = 0;
|
|
// }
|
|
// else if (nFrequency == enumTAFEachYear)
|
|
// {
|
|
// if (tmCur.tm_year != tmRcv.tm_year)
|
|
// m_ulReceiverNum = 0;
|
|
// }
|
|
}
|
|
}
|
|
|
|
[ StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
public struct svr_task_complete
|
|
{
|
|
public task_notify_base baseObj;
|
|
public uint cur_time;
|
|
public task_sub_tags sub_tags;
|
|
|
|
public void set_data(
|
|
uint _cur_time,
|
|
task_sub_tags _sub_tags
|
|
)
|
|
{
|
|
cur_time = _cur_time;
|
|
// memcpy(&sub_tags, &_sub_tags, _sub_tags.get_size());
|
|
sub_tags = _sub_tags;
|
|
}
|
|
|
|
public void get_data(
|
|
ref uint _cur_time,
|
|
ref task_sub_tags _sub_tags)
|
|
{
|
|
_cur_time = cur_time;
|
|
// memcpy(&_sub_tags, &sub_tags, sub_tags.get_size());
|
|
_sub_tags = sub_tags;
|
|
}
|
|
|
|
public int get_size() { return Marshal.SizeOf<task_notify_base>() + 4 + sub_tags.get_size(); }
|
|
|
|
public bool valid_size(int sz)
|
|
{
|
|
int base_sz = Marshal.SizeOf<task_notify_base>() + 4;
|
|
if (sz <= base_sz) return false;
|
|
return sub_tags.valid_size(sz - base_sz);
|
|
}
|
|
}
|
|
|
|
[StructLayout( LayoutKind.Sequential, Pack = 1)]
|
|
public struct special_award
|
|
{
|
|
public uint id1;
|
|
public uint id2;
|
|
public uint special_mask;
|
|
};
|
|
|
|
[StructLayout( LayoutKind.Sequential, Pack = 1)]
|
|
public struct svr_task_special_award
|
|
{
|
|
public svr_task_complete baseObj;
|
|
public special_award sa;
|
|
|
|
};
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
public struct FnshedTaskListHeader
|
|
{
|
|
public ushort m_uTaskCount;
|
|
public byte m_Version;
|
|
public byte m_Reserved;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
public struct FnshedTaskEntry
|
|
{
|
|
public ushort m_uTaskId;
|
|
public byte m_Buf;
|
|
// public byte m_Mask; // 1-bit mask: 0 = success, 1 = failure
|
|
// public byte m_Reserved; // Remaining 7 bits reserved
|
|
public byte m_FnshedCount; // Number of times the task has been completed
|
|
|
|
public byte m_Mask
|
|
{
|
|
get { return (byte)(m_Buf & 0x1); }
|
|
set { m_Buf = (byte)((m_Buf & 0xFE) | (value & 0x1)); }
|
|
}
|
|
|
|
public byte m_Reserved
|
|
{
|
|
get { return (byte)(m_Buf & 0x3); }
|
|
set { m_Buf = (byte)((m_Buf & 0xFE) | (value & 0x3)); }
|
|
}
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
public struct FinishedTaskList
|
|
{
|
|
// --- Layout 1: Header + List ---
|
|
public FnshedTaskListHeader m_FnshHeader
|
|
{
|
|
get {
|
|
FnshedTaskListHeader header = new FnshedTaskListHeader();
|
|
header.m_uTaskCount = BitConverter.ToUInt16(m_Buf, 0);
|
|
header.m_Version = m_Buf[2];
|
|
header.m_Reserved = m_Buf[3];
|
|
return header;
|
|
}
|
|
}
|
|
|
|
|
|
// [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_FINISHED_LIST_MAX_LEN)]
|
|
public FnshedTaskEntry[] m_aTaskList
|
|
{
|
|
get
|
|
{
|
|
FnshedTaskEntry[] taskList = new FnshedTaskEntry[TaskInterfaceConstants.TASK_FINISHED_LIST_MAX_LEN];
|
|
for (int i=0; i < m_FnshHeader.m_uTaskCount; i++)
|
|
{
|
|
int size = Marshal.SizeOf<FnshedTaskEntry>();
|
|
int startIndex = i * size + 4; // 4 bytes for m_FnshHeader
|
|
int endIndex = startIndex + size;
|
|
taskList[i] = GPDataTypeHelper.FromBytes<FnshedTaskEntry>(m_Buf[startIndex..endIndex]);
|
|
}
|
|
return taskList;
|
|
}
|
|
}
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_FINISHED_LIST_BUF_SIZE)]
|
|
public byte[] m_Buf;
|
|
|
|
public bool ReadFromBytes(byte[] data)
|
|
{
|
|
if (data.Length != TaskInterfaceConstants.TASK_FINISHED_LIST_BUF_SIZE)
|
|
return false;
|
|
|
|
m_Buf = new byte[TaskInterfaceConstants.TASK_FINISHED_LIST_BUF_SIZE];
|
|
Array.Copy(data, m_Buf, TaskInterfaceConstants.TASK_FINISHED_LIST_BUF_SIZE);
|
|
return true;
|
|
}
|
|
|
|
public int GetTaskPos(ulong ulID)
|
|
{
|
|
// TODO: Implement logic to get task position
|
|
//throw new NotImplementedException();
|
|
|
|
return 0;
|
|
}
|
|
|
|
public void AddOneTask(ulong ulID, bool bSuccess)
|
|
{
|
|
// TODO: Implement logic to add one task
|
|
//throw new NotImplementedException();
|
|
}
|
|
|
|
public void RemoveTask(ulong ulID)
|
|
{
|
|
// TODO: Implement logic to remove a task
|
|
//throw new NotImplementedException();
|
|
|
|
// unsigned long ulPos = GetTaskPos(ulID);
|
|
// if (static_cast<int>(ulPos) < 0) return;
|
|
//
|
|
// m_FnshHeader.m_uTaskCount--;
|
|
//
|
|
// if (m_FnshHeader.m_uTaskCount <= ulPos)
|
|
// return;
|
|
//
|
|
// memmove(
|
|
// &m_aTaskList[ulPos],
|
|
// &m_aTaskList[ulPos+1],
|
|
// (m_FnshHeader.m_uTaskCount-ulPos) * sizeof(FnshedTaskEntry));
|
|
}
|
|
|
|
public int SearchTask(ulong ulID)
|
|
{
|
|
// TODO: Implement logic to search for a task
|
|
//throw new NotImplementedException();
|
|
|
|
return 0;
|
|
}
|
|
|
|
public byte SearchTaskFinishCount(ulong ulID)
|
|
{
|
|
// TODO: Implement logic to search task finish count
|
|
//throw new NotImplementedException();
|
|
|
|
return 0;
|
|
}
|
|
|
|
public void ResetFinishCount(ulong ulID)
|
|
{
|
|
// TODO: Implement logic to reset finish count
|
|
//throw new NotImplementedException();
|
|
}
|
|
|
|
public void AddForFinishCount(ulong ulID, bool bSuccess)
|
|
{
|
|
// TODO: Implement logic to add for finish count
|
|
//throw new NotImplementedException();
|
|
}
|
|
|
|
public void RemoveAll()
|
|
{
|
|
Array.Clear(m_aTaskList, 0, m_aTaskList.Length);
|
|
Array.Clear(m_Buf, 0, m_Buf.Length);
|
|
}
|
|
|
|
public bool IsValid()
|
|
{
|
|
return m_FnshHeader.m_uTaskCount <= TaskInterfaceConstants.TASK_FINISHED_LIST_MAX_LEN;
|
|
}
|
|
}
|
|
} |