506 lines
18 KiB
C#
506 lines
18 KiB
C#
using System;
|
||
using System.Reflection;
|
||
using System.Runtime.InteropServices;
|
||
using BrewMonster.Network;
|
||
using BrewMonster.Scripts.Task;
|
||
using CSNetwork.GPDataType;
|
||
using PerfectWorld.Scripts.Task;
|
||
using UnityEngine;
|
||
|
||
namespace BrewMonster.Scripts.Task
|
||
{
|
||
|
||
// provide some global methods
|
||
public class TaskClient
|
||
{
|
||
#if _TASK_CLIENT
|
||
|
||
private const uint FINISH_DLG_SHOWN_TIME = 3000; // TODO: Confirm correct value
|
||
private static uint s_finishDlgShownTime = 0;
|
||
|
||
public static void OnTaskCheckStatus(TaskInterface pTask)
|
||
{
|
||
// 版本与交付合法性检查 // Version and deliver legality check
|
||
// CheckVersion not exposed on TaskInterface; skipping version check
|
||
if (pTask == null ||
|
||
!pTask.CheckVersion() ||
|
||
!pTask.IsDeliverLegal())
|
||
return;
|
||
|
||
|
||
// 读取激活任务列表 // Read active task list
|
||
ActiveTaskList pLst = TryGetActiveList(pTask);
|
||
if (pLst == null) return;
|
||
ActiveTaskEntry[] aEntries = pLst.m_TaskEntries;
|
||
uint ulCurTime = GetCurTime();
|
||
|
||
// 遍历所有激活任务 // Iterate active tasks
|
||
for (int i = 0; i < pLst.m_uTaskCount; i++)
|
||
{
|
||
ActiveTaskEntry CurEntry = aEntries[i];
|
||
if (CurEntry == null) continue;
|
||
|
||
if (CurEntry.m_ulTemplAddr == 0)
|
||
{
|
||
// assert(false) // English: unexpected empty template
|
||
continue;
|
||
}
|
||
|
||
ATaskTempl pTempl = CurEntry.GetTempl();
|
||
if (pTempl == null) continue;
|
||
|
||
// IsValidState from C++ not found in managed port; skip validity-state check
|
||
if (!pTempl.IsValidState())
|
||
continue;
|
||
|
||
// PQ子任务 // PQ subtask
|
||
if (pTempl.m_FixedData.m_bPQSubTask)
|
||
{
|
||
// CheckGlobalPQKeyValue(true) not ported; if implemented and returns 0, notify server then continue
|
||
if(pTempl.CheckGlobalPQKeyValue(true) == 0)
|
||
{
|
||
pTempl.IncValidCount();
|
||
_notify_svr(pTask, ClientNotificationConstants.TASK_CLT_NOTIFY_CHECK_FINISH, CurEntry.m_ID);
|
||
continue;
|
||
}
|
||
}
|
||
|
||
// 超时判断 // Timeout check
|
||
if (pTempl.m_FixedData.m_ulTimeLimit != 0
|
||
&& CurEntry.m_ulTaskTime + pTempl.m_FixedData.m_ulTimeLimit < ulCurTime)
|
||
{
|
||
pTempl.IncValidCount();
|
||
_notify_svr(pTask, (int)ClientNotificationConstants.TASK_CLT_NOTIFY_CHECK_FINISH, CurEntry.m_ID);
|
||
continue;
|
||
}
|
||
|
||
// 绝对失效时间判断 // Absolute fail time check
|
||
if (pTempl.m_FixedData.m_bAbsFail)
|
||
{
|
||
// TODO: Time zone bias and 'task_tm.before' not ported; skipping precise comparison
|
||
}
|
||
|
||
// 进入或离开区域导致失败 // Entering or leaving region causes failure
|
||
{
|
||
float[] pos = new float[3];
|
||
uint ulWorldId = (uint)pTask.GetPos(pos);
|
||
|
||
// 进入区域失败 // Enter region fail
|
||
if (pTempl.m_FixedData.m_bEnterRegionFail && ulWorldId == pTempl.m_FixedData.m_ulEnterRegionWorld)
|
||
{
|
||
for (uint iRegion = 0; iRegion < pTempl.m_FixedData.m_ulEnterRegionCnt; iRegion++)
|
||
{
|
||
Task_Region t = pTempl.m_FixedData.m_pEnterRegion[(int)iRegion];
|
||
if (IsInZone(t.zvMin, t.zvMax, pos))
|
||
{
|
||
pTempl.IncValidCount();
|
||
_notify_svr(pTask, (int)ClientNotificationConstants.TASK_CLT_NOTIFY_CHECK_FINISH, CurEntry.m_ID);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 离开区域失败 // Leave region fail
|
||
if (pTempl.m_FixedData.m_bLeaveRegionFail)
|
||
{
|
||
bool bLeaveRegion = false;
|
||
if (ulWorldId != pTempl.m_FixedData.m_ulLeaveRegionWorld) bLeaveRegion = true;
|
||
else
|
||
{
|
||
uint iRegion = 0;
|
||
for (; iRegion < pTempl.m_FixedData.m_ulLeaveRegionCnt; iRegion++)
|
||
{
|
||
Task_Region t = pTempl.m_FixedData.m_pLeaveRegion[(int)iRegion];
|
||
if (IsInZone(t.zvMin, t.zvMax, pos))
|
||
break;
|
||
}
|
||
if (iRegion >= pTempl.m_FixedData.m_ulLeaveRegionCnt) bLeaveRegion = true;
|
||
}
|
||
if (bLeaveRegion)
|
||
{
|
||
pTempl.IncValidCount();
|
||
_notify_svr(pTask, (int)ClientNotificationConstants.TASK_CLT_NOTIFY_CHECK_FINISH, CurEntry.m_ID);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 离开家族失败 // Leave faction fail
|
||
if (!pTask.IsAtCrossServer() && pTempl.m_FixedData.m_bLeaveFactionFail && !pTask.IsInFaction(1))
|
||
{
|
||
pTempl.IncValidCount();
|
||
_notify_svr(pTask, (int)ClientNotificationConstants.TASK_CLT_NOTIFY_CHECK_FINISH, CurEntry.m_ID);
|
||
continue;
|
||
}
|
||
|
||
// 对话/NPC完成类任务跳过本轮 // Skip talk-to-NPC or NPC-finish tasks here
|
||
if ((TaskCompletionMethod)pTempl.m_FixedData.m_enumMethod == TaskCompletionMethod.enumTMTalkToNPC
|
||
|| pTempl.m_FixedData.m_bMarriage
|
||
|| (TaskFinishType)pTempl.m_FixedData.m_enumFinishType == TaskFinishType.enumTFTNPC)
|
||
continue;
|
||
|
||
// 判断未完成的直接完成判定 // Check direct-finish for unfinished tasks
|
||
if (!CurEntry.IsFinished())
|
||
{
|
||
// 到达地点直接完成 // Reach-site direct finish
|
||
if ((TaskCompletionMethod)pTempl.m_FixedData.m_enumMethod == TaskCompletionMethod.enumTMReachSite
|
||
&& (TaskFinishType)pTempl.m_FixedData.m_enumFinishType == TaskFinishType.enumTFTDirect)
|
||
{
|
||
if (ulCurTime - s_finishDlgShownTime < FINISH_DLG_SHOWN_TIME)
|
||
continue;
|
||
|
||
float[] pos = new float[3];
|
||
uint ulWorldId = (uint)pTask.GetPos(pos);
|
||
|
||
if (ulWorldId == pTempl.m_FixedData.m_ulReachSiteId)
|
||
{
|
||
for (uint iRegion = 0; iRegion < pTempl.m_FixedData.m_ulReachSiteCnt; iRegion++)
|
||
{
|
||
Task_Region t = pTempl.m_FixedData.m_pReachSite[(int)iRegion];
|
||
if (IsInZone(t.zvMin, t.zvMax, pos))
|
||
{
|
||
var pTalk = pTempl.m_AwardTalk;
|
||
if (pTalk.num_window == 0 || (pTalk.num_window == 1 && pTalk.windows != null && pTalk.windows.Length > 0 && pTalk.windows[0].num_option == 0))
|
||
{
|
||
pTempl.IncValidCount();
|
||
_notify_svr(pTask, ClientNotificationConstants.TASK_CLT_NOTIFY_REACH_SITE, (ushort)pTempl.GetID());
|
||
}
|
||
else
|
||
{
|
||
// TODO: PopupTaskFinishDialog not exposed; implement UI as needed
|
||
s_finishDlgShownTime = ulCurTime;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
continue;
|
||
}
|
||
|
||
// 离开地点直接完成 // Leave-site direct finish
|
||
if ((TaskCompletionMethod)pTempl.m_FixedData.m_enumMethod == TaskCompletionMethod.enumTMLeaveSite
|
||
&& (TaskFinishType)pTempl.m_FixedData.m_enumFinishType == TaskFinishType.enumTFTDirect)
|
||
{
|
||
if (ulCurTime - s_finishDlgShownTime < FINISH_DLG_SHOWN_TIME)
|
||
continue;
|
||
|
||
float[] pos = new float[3];
|
||
uint ulWorldId = (uint)pTask.GetPos(pos);
|
||
bool regRet = false;
|
||
|
||
if (ulWorldId == pTempl.m_FixedData.m_ulLeaveSiteId)
|
||
{
|
||
for (uint iRegion = 0; iRegion < pTempl.m_FixedData.m_ulLeaveSiteCnt; iRegion++)
|
||
{
|
||
Task_Region t = pTempl.m_FixedData.m_pLeaveSite[(int)iRegion];
|
||
if (IsInZone(t.zvMin, t.zvMax, pos))
|
||
{
|
||
regRet = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if (!regRet)
|
||
{
|
||
var pTalk = pTempl.m_AwardTalk;
|
||
if (pTalk.num_window == 0 || (pTalk.num_window == 1 && pTalk.windows != null && pTalk.windows.Length > 0 && pTalk.windows[0].num_option == 0))
|
||
{
|
||
pTempl.IncValidCount();
|
||
_notify_svr(pTask, ClientNotificationConstants.TASK_CLT_NOTIFY_LEAVE_SITE, (ushort)pTempl.GetID());
|
||
}
|
||
else
|
||
{
|
||
// TODO: PopupTaskFinishDialog not exposed; implement UI as needed
|
||
s_finishDlgShownTime = ulCurTime;
|
||
}
|
||
}
|
||
continue;
|
||
}
|
||
}
|
||
|
||
// 非子任务:检查奖励条件并按需标记/通知 // If no children, check award conditions and update
|
||
if (pTempl != null && pTempl.m_pFirstChild == null)
|
||
{
|
||
bool bNeedServerCheck =
|
||
pTempl.RecursiveCheckAward(pTask, pLst, CurEntry, ulCurTime, -1) == 0
|
||
&& pTempl.CanFinishTask(pTask, CurEntry, ulCurTime);
|
||
|
||
if (pTempl.m_FixedData.m_bDisplayInExclusiveUI && pTempl.m_FixedData.m_bAutoDeliver
|
||
&& (TaskFinishType)pTempl.m_FixedData.m_enumFinishType == TaskFinishType.enumTFTDirect)
|
||
{
|
||
// TODO: Hook game UI and update auto-deliver countdown; no UI manager available here
|
||
uint ulRemainTime = 0;
|
||
if ((TaskCompletionMethod)pTempl.m_FixedData.m_enumMethod == TaskCompletionMethod.enumTMWaitTime)
|
||
{
|
||
uint ultime = CurEntry.m_ulTaskTime + pTempl.m_FixedData.m_ulWaitTime;
|
||
if (ultime > ulCurTime) ulRemainTime = ultime - ulCurTime;
|
||
}
|
||
|
||
// TODO: pTempl.m_bReadyToNotifyServer/ResetAutoDelTask workflow may need UI support
|
||
if (pTempl.m_FixedData.m_bReadyToNotifyServer && bNeedServerCheck)
|
||
{
|
||
pTempl.IncValidCount();
|
||
// TODO: pTempl.ResetAutoDelTask() not exposed; skip
|
||
_notify_svr(pTask, (int)ClientNotificationConstants.TASK_CLT_NOTIFY_CHECK_FINISH, (ushort)CurEntry.m_ID);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// TODO: UpdateTaskToConfirm not ported; implement confirmation UI/state if needed
|
||
UpdateTaskToConfirm(pTask, pTempl, bNeedServerCheck);
|
||
}
|
||
}
|
||
}
|
||
|
||
// ATaskTemplMan.UpdateStatus(pTask) not found in C# port; skipping
|
||
GetTaskTemplMan().UpdateStatus(pTask);
|
||
}
|
||
|
||
// ===== Helpers =====
|
||
|
||
// 取当前时间(服务器绝对时间) // Get current time (server absolute)
|
||
private static uint GetCurTime()
|
||
{
|
||
return (uint)EC_Game.GetServerAbsTime();
|
||
}
|
||
|
||
// 反射读取激活任务列表 // Read active task list via reflection
|
||
private static ActiveTaskList TryGetActiveList(TaskInterface pTask)
|
||
{
|
||
// Try to get private method GetActiveTaskList on CECTaskInterface
|
||
MethodInfo mi = pTask.GetType().GetMethod("GetActiveTaskList", BindingFlags.Instance | BindingFlags.NonPublic);
|
||
if (mi != null)
|
||
{
|
||
try { return mi.Invoke(pTask, null) as ActiveTaskList; } catch { }
|
||
}
|
||
// Fallback to private field m_pActiveListBuf
|
||
FieldInfo fi = pTask.GetType().GetField("m_pActiveListBuf", BindingFlags.Instance | BindingFlags.NonPublic);
|
||
if (fi != null)
|
||
{
|
||
try { return fi.GetValue(pTask) as ActiveTaskList; } catch { }
|
||
}
|
||
return null;
|
||
}
|
||
|
||
// 区域内检测(AABB) // In-zone check (AABB)
|
||
private static bool IsInZone(ZONE_VERT min, ZONE_VERT max, float[] pos)
|
||
{
|
||
if (pos == null || pos.Length < 3) return false;
|
||
return pos[0] >= min.x && pos[0] <= max.x
|
||
&& pos[1] >= min.y && pos[1] <= max.y
|
||
&& pos[2] >= min.z && pos[2] <= max.z;
|
||
}
|
||
|
||
public static void _notify_svr(TaskInterface pTask, byte uReason, ushort uTaskID)
|
||
{
|
||
ATaskTempl._notify_svr(pTask, uReason, uTaskID);
|
||
}
|
||
|
||
// 更新“待确认任务” // Update task to confirm
|
||
private static void UpdateTaskToConfirm(TaskInterface pTask, ATaskTempl pTempl, bool needServerCheck)
|
||
{
|
||
// TODO: Implement confirmation queue/UI if required by design
|
||
}
|
||
|
||
// Handle server notification for task updates
|
||
public static void OnServerNotify(TaskInterface pTask, byte[] pBuf, uint sz)
|
||
{
|
||
// Check version validity
|
||
// CheckVersion not exposed on TaskInterface; skipping version check
|
||
if (!pTask.CheckVersion())
|
||
return;
|
||
|
||
// Validate buffer size for base notification structure
|
||
if (sz < (uint)Marshal.SizeOf<task_notify_base>()) return;
|
||
|
||
// Marshal base notification structure from buffer
|
||
task_notify_base pNotify = GPDataTypeHelper.FromBytes<task_notify_base>(pBuf);
|
||
BMLogger.Log($"[TaskClient] OnServerNotify: reason={pNotify.reason}, task={pNotify.task}");
|
||
|
||
ATaskTempl pTempl = null;
|
||
ActiveTaskEntry pEntry = null;
|
||
|
||
// Handle error code notification
|
||
if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_ERROR_CODE)
|
||
{
|
||
// TODO: svr_task_err_code struct not defined; need to define or use alternative approach
|
||
// if (sz != Marshal.SizeOf<svr_task_err_code>()) return;
|
||
|
||
#if _ELEMENTCLIENT
|
||
// TODO: GetEntry method not implemented in ActiveTaskList; need to implement or use alternative
|
||
// ActiveTaskList pLst = TryGetActiveList(pTask);
|
||
// if (pLst != null)
|
||
// {
|
||
// pEntry = GetEntry(pLst, pNotify.task);
|
||
// if (pEntry != null) pEntry.SetErrReported();
|
||
// }
|
||
// TODO: TaskShowErrMessage not found; implement error message display
|
||
// TaskShowErrMessage(...);
|
||
#endif
|
||
return;
|
||
}
|
||
// Handle forget skill notification
|
||
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_FORGET_SKILL)
|
||
{
|
||
// OnForgetLivingSkill method not found in ATaskTemplMan; implement if needed
|
||
ATaskTemplMan pMan = GetTaskTemplMan();
|
||
if (pMan != null) pMan.OnForgetLivingSkill(pTask);
|
||
return;
|
||
}
|
||
// Handle new task notification
|
||
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_NEW)
|
||
{
|
||
ATaskTemplMan pMan = GetTaskTemplMan();
|
||
if (pMan != null) pTempl = pMan.GetTopTaskByID(pNotify.task);
|
||
}
|
||
// Handle dynamic task time mark notification
|
||
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_DYN_TIME_MARK)
|
||
{
|
||
// TODO: svr_task_dyn_time_mark struct not defined; need to define or use alternative
|
||
// if (sz != Marshal.SizeOf<svr_task_dyn_time_mark>()) return;
|
||
// TODO: OnDynTasksTimeMark method not found in ATaskTemplMan; implement if needed
|
||
// ATaskTemplMan pMan = GetTaskTemplMan(pTask);
|
||
// if (pMan != null)
|
||
// {
|
||
// svr_task_dyn_time_mark dynMark = Marshal.PtrToStructure<svr_task_dyn_time_mark>(handle.AddrOfPinnedObject());
|
||
// pMan.OnDynTasksTimeMark(pTask, dynMark.time_mark, dynMark.version);
|
||
// }
|
||
return;
|
||
}
|
||
// Handle dynamic task data notification
|
||
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_DYN_DATA)
|
||
{
|
||
if (sz <= (uint)Marshal.SizeOf<task_notify_base>()) return;
|
||
// TODO: OnDynTasksData method not found in ATaskTemplMan; implement if needed
|
||
ATaskTemplMan pMan = GetTaskTemplMan();
|
||
if (pMan != null)
|
||
{
|
||
byte[] dynData = new byte[sz - Marshal.SizeOf<task_notify_base>()];
|
||
Array.Copy(pBuf, Marshal.SizeOf<task_notify_base>(), dynData, 0, dynData.Length);
|
||
pMan.OnDynTasksData(pTask, dynData, dynData.Length, pNotify.task != 0);
|
||
}
|
||
return;
|
||
}
|
||
// Handle storage data notification
|
||
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_STORAGE)
|
||
{
|
||
// TODO: StorageTaskList struct not defined; need to define or use alternative
|
||
// if (sz != Marshal.SizeOf<task_notify_base>() + Marshal.SizeOf<StorageTaskList>()) return;
|
||
// TODO: OnStorageData method not found in ATaskTemplMan; implement if needed
|
||
// ATaskTemplMan pMan = GetTaskTemplMan(pTask);
|
||
// if (pMan != null)
|
||
// {
|
||
// byte[] storageData = new byte[Marshal.SizeOf<StorageTaskList>()];
|
||
// Array.Copy(pBuf, Marshal.SizeOf<task_notify_base>(), storageData, 0, storageData.Length);
|
||
// pMan.OnStorageData(pTask, storageData);
|
||
// }
|
||
// TODO: UpdateTaskUI static method not found; implement UI update if needed
|
||
// TaskInterface.UpdateTaskUI(pNotify.task, pNotify.reason);
|
||
return;
|
||
}
|
||
// Handle special award notification
|
||
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_SPECIAL_AWARD)
|
||
{
|
||
// Tsvr_task_special_award and special_award structs not defined; need to define
|
||
if (sz != Marshal.SizeOf<svr_task_special_award>()) return;
|
||
ATaskTemplMan pMan = GetTaskTemplMan();
|
||
if (pMan != null)
|
||
{
|
||
svr_task_special_award awardNotify = GPDataTypeHelper.FromBytes<svr_task_special_award>(pBuf);
|
||
pMan.OnSpecialAward(awardNotify.sa, pTask);
|
||
if (awardNotify.sa.id1 == 0)
|
||
{
|
||
// ID is 0 means no storage space, show newbie gift reminder
|
||
// TODO: CECGameUIMan and PopupNewbieGiftRemind not found; implement UI if needed
|
||
// CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan();
|
||
// pGameUI->PopupNewbieGiftRemind();
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
// Handle task limit increase notification
|
||
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_SET_TASK_LIMIT)
|
||
{
|
||
ActiveTaskList pLst = TryGetActiveList(pTask);
|
||
if (pLst != null)
|
||
{
|
||
// ExpandMaxSimultaneousCount method not implemented; implement if needed
|
||
pLst.ExpandMaxSimultaneousCount();
|
||
}
|
||
// PopChatMessage static method and FIXMSG_TASK_LIMIT_INCREASED constant not found
|
||
pTask.PopChatMessage((int)FixedMsg.FIXMSG_TASK_LIMIT_INCREASED);
|
||
return;
|
||
}
|
||
// Search for task entry in active task list
|
||
else
|
||
{
|
||
ActiveTaskList pLst = TryGetActiveList(pTask);
|
||
if (pLst != null)
|
||
{
|
||
for (byte i = 0; i < pLst.m_uTaskCount; i++)
|
||
{
|
||
ActiveTaskEntry CurEntry = pLst.m_TaskEntries[i];
|
||
if (CurEntry == null) continue;
|
||
|
||
if (CurEntry.m_ID != pNotify.task || CurEntry.m_ulTemplAddr == 0)
|
||
continue;
|
||
|
||
pTempl = CurEntry.GetTempl();
|
||
pEntry = CurEntry;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Handle player killed notification
|
||
if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_PLAYER_KILLED)
|
||
{
|
||
// TODO: CECUIHelper.OnTaskProcessUpdated not found; implement UI update if needed
|
||
// CECUIHelper.OnTaskProcessUpdated(pNotify.task);
|
||
}
|
||
// Handle monster killed notification
|
||
if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_MONSTER_KILLED)
|
||
{
|
||
// Monster kill count >= 2 triggers auto team
|
||
// TODO: svr_monster_killed struct not defined; need to define or use alternative
|
||
if (sz == Marshal.SizeOf<svr_monster_killed>())
|
||
{
|
||
svr_monster_killed pKilled = GPDataTypeHelper.FromBytes<svr_monster_killed>(pBuf) ;//Marshal.PtrToStructure<svr_monster_killed>(pNotify.AddrOfPinnedObject());
|
||
if (pKilled.monster_num >= 2)
|
||
{
|
||
// TODO: CECAutoTeam and DoAutoTeam not found; implement auto team if needed
|
||
// CECAutoTeam pAutoTeam = EC_Game.GetGameRun().GetHostPlayer().GetAutoTeam();
|
||
// pAutoTeam.DoAutoTeam(CECAutoTeam.TYPE_TASK, pNotify.task);
|
||
}
|
||
}
|
||
// TODO: CECUIHelper.OnTaskProcessUpdated not found; implement UI update if needed
|
||
// CECUIHelper.OnTaskProcessUpdated(pNotify.task);
|
||
}
|
||
// Handle task completion or give up notification
|
||
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_COMPLETE || pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_GIVE_UP)
|
||
{
|
||
// TODO: CECUIHelper.OnTaskCompleted not found; implement UI update if needed
|
||
// CECUIHelper.OnTaskCompleted(pNotify.task);
|
||
}
|
||
|
||
// Validate template was found
|
||
if (pTempl == null)
|
||
{
|
||
// TODO: Replace assert with appropriate error handling
|
||
Debug.Assert(false, "Task template not found");
|
||
return;
|
||
}
|
||
|
||
// Clear valid count and process server notification
|
||
pTempl.ClearValidCount();
|
||
// OnServerNotify method signature may need adjustment for C# (ref/out parameters)
|
||
pTempl.OnServerNotify(pTask, pEntry, pNotify, sz, pBuf);
|
||
}
|
||
|
||
// Helper method to get task template manager
|
||
private static ATaskTemplMan GetTaskTemplMan()
|
||
{
|
||
return EC_Game.GetTaskTemplateMan();
|
||
}
|
||
#endif
|
||
}
|
||
} |