using System.IO; using System.Collections.Generic; using UnityEngine; namespace PerfectWorld.Scripts.Task { public struct TASK_PACK_HEADER { public ulong magic; public ulong version; public ulong item_count; }; public class ATaskTemplMan { public const ulong TASK_PACK_MAGIC = 0x93858361; public const ulong _task_templ_cur_version = 121; private ulong g_ulNewCount = 0;// do we need this? private Dictionary m_TaskTemplMap = new Dictionary(); private Dictionary m_AllTemplMap = new Dictionary(); private Dictionary m_DynTaskMap = new Dictionary(); private Dictionary m_TitleTaskMap = new Dictionary(); private Dictionary m_ExlusiveAwardTaskMap = new Dictionary(); private Dictionary m_ProtectNPCMap = new Dictionary(); private Dictionary m_AutoDelvMap = new Dictionary(); private Dictionary m_DeathTrigMap = new Dictionary(); private Dictionary m_PQTemplMap = new Dictionary(); private List m_SkillTaskLst = new List(); #if _TASK_CLIENT // char m_szDynPackPath[512]; // bool m_bDynTasksVerified; // special_award m_SpecialAward; private List m_TasksCanSeekOut = new List(); // TaskTemplLst m_TasksCanDeliver; // struct TasksSeekOutDiff // { // ATaskTempl* task; // TasksSeekOutDiff():task(NULL){} // TasksSeekOutDiff(ATaskTempl* p):task(p){} // bool operator < (const TasksSeekOutDiff& rhs) const; // bool operator == (const TasksSeekOutDiff& rhs) const { return task == rhs.task; } // }; // typedef std::vector TasksSeekOutDiffList; // TasksSeekOutDiffList m_TasksToPush; #endif void Release() { } public bool LoadTasksFromPack(string szPackPath, bool bLoadDescript) { //TaskInterface::WriteLog(0, 0, 2, "LoadPack begin"); FileStream fs = new FileStream(szPackPath, FileMode.Open, FileAccess.Read); if (fs == null) return false; TASK_PACK_HEADER tph; // fread(&tph, sizeof(tph), 1, fp); tph = ReadStruct(fs); if (tph.magic != TASK_PACK_MAGIC || tph.version != _task_templ_cur_version) return false; if (tph.item_count == 0) return true; long[] pOffs = new long[tph.item_count]; g_ulNewCount++; // fread(pOffs, sizeof(long), tph.item_count, fp); // Convert fread(pOffs, sizeof(long), tph.item_count, fp); to C# // Read tph.item_count 8-byte integers (long) from the FileStream fs into pOffs array byte[] offsBuffer = new byte[tph.item_count * sizeof(long)]; int bytesRead = fs.Read(offsBuffer, 0, offsBuffer.Length); if (bytesRead != offsBuffer.Length) throw new EndOfStreamException("Could not read enough bytes for offsets"); for (ulong i = 0; i < tph.item_count; i++) { pOffs[i] = System.BitConverter.ToInt64(offsBuffer, (int)(i * sizeof(long))); } for (ulong i = 0; i < tph.item_count; i++) { // if (fseek(fp, pOffs[i], SEEK_SET) != 0) // continue; if (fs.Seek(pOffs[i], SeekOrigin.Begin) != 0) continue; ATaskTempl pTempl = new ATaskTempl(); g_ulNewCount++; if (!pTempl.LoadFromBinFile(fs)) { // TaskInterface::WriteLog(0, pTempl->m_ID, 0, "Cant Load Task"); // LOG_DELETE(pTempl); continue; } AddOneTaskTempl(pTempl); // TaskInterface::WriteLog(0, pTempl->m_ID, 2, "LoadTask"); } // char log[1024]; // sprintf(log, "LoadTask, Count = %d", m_TaskTemplMap.size()); // TaskInterface::WriteLog(0, 0, 2, log); //todo: check // LOG_DELETE_ARR(pOffs); fs.Close(); //todo: check UpdateTimeLimitCheckList // #if _TASK_CLIENT UpdateTimeLimitCheckList(); // #else SortTasksCanSeekOut(); // #endif #if _ELEMENTCLIENT _task_err.Release(); _task_err.Init("Configs\\task_err.txt", true); #endif return true; } // General method to read a struct from a FileStream private T ReadStruct(FileStream stream) where T : struct { int size = System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)); byte[] buffer = new byte[size]; int bytesRead = stream.Read(buffer, 0, size); if (bytesRead != size) throw new EndOfStreamException("Could not read enough bytes for struct"); var handle = System.Runtime.InteropServices.GCHandle.Alloc(buffer, System.Runtime.InteropServices.GCHandleType.Pinned); try { return (T)System.Runtime.InteropServices.Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); } finally { handle.Free(); } } public bool LoadNPCInfoFromPack(string szPath) { return true; } public void VerifyDynTasksPack(string szPath) { } private void AddOneTaskTempl(ATaskTempl pTask) { //todo: recheck - wrong logic if (m_AllTemplMap.ContainsKey(pTask.m_ID)) { CECTaskInterface.WriteLog(0, (int)pTask.m_ID, 0, "Dup Task Found"); // Optionally log duplicate task found, e.g.: // Debug.LogWarning($"Duplicate Task Found: {pTempl.m_ID}"); return; } m_TaskTemplMap[pTask.m_ID] = pTask; if (pTask.m_bDeathTrig) m_DeathTrigMap[pTask.m_ID] = pTask; else if (pTask.m_bAutoDeliver) m_AutoDelvMap[pTask.m_ID] = pTask; if (pTask.m_bPQTask) m_PQTemplMap[pTask.m_ID] = pTask; if (pTask.m_bSkillTask) m_SkillTaskLst.Add(pTask); //todo: recheck m_DynTaskType type if (pTask.m_DynTaskType) { TaskTemplMap::iterator itDyn = m_DynTaskMap.find(pTask.m_ID); if (itDyn != m_DynTaskMap.end()) TaskInterface::WriteLog(0, pTask.m_ID, 0, "Dup Dyn Task Found"); m_DynTaskMap[pTask.m_ID] = pTask; } if (pTask.m_bDisplayInTitleTaskUI) m_TitleTaskMap[pTask.m_ID] = pTask; if (pTask.m_bAutoDeliver && pTask.m_bDisplayInExclusiveUI) m_ExlusiveAwardTaskMap[pTask.m_ID] = pTask; # if _TASK_CLIENT if (pTask.m_ulDelvNPC != 0 && pTask.m_bCanSeekOut) m_TasksCanSeekOut.push_back(pTask); #endif AddTaskToMap(pTask); } private void AddTaskToMap(ATaskTempl pTempl) { if (pTempl.m_enumMethod == (ulong)TaskMethod.enumTMProtectNPC && pTempl.m_ulNPCToProtect > 0) m_ProtectNPCMap[pTempl.m_ulNPCToProtect] = pTempl; m_AllTemplMap[pTempl.m_ID] = pTempl; ATaskTempl pChild = pTempl.m_pFirstChild; while (pChild != null) { AddTaskToMap(pChild); pChild = pChild.m_pNextSibling; } } private void SortTasksCanSeekOut() { m_TasksCanSeekOut.Sort((lhs, rhs) => { if (lhs.m_ulPremItems != 0 && rhs.m_ulPremItems == 0) return -1; // lhs comes before rhs else if (lhs.m_ulPremItems == 0 && rhs.m_ulPremItems != 0) return 1; // rhs comes before lhs else if (lhs.m_ulPremItems != 0 && rhs.m_ulPremItems != 0) return rhs.m_ID.CompareTo(lhs.m_ID); // descending by ID else return rhs.m_ulPremise_Lev_Min.CompareTo(lhs.m_ulPremise_Lev_Min); // descending by Premise_Lev_Min }); } void UpdateTimeLimitCheckList() { m_TmLmtChkLst.clear(); TaskTemplMap::iterator it = m_TaskTemplMap.begin(); for (; it != m_TaskTemplMap.end(); ++it) if (it->second->m_ulMaxReceiver) m_TmLmtChkLst.push_back(it->second); } } }