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

560 lines
21 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 BrewMonster;
using ModelRenderer.Scripts.GameData;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using PerfectWorld.Scripts.Task;
using UnityEngine;
namespace BrewMonster.Scripts.Task
{
/// <summary>
/// contains and manages all task templates
/// init in EC_Game
/// </summary>
[Serializable]
public class ATaskTemplMan
{
public int TaskLoadedCount => m_TaskTemplMap.Count;
public const ulong TASK_PACK_MAGIC = 0x93858361;
public const ulong _task_templ_cur_version = 121;
private ulong g_ulNewCount = 0;// do we need this? // MH: I think not, it look like a debug counter
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 Dictionary<uint, uint> m_StorageEssenseMap = new Dictionary<uint, uint>();
private Dictionary<uint, uint> m_WeightEssenseMap = new Dictionary<uint, uint>();
private Dictionary<int, int> m_StorageTaskMap = new Dictionary<int, int>();
private List<ATaskTempl> m_SkillTaskLst = new List<ATaskTempl>();
private List<ATaskTempl> m_TmLmtChkLst = new List<ATaskTempl>();
private List<ATaskTempl> m_TasksCanSeekOut = new List<ATaskTempl>();
private elementdataman m_pEleDataMan;
#if _TASK_CLIENT
// char m_szDynPackPath[512];
bool m_bDynTasksVerified;
protected special_award m_SpecialAward;
#endif
public void Release()
{
}
public void Init(elementdataman pMan)
{
m_pEleDataMan = pMan;
}
public bool LoadTasksFromPack(string szPackPath, bool bLoadDescript)
{
//TaskInterface::WriteLog(0, 0, 2, "LoadPack begin");
BMLogger.Log("[Dat]- szPackPath: " + szPackPath);
if (!File.Exists(szPackPath))
{
BMLogger.LogError("[Dat]- File not found: " + szPackPath);
return false;
}
long readBytes = 0;
FileStream fs = new FileStream(szPackPath, FileMode.Open, FileAccess.Read);
TASK_PACK_HEADER tph = AAssit.ReadFromBinaryOf<TASK_PACK_HEADER>(fs, ref readBytes);
if (tph.magic != TASK_PACK_MAGIC
|| tph.version != _task_templ_cur_version)
return false;
if (tph.item_count == 0) return true;
uint[] pOffs = new uint[tph.item_count];
g_ulNewCount++;
// fread(pOffs, sizeof(long), tph.item_count, fp);
// read File and prepare offset array before loading tasks
pOffs = AAssit.ReadArrayFromBinary<uint>(fs, (int)tph.item_count, ref readBytes);
Debug.Log((int)tph.item_count);
//BMLogger.Log($" [MH] Task File Lenght: {fs.Length}");
// for (int i = 2058; i < 2059; i++) //TODO: tph.item_count
Debug.Log($" Starting to load {tph.item_count} task templates...");
for (int i = 0; i < tph.item_count; i++)
{
// mvoe file pointer to task offset
fs.Seek(pOffs[i], SeekOrigin.Begin);
// BMLogger.Log(" [MH] Loading Task Templ at offset: " + pOffs[i]);
ATaskTempl pTempl = new ATaskTempl();
g_ulNewCount++;
// Debug.Log($"Task Index {i}: Attempting to load task template...");
if (!pTempl.LoadFromBinFile(fs))
{
CECTaskInterface.WriteLog(0, (int)pTempl.m_FixedData.m_ID, 0, "Cant Load Task");
// LOG_DELETE(pTempl);
continue;
}
AddOneTaskTempl(pTempl);
// TaskInterface::WriteLog(0, pTempl->m_ID, 2, "LoadTask");
}
Debug.Log($" Finished loading {m_TaskTemplMap.Count} task templates.");
// // 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();
// UpdateTimeLimitCheckList();
#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)
{
}
public ATaskTempl GetTopTaskByID(uint ulID)
{
if (m_TaskTemplMap.TryGetValue(ulID, out ATaskTempl task))
{
return task;
}
return null;
}
public ATaskTempl GetTaskTemplByID(uint ulID)
{
if (m_AllTemplMap.TryGetValue((uint)ulID, out ATaskTempl task))
{
return task;
}
return null;
}
public bool CanGiveUpTask(uint ulTaskId)
{
var pTempl = GetTaskTemplByID(ulTaskId);
if (pTempl == null) return false;
pTempl = pTempl.GetTopTask();
return pTempl.m_FixedData.m_bCanGiveUp;
}
private void AddOneTaskTempl(ATaskTempl pTask)
{
if (m_TaskTemplMap.ContainsKey(pTask.m_FixedData.m_ID))
{
CECTaskInterface.WriteLog(0, (int)pTask.m_FixedData.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_FixedData.m_ID] = pTask;
if (pTask.m_FixedData.m_bDeathTrig) m_DeathTrigMap[pTask.m_FixedData.m_ID] = pTask;
else if (pTask.m_FixedData.m_bAutoDeliver) m_AutoDelvMap[pTask.m_FixedData.m_ID] = pTask;
if (pTask.m_FixedData.m_bPQTask) m_PQTemplMap[pTask.m_FixedData.m_ID] = pTask;
if (pTask.m_FixedData.m_bSkillTask) m_SkillTaskLst.Add(pTask);
//todo: recheck m_DynTaskType type
if (pTask.m_FixedData.m_DynTaskType != '\0')
{
if (m_DynTaskMap.TryGetValue(pTask.m_FixedData.m_ID, out ATaskTempl task))
{
CECTaskInterface.WriteLog(0, (int)pTask.m_FixedData.m_ID, 0, "Dup Dyn Task Found");
}
m_DynTaskMap[pTask.m_FixedData.m_ID] = pTask;
}
if (pTask.m_FixedData.m_bDisplayInTitleTaskUI)
m_TitleTaskMap[pTask.m_FixedData.m_ID] = pTask;
if (pTask.m_FixedData.m_bAutoDeliver && pTask.m_FixedData.m_bDisplayInExclusiveUI)
m_ExlusiveAwardTaskMap[pTask.m_FixedData.m_ID] = pTask;
#if _TASK_CLIENT
if (pTask.m_FixedData.m_ulDelvNPC != 0 && pTask.m_FixedData.m_bCanSeekOut)
m_TasksCanSeekOut.Add(pTask);
#endif
AddTaskToMap(pTask);
}
private void AddTaskToMap(ATaskTempl pTempl)
{
if (pTempl.m_FixedData.m_enumMethod == (ulong)TaskCompletionMethod.enumTMProtectNPC && pTempl.m_FixedData.m_ulNPCToProtect > 0)
m_ProtectNPCMap[pTempl.m_FixedData.m_ulNPCToProtect] = pTempl;
m_AllTemplMap[pTempl.m_FixedData.m_ID] = pTempl;
ATaskTempl pChild = pTempl.m_pFirstChild;
while (pChild != null)
{
AddTaskToMap(pChild);
pChild = pChild.m_pNextSibling;
}
}
void UpdateTimeLimitCheckList()
{
m_TmLmtChkLst.Clear();
foreach (var entry in m_TaskTemplMap)
{
if (entry.Value.m_FixedData.m_ulMaxReceiver != 0)
{
m_TmLmtChkLst.Add(entry.Value);
}
}
}
public bool InitStorageTask()
{
m_StorageEssenseMap.Clear();
m_WeightEssenseMap.Clear();
DATA_TYPE dt;
//ID_SPACE.ID_SPACE_ESSENCE
foreach (var pair in m_pEleDataMan.essence_id_data_type_map)
{
if (pair.Value == DATA_TYPE.DT_NPC_TASK_OUT_SERVICE)
{
dt = pair.Value;
NPC_TASK_OUT_SERVICE pData = (NPC_TASK_OUT_SERVICE)m_pEleDataMan.get_data_ptr(pair.Key, ID_SPACE.ID_SPACE_ESSENCE, ref dt);
if (pData.storage_id == 0) continue;
if (pData.storage_id > TaskTemplConstants.TASK_STORAGE_COUNT) return false;
if (m_StorageEssenseMap.ContainsKey(pData.storage_id)) return false;
m_StorageEssenseMap[pData.storage_id] = pData.id;
for (var i = 0; i < pData.id_tasks.Length; i++)
{
if (pData.id_tasks[i] > 0)
{
m_StorageTaskMap[(int)pData.id_tasks[i]] = (int)pData.storage_id;
}
}
}
}
// ID_SPACE_CONFIG
foreach (var pair in m_pEleDataMan.config_id_data_type_map)
{
if (pair.Value == DATA_TYPE.DT_NPC_TASK_OUT_SERVICE)
{
dt = pair.Value;
NPC_TASK_OUT_SERVICE pData = (NPC_TASK_OUT_SERVICE)m_pEleDataMan.get_data_ptr(pair.Key, ID_SPACE.ID_SPACE_ESSENCE, ref dt);
if (pData.storage_id == 0) continue;
if (pData.storage_id > TaskTemplConstants.TASK_STORAGE_COUNT) return false;
if (m_StorageEssenseMap.ContainsKey(pData.storage_id)) return false;
m_StorageEssenseMap[pData.storage_id] = pData.id;
for (var i = 0; i < pData.id_tasks.Length; i++)
{
if (pData.id_tasks[i] > 0)
{
m_StorageTaskMap[(int)pData.id_tasks[i]] = (int)pData.storage_id;
}
}
}
}
return true;
}
#if _TASK_CLIENT
public bool IsTaskToPush(int id)
{
// TODO: Implement this method properly
// int count = m_TasksToPush.size();
// for (size_t i = 0; i < count; ++i) {
// ATaskTempl pTempl = m_TasksToPush[i].task;
// if (pTempl && (int)pTempl->m_ID == id) return true;
// }
return false;
}
// 可接任务列表 // Available tasks list
public void GetAvailableTasks(TaskInterface pPlayer, List<ATaskTempl> lst)
{
if (lst == null) return;
if (lst.Capacity < 256) lst.Capacity = 256; // 预留容量 // reserve capacity
string log = "";
int count = m_TasksCanSeekOut.Count;
for (int i = 0; i < count; i++)
{
ATaskTempl pTempl = m_TasksCanSeekOut[i];
if (pTempl == null) continue;
// 如果等级条件不满足则跳过 // Skip if level requirements are not met
if (!pTempl.CheckReachLevel(pPlayer)) continue;
// 玩家可接此任务则加入列表 // If player can accept this task, add to list
var failCode = pPlayer.CanDeliverTask(pTempl.m_FixedData.m_ID);
if (failCode == 0)
{
lst.Add(pTempl);
}
else
{
log += $"Task ID {pTempl.m_FixedData.m_ID} Fail : {failCode} \n";
}
// if (i % 1000 == 0)
// {
// Debug.Log($"--- {i % 1000} Find Available Task --- \n {log}");
// log = "";
// }
}
}
public uint GetTaskStorageId(uint id)
{
// id1ʼ
// abase::hash_map<int, int>::iterator it = m_StorageTaskMap.find(id);
// return it == m_StorageTaskMap.end() ? 0 : it->second;
return m_StorageTaskMap.ContainsKey((int)id) ? (uint)m_StorageTaskMap[(int)id] : 0;
}
public void RemoveActiveStorageTask( StorageTaskList pLst, uint id)
{
// unsigned int set_id = GetTaskTemplMan()->GetTaskStorageId(id);
uint set_id = GetTaskStorageId(id);
if (set_id > 0)
{
int start = (int)set_id - 1;
ushort[] arr = pLst.m_Storages;
for (int i = start; i < TaskTemplConstants.TASK_STORAGE_LEN; i++)
{
if (arr[i] == (ushort)id)
{
arr[i] = 0;
break;
}
}
}
}
// 占位:可接返回0,不可接返回非0 // Placeholder: return 0 if deliverable, non-zero otherwise
// private int CanDeliverTask(TaskInterface pPlayer, uint templId)
// {
// // 后续可替换为正式逻辑 // Replace with real logic later
// var impl = pPlayer;
// return (impl != null && impl.IsDeliverLegal()) ? 0 : 1;
// }
public void OnSpecialAward(special_award p,TaskInterface pTask)
{
m_SpecialAward = p;
CheckSpecialAwardMask(pTask);
}
public void CheckSpecialAwardMask(TaskInterface pTask)
{
ActiveTaskList pLst = pTask.GetActiveTaskList();
uint ulCurTime = pTask.GetCurTime();
for (int i = 0;i < TaskTemplConstants.NUM_SPECIAL_AWARD;i++)
{
if ((m_SpecialAward.special_mask & (1 << i)) != 0)
{
// const ATaskTempl* pTempl = GetTaskTemplByID(static_cast<unsigned short>(TASK_SPECIAL_AWARD[i])); C++
var pTempl = GetTaskTemplByID((uint)TaskTemplConstants.TASK_SPECIAL_AWARD[i]);
if (pTempl != null && pTempl.CheckPrerequisite(pTask,pLst,ulCurTime) == 0)
{
// _notify_svr(pTask, TASK_CLT_NOTIFY_SPECIAL_AWARD_MASK,static_cast<unsigned short>(pTempl->m_ID)); C++
_notify_svr(pTask, ClientNotificationConstants.TASK_CLT_NOTIFY_SPECIAL_AWARD_MASK,(ushort)(pTempl.m_FixedData.m_ID));
}
}
}
}
private void _notify_svr(TaskInterface pTask, byte uReason, ushort uTaskID)
{
ATaskTempl._notify_svr(pTask, uReason, uTaskID);
}
public void CheckAutoDelv(TaskInterface pTask)
{
ATaskTempl pTempl = null;
// TaskTemplMap::iterator it = m_AutoDelvMap.begin();
var it = m_AutoDelvMap[0];
uint ulCurTime = pTask.GetCurTime();
ActiveTaskList pLst = pTask.GetActiveTaskList();
#if _ELEMENTLOCALIZE
#if _ELEMENTCLIENT
// if (CECCommandLine::GetBriefConfig(_AL("noautodelivertask"))) return;
#endif
#endif
// C++
// for (; it != m_AutoDelvMap.end(); ++it)
// {
// pTempl = it->second;
//
// if (!pTempl->IsValidState())
// continue;
//
// if (pTempl->CheckPrerequisite(pTask, pLst, ulCurTime) == 0)
// {
// pTempl->IncValidCount();
// _notify_svr(pTask, TASK_CLT_NOTIFY_AUTO_DELV, static_cast<unsigned short>(pTempl->m_ID));
// }
// }
foreach (var key in m_AutoDelvMap.Keys)
{
pTempl = m_AutoDelvMap[key];
if (!pTempl.IsValidState())
continue;
if (pTempl.CheckPrerequisite(pTask, pLst, ulCurTime) == 0)
{
pTempl.IncValidCount();
_notify_svr(pTask, ClientNotificationConstants.TASK_CLT_NOTIFY_AUTO_DELV, (ushort)(pTempl.m_FixedData.m_ID));
}
}
}
public void UpdateStatus(TaskInterface pTask)
{
// ΪCheckTitleƺݣֱȡƺ֮ǰܵ
if (!pTask.IsTitleDataReady()) return;
CheckAutoDelv(pTask);
// TODO: Implement other checks as needed
// if (CECUIConfig::Instance().GetGameUI().bEnableTitle)
// CheckTitleTask(pTask);
// UpdateTasksSeekOutDiff(pTask);
}
// extarn from TaskServer
private void OnTaskGiveUpOneTask(TaskInterface pTask, uint ulTaskId, bool bForce)
{
TaskServer.OnTaskGiveUpOneTask(pTask, ulTaskId, bForce);
}
#endif
public void OnForgetLivingSkill(TaskInterface pTask)
{
// FinishedTaskList* pList = static_cast<FinishedTaskList*>(pTask->GetFinishedTaskList()); // C++
FinishedTaskList pList = pTask.GetFinishedTaskList();
for (int i = 0; i < m_SkillTaskLst.Count; i++)
{
pList.RemoveTask(m_SkillTaskLst[i].GetID());
#if _TASK_CLIENT
OnTaskGiveUpOneTask(pTask, m_SkillTaskLst[i].GetID(), false);
#endif
}
#if _TASK_CLIENT
task_notify_base notify = new task_notify_base();
notify.reason = TaskTemplConstants.TASK_SVR_NOTIFY_FORGET_SKILL;
notify.task = 0;
pTask.NotifyClient(notify, Marshal.SizeOf<task_notify_base>());
#endif
}
// process part
#if _TASK_CLIENT
// void GetTitleTasks(TaskInterface pTask, TaskTemplLst lst);
// void GetAvailableTasks(TaskInterface* pPlayer, TaskTemplLst& lst);
// void ManualTrigTask(TaskInterface* pTask, unsigned long ulTask);
// void ForceGiveUpTask(TaskInterface* pTask, unsigned long ulTask);
// void ForceRemoveFinishTask(TaskInterface* pTask, unsigned long ulTask);
public bool IsDynTasksVerified() { return m_bDynTasksVerified; }
// void SetDynTasksVerified(bool b) { m_bDynTasksVerified = b; }
// void OnDynTasksTimeMark(TaskInterface* pTask, unsigned long ulTimeMark, unsigned short version);
// void OnDynTasksData(TaskInterface* pTask, const void* data, size_t sz, bool ended);
// void OnStorageData(TaskInterface* pTask, const void* data);
// void OnSpecialAward(const special_award* p,TaskInterface* pTask);
// void VerifyDynTasksPack(const char* szPath);
// const special_award* GetSpecialAward() const { return &m_SpecialAward; }
public void ClearSpecailAward()
{
// memset(&m_SpecialAward, 0, sizeof(m_SpecialAward));
m_SpecialAward = new special_award();
}
// void SortTasksCanSeekOut();
// void UpdateTasksSeekOutDiff(TaskInterface* pTask);
// bool IsTaskToPush(int id);
// void ClearTasksToPush() { m_TasksToPush.clear(); }
// bool HasTaskToPush() { return !m_TasksToPush.empty(); }
#else
void CheckDeathTrig(TaskInterface* pTask);
void OnTaskCheckAllTimeLimits(unsigned long ulCurTime);
void OnTaskGetDynTasksTimeMark(TaskInterface* pTask);
void OnTaskGetDynTasksData(TaskInterface* pTask);
void OnTaskGetSpecialAward(TaskInterface* pTask);
void OnTaskRemoveFinishTask(TaskInterface* pTask, unsigned long ulTask);
void OnTaskUpdateStorage(TaskInterface* pTask, unsigned long ulCurTime);
bool UpdateStorage(TaskInterface* pTask, StorageTaskList* pLst, unsigned long ulCurTime, unsigned long idStorage);
bool UpdateOneStorageDebug(TaskInterface* pTask, unsigned long ulCurTime, int idStorage, bool bUseDayAsSeed);
#endif
}
}