Files
mir_server/server/LogicServer/script/ext/ScriptTimeCall.cpp
aixianling 5c9f1dae4a init
2025-01-09 17:45:40 +08:00

389 lines
10 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.

#include "StdAfx.h"
#include "ScriptTimeCall.h"
#include "../../base/Container.hpp"
//定义BootCall文件头标志
const FileHeaders::FILEIDENT CScriptTimeCallManager::ScriptBootCallFileHeader::FileIdent =
{ MAKEFOURCC('S', 'B', 'C', 0) };
//定义BootCall文件版本号
const FileHeaders::FILEVERSION CScriptTimeCallManager::ScriptBootCallFileHeader::FileVersion =
{ MAKEFOURCC(1, 11, 3, 8) };
using namespace wylib::stream;
using namespace FDOP;
CScriptTimeCallManager::CScriptTimeCallManager()
:Inherited()
{
m_nMarkedRemoveCount = 0;
}
CScriptTimeCallManager::~CScriptTimeCallManager()
{
RemoveAll(FALSE);
ClearBootCallList();
}
VOID STDCALL CScriptTimeCallManager::ScriptTimeCallDispatcher(CScriptTimeCallManager *lpManager, CList<ScriptCallInfo>::NodeType *pCallInfoNode, INT_PTR nCount)
{
ScriptCallInfo &sc = *pCallInfoNode;
sc.pNPC->GetScript().Call(sc.sFn, sc.args, lpManager->m_SRetList, 0);
}
static ULONGLONG GetNextRunTime(LPCSTR sNextRunDateTime, UINT dwSecInterval)
{
INT y, m, d, h, n, s;
y = m = d = h = n = s = 0;
sscanf(sNextRunDateTime, "%d-%d-%d %d:%d:%d", &y, &m, &d, &h, &n, &s);
CMiniDateTime tRun, tNow = CMiniDateTime::now();
tRun.encode(y, m, d, h, n, s);
while (tNow.tv > tRun.tv)
{
tRun += dwSecInterval;
}
return tRun;
}
HANDLE CScriptTimeCallManager::RegisterTimeCall(CNpc *pNPC, LPCSTR sFnName, LPCSTR sNextCall,
UINT dwSecInterval, bool boCallOnNextBoot,const CScriptValueList &args)
{
//如果函数已经被注册,则返回空
if (GetTimeCall(pNPC, sFnName) || !dwSecInterval)
return NULL;
//添加注册信息到自身记录列表
ScriptCallInfo sc1;
CList<ScriptCallInfo>::NodeType *pNode = m_CallList.linkAtLast(sc1);
//为定时调用记录对象赋值
ScriptCallInfo &sc = *pNode;
ZeroMemory(&sc, sizeof(sc));
sc.pNPC = pNPC;
_asncpytA(sc.sFn, sFnName);
_asncpytA(sc.sNPCName, pNPC->GetEntityName());
_asncpytA(sc.sSceneName, pNPC->GetScene()->GetSceneName());
sc.boBootCall = boCallOnNextBoot;
sc.boMarkedRemove = FALSE;
sc.args = args;
ULONGLONG lNextCall = GetNextRunTime(sNextCall, dwSecInterval);
//向定时调用父类中注册调用
sc.hCall = AddTimeCall(this, (CTimeCaller::TimedCallBack)ScriptTimeCallDispatcher, pNode, dwSecInterval, lNextCall);
if (!sc.hCall)
{
sc.~ScriptCallInfo();
m_CallList.remove(pNode);
pNode = NULL;
}
return pNode;
}
bool CScriptTimeCallManager::UnregisterTimeCall(HANDLE hTimeCall)
{
CList<ScriptCallInfo>::Iterator it(m_CallList);
CList<ScriptCallInfo>::NodeType *pNode;
for (pNode = it.first(); pNode; pNode = it.next())
{
if (pNode == hTimeCall)
{
ScriptCallInfo &sc = *pNode;
//如果需要在下次启动的时候检查调用则存储此数据
if (sc.boBootCall)
AddToBootCall(sc);
//移除定时调用对象
RemoveTimeCall(sc.hCall);
//标记为移除
sc.boMarkedRemove = TRUE;
//增加移除标记数
m_nMarkedRemoveCount++;
return true;
}
}
return false;
}
HANDLE CScriptTimeCallManager::GetTimeCall(CNpc *pNPC, LPCSTR sFnName)
{
CList<ScriptCallInfo>::Iterator it(m_CallList);
CList<ScriptCallInfo>::NodeType *pNode;
for (pNode = it.first(); pNode; pNode = it.next())
{
ScriptCallInfo &sc = *pNode;
if (!sc.boMarkedRemove)
{
if (sc.pNPC == pNPC || !pNPC)
{
if (strcmp(sc.sFn, sFnName) == 0)
{
return pNode;
}
}
}
}
return NULL;
}
INT_PTR CScriptTimeCallManager::Run(ULONGLONG lRunTickLimit /* = 0 */)
{
SF_TIME_CHECK();
DECLARE_TIME_PROF("CScriptTimeCallManager::Run");
INT_PTR nRet = Inherited::Run(lRunTickLimit);
if (m_nMarkedRemoveCount > 0)
{
RemoveAll(TRUE);
}
return nRet;
}
VOID CScriptTimeCallManager::RemoveAll(BOOL boJustRemoveMarked)
{
CList<ScriptCallInfo>::Iterator it(m_CallList);
CList<ScriptCallInfo>::NodeType *pNode;
for (pNode = it.first(); pNode; pNode = it.next())
{
ScriptCallInfo &sc = *pNode;
if (boJustRemoveMarked && sc.boMarkedRemove)
{
sc.~ScriptCallInfo();
it.remove(pNode);
}
}
m_nMarkedRemoveCount = 0;
}
VOID CScriptTimeCallManager::AddToBootCall(const ScriptCallInfo& callInfo)
{
ScriptBootCallData bc1;
CList<ScriptBootCallData>::NodeType *pNode = m_BootCallList.linkAtLast(bc1);
ScriptBootCallData &bc = *pNode; //拷贝场景名称、NPC名称、函数名称信息
ZeroMemory(&bc, sizeof(bc));
_asncpytA(bc.sSceneName, callInfo.sSceneName);
_asncpytA(bc.sNPCName, callInfo.sNPCName);
_asncpytA(bc.sFn, callInfo.sFn);
//拷贝参数表
bc.args = callInfo.args;
//计算下次调用的CMiniDateTime类型的时间以及调用周期
ULONGLONG lInterval, lNextCallTick;
lInterval = GetCallInterval(callInfo.hCall, &lNextCallTick);
bc.dwSecInterval = (DWORD)lInterval;
bc.nNextCall = (int)lNextCallTick;
}
VOID CScriptTimeCallManager::ClearBootCallList()
{
/*CList<ScriptBootCallData>::NodeType *pNode;
CList<ScriptBootCallData>::Iterator it(m_BootCallList);*/
// 此地方会造成多次析构。m_BootCallList.clear()自身会析构对象
////循环调用析构函数
//for (pNode = it.first(); pNode; pNode = it.next())
//{
// ScriptBootCallData &bc = *pNode;
// bc.~ScriptBootCallData();
//}
m_BootCallList.clear();
}
INT_PTR CScriptTimeCallManager::RunBootCalls()
{
CNpc *pNpc;
CScene *pScene;
CFuBen *pFb;
INT_PTR Result = 0;
CMiniDateTime tNextCall;
CMiniDateTime tNow;
CFuBenManager *pFbMgr = GetLogicServer()->GetLogicEngine()->GetFuBenMgr();
CList<ScriptBootCallData>::NodeType *pNode;
CList<ScriptBootCallData>::Iterator it(m_BootCallList);
tNow = CMiniDateTime::now();
//必须按顺序检查和调用BootCall否则可能违背脚本中带有先后关系的调用逻辑顺序
for (pNode = it.first(); pNode; pNode = it.next())
{
ScriptBootCallData &bc = *pNode;
if (tNow.tv >= bc.nNextCall.tv)
{
//查找NPC所在场景对象
if (!pFbMgr->GetFbPtrBySceneName(bc.sSceneName, pFb, pScene))
{
OutputMsg(rmWaning, _T("can not call BootCall[%s-%s:%s] scene was removed"),
bc.sSceneName, bc.sNPCName, bc.sFn);
continue;
}
//在场景中查找NPC对象
if ( !(pNpc = pScene->GetNpc(bc.sNPCName)) )
{
OutputMsg(rmWaning, _T("can not call BootCall[%s-%s:%s] NPC was removed"),
bc.sSceneName, bc.sNPCName, bc.sFn);
continue;
}
//检查NPC脚本中是否还存在此函数
if ( !pNpc->GetScript().FunctionExists(bc.sFn) )
{
OutputMsg(rmWaning, _T("can not call BootCall[%s-%s:%s] function does not exists any more"),
bc.sSceneName, bc.sNPCName, bc.sFn);
continue;
}
//循环调用脚本
tNextCall = bc.nNextCall;
do
{
tNextCall.tv += bc.dwSecInterval;
pNpc->GetScript().Call(bc.sFn, bc.args, m_SRetList, 0);
}
while (tNow.tv >= tNextCall.tv);
Result++;
}
}
ClearBootCallList();//清空列表以防止重复调用
return Result;
}
INT_PTR CScriptTimeCallManager::LoadBootCalls(LPCTSTR sFilePath)
{
if (!FileExists(sFilePath))
return 0;
ScriptBootCallFileHeader* pHdr;
CMemoryStream ms;
if (ms.loadFromFile(sFilePath) < sizeof(pHdr))
return -1;
pHdr = (ScriptBootCallFileHeader*)ms.getMemory();
if(!pHdr)
{
return 0;
}
//验证文件是否有效
if (pHdr->ident.uIdent != ScriptBootCallFileHeader::FileIdent.uIdent)
{
OutputMsg(rmError, _T("invalid BootCall file"));
return -2;
}
if (pHdr->version.uVersion != ScriptBootCallFileHeader::FileVersion.uVersion)
{
OutputMsg(rmError, _T("invalid BootCall file vesion %d.%d.%d.%d"),
pHdr->version.p.v, pHdr->version.p.y, pHdr->version.p.m, pHdr->version.p.d);
return -3;
}
if (pHdr->dwSizeData != sizeof(ScriptBootCallData))
{
OutputMsg(rmError, _T("BootCall data structure has been modified"));
return -4;
}
if (pHdr->dwDataCRC32 != ~CRC32Update(0xFFFFFFFF, pHdr + 1, pHdr->dwDataSize))
{
OutputMsg(rmError, _T("BootCall data CRC check failure"));
return -5;
}
ClearBootCallList();
//读取BootCall数据
if (pHdr->dwNumCalls > 0)
{
ScriptBootCallData bcd;
ms.setPosition(sizeof(*pHdr));
for (INT_PTR i=pHdr->dwNumCalls-1; i>-1; --i)
{
CLinkedNode<ScriptBootCallData> *pNode = m_BootCallList.linkAtLast(bcd);
ScriptBootCallData& bc = *pNode;
ZeroMemory(&bc, sizeof(bc));
bc.loadFromStream(ms);
}
}
return pHdr->dwNumCalls;
}
INT_PTR CScriptTimeCallManager::SaveBootCalls(LPCTSTR sFilePath)
{
TCHAR sSavePath[1024];
//获取保存文件的目录路径,如果目录路径字符长度超出缓存长度则报错
if ( ExtractFileDirectory(sFilePath, sSavePath, ArrayCount(sSavePath)) >= ArrayCount(sSavePath) )
{
OutputMsg(rmError, _T("unable to save BootCall Data to %s, path to long"), sFilePath);
return -1;
}
//逐层判断目录是否存在,如果不存在则创建
if ( !DeepCreateDirectory(sSavePath) )
{
OutputError(GetLastError(), _T("unable to create BootCall directory %s "), sSavePath);
return -2;
}
ScriptBootCallFileHeader hdr;
CMemoryStream ms;
ZeroMemory(&hdr, sizeof(hdr));
hdr.ident = ScriptBootCallFileHeader::FileIdent;
hdr.version = ScriptBootCallFileHeader::FileVersion;
hdr.dwNumCalls = (DWORD)m_BootCallList.count();
hdr.dwSizeData = sizeof(ScriptBootCallData);
ms.setSize(sizeof(hdr));
ms.setPosition(sizeof(hdr));
//写入数据
CList<ScriptBootCallData>::NodeType *pNode;
CList<ScriptBootCallData>::Iterator it(m_BootCallList);
for (pNode = it.first(); pNode; pNode = it.next())
{
ScriptBootCallData &bc = *pNode;
bc.saveToStream(ms);
}
//计算数据断CRC
hdr.dwDataSize = (DWORD)ms.getSize() - sizeof(hdr);
if (hdr.dwDataSize == 0)
{
hdr.dwDataSize = 0;
}
else
{
hdr.dwDataCRC32 = ~CRC32Update(0xFFFFFFFF, (LPCSTR)ms.getMemory() + sizeof(hdr), hdr.dwDataSize);
}
//写入文件头
memcpy(ms.getMemory(), &hdr, sizeof(hdr));
ms.saveToFile(sFilePath);
return hdr.dwNumCalls;
}
ULONGLONG CScriptTimeCallManager::GetCurrentTick()
{
return GetGlobalLogicEngine()->getMiniDateTime();
}
bool CScriptTimeCallManager::ScriptBootCallData::loadFromStream(wylib::stream::CBaseStream &stm)
{
stm.read(sSceneName, sizeof(sSceneName));
stm.read(sNPCName, sizeof(sNPCName));
stm.read(sFn, sizeof(sFn));
stm.read(&nNextCall, sizeof(nNextCall));
stm.read(&dwSecInterval, sizeof(dwSecInterval));
args.loadFromStream(stm);
return true;
}
void CScriptTimeCallManager::ScriptBootCallData::saveToStream(wylib::stream::CBaseStream &stm)
{
stm.write(sSceneName, sizeof(sSceneName));
stm.write(sNPCName, sizeof(sNPCName));
stm.write(sFn, sizeof(sFn));
stm.write(&nNextCall, sizeof(nNextCall));
stm.write(&dwSecInterval, sizeof(dwSecInterval));
args.saveToStream(stm);
}