Files
2022-10-26 12:25:11 +08:00

418 lines
14 KiB
C++

#include "stdafx.h"
#include <PacketStruct_AG.h>
#include <PacketStruct_AW.h>
#include <UserSessions/User.h>
#include <UserSessions/UserManager.h>
#include <ServerSessions/BattleServerSession.h>
#include <ServerSessions/FieldServerSession.h>
#include <Zone/DungeonSSQ.h>
#include <Zone/ZoneManager.h>
#include <Party/PartyManager.h>
#include "WarControlManager.h"
#include "./SSQ/ISSQHandler.h"
// for debugging control
#undef WAVERIX_DEBUGGING_OUTPUTn
#undef WAVERIX_DEBUGGING_OUTPUTnV
#define WAVERIX_DEBUGGING_OUTPUTn(msg) \
SUNLOG(eCRITICAL_LOG, "[%s][%u][%u] %s\n", __FUNCTION__, __LINE__, \
(DWORD)((GetTickCount()-tickvalue)/(1000)), msg); \
tickvalue = GetTickCount()
#define WAVERIX_DEBUGGING_OUTPUTnV(value) \
{ CHAR _message[10]; \
WAVERIX_DEBUGGING_OUTPUTn(itoa(value, _message, sizeof(_message))); }
static DWORD tickvalue = GetTickCount();
#define __WAVERIX_LOG_FORMAT_0S(msg) \
{ SUNLOG(eCRITICAL_LOG, "[Func:%s][Line:%3u] %s", __FUNCTION__, __LINE__, msg); }
#define __WAVERIX_LOG_FORMAT_0S1N(msg, value) \
{ SUNLOG(eCRITICAL_LOG, "[Func:%s][Line:%3u] %s (%u)", __FUNCTION__, __LINE__, msg, value); }
#ifdef _DEBUG
#define WAVERIX_DEBUG_LOG_0S(msg) __WAVERIX_LOG_FORMAT_0S(msg)
#define WAVERIX_DEBUG_LOG_0S1N(msg, value) __WAVERIX_LOG_FORMAT_0S1N(msg, value)
#else
#define WAVERIX_DEBUG_LOG_0S(msg)
#define WAVERIX_DEBUG_LOG_0S1N(msg, value)
#endif
#include "./SSQ/SSQControlInfos.hxx"
#include "./SSQ/SSQUpdateCtrl.hxx"
#include "./SSQ/SSQPacketProcess.hxx"
#include "./SSQ/SSQControlManagerImpl.hxx"
//==================================================================================================
// <DEFINITION #2>
//
#define MGR_SSQIMPL ((SSQControlManagerImpl&)*m_pSSQImpl)
#define MGR_SSQIMPLS(this_) ((SSQControlManagerImpl&)*((this_)->m_pSSQImpl))
//==================================================================================================
// <WarControlManager>
WORK_KEY
WarControlManager::ms_WorkKey = 0;
WarControlManager*
WarControlManager::ms_pWarControlManager = NULL;
WarControlManager::WarControlManager()
{
ms_pWarControlManager = this;
m_pSSQImpl = new SSQControlManagerImpl();
}
WarControlManager::~WarControlManager()
{
SAFE_DELETE(m_pSSQImpl);
ms_pWarControlManager = NULL;
}
//--------------------------------------------------------------------------------------------------
// <IWorkNode Interface>
BOOL
WarControlManager::DoInit()
{
MGR_SSQIMPL.ScheduleUpdateTimer.SetTimer(INTERVALofUPDATE);
MGR_SSQIMPL.MessageUpdateTimer.SetTimer(INTERVALofUPDATE);
//__NA001189_081015_SSQ_TICKET_INFO_CTRL__
sTIME_INFO timeInfo;
sTIME_INFO::SetTimeValue(timeInfo);
const DWORD SSQTicketTimeInterval = 1*1000; //1sec
MGR_SSQIMPL.SSQTicketTimer.SetTimer(SSQTicketTimeInterval);
MGR_SSQIMPL.SSQTicketTimeInfoCtrl.Init();
MGR_SSQIMPL.SSQTicketTimeInfoCtrl.Update(&timeInfo.SysTime);
const SYSTEMTIME& rCountdown = MGR_SSQIMPL.SSQTicketTimeInfoCtrl.GetTicketTimeInfo();
__TOUCHED(rCountdown); // for debug
const nsSSQ::SSQTicketInfo& rInfo = MGR_SSQIMPL.SSQTicketTimeInfoCtrl.GetTicketInfo();
MGR_SSQIMPL.SSQTicketTimeInfoCtrl.QueryResult(rInfo);
MGR_SSQIMPL._InitializeUpdateCtrl();
return TRUE;
}
BOOL
WarControlManager::DoProcess()
{
sTIME_INFO* pTimeInfo = 0;
sTIME_INFO timeInfo;
ITimerBase& rTimeScheduler = MGR_SSQIMPL.ScheduleUpdateTimer;
if(rTimeScheduler.IsExpired())
{
sTIME_INFO::SetTimeValue(timeInfo);
pTimeInfo = &timeInfo;
SSQ_UPDATERS& rList = MGR_SSQIMPL.UpdateList;
FOREACH_CONTAINER(SSQ_UPDATER_NODE& rCtrlNode, rList, SSQ_UPDATERS)
{
rCtrlNode.pUpdater->UpdateMsg(timeInfo);
// (WAVERIX) (WARNING)
// - ->Update(~)를 호출한 이후의 pCtrl은 무결성이 깨질 수 있다.
// (내부에서 pCtrl 자체가 해제된다, 다음 상태를 준비해주고...)
// - 따라서 ->Update(~) 이후에 pCtrl에 대한 어떠한 제어 코드도 넣어서는 안된다.
rCtrlNode.pUpdater->Update(timeInfo);
// must be do not use 'pCtrl'
}
}
ITimerBase& rSSQTicketUpdate = MGR_SSQIMPL.SSQTicketTimer;
if(rSSQTicketUpdate.IsExpired())
{
if(!pTimeInfo)
sTIME_INFO::SetTimeValue(timeInfo);
MGR_SSQIMPL.SSQTicketTimeInfoCtrl.Update(&timeInfo.SysTime);
MGR_SSQIMPL.SSQSingletonNoticeCtrl.Update(timeInfo);
}
return TRUE;
}
BOOL
WarControlManager::IsComplete()
{
return FALSE;
}
BOOL
WarControlManager::DoRelease()
{
MGR_SSQIMPL._ReleaseUpdateCtrl();
return TRUE;
}
// Control Interface
VOID
WarControlManager::OnMsg(sSIG_MSG* pSIG_MSG)
{
__UNUSED(pSIG_MSG);
}
//--------------------------------------------------------------------------------------------------
// <INTERFACEs>
VOID
WarControlManager::Update()
{
}
#define SSQ_PACKET_HANDLER_CALL(c, p) \
case MAKEWORD(c, p): \
MGR_SSQIMPL.OnRecv_##p(static_cast<const MSG_##p*>(pMsg), wSize, pSession.m_pSession); \
break
VOID
WarControlManager::OnRecv(const MSG_BASE* const pMsg, const WORD wSize,
const SSQSessionCmd::FromClient& pSession)
{
const WORD protocol = MAKEWORD(pMsg->m_byCategory, pMsg->m_byProtocol);
switch(protocol)
{
SSQ_PACKET_HANDLER_CALL(CG_ZONE_EX, CG_ZONE_EX_SSQ_JOIN_INFO_SYN);
SSQ_PACKET_HANDLER_CALL(CG_ZONE_EX, CG_ZONE_EX_SSQ_JOIN_SYN);
SSQ_PACKET_HANDLER_CALL(CG_ZONE_EX, CG_ZONE_EX_SSQ_ROOM_INFO_SYN);
SSQ_PACKET_HANDLER_CALL(CG_ZONE_EX, CG_ZONE_EX_SSQ_OBSERVER_SYN);
default:
FlowControl::FCAssert(!"Unexpected Status");
}
return;
}
VOID
WarControlManager::OnRecv(const MSG_BASE* const pMsg, const WORD wSize,
const SSQSessionCmd::FromGame& pSession)
{
const WORD protocol = MAKEWORD(pMsg->m_byCategory, pMsg->m_byProtocol);
switch(protocol)
{
SSQ_PACKET_HANDLER_CALL(AG_ZONE, AG_ZONE_SSQ_JOIN_INFO_ACK);
SSQ_PACKET_HANDLER_CALL(AG_ZONE, AG_ZONE_SSQ_JOIN_ACK);
SSQ_PACKET_HANDLER_CALL(AG_ZONE, AG_ZONE_SSQ_ROOM_CTRL_CMD);
SSQ_PACKET_HANDLER_CALL(AG_ZONE, AG_ZONE_SSQ_ROOM_INFO_BRD);
default:
FlowControl::FCAssert(!"Unexpected Status");
}
return;
}
VOID
WarControlManager::OnRecv(const MSG_BASE* const pMsg, const WORD wSize, const SSQSessionCmd::FromWorld& pSession)
{
const WORD protocol = MAKEWORD(pMsg->m_byCategory, pMsg->m_byProtocol);
switch(protocol)
{
SSQ_PACKET_HANDLER_CALL(AW_OPERATION, AW_OPERATION_ROOM_CTRL_CMD);
default:
FlowControl::FCAssert(!"Unexpected Status");
}
return;
}
const nsSSQ::SSQTicketInfo&
WarControlManager::GetTicketInfo()
{
static const BYTE sNullTicketInfo[sizeof(nsSSQ::SSQTicketInfo)] = { 0, };
if(ms_pWarControlManager == 0)
return *reinterpret_cast<const nsSSQ::SSQTicketInfo*>(sNullTicketInfo);
WarControlManager* const this_ = ms_pWarControlManager;
return MGR_SSQIMPLS(this_).SSQTicketTimeInfoCtrl.GetTicketInfo();
}
VOID
WarControlManager::Serialize()
{
}
BOOL
WarControlManager::SendPacket(const MSG_BASE* pMsg, const WORD wSize)
{
__UNUSED((pMsg, wSize));
return TRUE;
}
//==================================================================================================
// <WarControlManager><SendPacket>
VOID
WarControlManager::OnMsg(const SSQCtrlCmd::Created&, DungeonSSQ* const pDungeonSSQ)
{
if(ms_pWarControlManager == 0)
return;
WarControlManager* const this_ = ms_pWarControlManager;
// 생성된 Key와 MapCode 연결시켜야 한다.
const MAPCODE CodeOfSSQ = pDungeonSSQ->GetMapCode();
const KEYTYPE zoneKey = pDungeonSSQ->GetKey();
MSG_AG_ZONE_INSTANCE_CREATE_CMD msg;
msg.m_dwKey = 0;
msg.m_MapCode = CodeOfSSQ;
msg.m_RoomKey = zoneKey;
msg.m_TypeOfIndun = INDUN_KIND_SS_QUEST;
msg.m_RoomInfo = *pDungeonSSQ->GetRoomInfo(); //< 생성할 방 정보
#ifdef _NA_004204_20120131_BATTLE_ZONE_PARTY_OBTAIN
msg.party_zone_info_ = PartyOfTopOfTrialByNormal;
#endif //_NA_004204_20120131_BATTLE_ZONE_PARTY_OBTAIN
pDungeonSSQ->SendToLinkedServer(&msg, sizeof(msg));
//////////////////////////////////////////////////////////////////////////
// 임시 처리
SSQ_UPDATERS_IT itFind = MGR_SSQIMPLS(this_)._FindCodeOfSSQ(CodeOfSSQ);
if(itFind == MGR_SSQIMPLS(this_).UpdateList.end())
return;
SSQ_UPDATER_NODE& rNode = *itFind;
// 아래와 같은 상황은 클리어 하지 못하다. 한번에 할 수 있도록 하자.
rNode.SetKey(zoneKey);
SSQUpdateCtrl& rCtrl = *rNode.pUpdater;
rCtrl.SetSSQField(pDungeonSSQ);
SSQMsgRouterInAgent* const pMsgRouter = rCtrl.GetMsgRouter();
if(pDungeonSSQ->GetLinkedServer())
{
pMsgRouter->RegisterLinkedServer(pDungeonSSQ->GetLinkedServer()->GetSessionIndex());
BROADCASTER_MSG_AG_ZONE_SSQ_ROOM_CTRL_CMD& rMsgCMD = pMsgRouter->GetCMD_AG();
WAR_MSG_HDR* const pHeader = &rMsgCMD.MSG_HEADER;
{
MSGSUB_SSQ_S2S_FIELD_CREATE msg;
msg.SerializeTo(pHeader);
}
}
//////////////////////////////////////////////////////////////////////////
}
VOID
WarControlManager::OnMsg(const SSQCtrlCmd::Destroy&, DungeonSSQ* const pDungeonSSQ)
{
// 1) Agent가 SSQ Process에 따른 종료를 발생시킬 경우,
// 2) Agent가 BattleServer down등의 이유로 관련 서버에 존재하는 존들을 일괄 종료시키는 경우
// 1-1) 1의 경우라면, 해당 BattleServer::SSQ에 유저들은 클리어 된 상황이어야 한다.
// BattleServer의 SSQ존 해제 <- SSQ존은 Instance Static Dungeon 형태, 유저가 없고, 타임아웃이 없는 상황에서 계속 살아있기 때문.
// 2-1) 2는 상당히 골치가 아픈 문제다. 복구 등등, 좀더 경우의 수를 따져서 평가해야 할 것이다.
// (080724)(FOCUS)
// - 해당 서버로 보낼 메시지 등의 무결성 문제를 해결하라.
// - 일단 종료 처리 순서상 LinkedServer의 Ptr및 정보 자체는 유효하다.
// - ...애시당초 서버가 끊어졌다고 종료되는 상황임을 어떻게 파악할 것인가?...
if(ms_pWarControlManager == 0)
return;
WarControlManager* const this_ = ms_pWarControlManager;
// 생성된 Key와 MapCode 연결시켜야 한다.
const MAPCODE CodeOfSSQ = pDungeonSSQ->GetMapCode();
const KEYTYPE zoneKey = pDungeonSSQ->GetKey();
//////////////////////////////////////////////////////////////////////////
// 임시 처리
SSQ_UPDATERS_IT itFind = MGR_SSQIMPLS(this_)._FindCodeOfSSQ(CodeOfSSQ);
if(itFind == MGR_SSQIMPLS(this_).UpdateList.end())
return;
SSQ_UPDATER_NODE& rNode = *itFind;
SSQUpdateCtrl* const pCtrl = rNode.pUpdater;
SSQMsgRouterInAgent* const pMsgRouter = pCtrl->GetMsgRouter();
pMsgRouter->Update(CodeOfSSQ); // flush buffer
//pMsgRouter->RegisterLinkedServer(0); // in Update : Auto-clear
// Last Process
rNode.SetKey(0);
pCtrl->SetSSQField(0); // clear
// replace pCtrl
const eTIME_TYPE updater_type = pCtrl->GetTimeType();
SSQUpdateCtrl_None* const pNoneCtrl = TAllocNew(SSQUpdateCtrl_None_Info::value_type);
{
pNoneCtrl->Migration(pNoneCtrl, pCtrl);
sTIME_INFO tmInfo;
sTIME_INFO::SetTimeValue(tmInfo);
pNoneCtrl->Init(tmInfo);
pNoneCtrl->RegisterUpdateCtrl(pNoneCtrl);
rNode.pUpdater = pNoneCtrl;
}
// < 이것 함수 호출 하나로 해결할 수 있도록 하자.
switch(updater_type)
{
case TT_NONE: TAllocDelete(SSQUpdateCtrl_None_Info::value_type, pCtrl); break;
case TT_NOTICE: TAllocDelete(SSQUpdateCtrl_Notice_Info::value_type, pCtrl); break;
case TT_WAITING:TAllocDelete(SSQUpdateCtrl_Waiting_Info::value_type, pCtrl); break;
case TT_BATTLE: TAllocDelete(SSQUpdateCtrl_Battle_Info::value_type, pCtrl); break;
case TT_CLEAR: TAllocDelete(SSQUpdateCtrl_Clear_Info::value_type, pCtrl); break;
}
//////////////////////////////////////////////////////////////////////////
//
}
VOID
WarControlManager::OnMsg(const SSQCtrlCmd::UserState& rInfo, DungeonSSQ* const pDungeonSSQ)
{
if(ms_pWarControlManager == 0)
return;
WarControlManager* const this_ = ms_pWarControlManager;
// (WAVERIX) (080727)
// - 유저가 SSQ를 빠져 나간 후에 보상 처리 방안을 강구하자.
// 현재 트랜잭션은 SSQ를 입장하기 전부터 일어난다. 일어난 후에도 얼마간은 유지하는 형태면 어떨까?
const MAPCODE CodeOfSSQ = pDungeonSSQ->GetMapCode();
SSQ_UPDATERS_IT itFind = MGR_SSQIMPLS(this_)._FindCodeOfSSQ(CodeOfSSQ);
if(itFind == MGR_SSQIMPLS(this_).UpdateList.end())
return;
SSQ_UPDATER_NODE& rNode = *itFind;
SSQUpdateCtrl* const pCtrl = rNode.pUpdater;
User* const pUser = rInfo.pUser;
rInfo.isEnter ? pCtrl->UserEnter(pUser)
: pCtrl->UserLeave(pUser);
}
VOID
WarControlManager::OnMsg(const SSQCtrlCmd::UserEvent& rInfo, DungeonSSQ* const pDungeonSSQ)
{
if(ms_pWarControlManager == 0)
return;
WarControlManager* const this_ = ms_pWarControlManager;
// (WAVERIX) (080727)
// - 유저가 SSQ를 빠져 나간 후에 보상 처리 방안을 강구하자.
// 현재 트랜잭션은 SSQ를 입장하기 전부터 일어난다. 일어난 후에도 얼마간은 유지하는 형태면 어떨까?
const MAPCODE CodeOfSSQ = pDungeonSSQ->GetMapCode();
SSQ_UPDATERS_IT itFind = MGR_SSQIMPLS(this_)._FindCodeOfSSQ(CodeOfSSQ);
if(itFind == MGR_SSQIMPLS(this_).UpdateList.end())
return;
SSQ_UPDATER_NODE& rNode = *itFind;
SSQUpdateCtrl* const pCtrl = rNode.pUpdater;
User* const pUser = rInfo.pUser;
switch(rInfo.event)
{
case SSQCtrlCmd::OnAG_RoomJoinAck:
{
MGR_SSQIMPLS(this_).OnRecv_AG_RoomJoinAck(pCtrl, pUser, pDungeonSSQ);
}
break;
}
}