using System; 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 class task_notify_base { public byte reason; public ushort task; }; [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct cmd_task_notify { public uint size; public byte placeholder; // Task data ... } [StructLayout(LayoutKind.Sequential, Pack = 1)] public class svr_monster_killed : task_notify_base { public uint monster_id; public ushort monster_num; public int dps; public int dph; public svr_monster_killed(task_notify_base baseObj) { reason = baseObj.reason; task = baseObj.task; } }; [StructLayout(LayoutKind.Sequential, Pack = 1)] public class svr_player_killed : task_notify_base { public ushort index; public ushort player_num; public svr_player_killed(task_notify_base baseObj) { reason = baseObj.reason; task = baseObj.task; } }; [StructLayout(LayoutKind.Sequential, Pack = 1)] public class svr_task_err_code : task_notify_base { public uint err_code; public svr_task_err_code(task_notify_base baseObj) { reason = baseObj.reason; task = baseObj.task; } }; [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; [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]; } } } public class svr_new_task : task_notify_base { 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 svr_new_task(task_notify_base baseObj) { reason = baseObj.reason; task = baseObj.task; } 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() + 8 + sub_tags.get_size(); } public bool valid_size(int sz) { int base_sz = Marshal.SizeOf() + 8; if (sz <= base_sz) return false; return sub_tags.valid_size(sz - base_sz); } } public class svr_treasure_map : task_notify_base { public int treasure_index; public svr_treasure_map(task_notify_base baseObj) { reason = baseObj.reason; task = baseObj.task; } } 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; // } } } public class svr_task_complete : task_notify_base { public uint cur_time; public task_sub_tags sub_tags; public svr_task_complete(task_notify_base baseObj) { reason = baseObj.reason; task = baseObj.task; } 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() + 4 + sub_tags.get_size(); } public bool valid_size(int sz) { int base_sz = Marshal.SizeOf() + 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 class svr_task_special_award : task_notify_base { public special_award sa; public svr_task_special_award(task_notify_base baseObj) { reason = baseObj.reason; task = baseObj.task; } }; [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(); int startIndex = i * size + 4; // 4 bytes for m_FnshHeader int endIndex = startIndex + size; taskList[i] = GPDataTypeHelper.FromBytes(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(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; } } }