Files
test/Assets/PerfectWorld/Scripts/Task/CECTaskInterface.cs
T
2025-12-20 11:52:13 +07:00

1865 lines
63 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 BrewMonster.Network;
using CSNetwork.GPDataType;
using PerfectWorld.Scripts.Task;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using BrewMonster.UI;
using CSNetwork;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using System;
namespace BrewMonster.Scripts.Task
{
[Serializable]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class Kill_Player_Requirements
{
public const uint MAX_OCCPU_MASK = ((uint)1 << TaskInterfaceConstants.MAX_OCCUPATIONS) - 1u;
public uint m_ulOccupations;
public int m_iMinLevel;
public int m_iMaxLevel;
public int m_iGender;
public int m_iForce;
public Kill_Player_Requirements()
{
m_iMinLevel = 10;
m_iMaxLevel = 100;
m_iGender = 0;
m_iForce = 0;
m_ulOccupations = MAX_OCCPU_MASK;
}
public bool IsMeetAllOccupation()
{
return m_ulOccupations == MAX_OCCPU_MASK;
}
public bool CheckRequirements(int iOccupation, int iLevel, bool bGender, int iForce)
{
bool bForce = false;
// У2ΪŮ // In editor: 1 is male, 2 is female
int iGender = bGender ? 2 : 1;
// 0ûҪ // In editor: 0 means no force requirement
if (m_iForce == 0)
{
bForce = true;
}
// ʾҪ // Otherwise indicates there is a force requirement
else
{
// ͻҹֱõһλʾ // Map force ids to bit positions
int iForceMask = 0;
if (iForce == 0)
{
return false;
}
else if (iForce == 1004)
{
iForceMask = 1 << 0;
}
else if (iForce == 1005)
{
iForceMask = 1 << 1;
}
else if (iForce == 1006)
{
iForceMask = 1 << 2;
}
bForce = (m_iForce & iForceMask) != 0;
}
return ((m_ulOccupations & (1u << iOccupation)) != 0)
&& m_iMinLevel <= iLevel
&& m_iMaxLevel >= iLevel
&& (m_iGender != 0 ? m_iGender == iGender : true)
&& bForce;
}
}
#if _TASK_CLIENT
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Task_State_info
{
public uint m_ulTimeLimit;
public uint m_ulTimePassed;
public uint m_ulNPCToProtect;
public uint m_ulProtectTime;
public uint m_ulWaitTime;
public uint m_ulErrCode;
public uint m_ulGoldWanted;
public uint m_ulReachLevel;
public uint m_ulReachReincarnation;
public uint m_ulReachRealm;
public uint m_ulPremLevelMin;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct m_MonsterWanted_s
{
public uint m_ulMonsterId;
public uint m_ulMonstersToKill;
public uint m_ulMonstersKilled;
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.MAX_MONSTER_WANTED)]
public m_MonsterWanted_s[] m_MonsterWanted;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct m_ItemsWanted_s
{
public uint m_ulItemId;
public uint m_ulItemsToGet;
public uint m_ulItemsGained;
public uint m_ulMonsterId;
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.MAX_ITEM_WANTED)]
public m_ItemsWanted_s[] m_ItemsWanted;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TASK_INFO_PLAYER
{
public uint m_ulPlayersToKill;
public uint m_ulPlayersKilled;
public Kill_Player_Requirements m_Requirements;
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.MAX_PLAYER_WANTED)]
public TASK_INFO_PLAYER[] m_PlayerWanted;
// abase::vector<wchar_t*> m_TaskCharArr (assumed 3 pointers: start, finish, end_of_storage; 32-bit layout)
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct abase_vector_wchar_t_ptr
{
public uint _start;
public uint _finish;
public uint _end_of_storage;
}
public abase_vector_wchar_t_ptr m_TaskCharArr;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Task_Award_Preview
{
public uint m_ulGold;
public uint m_ulExp;
public uint m_ulRealmExp;
public uint m_ulSP;
public bool m_bHasItem;
public bool m_bItemKnown;
public uint m_ulItemTypes;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.MAX_ITEM_AWARD)]
public uint[] m_ItemsId;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.MAX_ITEM_AWARD)]
public uint[] m_ItemsNum;
public int m_iForceActivity;
public int m_iForceContrib;
public int m_iForceRepu;
}
#endif
public class TaskInterfaceConstants
{
// Task Prerequisite Error Code
public const int TASK_PREREQU_FAIL_INDETERMINATE = 1;
public const int TASK_PREREQU_FAIL_NOT_ROOT = 2;
public const int TASK_PREREQU_FAIL_SAME_TASK = 3;
public const int TASK_PREREQU_FAIL_NO_SPACE = 4;
public const int TASK_PREREQU_FAIL_FULL = 5;
public const int TASK_PREREQU_FAIL_CANT_REDO = 6;
public const int TASK_PREREQU_FAIL_BELOW_LEVEL = 7;
public const int TASK_PREREQU_FAIL_ABOVE_LEVEL = 8;
public const int TASK_PREREQU_FAIL_NO_ITEM = 9;
public const int TASK_PREREQU_FAIL_BELOW_REPU = 10;
public const int TASK_PREREQU_FAIL_CLAN = 11;
public const int TASK_PREREQU_FAIL_WRONG_GENDER = 12;
public const int TASK_PREREQU_FAIL_NOT_IN_OCCU = 13;
public const int TASK_PREREQU_FAIL_WRONG_PERIOD = 14;
public const int TASK_PREREQU_FAIL_PREV_TASK = 15;
public const int TASK_PREREQU_FAIL_MAX_RCV = 16;
public const int TASK_PREREQU_FAIL_NO_DEPOSIT = 17;
public const int TASK_PREREQU_FAIL_NO_TASK = 18;
public const int TASK_PREREQU_FAIL_NOT_CAPTAIN = 19;
public const int TASK_PREREQU_FAIL_ILLEGAL_MEM = 20;
public const int TASK_PREREQU_FAIL_WRONG_TIME = 21;
public const int TASK_PREREQU_FAIL_NO_SUCH_SUB = 22;
public const int TASK_PREREQU_FAIL_MUTEX_TASK = 23;
public const int TASK_PREREQU_FAIL_NOT_IN_ZONE = 24;
public const int TASK_PREREQU_FAIL_WRONG_SUB = 25;
public const int TASK_PREREQU_FAIL_OUTOF_DIST = 26;
public const int TASK_PREREQU_FAIL_GIVEN_ITEM = 27;
public const int TASK_PREREQU_FAIL_LIVING_SKILL = 28;
public const int TASK_PREREQU_FAIL_SPECIAL_AWARD = 29;
public const int TASK_PREREQU_FAIL_GM = 30;
public const int TASK_PREREQU_FAIL_GLOBAL_KEYVAL = 31;
public const int TASK_PREREQU_FAIL_SHIELD_USER = 32;
public const int TASK_PREREQU_FAIL_ALREADY_HAS_PQ = 33;
public const int TASK_PREREQU_FAIL_MAX_ACC_CNT = 34;
public const int TASK_PREREQU_FAIL_RMB_NOT_ENOUGH = 35;
public const int TASK_PREREQU_FAIL_NOT_COUPLE = 36;
public const int TASK_PREREQU_FAIL_ERR_CHAR_TIME = 37;
public const int TASK_PREREQU_FAIL_NOT_IVTRSLOTNUM = 38; // version 81
public const int TASK_PREREQU_FAIL_BELOW_FACTION_CONTRIB = 39; // version 87
public const int TASK_PREREQU_FAIL_BELOW_RECORD_TASKS_NUM = 40; // version 91
public const int TASK_PREREQU_FAIL_OVER_RECEIVE_PER_DAY = 41;
public const int TASK_PREREQU_FAIL_TRANSFORM_MASK = 42;
public const int TASK_PREREQU_FAIL_FORCE = 43;
public const int TASK_PREREQU_FAIL_FORCE_REPUTATION = 44;
public const int TASK_PREREQU_FAIL_FORCE_CONTRIBUTION = 45;
public const int TASK_PREREQU_FAIL_EXP = 46;
public const int TASK_PREREQU_FAIL_SP = 47;
public const int TASK_PREREQU_FAIL_FORCE_AL = 48;
public const int TASK_PREREQU_FAIL_WEDDING_OWNER = 49;
public const int TASK_PREREQU_FAIL_CROSSSERVER_NO_ACOUNT_LIMIT = 50;
public const int TASK_PREREQU_FAIL_CROSSSERVER_NO_MARRIAGE = 51;
public const int TASK_PREREQU_FAIL_CROSSSERVER_NO_FORCE = 52;
public const int TASK_PREREQU_FAIL_KING = 53;
public const int TASK_PREREQU_FAIL_IN_TEAM = 54;
public const int TASK_PREREQU_FAIL_TITLE = 55;
public const int TASK_PREREQU_FAIL_HISTORYSTAGE = 56;
public const int TASK_PREREQU_FAIL_NO_GIFTCARD_TASK = 57;
public const int TASK_PREREQU_FAIL_BELOW_REINCARNATION = 57;
public const int TASK_PREREQU_FAIL_ABOVE_REINCARNATION = 58;
public const int TASK_PREREQU_FAIL_BELOW_REALMLEVEL = 59;
public const int TASK_PREREQU_FAIL_ABOVE_REALMLEVEL = 60;
public const int TASK_PREREQU_FAIL_REALM_EXP_FULL = 61;
public const int TASK_PREREQU_FAIL_CARD_COUNT_COLLECTION = 62;
public const int TASK_PREREQU_FAIL_MAX_ROLE_CNT = 63;
public const int TASK_PREREQU_FAIL_CARD_COUNT_RANK = 64;
public const int TASK_PREREQU_FAIL_TASK_FORBID = 65;
public const int TASK_PREREQU_FAIL_NO_NAVIGATE_INSHPAED = 66;
public const int TASK_AWARD_FAIL_GIVEN_ITEM = 150;
public const int TASK_AWARD_FAIL_NEW_TASK = 151;
public const int TASK_AWARD_FAIL_REPUTATION = 152;
public const int TASK_AWARD_FAIL_GLOBAL_KEYVAL = 153;
public const int TASK_AWARD_FAIL_CROSSSERVER_NO_ACOUNT_LIMIT = 154;
public const int TASK_AWARD_FAIL_CROSSSERVER_NO_ACOUNT_STORAGE = 155;
public const int TASK_AWARD_FAIL_CROSSSERVER_NO_DIVORCE = 156;
public const int TASK_AWARD_FAIL_CROSSSERVER_NO_FACTION_RALATED = 157;
public const int TASK_AWARD_FAIL_CROSSSERVER_NO_FORCE_RALATED = 158;
public const int TASK_AWARD_FAIL_CROSSSERVER_NO_DIVIEND = 159;
public const int TASK_AWARD_FAIL_LEVEL_CHECK = 160;
// Task messages
public const int TASK_MSG_NEW = 1;
public const int TASK_MSG_SUCCESS = 2;
public const int TASK_MSG_FAIL = 3;
public const int TASK_ACTIVE_LIST_HEADER_LEN = 8;
public const int TASK_ACTIVE_LIST_MAX_LEN = 175;
public const int TASK_FINISHED_LIST_MAX_LEN = 2040;
public const int TASK_DATA_BUF_MAX_LEN = 32;
public const int TASK_FINISH_TIME_MAX_LEN = 1700;
public const int TASK_FINISH_COUNT_MAX_LEN = 730;
// 库任务 // Library tasks
public const int TASK_MAX_DELIVER_COUNT = 5;
public const int TASK_STORAGE_COUNT = 32;
public const int TASK_STORAGE_LEN = 10;
public const int TASK_STORAGE_WHELL_SCALE = 10000; // 10000.f originally
// 当前激活的任务列表缓冲区大小 // Current active task list buffer size
public const int TASK_ACTIVE_LIST_BUF_SIZE = (TASK_ACTIVE_LIST_MAX_LEN * TASK_DATA_BUF_MAX_LEN + TASK_ACTIVE_LIST_HEADER_LEN);
// 已完成的任务列表缓冲区大小 // Completed task list buffer size
public const int TASK_FINISHED_LIST_BUF_SIZE = 8192;
public const int TASK_FINISHED_LIST_BUF_SIZE_OLD = 4096;
// 任务全局数据大小 // Task global data size
public const int TASK_GLOBAL_DATA_SIZE = 256;
// 任务完成时间 // Task completion time
public const int TASK_FINISH_TIME_LIST_BUF_SIZE = 10240;
//任务完成次数 // Task completion count
public const int TASK_FINISH_COUNT_LIST_BUF_SIZE = 10240;
// 库任务 // Library tasks
public const int TASK_STORAGE_LIST_BUF_SIZE = 1024;
// Masks
public const int TASK_MASK_KILL_MONSTER = 0x00000001;
public const int TASK_MASK_COLLECT_ITEM = 0x00000002;
public const int TASK_MASK_TALK_TO_NPC = 0x00000004;
public const int TASK_MASK_REACH_SITE = 0x00000008;
public const int TASK_MASK_ANSWER_QUESTION = 0x00000010;
public const int TASK_MASK_TINY_GAME = 0x00000020;
public const int TASK_MASK_KILL_PQ_MONSTER = 0x00000040;
public const int TASK_MASK_KILL_PLAYER = 0x00000080;
public const int MAX_MONSTER_WANTED = 3; // 受ActiveTaskEntry大小限制,最大3 // Limited by ActiveTaskEntry size, max 3
public const int MAX_PLAYER_WANTED = MAX_MONSTER_WANTED;
public const int MAX_ITEM_WANTED = 10;
public const int MAX_ITEM_AWARD = 64;
public const int MAX_MONSTER_SUMMONED = 32; // 最大召唤出的怪物数量 // Maximum number of summoned monsters
public const int MAX_OCCUPATIONS = 12; // 职业 // Occupations
public const int TASK_MSG_CHANNEL_LOCAL = 0;
public const int TASK_MSG_CHANNEL_WORLD = 1;
public const int TASK_MSG_CHANNEL_BROADCAST = 9;
public const int TASK_TEAM_RELATION_MARRIAGE = 1;
public const int TASK_AWARD_MAX_CHANGE_VALUE = 255;
public const int TASK_AWARD_MAX_DISPLAY_VALUE = 64;
public const int TASK_AWARD_MAX_DISPLAY_EXP_CNT = 32; // 表达式的个数 // Number of expressions
public const int TASK_AWARD_MAX_DISPLAY_CHAR_LEN = 64; // 表达式的长度 // Length of expression
public const int TASK_WORLD_CONTRIBUTION_SPEND_PER_DAY = 30; // 免费玩家每日消费贡献度上限 // Daily contribution spend cap for free players
}
public class CECTaskInterface : TaskInterface
{
private CancellationTokenSource _cts;
public void Despose()
{
_cts?.Cancel();
_cts?.Dispose();
}
public int GetCurHistoryStageIndex()
{
return EC_Game.GetGameRun().GetCurStageIndex() + 1;
}
public uint GetObtainedGeneralCardCount()
{
return 0;
//return m_pHost ? m_pHost.GetGeneralCardData().GetObtainedCount() : 0;
}public uint GetObtainedGeneralCardCountByRank(int rank)
{
return 0;
//return m_pHost ? m_pHost.GetGeneralCardData().GetObtainedCount() : 0;
}
public bool HaveGotTitle(uint id_designation)
{
return true;
}
// public const int TASK_MAX_DELIVER_COUNT = 5;
// public const int TASK_STORAGE_COUNT = 32;
// public const int TASK_STORAGE_LEN = 10;
// public const float TASK_STORAGE_WHELL_SCALE = 10000;
//
// public const int TASK_ACTIVE_LIST_HEADER_LEN = 8;
// public const int TASK_ACTIVE_LIST_MAX_LEN = 175;
// public const int TASK_FINISHED_LIST_MAX_LEN = 2040;
// public const int TASK_DATA_BUF_MAX_LEN = 32;
// public const int TASK_FINISH_TIME_MAX_LEN = 1700;
// public const int TASK_FINISH_COUNT_MAX_LEN = 730;
// µ±Ç°¼¤»îµÄÈÎÎñÁÐ±í»º³åÇø´óС
public int TASK_ACTIVE_LIST_BUF_SIZE =>
(TaskInterfaceConstants.TASK_ACTIVE_LIST_MAX_LEN * TaskInterfaceConstants.TASK_DATA_BUF_MAX_LEN + TaskInterfaceConstants.TASK_ACTIVE_LIST_HEADER_LEN);
CECHostPlayer m_pHost;
ActiveTaskList m_pActiveListBuf; // Active task list buffer
// private byte[] m_pActiveListRawBuf; // raw buffer backing for active list (converted from C++)
byte[] m_pFinishedListBuf; // Finished task list buffer
byte[] m_pFinishedTimeListBuf; // Finished time list buffer
byte[] m_pFinishedCountListBuf;// Finished count list buffer
byte[] m_pStorageTaskListBuf; // Storage tasks list buffer
private Dictionary<int, bool> m_TasksToConfirm = new Dictionary<int, bool>();
private readonly Dictionary<uint, bool> m_emotionTask = new System.Collections.Generic.Dictionary<uint, bool>();
private bool m_bForceNavigateFinish;
private int m_tmFinishDlgShown;
public CECTaskInterface()
{
}
public CECTaskInterface(CECHostPlayer pHost)
{
m_pHost = pHost;
m_pActiveListBuf = null;
m_pFinishedListBuf = null;
m_pFinishedTimeListBuf = null;
m_pFinishedCountListBuf = null;
m_pStorageTaskListBuf = null;
}
// Initialize object
public async UniTask<bool> Init(byte[] pActiveListBuf, int iActiveListLen, byte[] pFinishedListBuf,
int iFinishedListLen, byte[] pFinishedTimeListBuf, int iFinishedTimeListLen,
byte[] pFinishedCountListBuf, int iFinishedCountListLen, byte[] pStorageTaskListBuf, int iStorageTaskListLen)
{
_cts = new CancellationTokenSource();
// basic argument check (converted from ASSERT)
if (pActiveListBuf == null || pFinishedListBuf == null || pFinishedTimeListBuf == null || pFinishedCountListBuf == null)
{
return false;
}
// SceneLoader.SceneLoadProcess = SceneLoadProcess.Loading;
// SceneLoader.LoadingProgress = 0;
LoadingSceneController.Instance.ShowLoadingScene(true);
m_pActiveListBuf = new ActiveTaskList();
m_pActiveListBuf.ReadFromBuffer(pActiveListBuf);
m_pFinishedListBuf = new byte[TaskInterfaceConstants.TASK_FINISHED_LIST_BUF_SIZE];
{
int copy = Mathf.Min(iFinishedListLen, TaskInterfaceConstants.TASK_FINISHED_LIST_BUF_SIZE);
if (copy > 0) System.Buffer.BlockCopy(pFinishedListBuf, 0, m_pFinishedListBuf, 0, copy);
}
m_pFinishedTimeListBuf = new byte[TaskInterfaceConstants.TASK_FINISH_TIME_LIST_BUF_SIZE];
{
int copy = Mathf.Min(iFinishedTimeListLen, TaskInterfaceConstants.TASK_FINISH_TIME_LIST_BUF_SIZE);
if (copy > 0) System.Buffer.BlockCopy(pFinishedTimeListBuf, 0, m_pFinishedTimeListBuf, 0, copy);
}
m_pFinishedCountListBuf = new byte[TaskInterfaceConstants.TASK_FINISH_COUNT_LIST_BUF_SIZE];
{
int copy = Mathf.Min(iFinishedCountListLen, TaskInterfaceConstants.TASK_FINISH_COUNT_LIST_BUF_SIZE);
if (copy > 0) System.Buffer.BlockCopy(pFinishedCountListBuf, 0, m_pFinishedCountListBuf, 0, copy);
}
m_pStorageTaskListBuf = new byte[TaskInterfaceConstants.TASK_STORAGE_LIST_BUF_SIZE];
{
int copy = Mathf.Min(iStorageTaskListLen, TaskInterfaceConstants.TASK_STORAGE_LIST_BUF_SIZE);
if (copy > 0) System.Buffer.BlockCopy(pStorageTaskListBuf, 0, m_pStorageTaskListBuf, 0, copy);
}
// Clear rest buffer // 清理剩余缓冲区
// No-op in C# because arrays are zero-initialized.
ATaskTemplMan pTaskMan = GetTaskTemplMan();
pTaskMan.Release();
LoadingSceneController.Instance.ShowLoadingScene(true);
LoadingSceneController.Instance.UpdateUI(0f);
LoadingSceneController.Instance.SetLoadingText("Loading Tasks From Pack");
bool result = await MoveShopDataToPersistentPath("data/tasks.data");
if (!result)
{
BMLogger.LogError($"CECTaskInterface: Failed to move tasks data to persistent path");
return false;
}
string task_data_path = Path.Combine(Application.persistentDataPath, "data/tasks.data");
await pTaskMan.LoadTasksFromPack(task_data_path, true, (x) =>
{
LoadingSceneController.Instance.SetProgress(x);
}, _cts.Token);
#if UNITY_ANDROID && !UNITY_EDITOR
result = await MoveShopDataToPersistentPath("data/tasks.data");
if (!result)
{
BMLogger.LogError($"CECTaskInterface: Failed to move tasks data to persistent path");
return false;
}
var task_npc_path = Path.Combine(Application.persistentDataPath, "data/task_npc.data");
#else
var task_npc_path = Path.Combine(Application.streamingAssetsPath, "data/task_npc.data");
#endif
await pTaskMan.LoadNPCInfoFromPack(task_npc_path);
#if UNITY_ANDROID && !UNITY_EDITOR
result = await MoveShopDataToPersistentPath("data/tasks.data");
if (!result)
{
BMLogger.LogError($"CECTaskInterface: Failed to move tasks data to persistent path");
return false;
}
var dyn_tasks_path = Path.Combine(Application.persistentDataPath, "data/dyn_tasks.data");
#else
var dyn_tasks_path = Path.Combine(Application.streamingAssetsPath, "data/dyn_tasks.data");
#endif
await pTaskMan.VerifyDynTasksPack(dyn_tasks_path);
InitActiveTaskList();
SceneLoader.SceneLoadProcess = SceneLoadProcess.EndLoading;
LoadingSceneController.Instance.ShowLoadingScene(false);
m_bForceNavigateFinish = false;
return true;
}
public async UniTask<bool> MoveShopDataToPersistentPath(string shopDataPath)
{
BMLogger.Log($"CECTaskInterface: Moving shop data to persistent path: {shopDataPath}");
var destinationPath = Path.Combine(UnityEngine.Application.persistentDataPath, shopDataPath);
var sourcePath = Path.Combine(UnityEngine.Application.streamingAssetsPath, shopDataPath);
if (File.Exists(destinationPath))
{
return true;
}
var destinationDirectory = Path.GetDirectoryName(destinationPath);
Directory.CreateDirectory(destinationDirectory);
UnityWebRequest request = UnityWebRequest.Get(sourcePath);
await request.SendWebRequest();
if (request.result != UnityWebRequest.Result.Success)
{
BMLogger.LogError($"CECTaskInterface: Failed to move element file to persistent path: {request.error}");
return false;
}
File.WriteAllBytes(destinationPath, request.downloadHandler.data);
BMLogger.Log($"CECTaskInterface: Successfully moved element file to persistent path: {destinationPath}");
return true;
}
public void CheckPQEnterWorldInit()
{
// TODO: implement PQ enter-world init if needed
}
public static void WriteLog(int nPlayerId, int nTaskId, int nType, string szLog)
{
//do something?
}
public bool IsDeliverLegal()
{
return !m_pHost.IsTrading() && m_pHost.GetBoothState() == 0 && !m_pHost.IsDead();
}
public int GetCommonItemCount(uint ulCommonItem)
{
// CECInventory pPack = m_pHost.GetPack();
// return pPack != null ? pPack.GetItemTotalNum((int)ulCommonItem) : 0;
var inv = m_pHost?.GetInventory(InventoryConst.IVTRTYPE_PACK);
return inv != null ? inv.GetItemTotalNum((int)ulCommonItem) : 0;
}
public int GetTaskItemCount(uint ulTaskItem)
{
// CECInventory* pPack = m_pHost.GetTaskPack();
// return pPack ? pPack.GetItemTotalNum((int)ulTaskItem) : 0;
var inv = m_pHost?.GetInventory(InventoryConst.IVTRTYPE_TASKPACK);
return inv != null ? inv.GetItemTotalNum((int)ulTaskItem) : 0;
}
public ATaskTemplMan GetTaskTemplMan()
{
return EC_Game.GetTaskTemplateMan();
}
public ActiveTaskList GetActiveTaskList()
{
return m_pActiveListBuf;
}
// private void InitActiveTaskList()
// {
// ActiveTaskList pLst = GetActiveTaskList();
// if (pLst == null) return;
//
// ATaskTemplMan pMan = GetTaskTemplMan();
// if (pMan == null) return;
//
// // reset counters
// pLst.m_uTopShowTaskCount = 0;
// pLst.m_uTopHideTaskCount = 0;
// pLst.m_uTitleTaskCount = 0;
//
// byte i = 0;
// while (i < pLst.m_uTaskCount)
// {
// ActiveTaskEntry entry = pLst.m_TaskEntries[i];
// if (entry == null)
// {
// i++;
// continue;
// }
//
// // repair sibling linkage
// if (entry.m_NextSblIndex != (char)0xff)
// {
// ActiveTaskEntry entryNextSbl = pLst.m_TaskEntries[entry.m_NextSblIndex];
// if (entryNextSbl == null || entryNextSbl.m_PrevSblIndex != (char)i)
// {
// entry.m_NextSblIndex = (char)0xff;
// }
// }
//
// // resolve template for top-level entries; children left unresolved in C#
// if (entry.m_ParentIndex == (char)0xff)
// {
// // entry.m_ulTemplAddr = 0u;
// entry.m_ulTemplAddr = pMan.GetTopTaskByID(entry.m_ID) != null ? 1u : 0u;
//
// ATaskTempl topTempl = pMan.GetTopTaskByID(entry.m_ID);
// if (topTempl != null)
// {
// if (topTempl.m_FixedData.m_bHidden)
// pLst.m_uTopHideTaskCount++;
// else if (topTempl.m_FixedData.m_bDisplayInTitleTaskUI)
// pLst.m_uTitleTaskCount++;
// else
// pLst.m_uTopShowTaskCount++;
// }
// }
// else
// {
// entry.m_ulTemplAddr = 0u;
// }
//
// // cap template best-effort (no pointer in managed)
// if (entry.m_uCapTaskId != 0)
// {
// ATaskTempl cap = pMan.GetTopTaskByID(entry.m_uCapTaskId);
// entry.m_ulCapTemplAddr = 0u;
// if (cap == null)
// {
// entry.m_uCapTaskId = 0;
// }
// }
// else
// {
// entry.m_ulCapTemplAddr = 0u;
// }
//
// i++;
// }
//
// // approximate used count
// pLst.m_uUsedCount = pLst.m_uTaskCount;
// }
public void InitActiveTaskList()
{
ActiveTaskList pLst = GetActiveTaskList();
FinishedTaskList pFnsh = GetFinishedTaskList();
// TaskFinishTimeList* pFnshTime = static_cast<TaskFinishTimeList*>(GetFinishedTimeList());
TaskFinishTimeList pFnshTime = new TaskFinishTimeList(GetFinishedTimeList());
TaskFinishCountList pFnshCount = new TaskFinishCountList();
pFnshCount.ReadFromBytes(GetFinishedCntList());
ActiveTaskEntry[] pEntries = pLst.m_TaskEntries;
ATaskTemplMan pMan = GetTaskTemplMan();
if (!CheckVersion() || !pLst.IsValid() || !pFnsh.IsValid() || !pFnshTime.IsValid())
{
pLst.RemoveAll();
pFnsh.RemoveAll();
pFnshTime.RemoveAll();
// TaskInterface::WriteLog(0, 0, 0, "InitLst, list is invalid");
}
if(!pFnshCount.IsValid())
{
pFnshCount.RemoveAll();
// TaskInterface::WriteLog(0, 0, 0, "InitLst, finish count list is invalid");
}
if (pFnsh.m_FnshHeader.m_Version == 0){
List<FnshedTaskEntryOld> list_old = new ();
// list_old.reserve(pFnsh->m_FnshHeader.m_uTaskCount);
list_old.Capacity = pFnsh.m_FnshHeader.m_uTaskCount; // C# equivalent of reserve
// FnshedTaskListOld* pListOld = (FnshedTaskListOld*)pFnsh;
FnshedTaskListOld pListOld = new FnshedTaskListOld(pFnsh.m_Buf);
for (int i = 0; i < pFnsh.m_FnshHeader.m_uTaskCount; i++)
{
list_old.Add(pListOld.m_aTaskList[i]);
}
var FnshHeader = pFnsh.m_FnshHeader;
FnshHeader.m_Version = 1;
pFnsh.m_FnshHeader = FnshHeader;
for (int i = 0; i < pFnsh.m_FnshHeader.m_uTaskCount; i++)
{
pFnsh.m_aTaskList[i].m_uTaskId = (ushort)(list_old[i].m_uTaskId & 0x7fff);
pFnsh.m_aTaskList[i].m_Mask = (byte)(list_old[i].m_uTaskId >> 15);
}
}
#if _TASK_CLIENT
// Debug output of finished tasks, for developer use -> not converted to C#
// FILE* fp = fopen("logs\\Tasks.log", "wb");
//
// if (fp)
// {
// unsigned short magic = 0xfeff;
// fwrite(&magic, sizeof(magic), 1, fp);
//
// for (unsigned long n = 0; n < pFnsh->m_FnshHeader.m_uTaskCount; n++)
// {
// ATaskTempl* pTempl = GetTaskTemplMan()->GetTaskTemplByID(pFnsh->m_aTaskList[n].m_uTaskId);
//
// fwprintf(
// fp,
// L"task = %d, name = %s\r\n",
// pFnsh->m_aTaskList[n].m_uTaskId,
// pTempl ? pTempl->GetName() : L"");
// }
//
// for (unsigned short m = 0; m < pFnshTime->m_uCount; m++)
// {
// ATaskTempl* pTempl = GetTaskTemplMan()->GetTaskTemplByID(pFnshTime->m_aList[m].m_uTaskId);
// unsigned long his_time = pFnshTime->m_aList[m].m_ulTimeMark;
// his_time -= unsigned long(TaskInterface::GetTimeZoneBias() * 60);
//
// if ((long)(his_time) < 0)
// his_time = 0;
//
// tm t = *gmtime((time_t*)&his_time);
// wchar_t buf[256];
// swprintf(buf, L"%d-%02d-%02d-%02d-%02d-%02d", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
//
// fwprintf(
// fp,
// L"task = %d, deliver time = %s, name = %s\r\n",
// pFnshTime->m_aList[m].m_uTaskId,
// buf,
// pTempl ? pTempl->GetName() : L"");
// }
//
// fclose(fp);
// }
if (!GetTaskTemplMan().IsDynTasksVerified())
{
// ȡ̬ʱǩ
_notify_svr(this, ClientNotificationConstants.TASK_CLT_NOTIFY_DYN_TIMEMARK, 0);
}
else
{
// Ϣ
GetTaskTemplMan().ClearSpecailAward();
_notify_svr(this, ClientNotificationConstants.TASK_CLT_NOTIFY_SPECIAL_AWARD, 0);
// ȡֿ
_notify_svr(this, ClientNotificationConstants.TASK_CLT_NOTIFY_STORAGE, 0);
}
#else
uint ulCurTime = GetCurTime();
const ATaskTempl pTempl;
pLst.m_Version = TASK_ENTRY_DATA_CUR_VER;
bool bTimeMarkUpdated = pLst.IsTimeMarkUpdate();
pLst.m_uTopShowTaskCount = 0;
pLst.m_uTopHideTaskCount = 0;
pLst.m_uTitleTaskCount = 0;
#endif
// unsigned char i = 0;
for (int i=0; i < pLst.m_uTaskCount; i++)
{
ActiveTaskEntry entry = pEntries[i];
if (!entry.IsValid((char)i, (char)pLst.m_uTaskCount))
{
pLst.RemoveAll();
// TaskInterface::WriteLog(0, 0, 0, "InitLst, active list is invalid");
break;
}
}
int i1 = 0;
while (i1 < pLst.m_uTaskCount)
{
ActiveTaskEntry entry = pEntries[i1];
if (entry.m_NextSblIndex != 0xff) {
ActiveTaskEntry entryNextSbl = pEntries[entry.m_NextSblIndex];
if (entryNextSbl.m_PrevSblIndex != i1) entry.m_NextSblIndex = (char)0xff;
}
if (entry.m_ParentIndex == 0xff)
entry.m_ulTemplAddr = pMan.GetTopTaskByID(entry.m_ID).m_FixedData.m_ID;
else
{
ATaskTempl pParent = pLst.m_TaskEntries[entry.m_ParentIndex].GetTempl();
if (pParent != null)
entry.m_ulTemplAddr = pParent.GetConstSubById(entry.m_ID).m_FixedData.m_ID;
else
entry.m_ulTemplAddr = 0;
}
#if !_TASK_CLIENT
// if (entry.m_ulTemplAddr != 0)
// {
// // TaskInterface::WriteLog(0, entry.m_ID, 0, "InitLst, Cant Find Task");
//
// pLst.ClearTask(this, entry, false);
// continue;
// }
//
// // ûɣ
// if (entry.m_ChildIndex == 0xff
// && entry.GetTempl().m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMNone
// && !entry.IsFinished())
// {
// // TaskInterface::WriteLog(0, entry.m_ID, 0, "InitLst, Task is Impossible");
// pLst.ClearTask(this, entry, false);
// continue;
// }
#endif
if (entry.m_uCapTaskId != 0)
{
entry.m_ulCapTemplAddr = GetTaskTemplMan().GetTopTaskByID(entry.m_uCapTaskId).m_FixedData.m_ID;
if (entry.m_ulCapTemplAddr != 0)
{
entry.m_uCapTaskId = 0;
// TaskInterface::WriteLog(0, entry.m_uCapTaskId, 0, "InitLst, Cant Find CapTask");
}
}
else
entry.m_ulCapTemplAddr = 0;
#if !_TASK_CLIENT
// if (bTimeMarkUpdated != 0)
// {
// var pTempl = entry.GetTempl();
//
// if (!pTempl.m_FixedData.m_bAbsTime && !pTempl.m_FixedData.m_bPQTask && !pTempl.m_FixedData.m_bPQSubTask)
// entry.m_ulTaskTime = ulCurTime - entry.m_ulTaskTime;
// }
#endif
#if !_TASK_CLIENT
// ʼеءʾ
// if (entry.m_ParentIndex == 0xff)
// {
// if (entry.GetTempl()->m_bHidden)
// pLst->m_uTopHideTaskCount++;
// else if (entry.GetTempl()->m_bDisplayInTitleTaskUI)
// pLst->m_uTitleTaskCount++;
// else pLst->m_uTopShowTaskCount++;
//
// }
#endif
i1++;
}
#if !_TASK_CLIENT
// pLst->SetTimeMarkUpdate();
// pLst->UpdateTaskMask(*GetTaskMask());
#endif
pLst.UpdateUsedCount();
}
public bool CheckTaskForbid(uint task_id){ return false; }
public bool IsAtCrossServer()
{
// TODO: cross server
// return CECCrossServer.Instance().IsOnSpecialServer();
return false;
}
public uint GetPlayerLevel()
{
return (uint)m_pHost.GetBasicProps().iLevel;
}
public uint GetGoldNum()
{
return (uint)m_pHost.GetMoneyAmount();
}
public int GetGlobalValue(int lKey)
{
return EC_Game.GetGameRun().GetCommonData(lKey);
}
// C++: long CECTaskInterface::GetGlobalValue(long lKey)
public long GetGlobalValue(long key)
{
// NOTE: Engine exposes only int common data; cast to long
return EC_Game.GetGameRun().GetCommonData((int)key);
}
public byte GetShapeMask()
{
return m_pHost.GetShapeMask();
}
public int GetPos(float[] pos)
{
A3DVECTOR3 vPos = m_pHost.GetPos();
if (pos != null && pos.Length >= 3)
{
pos[0] = vPos.x;
pos[1] = vPos.y;
pos[2] = vPos.z;
}
var world = World.CECWorld.Instance;
//TODO: world.GetInstanceID()
return world != null ? 0 /*world.GetInstanceID()*/ : 0;
}
public bool CheckSimpleTaskFinshConditon(uint task_id)
{
ATaskTempl pTempl = GetTaskTemplMan().GetTaskTemplByID(task_id);
if (pTempl == null) return false;
if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMSimpleClientTask && pTempl.m_FixedData.m_uiEmotion != 0)
{
if (m_emotionTask != null && m_emotionTask.TryGetValue(task_id, out bool finished))
return finished;
return false;
}
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMSimpleClientTaskForceNavi)
{
return GetForceNavigateFinishFlag();
}
return true;
}
public int GetFactionConsumeContrib()
{
return m_pHost.GetContribInfo().consume_contrib;
}
public int GetFactionExpContrib()
{
return m_pHost.GetContribInfo().exp_contrib;
}
public bool HasTask(uint ulTaskId)
{
ActiveTaskList pLst = GetActiveTaskList();
if (pLst == null) return false;
for (int i = 0; i < pLst.m_uTaskCount; i++)
{
ActiveTaskEntry entry = pLst.m_TaskEntries[i];
if ((uint)entry.m_ID == ulTaskId && entry.GetTempl() != null)
return true;
}
return false;
}
// ===== Additional TaskInterface methods ported from C++ =====
public uint GetMaxHistoryLevel()
{
// TODO: Use reincarnation tome when available (GetReincarnationTome().max_level)
return (uint)m_pHost.GetBasicProps().iLevel;
}
public uint GetReincarnationCount()
{
// TODO: Hook to host reincarnation count when available
return 0u;
}
public bool IsRealmExpFull()
{
// TODO: Implement via host API when available
return false;
}
public uint GetReputation()
{
// TODO: Expose reputation on host; return 0 for now
return 0u;
}
public int GetFactionRole()
{
// TODO: Expose faction role id on host
return 0;
}
public bool IsInFaction(uint factionId)
{
// TODO: Expose faction id on host; cannot verify now
return false;
}
public bool IsMale()
{
return m_pHost.m_iGender == GENDER.GENDER_MALE;
}
public uint GetPlayerOccupation()
{
return (uint)m_pHost.m_iProfession;
}
public uint GetCurPeriod()
{
// Maps to "second level" in basic props (realm level)
return (uint)m_pHost.GetBasicProps().iLevel2;
}
public bool IsGM()
{
// TODO: Expose GM flag on host
return false;
}
public bool IsShieldUser()
{
// TODO: Expose ShieldUser flag on host
return false;
}
public bool IsMarried()
{
// TODO: Expose spouse id on host
return false;
}
public bool IsWeddingOwner()
{
// TODO: Expose wedding scene info and compare with host id
return false;
}
public uint GetInvEmptySlot()
{
var inv = m_pHost?.GetInventory(InventoryConst.IVTRTYPE_PACK);
return inv != null ? (uint)inv.GetEmptySlotNum() : 0u;
}
public int GetFactionContrib()
{
return m_pHost.GetContribInfo().cumulate_contrib;
}
public int GetForce()
{
// TODO: Expose force id on host
return 0;
}
public int GetForceReputation()
{
// TODO: Expose force reputation on host
return 0;
}
public int GetForceContribution()
{
// TODO: Expose force contribution on host
return 0;
}
public int GetExp()
{
return m_pHost.GetBasicProps().iExp;
}
public int GetSP()
{
return m_pHost.GetBasicProps().iSP;
}
public int GetForceActivityLevel()
{
// TODO: Expose force activity level on host
return -1;
}
public bool IsKing()
{
// TODO: Expose king status on host
return false;
}
public bool IsInTeam()
{
// TODO: Implement team system and check membership
return false;
}
public uint GetAccountTotalCash()
{
// TODO: Expose account total cash on host/session
return 0u;
}
#if _TASK_CLIENT
// Prepare award preview based on task and state
public void GetTaskAwardPreview(uint ulTaskId, ref Task_Award_Preview p, bool bActiveTask=true)
{
// Zero and init output
p = default;
if (p.m_ItemsId == null) p.m_ItemsId = new uint[TaskInterfaceConstants.MAX_ITEM_AWARD];
if (p.m_ItemsNum == null) p.m_ItemsNum = new uint[TaskInterfaceConstants.MAX_ITEM_AWARD];
// Gather context
ActiveTaskList pLst = GetActiveTaskList();
uint ulCurTime = GetCurTime();
ATaskTempl pTempl = null;
AWARD_DATA ad = default;
uint ulMulti = 1u;
// Resolve template and dynamic award when active
if (bActiveTask && pLst != null)
{
for (int i = 0; i < pLst.m_uTaskCount; i++)
{
ActiveTaskEntry CurEntry = pLst.m_TaskEntries[i];
if (CurEntry.m_ID != ulTaskId || CurEntry.m_ulTemplAddr == 0) continue;
pTempl = CurEntry.GetTempl();
// TODO: CalcAwardData/CalcAwardMulti not implemented yet in C#; use fixed success award and multiplier 1
if (pTempl != null)
{
ad = pTempl.m_FixedData.m_Award_S;
ulMulti = 1u;
}
if (ulMulti == 0u) return;
break;
}
}
// Fallback to top template when inactive
else
{
pTempl = GetTaskTemplMan().GetTopTaskByID(ulTaskId);
if (pTempl == null) return;
ad = pTempl.m_FixedData.m_Award_S;
}
// Fill basic award fields
unchecked
{
p.m_ulGold = ad.m_ulGoldNum * ulMulti;
p.m_ulExp = ad.m_ulExp * ulMulti;
p.m_ulSP = ad.m_ulSP * ulMulti;
}
p.m_iForceActivity = ad.m_iForceActivity;
p.m_iForceContrib = ad.m_iForceContribution;
p.m_iForceRepu = ad.m_iForceReputation;
p.m_ulRealmExp = ad.m_ulRealmExp;
// Apply level coefficient if configured (coefficient table not available; skip scaling)
if (ad.m_bUseLevCo)
{
uint ulLev = GetPlayerLevel();
if (ulLev == 0) ulLev = 1;
uint ulUpper = 0;
if (pTempl != null && pTempl.GetTopTask() != null)
ulUpper = pTempl.GetTopTask().m_FixedData.m_ulPremise_Lev_Max;
if (ulUpper != 0 && ulLev > ulUpper) ulLev = ulUpper;
// NOTE: Original code multiplies by _lev_co[ulLev-1]. Not available here; keep as-is.
}
// Candidate items handling
if (ad.m_ulCandItems == 1 && ad.m_CandItems != null && ad.m_CandItems.Length > 0)
{
p.m_bHasItem = true;
p.m_bItemKnown = true;
AWARD_ITEMS_CAND ic = ad.m_CandItems[0];
if (ic.m_bRandChoose)
{
p.m_bItemKnown = false;
}
else
{
for (int j = 0; j < ic.m_ulAwardItems; j++)
{
ITEM_WANTED wi = ic.m_AwardItems[j];
if (!wi.m_bCommonItem) continue;
else if (wi.m_fProb != 1.0f)
{
p.m_bItemKnown = false;
break;
}
else
{
// Period conversion not implemented; assume valid
if (p.m_ulItemTypes < TaskInterfaceConstants.MAX_ITEM_AWARD)
{
p.m_ItemsId[p.m_ulItemTypes] = wi.m_ulItemTemplId;
p.m_ItemsNum[p.m_ulItemTypes] = wi.m_ulItemNum;
p.m_ulItemTypes++;
}
}
}
}
}
else if (ad.m_ulCandItems > 1)
{
p.m_bHasItem = true;
}
// Done
return;
}
public uint GetTaskCount()
{
ActiveTaskList pLst = GetActiveTaskList();
uint ulCount = 0;
if (pLst == null) return 0u;
for (int i = 0; i < pLst.m_uTaskCount; i++)
{
ActiveTaskEntry CurEntry = pLst.m_TaskEntries[i];
ATaskTempl pTempl = CurEntry.GetTempl();
if (pTempl != null
&& !pTempl.m_FixedData.m_bDisplayInTitleTaskUI
&& CurEntry.m_ParentIndex == (char)0xff)
{
if (!pTempl.m_FixedData.m_bHidden || pTempl.m_FixedData.m_bShowPrompt)
{
ulCount++;
}
}
}
return ulCount;
}
public uint GetTaskId(uint ulIndex)
{
ActiveTaskList pLst = GetActiveTaskList();
byte uTopCount = 0;
int uCount = 0;
if (pLst == null) return 0u;
while (uCount < pLst.m_uTaskCount)
{
ActiveTaskEntry CurEntry = pLst.m_TaskEntries[uCount];
ATaskTempl pTempl = CurEntry.GetTempl();
if (pTempl != null
&& !pTempl.m_FixedData.m_bDisplayInTitleTaskUI
&& CurEntry.m_ParentIndex == (char)0xff)
{
if (!pTempl.m_FixedData.m_bHidden || pTempl.m_FixedData.m_bShowPrompt)
{
if (ulIndex == uTopCount)
return CurEntry.m_ID;
else
uTopCount++;
}
}
uCount++;
}
return 0u;
}
public uint CanDeliverTask(uint ulTaskId)
{
ATaskTempl pTempl = GetTaskTemplMan().GetTopTaskByID(ulTaskId);
if (pTempl == null) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_NO_TASK;
if (!IsDeliverLegal()) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_INDETERMINATE;
// return pTempl.CheckPrerequisite(this, static_cast<ActiveTaskList*>(GetActiveTaskList()), GetCurTime(), true, true, false);
return pTempl.CheckPrerequisite(this, GetActiveTaskList(), GetCurTime(), true, true, false);
}
public bool CanDeliverCommonItem(uint ulTypes)
{
return m_pHost.GetPack().GetEmptySlotNum() >= (int)(ulTypes);
}
public bool CanDeliverTaskItem(uint ulTypes)
{
return m_pHost.GetTaskPack().GetEmptySlotNum() >= (int)ulTypes;
}
public void ShowPunchBagMessage(bool bSucced,bool bMax,uint MonsterTemplID,int dps,int dph)
{
// TODO : implement UI message box
// CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan();
//
// if (pGameUI == NULL) return;
//
// elementdataman *pDataMan = g_pGame->GetElementDataMan();
//
// DATA_TYPE dt;
// MONSTER_ESSENCE *pMonster = (MONSTER_ESSENCE *)pDataMan->get_data_ptr(MonsterTemplID, ID_SPACE_ESSENCE, dt);
//
// ACString strNpcName;
// if( dt == DT_MONSTER_ESSENCE )
// {
// if( pMonster)
// strNpcName = pMonster->name;
// }
//
// ACString str;
// if (!bSucced)
// {
// str.Format(pGameUI->GetStringFromTable(303),strNpcName);
// pGameUI->MessageBox("",str,MB_OK,A3DCOLORRGBA(255, 255, 255, 160));
// }
//
// else if (bMax)
// {
// str.Format(pGameUI->GetStringFromTable(304),dph);
// pGameUI->MessageBox("",str,MB_OK,A3DCOLORRGBA(255, 255, 255, 160));
// }
// else
// {
// str.Format(pGameUI->GetStringFromTable(305),dph);
// pGameUI->MessageBox("",str,MB_OK,A3DCOLORRGBA(255, 255, 255, 160));
// }
}
#endif
private bool GetForceNavigateFinishFlag()
{
return m_bForceNavigateFinish;
}
public void GetTaskStateInfo(uint ulTaskId, ref Task_State_info pInfo, bool bActiveTask=true)
{
// 清零并准备输出结构 // Zero and prepare output struct
pInfo = default;
if (pInfo.m_MonsterWanted == null)
pInfo.m_MonsterWanted = new Task_State_info.m_MonsterWanted_s[TaskInterfaceConstants.MAX_MONSTER_WANTED];
if (pInfo.m_ItemsWanted == null)
pInfo.m_ItemsWanted = new Task_State_info.m_ItemsWanted_s[TaskInterfaceConstants.MAX_ITEM_WANTED];
if (pInfo.m_PlayerWanted == null)
pInfo.m_PlayerWanted = new Task_State_info.TASK_INFO_PLAYER[TaskInterfaceConstants.MAX_PLAYER_WANTED];
ActiveTaskList pLst = GetActiveTaskList();
uint ulCurTime = GetCurTime(); // 当前时间 // current time
ATaskTempl pTempl = null;
int foundEntryIndex = -1; // Keep track of entry index like C++ code does
if (bActiveTask)
{
// 在激活任务列表中查找 // Search in active task list
for (int i = 0; i < pLst.m_uTaskCount; i++)
{
ActiveTaskEntry CurEntry = pLst.m_TaskEntries[i];
if (CurEntry.m_ID != ulTaskId || CurEntry.m_ulTemplAddr == 0) continue;
pTempl = CurEntry.GetTempl();
foundEntryIndex = i; // Store index to access entry later
// 检查任务是否可以完成 // Check if task can be completed
if (pTempl != null && pTempl.CanFinishTask(this, CurEntry, ulCurTime))
{
pInfo.m_ulErrCode = pTempl.RecursiveCheckAward(this, pLst, CurEntry, ulCurTime, -1);
if (pInfo.m_ulErrCode == TaskInterfaceConstants.TASK_AWARD_FAIL_LEVEL_CHECK)
{
ATaskTempl pParent = pTempl;
while (pParent != null && pParent.m_FixedData.m_ulPremise_Lev_Min == 0)
pParent = pParent.m_pParent;
if (pParent != null)
pInfo.m_ulPremLevelMin = pParent.m_FixedData.m_ulPremise_Lev_Min;
}
}
pInfo.m_ulTimePassed = ulCurTime > CurEntry.m_ulTaskTime ? (ulCurTime - CurEntry.m_ulTaskTime) : 0;
if (pTempl != null && pTempl.m_FixedData.m_ulPremise_Lev_Min != 0)
{
if (pTempl.m_FixedData.m_bPremCheckMaxHistoryLevel != 0 && GetPlayerLevel() < pTempl.m_FixedData.m_ulPremise_Lev_Min)
{
pInfo.m_ulErrCode = TaskInterfaceConstants.TASK_AWARD_FAIL_LEVEL_CHECK;
pInfo.m_ulPremLevelMin = pTempl.m_FixedData.m_ulPremise_Lev_Min;
}
}
break;
}
}
else
{
pTempl = GetTaskTemplMan().GetTopTaskByID(ulTaskId);
}
if (pTempl == null)
return;
// 基本任务要求 // Basic task requirements
if (pTempl.m_FixedData.m_ulTimeLimit != 0) pInfo.m_ulTimeLimit = pTempl.m_FixedData.m_ulTimeLimit;
if (pTempl.m_FixedData.m_ulGoldWanted != 0) pInfo.m_ulGoldWanted = pTempl.m_FixedData.m_ulGoldWanted;
// 任务类型分支 // Task method branches
if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMCollectNumArticle)
{
for (int j = 0; j < pTempl.m_FixedData.m_ulItemsWanted; j++)
{
var iw = pTempl.m_FixedData.m_ItemsWanted[j];
pInfo.m_ItemsWanted[j].m_ulItemId = iw.m_ulItemTemplId;
pInfo.m_ItemsWanted[j].m_ulItemsToGet = iw.m_ulItemNum;
pInfo.m_ItemsWanted[j].m_ulItemsGained = ATaskTempl._get_item_count(this, iw.m_ulItemTemplId, iw.m_bCommonItem);
}
}
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMKillNumMonster)
{
int ulItemCount = 0;
int ulMonsterCount = 0;
for (int j = 0; j < pTempl.m_FixedData.m_ulMonsterWanted; j++)
{
var mw = pTempl.m_FixedData.m_MonsterWanted[j];
if (mw.m_ulDropItemId != 0)
{
pInfo.m_ItemsWanted[ulItemCount].m_ulMonsterId = mw.m_ulMonsterTemplId;
pInfo.m_ItemsWanted[ulItemCount].m_ulItemId = mw.m_ulDropItemId;
pInfo.m_ItemsWanted[ulItemCount].m_ulItemsToGet = mw.m_ulDropItemCount;
pInfo.m_ItemsWanted[ulItemCount].m_ulItemsGained = ATaskTempl._get_item_count(this, mw.m_ulDropItemId, mw.m_bDropCmnItem);
ulItemCount++;
}
else
{
pInfo.m_MonsterWanted[ulMonsterCount].m_ulMonsterId = mw.m_ulMonsterTemplId;
pInfo.m_MonsterWanted[ulMonsterCount].m_ulMonstersToKill = mw.m_ulMonsterNum;
// Access the entry directly from the list using stored index, like C++ code does
if (bActiveTask && foundEntryIndex >= 0)
{
ActiveTaskEntry CurEntry = pLst.m_TaskEntries[foundEntryIndex];
pInfo.m_MonsterWanted[ulMonsterCount].m_ulMonstersKilled = CurEntry.m_wMonsterNum[j];
}
ulMonsterCount++;
}
}
}
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMKillPlayer)
{
int ulItemCount = 0;
int ulPlayerCount = 0;
for (int j = 0; j < pTempl.m_FixedData.m_ulPlayerWanted; j++)
{
var pw = pTempl.m_FixedData.m_PlayerWanted[j];
if (pw.m_ulDropItemId != 0)
{
pInfo.m_ItemsWanted[ulItemCount].m_ulItemId = pw.m_ulDropItemId;
pInfo.m_ItemsWanted[ulItemCount].m_ulItemsToGet = pw.m_ulDropItemCount;
pInfo.m_ItemsWanted[ulItemCount].m_ulItemsGained = ATaskTempl._get_item_count(this, pw.m_ulDropItemId, pw.m_bDropCmnItem);
ulItemCount++;
}
else
{
pInfo.m_PlayerWanted[ulPlayerCount].m_ulPlayersToKill = pw.m_ulPlayerNum;
// Access the entry directly from the list using stored index, like C++ code does
if (bActiveTask && foundEntryIndex >= 0)
{
ActiveTaskEntry CurEntry = pLst.m_TaskEntries[foundEntryIndex];
pInfo.m_PlayerWanted[ulPlayerCount].m_ulPlayersKilled = CurEntry.m_wMonsterNum[j];
}
pInfo.m_PlayerWanted[ulPlayerCount].m_Requirements = pw.m_Requirements;
ulPlayerCount++;
}
}
}
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMProtectNPC)
{
pInfo.m_ulNPCToProtect = pTempl.m_FixedData.m_ulNPCToProtect;
pInfo.m_ulProtectTime = pTempl.m_FixedData.m_ulProtectTimeLen;
}
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMWaitTime)
{
pInfo.m_ulWaitTime = pTempl.m_FixedData.m_ulWaitTime;
}
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMGlobalValOK)
{
pTempl.GetGlobalTaskChar(this, pInfo.m_TaskCharArr);
}
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMReachLevel)
{
pInfo.m_ulReachLevel = pTempl.m_FixedData.m_ulReachLevel;
pInfo.m_ulReachReincarnation = pTempl.m_FixedData.m_ulReachReincarnationCount;
pInfo.m_ulReachRealm = pTempl.m_FixedData.m_ulReachRealmLevel;
}
return;
}
public uint GetCurTime()
{
// use this to avoid task hack by changing the system time
return (uint)EC_Game.GetServerAbsTime();
}
private const string SYMBOL_HOSTNAME = "$name";
public string FormatTaskTalk(string taskTalk)
{
string ret = taskTalk ?? string.Empty;
if (taskTalk == null) return ret;
string strName = m_pHost.GetName(); // assumes string; use ToString() if needed
return ret.Replace(SYMBOL_HOSTNAME, $"&{strName}&");
}
public bool GetAwardCandidates(uint ulTaskId, ref AWARD_DATA pAward)
{
ActiveTaskList pLst = GetActiveTaskList() as ActiveTaskList;
ActiveTaskEntry pEntry = pLst.GetEntry(ulTaskId);
if (pEntry == null || pEntry.m_ulTemplAddr == 0) return false;
uint ulCurTime = GetCurTime();
pEntry.GetTempl().CalcAwardData(
this,
ref pAward,
pEntry,
pEntry.m_ulTaskTime,
ulCurTime);
return true;
}
public uint GetTaskFinishedTime(uint value) { return 0; }
bool IsCaptain()
{
// TO DO: fix later
//CECTeam pTeam = m_pHost.GetTeam();
//if (!pTeam)
// return false;
//return pTeam.GetLeaderID() == m_pHost.GetCharacterID();
return true;
}
public bool CanFinishTask(uint ulTaskId)
{
ActiveTaskEntry pEntry = (GetActiveTaskList() as ActiveTaskList).GetEntry(ulTaskId);
if (pEntry == null)
return false;
ATaskTempl pTempl = pEntry.GetTempl();
if (pTempl == null)
return false;
if (pTempl.m_FixedData.m_bMarriage && !IsCaptain())
return false;
return pTempl.CanFinishTask(this, pEntry, GetCurTime());
}
public bool CanShowTask(uint ulTaskId)
{
ATaskTempl pTempl = GetTaskTemplMan().GetTopTaskByID(ulTaskId);
return pTempl != null && pTempl.CanShowTask(this);
}
public void SetFinishDlgShowTime(int t) { m_tmFinishDlgShown = t; }
public void OnUIDialogEnd(uint ulTask)
{
SetFinishDlgShowTime(0);
ActiveTaskList pLst = GetActiveTaskList() as ActiveTaskList;
ActiveTaskEntry pEntry = pLst.GetEntry(ulTask);
if (pEntry == null || pEntry.m_ulTemplAddr == 0) return;
//ATaskTempl pTempl = (pEntry.m_ulTemplAddr) as ATaskTempl;
ATaskTempl pTempl = GetTaskTemplMan().GetTaskTemplByID(pEntry.m_ulTemplAddr);
switch (pTempl.m_FixedData.m_enumMethod)
{
case (uint)TaskCompletionMethod.enumTMReachSite:
pTempl.IncValidCount();
_notify_svr(this, 3, (ushort)ulTask); //TASK_CLT_NOTIFY_REACH_SITE = 3
break;
}
}
public void GiveUpTask(uint ulTaskId)
{
ActiveTaskEntry pEntry = (GetActiveTaskList() as ActiveTaskList).GetEntry(ulTaskId);
if (pEntry == null || pEntry.GetTempl() == null) return;
_notify_svr(this, 2, (ushort)(pEntry.GetTempl().GetTopTask().GetID())); //TASK_CLT_NOTIFY_CHECK_GIVEUP = 2
}
void _notify_svr(TaskInterface pTask, byte uReason, ushort uTaskID)
{
TaskClient._notify_svr(pTask, uReason, uTaskID);
}
public bool IsTaskReadyToConfirm(int iTaskID)
{
if (m_TasksToConfirm == null) return false;
bool ret;
if (m_TasksToConfirm.TryGetValue(iTaskID, out ret)) return ret;
return false;
}
public bool CheckVersion()
{
// return static_cast<ActiveTaskList*>(GetActiveTaskList())->m_Version == TASK_ENTRY_DATA_CUR_VER;
return GetActiveTaskList().m_Version == TaskTemplConstants.TASK_ENTRY_DATA_CUR_VER;
}
public StorageTaskList GetStorageTaskList()
{
StorageTaskList ret = new StorageTaskList();
// Initialize arrays before use
ret.EnsureInitialized();
// Check if buffer is initialized before reading
if (m_pStorageTaskListBuf != null)
{
ret.ReadByte(m_pStorageTaskListBuf);
}
// If buffer is null, return empty/default StorageTaskList
// This can happen if Init() hasn't been called yet or failed
return ret;
}
// 设置存储任务列表缓冲区 // Set storage task list buffer
public void SetStorageTaskListBuffer(byte[] data)
{
if (data == null || m_pStorageTaskListBuf == null) return;
int copy = Mathf.Min(data.Length, m_pStorageTaskListBuf.Length);
if (copy > 0)
{
System.Buffer.BlockCopy(data, 0, m_pStorageTaskListBuf, 0, copy);
}
}
public uint GetTaskMask()
{
return 0;
}
public byte[] GetFinishedTimeList()
{
return m_pFinishedTimeListBuf;
}
public byte[] GetFinishedCntList()
{
return m_pFinishedCountListBuf;
}
void SetForceNavigateFinishFlag(bool bFinish) { m_bForceNavigateFinish = bFinish;} //
public void OnNewTask(int iTaskID)
{
ATaskTempl pTempl = GetTaskTemplMan().GetTaskTemplByID((uint)iTaskID);
if (pTempl != null
&& pTempl.m_FixedData.m_enumMethod== (uint)TaskCompletionMethod.enumTMSimpleClientTaskForceNavi)
{
SetForceNavigateFinishFlag(false);
// TODO: trigger navigation event
// m_pHost.OnNaviageEvent(iTaskID,CECNavigateCtrl::EM_PREPARE);
}
}
public void OnTaskConfirmUpdate()
{
// TODO: update task confirm UI
// CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan();
// if (pGameUI) pGameUI->UpdateTaskConfirm();
}
public void UpdateConfirmTasksMap()
{
m_TasksToConfirm.Clear();
TaskClient.OnTaskCheckStatus(this);
OnTaskConfirmUpdate();
}
public void OnCompleteTask(int iTaskID)
{
ATaskTempl pTempl = GetTaskTemplMan().GetTaskTemplByID((uint)iTaskID);
if (pTempl != null &&
pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMSimpleClientTaskForceNavi)
{
//TODO: trigger navigation end event
// m_pHost.OnNaviageEvent(iTaskID,CECNavigateCtrl::EM_END);
SetForceNavigateFinishFlag(false);
}
}
public void TakeAwayCommonItem(uint ulTemplId, uint ulNum) {}
public void TakeAwayTaskItem(uint ulTemplId, uint ulNum) {}
public void TakeAwayGold(uint ulNum) {}
public void TakeAwayFactionConsumeContrib(int ulNum){}
public void OnGiveupTask(int iTaskID)
{
ATaskTempl pTempl = GetTaskTemplMan().GetTaskTemplByID((uint)iTaskID);
if (pTempl != null &&
pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMSimpleClientTaskForceNavi)
{
// TODO: trigger navigation end event
// m_pHost.OnNaviageEvent(iTaskID,CECNavigateCtrl::EM_END);
SetForceNavigateFinishFlag(false);
}
}
public void UpdateTaskUI(uint idTask, int reason)
{
// TODO: update task UI
CECGameUIMan pGameUI = CECUIManager.Instance.GetInGameUIMan();
if (pGameUI != null )
{
pGameUI.UpdateTask(idTask, reason);
}
}
public bool IsTitleDataReady()
{
return m_pHost.IsTitleDataReady();
}
public FinishedTaskList GetFinishedTaskList()
{
FinishedTaskList ret = new FinishedTaskList();
ret.ReadFromBytes(m_pFinishedListBuf);
return ret;
}
// 记录任务完成/失败到已完成列表(用于前置任务/可重复接任务判断)
// English: Record task finish/fail into FinishedTaskList (used by prerequisite checks)
public void RecordFinishedTask(uint taskId, bool success)
{
if (m_pFinishedListBuf == null) return;
FinishedTaskList lst = new FinishedTaskList();
lst.ReadFromBytes(m_pFinishedListBuf);
lst.AddOneTask(taskId, success);
// Persist back into buffer
if (lst.m_Buf != null && lst.m_Buf.Length == m_pFinishedListBuf.Length)
{
global::System.Buffer.BlockCopy(lst.m_Buf, 0, m_pFinishedListBuf, 0, m_pFinishedListBuf.Length);
}
}
// Persist an updated FinishedTaskList back into the underlying buffer.
public void WriteFinishedTaskList(FinishedTaskList lst)
{
if (m_pFinishedListBuf == null) return;
if (lst.m_Buf == null || lst.m_Buf.Length != m_pFinishedListBuf.Length) return;
global::System.Buffer.BlockCopy(lst.m_Buf, 0, m_pFinishedListBuf, 0, m_pFinishedListBuf.Length);
}
// Reset role-based finish counter for a task when period rolls over (used by CheckDeliverTime).
public void ResetRoleFinishCount(uint taskId)
{
if (m_pFinishedListBuf == null) return;
FinishedTaskList lst = new FinishedTaskList();
lst.ReadFromBytes(m_pFinishedListBuf);
lst.ResetFinishCount(taskId);
WriteFinishedTaskList(lst);
}
public int GetPlayerId()
{
return m_pHost.GetCharacterID();
}
public void PopChatMessage(int iIndex,int dwNum=0)
{
switch((FixedMsg)iIndex)
{
case FixedMsg.FIXMSG_TASK_LIMIT_INCREASED:
// TODO: show chat message
// g_pGame->GetGameRun()->AddFixedChannelMsg(FIXMSG_TASK_LIMIT_INCREASED,GP_CHAT_SYSTEM);
// EC_Game.GetGameRun().AddFixedChannelMsg(FIXMSG_TASK_LIMIT_INCREASED,GP_CHAT_SYSTEM);
break;
default:
break;
}
}
public void NotifyServer(byte[] pBuf, uint sz)
{
// g_pGame->GetGameSession()->c2s_CmdTaskNotify(pBuf, sz);
UnityGameSession.c2s_CmdTaskNotify(pBuf, sz);
}
#region Emote
public void SetEmotion(int emotion)
{
ActiveTaskList pList = GetActiveTaskList();
List<ActiveTaskEntry> aEntries = new List<ActiveTaskEntry>(pList.m_TaskEntries);
ATaskTempl pTempl;
if (emotion < (int)TaskInterface.CommandTaskAction.CMD_EMOTION_BINDBUDDY)// pTempl->m_uiEmotion ֵΪ0±íʾ²»¼ì²é£¬ËùÒÔËùÓбíÇéÐòºÅ¶¼ºóÒÆ1
emotion += 1;
for (int i = 0; i < pList.m_uTaskCount; i++)
{
ActiveTaskEntry curEntry = aEntries[i];
pTempl = curEntry.GetTempl();
if (pTempl != null &&
pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMSimpleClientTask &&
pTempl.m_FixedData.m_uiEmotion > 0)
{
uint id = pTempl.GetID();
// Check if map does not contain OR value == false
if (!m_emotionTask.TryGetValue(id, out bool exists) || !exists)
{
m_emotionTask[id] = (pTempl.m_FixedData.m_uiEmotion == (uint)emotion);
}
}
}
}
// void CECTaskInterface::UpdateTaskEmotionAction(unsigned int task_id)
// {
// if (m_emotionTask.find(task_id)!=m_emotionTask.end())
// {
// m_emotionTask[task_id] = false;
// }
// }
// void CECTaskInterface::UpdateEmotionDlg(unsigned int task)
// {
// ActiveTaskList* pList = static_cast<ActiveTaskList*>(GetActiveTaskList());
// ActiveTaskEntry* aEntries = pList->m_TaskEntries;
// unsigned char i;
// const ATaskTempl* pTempl, *pTarget = NULL;
// ActiveTaskEntry* pTargetEntry = NULL;
//
// for (i = 0; i < pList->m_uTaskCount; i++)
// {
// ActiveTaskEntry& CurEntry = aEntries[i];
// pTempl = CurEntry.GetTempl();
//
// if (!pTempl || pTempl->GetID() == task)
// continue;
//
// if (pTempl && pTempl->m_enumMethod==enumTMSimpleClientTask && pTempl->m_uiEmotion)
// {
// pTarget = pTempl;
// pTargetEntry = &CurEntry;
// break;
// }
// }
// if (pTarget && pTargetEntry && !pTempl->CanFinishTask(this, pTargetEntry, GetCurTime()))
// {
// PopEmotionUI(pTarget->GetID(),pTarget->m_uiEmotion,true);
// }
// }
// void TaskInterface::PopEmotionUI(unsigned int task_id,unsigned int uiEmotion,bool bShow)
// {
// CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan();
//
// if (pGameUI)
// {
// pGameUI->PopTaskEmotionDlg(task_id,uiEmotion,bShow);
// }
// }
#endregion
}
}