242 lines
8.8 KiB
C#
242 lines
8.8 KiB
C#
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<ulong, ATaskTempl> m_TaskTemplMap = new Dictionary<ulong, ATaskTempl>();
|
|
private Dictionary<ulong, ATaskTempl> m_AllTemplMap = new Dictionary<ulong, ATaskTempl>();
|
|
private Dictionary<ulong, ATaskTempl> m_DynTaskMap = new Dictionary<ulong, ATaskTempl>();
|
|
private Dictionary<ulong, ATaskTempl> m_TitleTaskMap = new Dictionary<ulong, ATaskTempl>();
|
|
private Dictionary<ulong, ATaskTempl> m_ExlusiveAwardTaskMap = new Dictionary<ulong, ATaskTempl>();
|
|
private Dictionary<ulong, ATaskTempl> m_ProtectNPCMap = new Dictionary<ulong, ATaskTempl>();
|
|
private Dictionary<ulong, ATaskTempl> m_AutoDelvMap = new Dictionary<ulong, ATaskTempl>();
|
|
private Dictionary<ulong, ATaskTempl> m_DeathTrigMap = new Dictionary<ulong, ATaskTempl>();
|
|
private Dictionary<ulong, ATaskTempl> m_PQTemplMap = new Dictionary<ulong, ATaskTempl>();
|
|
private List<ATaskTempl> m_SkillTaskLst = new List<ATaskTempl>();
|
|
|
|
#if _TASK_CLIENT
|
|
// char m_szDynPackPath[512];
|
|
// bool m_bDynTasksVerified;
|
|
// special_award m_SpecialAward;
|
|
private List<ATaskTempl> m_TasksCanSeekOut = new List<ATaskTempl>();
|
|
// 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<TasksSeekOutDiff> 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<TASK_PACK_HEADER>(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<T>(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);
|
|
}
|
|
}
|
|
} |