using BrewMonster; using BrewMonster.Network; using BrewMonster.Scripts; using BrewMonster.Scripts.Task; using CSNetwork.GPDataType; using Cysharp.Threading.Tasks; using System; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using UnityEngine; using static CECNPC; public class CECNPCServer : CECNPC { NPC_ESSENCE? m_pDBEssence; MONSTER_ESSENCE? m_pMonEssence; float m_fTaxRate = 0.05f; // Tax rate private IconTaskType m_TaskIcon = IconTaskType.QI_NONE; private CECCounter m_TaskCounter = new CECCounter(); private bool _needUpdateTaskIcon = false; public override void SetUpCECNPC(CECNPCMan pNPCMan) { base.SetUpCECNPC(pNPCMan); m_iCID = (int)Class_ID.OCID_SERVER; m_pDBEssence = null; m_TaskCounter.SetPeriod(1000); } public override bool Init(int tid, in info_npc info, ReadOnlySpan packet, int infoOffset) { base.Init(tid, info, packet, infoOffset); var pDB = ElementDataManProvider.GetElementDataMan(); DATA_TYPE DataType = default; var data = pDB.get_data_ptr((uint)tid, ID_SPACE.ID_SPACE_ESSENCE, ref DataType); m_pDBEssence = data != null ? (NPC_ESSENCE?)data : null; var data1 = pDB.get_data_ptr(m_pDBEssence.Value.id_src_monster, ID_SPACE.ID_SPACE_ESSENCE, ref DataType); if (data1 == null) { if ((data1 = (MONSTER_ESSENCE?)pDB.get_data_ptr(4249, ID_SPACE.ID_SPACE_ESSENCE, ref DataType)) == null) { BMLogger.LogError("HoangDEv : CECNPCServer::Init, server NPC reference to null monster data"); return false; } } m_pMonEssence = (MONSTER_ESSENCE?)data1; m_fTouchRad = m_pMonEssence.Value.size; m_BasicProps.iLevel = m_pMonEssence.Value.level; QueueLoadNPCModel(); /* float fExt = m_fTouchRad * 1.5f; m_cdr.vExts.Set(fExt, fExt, fExt); m_pNPCModelPolicy.SetDefaultPickAABBExt(m_cdr.vExts);*/ // If NPC doesn't have specific name, use the name in database if ((info.state & (int)PlayerNPCState.GP_STATE_NPC_NAME) == 0) { m_strName = Encoding.Unicode.GetString(MemoryMarshal.AsBytes(m_pDBEssence.Value.name)); m_npcUI.SetName(m_strName); } transform.forward = EC_Utility.ToVector3(EC_Utility.glb_DecompressDirH(info.dir)); transform.position = EC_Utility.ToVector3(info.pos); StartWork((int)WorkType.WT_NOTHING, (int)WorkID.WORK_STAND); return true; } protected override void Awake() { base.Awake(); var destroyToken = this.GetCancellationTokenOnDestroy(); UniTask.RunOnThreadPool(UpdateCurTaskIconProcess, false, cancellationToken: destroyToken).Forget(); } protected override void Update() { base.Update(); if (_needUpdateTaskIcon) { UpdateTaskIconUI(); _needUpdateTaskIcon = false; } } private async UniTask UpdateCurTaskIconProcess() { while (true) { await Task.Delay(1000); UpdateCurTaskIcon(); } } // Get way point ID bound with this NPC public uint? GetWayPointID() { uint? dwID = 0; if ((m_pDBEssence?.combined_services & 0x08) != 0) dwID = m_pDBEssence?.id_to_discover; return dwID; } // Get essence data in database public NPC_ESSENCE? GetDBEssence() { return m_pDBEssence; } // Get tax rate public float GetTaxRate() { return m_fTaxRate; } // Get item price scale factor public float GetPriceScale() { return 1.0f + m_pDBEssence.Value.tax_rate; } private void UpdateCurTaskIcon() { var pHost = CECGameRun.Instance.GetHostPlayer(); if (pHost == null || pHost.GetTaskInterface() == null) { return; } if (m_pDBEssence == null) { return; } var pTaskMan = EC_Game.GetTaskTemplateMan(); var pDataMan = ElementDataManProvider.GetElementDataMan(); var pTask = pHost.GetTaskInterface(); const uint TASK_HAVE_COMPLETE = 0x10000000; const uint TASK_COMPLETE = 0x01; const uint TASK_INCOMPLETE = 0x02; const uint TASK_CANGET = 0x04; const uint TASK_CANNOTGET = 0x08; const uint TASK_COMPLETE_TYPE1 = 0x10; const uint TASK_CANGET_TYPE1 = 0x20; const uint TASK_COMPLETE_TYPE2 = 0x40; const uint TASK_CANGET_TYPE2 = 0x80; const uint TASK_COMPLETE_TYPE3 = 0x100; const uint TASK_CANGET_TYPE3 = 0x200; const uint TASK_COMPLETE_TYPE4 = 0x400; const uint TASK_CANGET_TYPE4 = 0x800; m_TaskIcon = IconTaskType.QI_NONE; uint taskFlag = 0; //BMLogger.Log($"[UpdateCurTaskIcon] NPC {m_NPCInfo.nid}, id_task_in_service={m_pDBEssence.Value.id_task_in_service}, id_task_out_service={m_pDBEssence.Value.id_task_out_service}"); if (m_pDBEssence.Value.id_task_in_service != 0) { DATA_TYPE dt = DATA_TYPE.DT_INVALID; var serviceData = pDataMan.get_data_ptr(m_pDBEssence.Value.id_task_in_service, ID_SPACE.ID_SPACE_ESSENCE, ref dt); if (serviceData != null && dt == DATA_TYPE.DT_NPC_TASK_IN_SERVICE) { var inService = (NPC_TASK_IN_SERVICE)serviceData; for (int i = 0; i < inService.id_tasks.Length; i++) { uint idTask = inService.id_tasks[i]; if (idTask <= 0 || !pTask.HasTask(idTask)) continue; var pTaskTemp = pTaskMan.GetTaskTemplByID(idTask); if (pTaskTemp == null) continue; if (pTask.CanFinishTask(idTask)) { taskFlag |= TASK_HAVE_COMPLETE; if (pTaskTemp.IsKeyTask()) { m_TaskIcon = IconTaskType.QI_IN_K; _needUpdateTaskIcon = true; return; } else if (pTaskTemp.GetType() == (uint)ENUM_TASK_TYPE.enumTTEvent || pTaskTemp.GetType() == (uint)ENUM_TASK_TYPE.enumTTDaily) { taskFlag |= TASK_COMPLETE_TYPE3; } else if (pTaskTemp.GetType() == (uint)ENUM_TASK_TYPE.enumTTQiShaList) { taskFlag |= TASK_COMPLETE_TYPE2; } else if (pTaskTemp.GetType() == (uint)ENUM_TASK_TYPE.enumTTFaction || pTaskTemp.GetType() == (uint)ENUM_TASK_TYPE.enumTTFunction) { taskFlag |= TASK_COMPLETE_TYPE1; } else if (pTaskTemp.GetType() == (uint)ENUM_TASK_TYPE.enumTTMajor) { taskFlag |= TASK_COMPLETE_TYPE4; } else { taskFlag |= TASK_COMPLETE; } } else { taskFlag |= TASK_INCOMPLETE; } } } } if ((taskFlag & TASK_HAVE_COMPLETE) != 0) { if ((taskFlag & TASK_COMPLETE_TYPE4) != 0) m_TaskIcon = IconTaskType.QI_IN_TYPE4; else if ((taskFlag & TASK_COMPLETE_TYPE3) != 0) m_TaskIcon = IconTaskType.QI_IN_TYPE3; else if ((taskFlag & TASK_COMPLETE_TYPE2) != 0) m_TaskIcon = IconTaskType.QI_IN_TYPE2; else if ((taskFlag & TASK_COMPLETE) != 0) m_TaskIcon = IconTaskType.QI_IN; else if ((taskFlag & TASK_COMPLETE_TYPE1) != 0) m_TaskIcon = IconTaskType.QI_IN_TYPE1; _needUpdateTaskIcon = true; return; } if (m_pDBEssence.Value.id_task_out_service != 0) { DATA_TYPE dt = DATA_TYPE.DT_INVALID; var serviceData = pDataMan.get_data_ptr( m_pDBEssence.Value.id_task_out_service, ID_SPACE.ID_SPACE_ESSENCE, ref dt ); if (serviceData != null && dt == DATA_TYPE.DT_NPC_TASK_OUT_SERVICE) { var outService = (NPC_TASK_OUT_SERVICE)serviceData; if (outService.storage_id != 0 && outService.storage_open_item != 0) { var pack = pHost.GetInventory(InventoryConst.IVTRTYPE_PACK); if (pack != null && pack.GetItemTotalNum((int)outService.storage_open_item) > 0) { taskFlag |= TASK_CANGET_TYPE2; } } // Check normal tasks for (int i = 0; i < outService.id_tasks.Length; i++) { uint idTask = outService.id_tasks[i]; if (idTask <= 0) continue; if (!pTask.CanShowTask(idTask)) continue; var pTaskTemp = pTaskMan.GetTaskTemplByID(idTask); if (pTaskTemp == null) continue; if (pTask.CanDeliverTask(idTask) == 0) { if (pTaskTemp.IsKeyTask()) { m_TaskIcon = IconTaskType.QI_OUT_K; _needUpdateTaskIcon = true; return; } else if (pTaskTemp.GetType() == (uint)ENUM_TASK_TYPE.enumTTEvent || pTaskTemp.GetType() == (uint)ENUM_TASK_TYPE.enumTTDaily) { taskFlag |= TASK_CANGET_TYPE3; } else if (pTaskTemp.GetType() == (uint)ENUM_TASK_TYPE.enumTTQiShaList) { taskFlag |= TASK_CANGET_TYPE2; } else if (pTaskTemp.GetType() == (uint)ENUM_TASK_TYPE.enumTTFaction || pTaskTemp.GetType() == (uint)ENUM_TASK_TYPE.enumTTFunction) { taskFlag |= TASK_CANGET_TYPE1; } else if (pTaskTemp.GetType() == (uint)ENUM_TASK_TYPE.enumTTMajor) { taskFlag |= TASK_CANGET_TYPE4; } else { taskFlag |= TASK_CANGET; } } else { taskFlag |= TASK_CANNOTGET; } } } } // Set icon by available task priority if ((taskFlag & TASK_CANGET_TYPE4) != 0) m_TaskIcon = IconTaskType.QI_OUT_TYPE4; else if ((taskFlag & TASK_CANGET_TYPE3) != 0) m_TaskIcon = IconTaskType.QI_OUT_TYPE3; else if ((taskFlag & TASK_CANGET_TYPE2) != 0) m_TaskIcon = IconTaskType.QI_OUT_TYPE2; else if ((taskFlag & TASK_CANGET) != 0) m_TaskIcon = IconTaskType.QI_OUT; else if ((taskFlag & TASK_CANGET_TYPE1) != 0) m_TaskIcon = IconTaskType.QI_OUT_TYPE1; else if ((taskFlag & TASK_INCOMPLETE) != 0) m_TaskIcon = IconTaskType.QI_IN_N; else if ((taskFlag & TASK_CANNOTGET) != 0) m_TaskIcon = IconTaskType.QI_OUT_N; //BMLogger.Log($"[UpdateCurTaskIcon] Final icon {m_TaskIcon}, taskFlag={taskFlag}"); _needUpdateTaskIcon = true; } private void UpdateTaskIconUI() { if(m_npcUI != null) { m_npcUI.SetTaskIcon(m_TaskIcon); } } }