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

2685 lines
95 KiB
C++

#include "stdafx.h"
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#include "ZoneManager.h"
#include <PacketStruct_AG.h>
#include <Zone/PortalManager.h>
#include <UserSessions/UserManager.h>
//_NA_20110630_BATTLE_ZONE_RENEWAL
#include "..\AgentParty\PartyRoomList.h"
#include "..\Party\PartyRoom.h"
ZoneManager g_ZoneManager;
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// <Imlementation for Control Fuctions>
//
#include "ZoneManager.Addin.hxx"
#ifdef _NA_007734_20141027_ADD_ROOMKIND_SPECIALMISSION
#include "BattlezoneMissionTreeParser.h"
#endif //_NA_007734_20141027_ADD_ROOMKIND_SPECIALMISSION
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// <Implementation>
//
ZoneManager::ZoneManager(void)
{
// Zone의 키값이 WORD를 넘어가면 GameZone의 m_Key 값을 DWORD로 바꿔줘야하고,
//m_ZoneKeyGenerater.Create(1, 10000);
m_pObjectKeyStream = new ObjectKeyStream;
m_UpdateTimer.SetTimer(1*1000);
m_ZoneUserCountTotal = 0;
ZeroMemory(&m_ZoneCounts, sizeof(m_ZoneCounts));
ZeroMemory(&m_ZoneUserCounts, sizeof(m_ZoneUserCounts));
#undef REG_ZONE_NODE
#define REG_ZONE_NODE(_typeinfo) \
m_PoolRouter.Register<_typeinfo::type>(_typeinfo::value);
REG_ZONE_LIST();
#undef REG_ZONE_NODE
#define REG_ZONE_NODE(_typeinfo) \
m_PoolRouter.Initialize(_typeinfo::value, _typeinfo::size_init_pool, _typeinfo::size_addin_pool, #_typeinfo, AssertionLogger4Pool_Server);
REG_ZONE_LIST();
#undef REG_ZONE_NODE
#define REG_ZONE_NODE(_typeinfo) \
m_PoolRouterForIndun.Register<_typeinfo::type>(_typeinfo::value);
REG_INDUN_LIST();
#undef REG_ZONE_NODE
#define REG_ZONE_NODE(_typeinfo) \
m_PoolRouterForIndun.Initialize(_typeinfo::value, _typeinfo::size_init_pool, _typeinfo::size_addin_pool, #_typeinfo, AssertionLogger4Pool_Server);
REG_INDUN_LIST();
//_InitAlignKeyMatchingInfo();
}
ZoneManager::~ZoneManager(void)
{
SAFE_DELETE(m_pObjectKeyStream);
m_PoolRouter.Release();
m_PoolRouterForIndun.Release();
if (m_StaticZones.empty() == false) {
m_StaticZones.clear();
};
}
ZoneInterface*
ZoneManager::_FindRoomBySeperated(const eZONETYPE zoneType, const KEYTYPE key) const
{
const DWORD ROOM_TYPE_MASK = (1 << eZONETYPE_LOBBY )
| (1 << eZONETYPE_HUNTING )
| (1 << eZONETYPE_MISSION )
| (1 << eZONETYPE_PVP )
| (1 << eZONETYPE_CHUNTING );
const DWORD inputedType = 1 << zoneType;
if((ROOM_TYPE_MASK & inputedType) == 0)
return NULL;
const ObjectKeyStream::sNode* pNode = m_pObjectKeyStream->GetObjectInfo(key);
if((pNode && pNode->pObject) == 0)
return NULL;
const eZONETYPE storedType = (eZONETYPE)pNode->AddinInfo.ZoneType;
return (zoneType == storedType)
? pNode->pObject
: NULL;
}
LobbyRoom*
ZoneManager::_FindLobbyBySeperated(const eZONETYPE zoneTypeOfLobby, const KEYTYPE key) const
{
const DWORD LOOBYforROOM_TYPE_MASK = (1<<eZONETYPE_HUNTING )
| (1<<eZONETYPE_MISSION )
| (1<<eZONETYPE_PVP )
| (1<<eZONETYPE_CHUNTING );
const DWORD inputedType = 1 << zoneTypeOfLobby;
if((LOOBYforROOM_TYPE_MASK & inputedType) == 0)
return NULL;
const ObjectKeyStream::sNode* pNode = m_pObjectKeyStream->GetObjectInfo(key);
if((pNode && pNode->pObject) == 0)
return NULL;
const eZONETYPE storedType = eZONETYPE(pNode->AddinInfo.ZoneType);
if(eZONETYPE_LOBBY == storedType)
{
LobbyRoom* const pLobbyRoom = LobbyRoom_Info::downcast(pNode->pObject);
const eZONETYPE lobbyForXRoom = pLobbyRoom->GetLobbyType();
if (zoneTypeOfLobby == lobbyForXRoom) {
return pLobbyRoom;
};
}
return NULL;
}
VOID
ZoneManager::_FreeZone(ZoneInterface* IN pZone)
{
m_PoolRouter.Free(pZone->GetType(), pZone);
}
VOID
ZoneManager::_FreeIndun(ZoneInterface* IN pZone)
{
InstanceDungeon* const pInstanceDungeon = InstanceDungeon_Info::downcast(pZone);
m_PoolRouterForIndun.Free(pInstanceDungeon->GetDungeonType(), pZone);
}
//ZoneInterface*
//ZoneManager::FindZone(const KEYTYPE key)
//{
// ZONE_TABLE& rTable = m_ZoneTableList[eZONETYPE_SHI_TOTAL];
// ZONE_TABLE_IT it = rTable.find(key);
// return it != rTable.end() ? it->second : NULL;
//}
ZoneInterface*
ZoneManager::FindStaticZone(const MAPCODE mapCode) const
{
const DWORD STATIC_ZONE_MASK =
(1 << eZONETYPE_VILLAGE) | (1 << eZONETYPE_FIELD) | (1 << eZONETYPE_DOMINATION_FIELD) | ( 1 << eZONETYPE_SPA_FIELD);
ZONE_MCODE_TABLE::const_iterator itFind = m_StaticZones.find(mapCode);
if(itFind != m_StaticZones.end())
{
const KEYTYPE zoneKey = itFind->second;
ZoneInterface* const pZoneInterface = FindZone(zoneKey);
if(pZoneInterface)
{
const DWORD zoneTypeBit = 1<<pZoneInterface->GetType();
if(STATIC_ZONE_MASK & zoneTypeBit)
return pZoneInterface;
}
}
return NULL;
}
Village*
ZoneManager::FindVillage(const MAPCODE mapCode) const
{
const DWORD STATIC_ZONE_MASK = (1<<eZONETYPE_VILLAGE);
ZoneInterface* const pZoneInterface = FindStaticZone(mapCode);
if(pZoneInterface)
{
const DWORD zoneTypeBit = 1 << pZoneInterface->GetType();
if(STATIC_ZONE_MASK & zoneTypeBit)
return Village_Info::downcast(pZoneInterface);
}
return NULL;
}
HuntingField*
ZoneManager::FindHuntingField(const MAPCODE mapCode) const
{
const DWORD STATIC_ZONE_MASK = (1<<eZONETYPE_FIELD);
ZoneInterface* const pZoneInterface = FindStaticZone(mapCode);
if(pZoneInterface)
{
const DWORD zoneTypeBit = 1 << pZoneInterface->GetType();
if(STATIC_ZONE_MASK & zoneTypeBit)
return HuntingField_Info::downcast(pZoneInterface);
}
return NULL;
}
DominationField*
ZoneManager::FindDominationField(const MAPCODE mapCode) const
{
const DWORD STATIC_ZONE_MASK = (1<<eZONETYPE_DOMINATION_FIELD);
ZoneInterface* const pZoneInterface = FindStaticZone(mapCode);
if(pZoneInterface)
{
const DWORD zoneTypeBit = 1 << pZoneInterface->GetType();
if(STATIC_ZONE_MASK & zoneTypeBit)
return DominationField_Info::downcast(pZoneInterface);
}
return NULL;
}
InstanceDungeon*
ZoneManager::FindStaticDungeon(const MAPCODE mapCode) const
{
const DWORD STATIC_DUNGEON_MASK = (1 << eZONETYPE_INSTANCE);
const DWORD INDUN_KIND_MASK = (1 << INDUN_KIND_SS_QUEST);
ZONE_MCODE_TABLE::const_iterator itFind = m_StaticDungeons.find(mapCode);
if(itFind != m_StaticDungeons.end())
{
const KEYTYPE zoneKey = itFind->second;
ZoneInterface* const pZoneInterface = FindZone(zoneKey);
if(pZoneInterface)
{
const DWORD zoneTypeBit = 1 << pZoneInterface->GetType();
if(STATIC_DUNGEON_MASK & zoneTypeBit)
{
InstanceDungeon* const pInstanceDungeon = InstanceDungeon_Info::downcast(pZoneInterface);
const DWORD indunTypeBit = 1 << pInstanceDungeon->GetDungeonType();
if(INDUN_KIND_MASK & indunTypeBit)
return pInstanceDungeon;
else
FlowControl::FCAssert(!"Invalid Static Dungeon : Check ZoneManager Control Flow");
}
}
}
return NULL;
}
//Village*
//ZoneManager::FindVillage(const MAPCODE mapCode)
//{
// ZONE_TABLE& rTable = m_ZoneTableList[eZONETYPE_VILLAGE];
// ZONE_TABLE_IT it = rTable.find(mapCode);
// return it != rTable.end() ? Village_Info::downcast(it->second) : NULL;
//}
CharSelect*
ZoneManager::FindCharSelect(const KEYTYPE key) const
{
const KEYTYPE charselect_key = nsKeyInfo::ZONE_KEY_START+1;
WAVERIX_ZONE_ASSERT(charselect_key == key);
ZoneInterface* const pZoneInterface = FindZone(key);
if(pZoneInterface)
{
const eZONETYPE zoneType = pZoneInterface->GetType();
if(eZONETYPE_CHARSELECT == zoneType)
return CharSelect_Info::downcast(pZoneInterface);
}
return 0;
}
LobbyRoom*
ZoneManager::FindCHuntingLobbyByCkey(const KEYTYPE key) const
{
STLX_MAP< KEYTYPE, KEYTYPE >::const_iterator itFind = m_CHuntingLobbyByCKey.find(key);
if(itFind != m_CHuntingLobbyByCKey.end())
{
const KEYTYPE lobbyKey = itFind->second;
const ObjectKeyStream::sNode* pNode = m_pObjectKeyStream->GetObjectInfo(lobbyKey);
if(!(pNode && pNode->pObject))
return NULL;
LobbyRoom_Info::pointer_r pLobby = LobbyRoom_Info::downcast(pNode->pObject);
return pLobby;
}
return NULL;
}
VOID
ZoneManager::CreateCharSelect()
{
CharSelect_Info::pointer_r pCharSelect = CharSelect_Info::downcast(_AllocZone(CharSelect_Info::value));
const KEYTYPE charselect_key = nsKeyInfo::ZONE_KEY_START+1;
const KEYTYPE key = AllocKey();
WAVERIX_ZONE_ASSERT(charselect_key == key);
pCharSelect->Create(key);
AddRoom(pCharSelect);
}
#ifdef __NA000000_081029_STATIC_ZONE_MATCHING_TABLE__
// post script loaded, make key-mapcode table for sync worldserver
void ZoneManager::CreateConstStaticZoneTable()
{
// NOTE: f110520.5L, f081029.x, make static field unique index
// like villages, fields and domination fields.
// the '1' key index reserved here to support the character selectable zone.
const KEYTYPE kConstStaticZoneStartKey = 2;
if (FlowControl::FCAssert(AllocKey() == kConstStaticZoneStartKey) == false) {
__debugbreak();
return;
};
const MapInfoParser* const map_parser = MapInfoParser::Instance();
const KEYTYPE instance_map_start_index = map_parser->GetInstanceMapStartIndex();
// pop reserved indices
for (KEYTYPE reserved_index = this->AllocKey();
reserved_index < instance_map_start_index;
reserved_index = this->AllocKey())
{
continue;
}
}
#endif //__NA000000_081029_STATIC_ZONE_MATCHING_TABLE__
RC::eROOM_RESULT
ZoneManager::CreateVillage(MAPCODE mapCode, ZoneInterface* OUT pVillageOut)
{
ServerSession* pServerSession = (ServerSession*)ServerSessionManager::Instance()->GetFieldServer();
if(!pServerSession)
{
SUNLOG(eFULL_LOG, "[RoomControler::CreateVillageRoom] 필드서버가 아닌 세션을 연결하려한다.1\n");
return RC::RC_ROOM_FAILED;
}
Village_Info::pointer_r pVillage = Village_Info::downcast(_AllocZone(Village_Info::value));
#ifdef __NA000000_081029_STATIC_ZONE_MATCHING_TABLE__
// NOTE: f110520.5L, static fields use the reserved unique key.
const MapInfoParser* const map_parser = MapInfoParser::Instance();
const sMAPINFO* map_info = map_parser->FindMapInfo(mapCode);
if (FlowControl::FCAssert(map_info != NULL) == false) {
return RC::RC_ROOM_FAILED;
};
const KEYTYPE alloced_key = map_info->reserved_key_index_;
#else
const KEYTYPE alloced_key = AllocKey();
#endif
pVillage->Create(alloced_key, mapCode, pServerSession);
AddRoom(pVillage);
if(pVillageOut)
pVillageOut = pVillage;
return RC::RC_ROOM_SUCCESS;
}
RC::eROOM_RESULT
ZoneManager::CreateHuntingField(MAPCODE mapCode, ZoneInterface* OUT pHuntingField)
{
ServerSession* pServerSession = (ServerSession*)ServerSessionManager::Instance()->GetFieldServer();
if(!pServerSession)
{
SUNLOG(eFULL_LOG, "[RoomControler::CreateHuntingField] 필드서버가 아닌 세션을 연결하려한다.1\n");
return RC::RC_ROOM_FAILED;
}
HuntingField_Info::pointer_r pField = HuntingField_Info::downcast(_AllocZone(HuntingField_Info::value));
#ifdef __NA000000_081029_STATIC_ZONE_MATCHING_TABLE__
// NOTE: f110520.5L, static fields use the reserved unique key.
const MapInfoParser* const map_parser = MapInfoParser::Instance();
const sMAPINFO* map_info = map_parser->FindMapInfo(mapCode);
if (FlowControl::FCAssert(map_info != NULL) == false) {
return RC::RC_ROOM_FAILED;
};
const KEYTYPE alloced_key = map_info->reserved_key_index_;
#else
const KEYTYPE alloced_key = AllocKey();
#endif
pField->Create(alloced_key, mapCode, pServerSession);
AddRoom(pField);
if(pHuntingField)
pHuntingField = pField;
return RC::RC_ROOM_SUCCESS;
}
RC::eROOM_RESULT
ZoneManager::CreateDominationField(MAPCODE mapCode, ZoneInterface* OUT pDominationField)
{
ServerSession* pServerSession = (ServerSession*)ServerSessionManager::Instance()->GetFieldServer();
if(!pServerSession)
{
SUNLOG(eFULL_LOG, "[RoomControler::CreateDominationField] 필드서버가 아닌 세션을 연결하려한다.1\n");
return RC::RC_ROOM_FAILED;
}
DominationField_Info::pointer_r pField = DominationField_Info::downcast(_AllocZone(DominationField_Info::value));
#ifdef __NA000000_081029_STATIC_ZONE_MATCHING_TABLE__
// NOTE: f110520.5L, static fields use the reserved unique key.
const MapInfoParser* const map_parser = MapInfoParser::Instance();
const sMAPINFO* map_info = map_parser->FindMapInfo(mapCode);
if (FlowControl::FCAssert(map_info != NULL) == false) {
return RC::RC_ROOM_FAILED;
};
const KEYTYPE alloced_key = map_info->reserved_key_index_;
#else
const KEYTYPE alloced_key = AllocKey();
#endif
pField->Create(alloced_key, mapCode, pServerSession);
AddRoom(pField);
if(pDominationField)
pDominationField = pField;
return RC::RC_ROOM_SUCCESS;
}
ServerSessionEx*
ZoneManager::_CheckRoomCountLimit(FlowControl& flow) // 방 개수 제한과 같은 LinkServer Check
{
FLOWCONTROL_START()
{
// start LOGIC_BLOCK
ServerSessionManager* const pServerSessionManager = ServerSessionManager::Instance();
ServerSessionEx* pServerSession = pServerSessionManager->GetFieldServer();
IfFailThenBreak(pServerSession, RC::RC_ROOM_FAILED);
const DWORD battleSessions = pServerSessionManager->GetBattleServerSessionNum();
IfFailThenBreak(battleSessions, RC::RC_ROOM_CANNOT_CREATE_ROOM_FOR_LIMIT);
const SERVER_COMMON_OPTION& stServerOptionInfo = ServerOptionParserEx::Instance()->GetServerOption();
const WORD limit_max_room = stServerOptionInfo.m_wMAX_ROOM_COUNT;
IfFailThenBreak(GetBattleServerZoneCount() < limit_max_room * battleSessions,
RC::RC_ROOM_CANNOT_CREATE_ROOM_FOR_LIMIT);
return pServerSession;
}
FLOWCONTROL_END;
return NULL;
};
void
ZoneManager::CheckRuleForRoom(User* creator, const BASE_ROOMINFO& base, BASE_ROOMINFO* OUT modified)
{
// Create~~Room을 수행하기 전에 한번 거치도록 하자.
*modified = base;
// (WAVERIX) (090829) (NOTE) 빌링에 의한 PC방 정량 만료 정책은 국내밖에 없다고 한다.
#ifdef _PCBANG_POLICY_CHANGE_POST_EXPIRED
if(modified->m_SpecialType == eROOM_SPECIAL_PCBANG_SUPER_ROOM) {
if(creator->CanApplyPCBangBenefit(TRUE) == 0)
modified->m_SpecialType = eROOM_SPECIAL_NORMAL;
}
#endif
}
RC::eROOM_RESULT
ZoneManager::CreateLobbyRoom(KEYTYPE staticZoneKey, User* pMasterUser,
MAPCODE mapCode, eZONETYPE eLobbyType, eZONEPUBLIC ePublic,
TCHAR* pszRoomTitle, TCHAR* pszRoomPWD, BASE_ROOMINFO& IN roomInfo,
BYTE byMaxLimitUserNum, KEYTYPE linkHuntingKey,
LobbyRoom*& OUT pLobbyRoom)
{
FlowControl flow;
FLOWCONTROL_START()
{
// start LOGIC_BLOCK
ServerSessionEx* pServerSession = _CheckRoomCountLimit(flow);
if(NULL == pServerSession)
break;
// (WAVERIX) (090522) (CHANGES) 튜토리얼 예외 검사 기능 수정
ZoneInterface* const pRequestedZone = FindZone(staticZoneKey);
BOOLEAN isAcceptable = pRequestedZone &&
(pRequestedZone->GetType() == eZONETYPE_VILLAGE ||
pRequestedZone->GetMapCode() == HardCode::MAPCODE_for_TUTORIAL_FIELD);
IfFailThenBreak(isAcceptable != 0, RC::RC_ROOM_NOTEXISTVILLAGE);
//////////////////////////////////////////////////////////////////////////
// <Main Logic>
const KEYTYPE lobbyKey = AllocKey();
pLobbyRoom = LobbyRoom_Info::downcast(_AllocZone(LobbyRoom_Info::value));
RC::eROOM_RESULT rt = pLobbyRoom->Create(pMasterUser, lobbyKey, mapCode, eLobbyType, ePublic, pszRoomTitle, pszRoomPWD, roomInfo, (ServerSession*)pServerSession, linkHuntingKey);
IfFailThenBreak(rt == RC::RC_ROOM_SUCCESS, rt);
// 인원수 제한
// 최대인원 제한을 설정한다.
#ifdef __NA_000000_20070528_TAIWAN_GUILD_PVP
if(roomInfo.IsSpecialType(eROOM_SPECIAL_GUILD_PVP))
pLobbyRoom->SetLimitMaxUserNum(5);
else
#endif
if(byMaxLimitUserNum)
{ // (WAVERIX) (090522) (CHANGES)
const sMAPINFO* pInfo = pLobbyRoom->GetMapInfo();
//const sMAPINFO* pInfo = pMapInfoParser->FindMapInfo(mapCode);
byMaxLimitUserNum = min(pInfo->byMaxUserNum, byMaxLimitUserNum);
pLobbyRoom->SetLimitMaxUserNum(byMaxLimitUserNum);
}
AddRoom(pLobbyRoom);
// 방장 파티상태에 따라서 방에 새로이 파티를 생성하거나 설정한다.
AgentPartyManager::Instance()->CreateZone(pMasterUser, pRequestedZone, pLobbyRoom);
RoomArgument args(ePublic, pszRoomPWD);
rt = MoveZone(pRequestedZone, pLobbyRoom, pMasterUser, args);
IfFailThenBreak(rt == RC::RC_ROOM_SUCCESS, rt);
// 어... pLobbyRoom 붕~ 뜨네?
// 문제 없는지 확인 필요.
return rt;
}
FLOWCONTROL_END;
const DWORD errCode = flow.GetErrorCode();
DWORD OUT errAddin = 0;
switch(errCode)
{
case RC::RC_ROOM_FAILED: break;
case RC::RC_ROOM_CANNOT_CREATE_ROOM_FOR_LIMIT: errAddin = GetBattleServerZoneCount(); break;
case RC::RC_ROOM_NOTEXISTVILLAGE: errAddin = pMasterUser->GetZoneType(); break;
default:
break;
}
SUNLOG(eCRITICAL_LOG, _T("[%s][%u] - info [%u]"), __FUNCTION__, errCode, errAddin);
return (RC::eROOM_RESULT)errCode;
}
RC::eROOM_RESULT
ZoneManager::CreateMissionRoom(KEYTYPE lobbyKey, User* pMasterUser, MissionRoom*& OUT pMissionRoom)
{
ZoneInterface* pRoom = FindZone(lobbyKey);
if(!pRoom || pRoom->GetType() != eZONETYPE_LOBBY)
return RC::RC_ROOM_NOTEXISTLOBBY;
LobbyRoom* pLobbyRoom = (LobbyRoom *)pRoom;
if(pLobbyRoom->GetMaster() != pMasterUser)
return RC::RC_ROOM_ISNOTMATERPLAYER;
if(pLobbyRoom->GetLobbyType() != eZONETYPE_MISSION)
return RC::RC_ROOM_INVALID_LASTROOMTYPE;
if(!pLobbyRoom->IsAllReady())
return RC::RC_ROOM_IS_NOT_ALL_READY;
if(!pLobbyRoom->IsPrepareUserNum())
return RC::RC_ROOM_INSUFFICIENT_USER_NUM;
DWORD dwServerSessionIndex = ServerSessionManager::Instance()->Incr_LOF_BattleServer();
if(dwServerSessionIndex == 0)
return RC::RC_ROOM_FAILED;
ServerSession* pServerSession = (ServerSession*)ServerSessionManager::Instance()->FindServer(dwServerSessionIndex);
if(!pServerSession || pServerSession->GetServerType() != BATTLE_SERVER)
{
SUNLOG(eFULL_LOG, "배틀서버가 아닌 세션을 연결하려한다.2\n");
return RC::RC_ROOM_FAILED;
}
KEYTYPE MissionKey = AllocKey();
pMissionRoom = MissionRoom_Info::downcast(_AllocZone(MissionRoom_Info::value));
RC::eROOM_RESULT rt = pMissionRoom->Migrate(MissionKey, pLobbyRoom, pServerSession);
if(rt != RC::RC_ROOM_SUCCESS)
{
FreeKey(MissionKey);
_FreeZone(pMissionRoom);
return rt;
}
AddRoom(pMissionRoom);
// 방장 파티상태에 따라서 방에 새로이 파티를 생성하거나 설정한다.
AgentPartyManager::Instance()->CreateZone(pMasterUser, pLobbyRoom, pMissionRoom);
RoomArgument args(pLobbyRoom->GetZonePublic(), pLobbyRoom->GetRoomPWD());
rt = MoveZone(pLobbyRoom, pMissionRoom, pMasterUser, args);
ASSERT(rt == RC::RC_ROOM_SUCCESS);
return RC::RC_ROOM_SUCCESS;
}
RC::eROOM_RESULT
ZoneManager::CreatePVPRoom(KEYTYPE lobby_key, User* master_user, PVPRoom*& OUT pvp_room)
{
ZoneInterface* room = FindZone(lobby_key);
if (room == NULL || room->GetType() != eZONETYPE_LOBBY)
{
return RC::RC_ROOM_NOTEXISTLOBBY;
}
LobbyRoom* lobby_room = static_cast<LobbyRoom*>(room);
if (lobby_room->GetMaster() != master_user)
{
return RC::RC_ROOM_ISNOTMATERPLAYER;
}
if (lobby_room->GetLobbyType() != eZONETYPE_PVP)
{
return RC::RC_ROOM_INVALID_LASTROOMTYPE;
}
if (lobby_room->IsAllReady() == FALSE)
{
return RC::RC_ROOM_IS_NOT_ALL_READY;
}
if (lobby_room->IsPrepareUserNum() == FALSE)
{
return RC::RC_ROOM_INSUFFICIENT_USER_NUM;
}
DWORD server_session_index = ServerSessionManager::Instance()->Incr_LOF_BattleServer();
if (server_session_index == 0)
{
return RC::RC_ROOM_FAILED;
}
ServerSession* server_session =
(ServerSession*)ServerSessionManager::Instance()->FindServer(server_session_index);
if (server_session == NULL || server_session->GetServerType() != BATTLE_SERVER)
{
SUNLOG(eFULL_LOG, __FUNCTION__" : Invalid server session to connect");
return RC::RC_ROOM_FAILED;
}
KEYTYPE pvp_room_key = AllocKey();
pvp_room = PVPRoom_Info::downcast(_AllocZone(PVPRoom_Info::value));
RC::eROOM_RESULT result_code = pvp_room->Migrate(pvp_room_key, lobby_room, server_session);
if (result_code != RC::RC_ROOM_SUCCESS)
{
FreeKey(pvp_room_key);
_FreeZone(pvp_room);
return result_code;
}
AddRoom(pvp_room);
// 방장 파티상태에 따라서 방에 새로이 파티를 생성하거나 설정한다.
AgentPartyManager::Instance()->CreateZone(master_user, lobby_room, pvp_room);
RoomArgument args(lobby_room->GetZonePublic(), lobby_room->GetRoomPWD());
result_code = MoveZone(lobby_room, pvp_room, master_user, args);
ASSERT(result_code == RC::RC_ROOM_SUCCESS);
return RC::RC_ROOM_SUCCESS;
}
RC::eROOM_RESULT
ZoneManager::CreateRelayMissionLobbyRoom(MissionRoom* IN pMissionRoom , User* pMasterUser ,
LobbyRoom*& OUT pLobbyRoom)
{
ServerSessionEx* pServerSession = ServerSessionManager::Instance()->GetFieldServer();
if(!pServerSession)
{
SUNLOG(eCRITICAL_LOG, "[CreateRelayMissionLobbyRoom] 필드서버가 존재하지 않습니다.\n");
return RC::RC_ROOM_FAILED;
}
if(!AgentPartyManager::Instance()->IsMaster(pMasterUser))
return RC::RC_ROOM_ISNOTMATERPLAYER;
KEYTYPE lobbyKey = AllocKey();
pLobbyRoom = LobbyRoom_Info::downcast(_AllocZone(LobbyRoom_Info::value));
RC::eROOM_RESULT rt = pLobbyRoom->Create(pMasterUser, lobbyKey, pMissionRoom->GetMapCode(), eZONETYPE_MISSION,
pMissionRoom->GetZonePublic(), pMissionRoom->GetRoomTitle(), pMissionRoom->GetRoomPWD(),
*pMissionRoom->GetRoomInfo(), (ServerSession*)pServerSession, 0);
if(rt != RC::RC_ROOM_SUCCESS)
{
FreeKey(lobbyKey);
_FreeZone(pLobbyRoom);
SUNLOG(eFULL_LOG, "[CreateRelayMissionLobbyRoom] 로비생성 실패! ErrorCode[%d] lobbyKey[%d] mapCode[%d]", rt, lobbyKey, pMissionRoom->GetMapCode());
return rt;
}
// 최대인원 제한을 설정한다.
pLobbyRoom->SetLimitMaxUserNum(pMissionRoom->GetLimitMaxUserNum());
// 파티원들이 들어올 수 있도록 대기시간을 설정한다.
pLobbyRoom->SetWaitTimer(MISSION_RELAY_NOTICE_TIME);
AddRoom(pLobbyRoom);
// 방장 파티상태에 따라서 방에 새로이 파티를 생성하거나 설정한다.
AgentPartyManager::Instance()->CreateZone(pMasterUser, pMissionRoom, pLobbyRoom);
RoomArgument args(pMissionRoom->GetZonePublic(), pMissionRoom->GetRoomPWD());
rt = MoveZone(pMissionRoom, pLobbyRoom, pMasterUser, args);
if(rt != RC::RC_ROOM_SUCCESS)
{
SUNLOG(eCRITICAL_LOG, "[CreateRelayMissionLobbyRoom] MoveZone Fail! Error Code[%d]\n", rt);
ASSERT(rt == RC::RC_ROOM_SUCCESS);
}
return rt;
}
RC::eROOM_RESULT
ZoneManager::CreateInstanceDungeon(KEYTYPE zoneKey, User* pMasterUser, MAPCODE mapCode,
InstanceDungeon*& pInstanceDungeon, eINSTANCE_DUNGEON_KIND eKind,
BOOL UseChargeItem)
{
ServerSessionManager* const pServerSessionManager = ServerSessionManager::Instance();
pInstanceDungeon = NULL;
KEYTYPE allocedKey = 0;
FlowControl flow;
FLOWCONTROL_START()
{
// start LOGIC_BLOCK
ServerSessionEx* const pFieldSession = _CheckRoomCountLimit(flow);
if(NULL == pFieldSession)
break;
ZoneInterface* const pZoneInterface = FindZone(zoneKey);
if (pMasterUser) {
IfFailThenBreak(pZoneInterface, RC::RC_ROOM_FAILED);
}
const DWORD alignedSessionIdx = pServerSessionManager->Incr_LOF_BattleServer();
IfFailThenBreak(alignedSessionIdx, RC::RC_ROOM_FAILED);
ServerSessionEx* const pBattleSession = pServerSessionManager->FindServer(alignedSessionIdx);
IfFailThenBreak(pBattleSession && pBattleSession->GetServerType() == BATTLE_SERVER,
RC::RC_ROOM_FAILED);
allocedKey = AllocKey();
pInstanceDungeon = InstanceDungeon_Info::downcast(_AllocIndun(eKind));
IfFailThenBreak(pInstanceDungeon->RegisterRuleset(mapCode), RC::RC_ROOM_FAILED);
const RC::eROOM_RESULT rt = pInstanceDungeon->Create(pMasterUser, mapCode, allocedKey, pBattleSession, UseChargeItem);
IfFailThenBreak(RC::RC_ROOM_SUCCESS == rt, rt);
AddRoom(pInstanceDungeon);
AgentPartyManager::Instance()->CreateZone(pMasterUser, pZoneInterface, pInstanceDungeon);
return RC::RC_ROOM_SUCCESS;
}
FLOWCONTROL_END;
const DWORD errCode = flow.GetErrorCode();
DWORD OUT errAddin = 0;
switch(errCode)
{
case RC::RC_ROOM_FAILED: break;
case RC::RC_ROOM_ISNOT_MASTER_OF_PARTY:
case RC::RC_ROOM_CANNOT_CREATE_ROOM_FOR_LIMIT: errAddin = GetBattleServerZoneCount(); break;
case RC::RC_ROOM_NOTEXISTVILLAGE: errAddin = pMasterUser->GetZoneType(); break;
}
// release resource
if(allocedKey) FreeKey(allocedKey);
if(pInstanceDungeon) _FreeIndun(pInstanceDungeon);
SUNLOG(eCRITICAL_LOG, _T("[%s][%u] - info [%u]"), __FUNCTION__, errCode, errAddin);
return (RC::eROOM_RESULT)errCode;
}
RC::eROOM_RESULT
ZoneManager::CreateStaticDungeon(const MAPCODE mapCode,
InstanceDungeon*& OUT rpStaticDungeon,
const eINSTANCE_DUNGEON_KIND kindOfDungeon,
BOOL bUseChargeItem) // current, not used
{
ServerSessionManager* const pServerSessionManager = ServerSessionManager::Instance();
rpStaticDungeon = NULL;
KEYTYPE allocedKey = 0;
// (THINKING) (NOTEs)
// - Agent->Battle는 1..n의 형태이다. Load Balancing은 어캐할 것인가?
// - 일단 고정 생성으로 수행하기로 한다.
FlowControl flow;
FLOWCONTROL_START()
{
// start LOGIC_BLOCK
ServerSessionEx* const pFieldSession = _CheckRoomCountLimit(flow);
if(NULL == pFieldSession)
break;
const DWORD alignedSessionIdx = pServerSessionManager->Incr_LOF_BattleServer();
IfFailThenBreak(alignedSessionIdx, RC::RC_ROOM_FAILED);
ServerSessionEx* const pBattleSession = pServerSessionManager->FindServer(alignedSessionIdx);
IfFailThenBreak(pBattleSession && pBattleSession->GetServerType() == BATTLE_SERVER,
RC::RC_ROOM_FAILED);
// static dungeon은 하나만 존재한다.
IfFailThenBreak(!FindStaticDungeon(mapCode), RC::RC_ROOM_CANNOT_CREATE_ROOM_FOR_LIMIT);
allocedKey = AllocKey();
rpStaticDungeon = InstanceDungeon_Info::downcast(_AllocIndun(kindOfDungeon));
// (NOTE) (WAVERIX) remove code which is presented by [48549],
// because of the result of a _AllocXXX must be succeed.
// I suppose a fail status for reason of a memory problem.
// the below skipped code section has a leak resource problem
// which is based on return directly.
/*if(rpStaticDungeon == NULL)
{
SUNLOG(eCRITICAL_LOG, _T("_AllocIndun fail [%s]"), __FUNCTION__);
return RC::RC_ROOM_FAILED;
}*/
IfFailThenBreak(rpStaticDungeon,RC::RC_ROOM_FAILED);
IfFailThenBreak(rpStaticDungeon->RegisterRuleset(mapCode), RC::RC_ROOM_FAILED);
const RC::eROOM_RESULT rt = rpStaticDungeon->Create(NULL, mapCode, allocedKey, pBattleSession, bUseChargeItem);
IfFailThenBreak(RC::RC_ROOM_SUCCESS == rt, rt);
AddRoom(rpStaticDungeon);
return RC::RC_ROOM_SUCCESS;
}
FLOWCONTROL_END;
const DWORD errCode = flow.GetErrorCode();
DWORD OUT errAddin = 0;
switch(errCode)
{
case RC::RC_ROOM_FAILED: break;
case RC::RC_ROOM_CANNOT_CREATE_ROOM_FOR_LIMIT: errAddin = GetBattleServerZoneCount(); break;
}
// release resource
if(allocedKey) FreeKey(allocedKey);
if(rpStaticDungeon) _FreeIndun(rpStaticDungeon);
SUNLOG(eCRITICAL_LOG, _T("[%s][%u] - info [%u]"), __FUNCTION__, errCode, errAddin);
return (RC::eROOM_RESULT)errCode;
}
#if defined(__NA1279_1281_090209_TIMELINE_QUEST_BASED_MISSION__) && \
!defined(__NA_0_20081029_PARTY_REFACTORING)
#error "Impossible Build!! - Reason: Violation Dependency Chain"
#endif
RC::eROOM_RESULT
ZoneManager::CreatePortal(const QuestPortalInfo& rQuestPortalInfo, User* pUser, BOOLEAN isTempPortal)
{
// 포탈 관련 처리는 모두 PortalManager에서 수행한다.
// 방 생성 문제, 방 생성 정보 문제 땜시 ZoneManager에서 해결해야 하는 것들이 존재한다.
FlowControl flow;
ServerSessionEx* pFieldSession = _CheckRoomCountLimit(flow);
ServerSessionEx* pBattleSession = 0;
{ // session constraints
if(pFieldSession == 0)
return (RC::eROOM_RESULT)flow.GetErrorCode();
ServerSessionManager* pSessionManager = ServerSessionManager::Instance();
DWORD alignedSessionIdx = pSessionManager->Incr_LOF_BattleServer();
if(alignedSessionIdx == 0)
return RC::RC_ROOM_FAILED;
pBattleSession = pSessionManager->FindServer(alignedSessionIdx);
if(pBattleSession == 0)
return RC::RC_ROOM_FAILED;
};
if(PortalManager::IsValidRequesterForCreatePortal(pUser) == FALSE)
return RC::RC_ROOM_INVALIDROOMTYPE;
const MAPCODE enterableMapCode = rQuestPortalInfo.enterableMapCode;
const sMAPINFO* pMapInfo = MapInfoParser::Instance()->FindMapInfo(enterableMapCode);
if(pMapInfo == 0)
return RC::RC_ROOM_INVALID_MAPCODE;
//const DWORD playerKey = pUser->GetPlayerKey();
//User* pMasterUser = pUser;
//AgentPartyManager* pPartyManager = AgentPartyManager::Instance();
//{ // (WAVERIX) (090211) (NOTE) partyKey에 대한 INVALID_VALUE가 정의를 사용한다면,
// // 굳이 아래와 같은 처리를 하지 않아도 된다.
// WORD partyKey = pUser->GetPartyState().GetPartyKey();
// DWORD masterKey = pPartyManager->GetMasterKey(partyKey);
// if(masterKey && (playerKey != masterKey))
// pMasterUser = UserManager::Instance()->GetUserByObjKey(masterKey);
//};
RoomArgumentForRoomSetup args;
BASE_ROOMINFO& rRoomInfo = args.m_RoomInfo;
// (WAVERIX) (090829) (WARNING) (CURRENT) LEVELTYPE : WORD
rRoomInfo.m_MinLV = BYTE(pMapInfo->minLV); // 고민된다. 지금 형변환 해버리면 나중에 찾기가...
rRoomInfo.m_MaxLV = BYTE(pMapInfo->maxLV);
rRoomInfo.m_ClassLimit = UCHAR_MAX;
//{__NA1335_090407_PORTAL_MISSION_ROOM_CONSTRAINTS__
BOOLEAN isSuperRoomPc = !!pUser->CanApplyPCBangBenefit(true);
BOOLEAN isSuperRoomItem = !!pUser->GetItemOwnFlag().FindItemInfo(eITEMTYPE_SUPERMASTER);
#ifdef __NA_000000_20070528_TAIWAN_GUILD_PVP
if(isSuperRoomPc)
rRoomInfo.m_SpecialType |= eROOM_SPECIAL_PCBANG_SUPER_ROOM;
if(isSuperRoomItem)
rRoomInfo.m_SpecialType |= eROOM_SPECIAL_ITEM1_SUPER_ROOM;
#else
rRoomInfo.m_SpecialType = isSuperRoomPc ? eROOM_SPECIAL_PCBANG_SUPER_ROOM
: isSuperRoomItem ? eROOM_SPECIAL_ITEM1_SUPER_ROOM
: 0;
#endif
//}
// 인원수 제한
// 최대인원 제한을 설정한다.
BYTE maxLimitUserNum = 10;
#ifdef __NA_000000_20070528_TAIWAN_GUILD_PVP
if(rRoomInfo.IsSpecialType(eROOM_SPECIAL_GUILD_PVP))
{
maxLimitUserNum = 5;
}
else
#endif
{
maxLimitUserNum = min(pMapInfo->byMaxUserNum, maxLimitUserNum);
}
args.m_pMapInfo = pMapInfo;
args.m_MaxLimitUserNum = maxLimitUserNum;
PORTALKEY portalKey = PortalManager::CreatePortal(rQuestPortalInfo, isTempPortal, args);
if(portalKey == INVALID_PORTAL_KEY)
return RC::RC_ROOM_FAILED;
return RC::RC_ROOM_SUCCESS;
}
// called by PortalManager::Update (timeout event)
RC::eROOM_RESULT
ZoneManager::ClosePortal(const QuestPortalInfo& rQuestPortalInfo, KEYTYPE roomKey)
{
__TOUCHED(rQuestPortalInfo);
if(roomKey == 0)
return RC::RC_ROOM_SUCCESS;
// portal에 의해 생성된 방은 PortalManager의 직접적인 관리대상이 아니다.
ZoneInterface* pZone = FindZone(roomKey);
if(pZone == 0)
return RC::RC_ROOM_SUCCESS;
if(!FlowControl::FCAssert(pZone->IsRoomType()))
return RC::RC_ROOM_INVALID_ROOM_TYPE;
//RoomInterface* pRoom = static_cast<RoomInterface*>(pZone);
// (WAVERIX) (090415) (LOGIC-CHANGE) 포탈 제거시 방에 걸린 정보도 초기화 하면 안된다.
// 정보가 사라지잖아? 실제 PORTAL정보가 없다 할지라도...
//{
// PolicymentForRoom& rPolicymentForRoom = pRoom->RoomPolicyment;
// rPolicymentForRoom.SetPortalKey(INVALID_PORTAL_KEY);
// pRoom->ChangePolicy(rPolicymentForRoom.FIELD & ~rPolicymentForRoom.QUEST_PORTAL_CONTROL);
//}
return RC::RC_ROOM_SUCCESS;
}
RC::eROOM_RESULT
ZoneManager::CreateRoomByPortal(PORTALKEY portalKey, User* pFirstEnterUser,
const RoomArgumentForRoomSetup& rRoomArgument)
{
if(!FlowControl::FCAssert(rRoomArgument.m_pMapInfo))
return RC::RC_ROOM_INVALID_ROOM_TYPE;
FlowControl flow;
ServerSessionEx* pFieldSession = _CheckRoomCountLimit(flow);
ServerSessionEx* pBattleSession = 0;
{ // session constraints
if(pFieldSession == 0)
return (RC::eROOM_RESULT)flow.GetErrorCode();
ServerSessionManager* pSessionManager = ServerSessionManager::Instance();
DWORD alignedSessionIdx = pSessionManager->Incr_LOF_BattleServer();
if(alignedSessionIdx == 0)
return RC::RC_ROOM_FAILED;
pBattleSession = pSessionManager->FindServer(alignedSessionIdx);
if(pBattleSession == 0) // 어, 세션정보도 저장해야 한다.
return RC::RC_ROOM_FAILED;
};
const eZONETYPE toZoneType = eZONETYPE(rRoomArgument.m_pMapInfo->byMKind);
if(PortalManager::IsValidCreatingZone(toZoneType) == FALSE)
return RC::RC_ROOM_INVALID_ROOM_TYPE; //...포탈 생성시 체크할 것...
const KEYTYPE allocKey = AllocKey();
RC::eROOM_RESULT result = RC::RC_ROOM_SUCCESS;
RoomInterface* allocRoom = 0;
if(toZoneType == MissionRoom_Info::value)
{
if(!FlowControl::FCAssert(pFirstEnterUser->IsBeginTransaction() == FALSE))
result = RC::RC_ROOM_INVALID_ROOM_TYPE;
if(result == RC::RC_ROOM_SUCCESS)
{
MissionRoom* pRoom = MissionRoom_Info::downcast(_AllocZone(MissionRoom_Info::value));
allocRoom = pRoom;
PolicymentForRoom& rRoomPolicyment = pRoom->RoomPolicyment;
pRoom->ChangePolicy(rRoomPolicyment.FIELD | rRoomPolicyment.QUEST_PORTAL_CONTROL);
rRoomPolicyment.SetPortalKey(portalKey);
pFirstEnterUser->SetBehaveState(PLAYER_BEHAVE_IDLE_STATE);
pFirstEnterUser->BeginTransaction(TR_LEAVE_FIELD_FOR_ROOM_BY_PORTAL);
result = pRoom->MigratePortalUserFirstEnter(allocKey, rRoomArgument,
pFirstEnterUser, pBattleSession);
}
if(result != RC::RC_ROOM_SUCCESS)
{
FreeKey(allocKey);
_FreeZone(allocRoom);
pFirstEnterUser->EndTransaction();
return result;
}
AddRoom(allocRoom);
KEYTYPE fromZoneKey = pFirstEnterUser->GetZoneKey();
ZoneInterface* pFromZone = FindZone(fromZoneKey);
AgentPartyManager* pPartyManager = AgentPartyManager::Instance();
pPartyManager->EnterZoneByPortal(portalKey, pFirstEnterUser, pFromZone, allocRoom);
allocRoom->SetRoomState(eROOMSTATE_GENERNAL);
CheckMoveZonePolicy* const pCheckMoveZonePolicy =
MoveZonePolicy<MZTF_STATIC_TO_ROOM>::AlignInfo(
pFirstEnterUser,
//{ From | To }
pFromZone->GetType(), allocRoom->GetType(), // eZONETYPE
fromZoneKey, allocRoom->GetKey()); // zoneKey
result = MoveZone(pCheckMoveZonePolicy, rRoomArgument);
if(result != RC::RC_ROOM_SUCCESS)
{
pFirstEnterUser->EndTransaction();
// (WAVERIX) (090323) (BUG-FIX) 유저 입장 실패시 참가한 파티에서 탈퇴
// 리소스 해제... 피곤하넹...
pPartyManager->LeaveParty(pFirstEnterUser, eREASON_LEAVE_PARTY_INTEND);
DestroyZone(allocRoom);
return result;
}
pFirstEnterUser->SetTRRoomKey(allocKey);
return RC::RC_ROOM_SUCCESS;
}
else if(toZoneType == InstanceDungeon_Info::value)
{
// TODO(WAVERIX) 구현이 미진하다.
ASSERT(!"Not Implementation! Instance Dungeon Portal");
//InstanceDungeon* pRoom = InstanceDungeon_Info::downcast(pRefRoom);
//allocRoom = pRoom;
//result = pRoom->MigratePortalUser(allocKey, pRefRoom, pBattleSession);
}
return RC::RC_ROOM_FAILED;
}
RC::eROOM_RESULT
ZoneManager::EnterPortal(PORTALKEY portalKey, User* pUser,
const RoomArgumentForRoomSetup& rRoomArgument, KEYTYPE enterableRoomKey)
{
const eZONETYPE enterZoneType = eZONETYPE(rRoomArgument.m_pMapInfo->byMKind);
//if(PortalManager::IsValidCreatingZone(enterZoneType) == FALSE)
// return RC::RC_ROOM_INVALID_ROOM_TYPE; //...포탈 생성시 체크할 것...
RC::eROOM_RESULT result = RC::RC_ROOM_SUCCESS;
RoomInterface* pRoom = 0;
{
ZoneInterface* pZone = FindZone(enterableRoomKey);
if(pZone->IsRoomType() == FALSE)
return RC::RC_ROOM_INVALID_ROOM_TYPE;
pRoom = static_cast<RoomInterface*>(pZone);
};
if(enterZoneType == MissionRoom_Info::value)
{
if(!FlowControl::FCAssert(pRoom &&
pUser->IsBeginTransaction() == FALSE))
result = RC::RC_ROOM_INVALID_ROOM_TYPE;
if(result != RC::RC_ROOM_SUCCESS)
return result;
pUser->SetBehaveState(PLAYER_BEHAVE_IDLE_STATE);
pUser->BeginTransaction(TR_LEAVE_FIELD_FOR_ROOM_BY_PORTAL);
//result = pRoom->MigratePortalUser(allocKey, pRefRoom, pUser, pBattleSession);
//PortalManager::OnRoomEvent(portalKey, true, allocKey);
KEYTYPE fromZoneKey = pUser->GetZoneKey();
ZoneInterface* pFromZone = FindZone(fromZoneKey);
KEYTYPE toZoneKey = pRoom->GetKey();
{ // about party
AgentPartyManager* pPartyManager = AgentPartyManager::Instance();
pPartyManager->EnterZoneByPortal(portalKey, pUser, pFromZone, pRoom);
//AgentPartyManager::Instance()->Join~(pMasterUser, /*pZoneInterface*/, allocRoom);
}
CheckMoveZonePolicy* const pCheckMoveZonePolicy =
MoveZonePolicy<MZTF_STATIC_TO_ROOM>::AlignInfo(
pUser,
//{ From | To }
pFromZone->GetType(), pRoom->GetType(), // eZONETYPE
fromZoneKey, toZoneKey); // zoneKey
result = MoveZone(pCheckMoveZonePolicy, rRoomArgument);
if(result != RC::RC_ROOM_SUCCESS)
{
pUser->EndTransaction();
return result;
}
pUser->SetTRRoomKey(toZoneKey);
return RC::RC_ROOM_SUCCESS;
}
else if(enterZoneType == InstanceDungeon_Info::value)
{
// TODO(WAVERIX) 구현이 미진하다.
ASSERT(!"Not Implementation! Instance Dungeon Portal");
//InstanceDungeon* pRoom = InstanceDungeon_Info::downcast(pRefRoom);
//allocRoom = pRoom;
//result = pRoom->MigratePortalUser(allocKey, pRefRoom, pBattleSession);
//if(result != RC::RC_ROOM_SUCCESS)
//{
// FreeKey(allocKey);
// _FreeZone(pRoom);
// return result;
//}
}
return RC::RC_ROOM_FAILED;
}
BOOL
ZoneManager::AutoMatching(KEYTYPE lobbyKey, User* pMasterUser, CHuntingRoom*& OUT pCHuntingRoom)
{
ZoneInterface* pRoom = FindZone(lobbyKey);
if(!pRoom || pRoom->GetType() != eZONETYPE_LOBBY)
return FALSE;
LobbyRoom* pLobbyRoom = (LobbyRoom *)pRoom;
if(pLobbyRoom->GetMaster() != pMasterUser)
return FALSE;
if(pLobbyRoom->GetLobbyType() != eZONETYPE_CHUNTING)
return FALSE;
if(!pLobbyRoom->IsAllReady())
return FALSE;
if(pLobbyRoom->GetZonePublic() == eZONEPUBLIC_PRIVATE)
return FALSE;
// 유저수 체크는 다시 한번 생각해 보자!
if(!pLobbyRoom->IsPrepareUserNum())
return FALSE;
SERVER_COMMON_OPTION& stServerOptionInfo = ServerOptionParserEx::Instance()->GetServerOption();
// 유저수가 1명인 경우는 매칭대상에서 제외된다.
if(pLobbyRoom->GetCurUserNum() < stServerOptionInfo.m_byMATCHING_MIN_USER_NUM)
return FALSE;
// 현재 로비방의 평균레벨, 평균승률, 옵션정보
LEVELTYPE LobbyAvgLevel = pLobbyRoom->GetAvgLevel();
BYTE LobbyAvgWinRatio = 0; DWORD LobbyTotCount = 0;
pLobbyRoom->GetCHuntingScore(LobbyAvgWinRatio, LobbyTotCount);
int MatchingCondition = stServerOptionInfo.m_byMATCHING_WIN_RATIO;
// 길드전 경쟁헌팅인가
#ifdef __NA_000000_20070528_TAIWAN_GUILD_PVP
BOOL bLobbyGuildPVP = pLobbyRoom->GetRoomInfo()->IsSpecialType(eROOM_SPECIAL_GUILD_PVP);
#endif
{
const INT _matchingCondValue = (INT)((INT)stServerOptionInfo.m_byMATCHING_WIN_RATIO - LobbyTotCount / 200);
MatchingCondition = max(5, _matchingCondValue);
};
const ADDITIONAL_CHUNTINGINFO_EX* pLobbyInfo = pLobbyRoom->GetAdditionalCHuntingInfo();
// 매칭조건에 맞는 방이 존재하는지 검색
const MAPCODE lobbyMapCode = pLobbyRoom->GetMapCode();
const DWORD lobbyUsers = pLobbyRoom->GetCurUserNum();
const BYTE cMatchingLevelLimit = stServerOptionInfo.m_byMATCHING_LEVEL_LIMIT;
FOREACH_CONTAINER(const ZONE_LIST::value_type& rNode, m_CHuntingRooms, ZONE_LIST)
{
const KEYTYPE key = rNode;
const ObjectKeyStream::sNode* pNode = m_pObjectKeyStream->GetObjectInfo(key);
if(!(pNode && pNode->pObject))
{
WAVERIX_ZONE_ASSERT(!"m_CHuntingRooms empty slot");
continue;
}
CHuntingRoom* const pCRoom = CHuntingRoom_Info::downcast(pNode->pObject);
// 이미 진행중인지 체크
if(pCRoom->IsCompetition()) continue;
// 비밀방은 제외
if(pCRoom->GetZonePublic() == eZONEPUBLIC_PRIVATE) continue;
// 경쟁헌팅룸 인원과 로비인원이 같아야 들어갈 수 있다.
if(pCRoom->GetCurUserNum() != lobbyUsers) continue;
// 필드, 룰, 모드 체크
if(lobbyMapCode != pCRoom->GetMapCode()) continue;
const ADDITIONAL_CHUNTINGINFO* pCHuntingInfo = pCRoom->GetAdditionalCHuntingInfo();
if(pLobbyInfo->m_Rule != pCHuntingInfo->m_Rule) continue;
if(pLobbyInfo->m_Mode != pCHuntingInfo->m_Mode) continue;
// 평균레벨 체크
const INT avgLevel = (INT)pCRoom->GetAvgLevel() - (INT)LobbyAvgLevel;
const BYTE LevelDiff = static_cast<BYTE>(std::abs(avgLevel));
if(LevelDiff > cMatchingLevelLimit) continue;
BYTE CRoomWinRatio = 0;
DWORD CRoomTotCount = 0;
#ifdef __NA_000000_20070528_TAIWAN_GUILD_PVP
// 같은 길드 PVP 방끼리만 매칭이 된다.
BOOL bCRoomGuildPVP = pCRoom->GetRoomInfo()->IsSpecialType(eROOM_SPECIAL_GUILD_PVP);
if(bLobbyGuildPVP != bCRoomGuildPVP) continue;
if(bLobbyGuildPVP)
{ // 같은 길드끼리는 매칭이 안되게 한다.
User* const pCHuntingMasterUser = pCRoom->GetMaster();
if(pCHuntingMasterUser
&& (pMasterUser->GetSelectedCharGuildGuid()
== pCHuntingMasterUser->GetSelectedCharGuildGuid())
) continue;
}
else
{ // 평균승률 체크
pCRoom->GetCHuntingScore(CRoomWinRatio, CRoomTotCount);
const BYTE WinRatioDiff = abs(CRoomWinRatio - LobbyAvgWinRatio);
if(WinRatioDiff > MatchingCondition) continue;
}
#else
pCRoom->GetCHuntingScore(CRoomWinRatio, CRoomTotCount);
const BYTE WinRatioDiff = static_cast<BYTE>(std::abs(CRoomWinRatio - LobbyAvgWinRatio));
if(WinRatioDiff > MatchingCondition) continue;
#endif
// 같은 방에 특정시간에 특정회수 이상의 조인을 막는다.
if(pLobbyRoom->CheckAbusing(pCRoom)) continue;
pCHuntingRoom = pCRoom;
return TRUE;
}
return FALSE;
}
RC::eROOM_RESULT
ZoneManager::CreateCHuntingRoom(KEYTYPE lobbyKey, User* pMasterUser, CHuntingRoom*& OUT pCHuntingRoom)
{
ZoneInterface* pRoom = FindZone(lobbyKey);
if(!pRoom || pRoom->GetType() != eZONETYPE_LOBBY)
return RC::RC_ROOM_NOTEXISTLOBBY;
LobbyRoom* pLobbyRoom = (LobbyRoom *)pRoom;
if(pLobbyRoom->GetMaster() != pMasterUser)
return RC::RC_ROOM_ISNOTMATERPLAYER;
if(pLobbyRoom->GetLobbyType() != eZONETYPE_CHUNTING)
return RC::RC_ROOM_INVALID_LASTROOMTYPE;
if(!pLobbyRoom->IsAllReady())
return RC::RC_ROOM_IS_NOT_ALL_READY;
if(!pLobbyRoom->IsPrepareUserNum())
return RC::RC_ROOM_INSUFFICIENT_USER_NUM;
#ifdef __NA_000000_20070528_TAIWAN_GUILD_PVP
RC::eROOM_RESULT rcResult = pLobbyRoom->CanMigrateToChunting();
if(rcResult != RC::RC_ROOM_SUCCESS)
return rcResult;
#endif
DWORD dwServerSessionIndex = ServerSessionManager::Instance()->Incr_LOF_BattleServer();
if(dwServerSessionIndex == 0)
return RC::RC_ROOM_FAILED;
ServerSession* pServerSession = (ServerSession*)ServerSessionManager::Instance()->FindServer(dwServerSessionIndex);
if(!pServerSession || pServerSession->GetServerType() != BATTLE_SERVER)
{
SUNLOG(eFULL_LOG, "배틀서버가 아닌 세션을 연결하려한다.2\n");
return RC::RC_ROOM_FAILED;
}
KEYTYPE CHuntingKey = AllocKey();
pCHuntingRoom = CHuntingRoom_Info::downcast(_AllocZone(CHuntingRoom_Info::value));
RC::eROOM_RESULT rt = pCHuntingRoom->Migrate(CHuntingKey, pLobbyRoom, pServerSession);
if(rt != RC::RC_ROOM_SUCCESS)
{
FreeKey(CHuntingKey);
_FreeZone(pCHuntingRoom);
return rt;
}
AddRoom(pCHuntingRoom);
// 방장 파티상태에 따라서 방에 새로이 파티를 생성하거나 설정한다.
AgentPartyManager::Instance()->CreateZone(pMasterUser, pLobbyRoom, pCHuntingRoom);
RoomArgument args(pLobbyRoom->GetZonePublic(), pLobbyRoom->GetRoomPWD());
rt = MoveZone(pLobbyRoom, pCHuntingRoom, pMasterUser, args);
ASSERT(rt == RC::RC_ROOM_SUCCESS);
return RC::RC_ROOM_SUCCESS;
}
RC::eROOM_RESULT
ZoneManager::MigrateCHuntingRoom(User* pMasterUser, KEYTYPE lobbyKey, CHuntingRoom* IN pCHuntingRoom)
{
ZoneInterface* pRoom = FindZone(lobbyKey);
if(!pRoom || pRoom->GetType() != eZONETYPE_LOBBY)
return RC::RC_ROOM_NOTEXISTLOBBY;
LobbyRoom* pLobbyRoom = (LobbyRoom *)pRoom;
if(pLobbyRoom->GetMaster() != pMasterUser)
return RC::RC_ROOM_ISNOTMATERPLAYER;
if(pLobbyRoom->GetLobbyType() != eZONETYPE_CHUNTING)
return RC::RC_ROOM_INVALID_LASTROOMTYPE;
if(!pLobbyRoom->IsAllReady())
return RC::RC_ROOM_IS_NOT_ALL_READY;
if(!pLobbyRoom->IsPrepareUserNum())
return RC::RC_ROOM_INSUFFICIENT_USER_NUM;
#ifdef __NA_000000_20070528_TAIWAN_GUILD_PVP
RC::eROOM_RESULT rcResult = pLobbyRoom->CanMigrateToChunting();
if(rcResult != RC::RC_ROOM_SUCCESS)
return rcResult;
#endif
if(!pCHuntingRoom)
return RC::RC_ROOM_INVALID_CHUNTING_LINK_KEY;
// 경쟁중에는 들어갈 수 없다.
if(pCHuntingRoom->IsCompetition())
return RC::RC_ROOM_DOING_COMPETITION;
// 경쟁헌팅룸 인원과 로비인원이 같아야 들어갈 수 있다.
if(pCHuntingRoom->GetCurUserNum() != pLobbyRoom->GetCurUserNum())
return RC::RC_ROOM_MEMBERNUM_OF_PARTY_IS_MANY;
// 두 번째 파티가 들어간다고 셋팅
pCHuntingRoom->EnterTeam(pLobbyRoom, TRUE);
// 매칭되는 방과 SpecialType이 틀리면 클라에 알려준다.
if(pLobbyRoom->GetRoomInfo()->m_SpecialType != pCHuntingRoom->GetRoomInfo()->m_SpecialType)
{
// 클라에 알린다.
MSG_CG_ZONE_CHANGE_SPECIALTYPE_CMD CGMsg;
CGMsg.m_SpecialType = pCHuntingRoom->GetRoomInfo()->m_SpecialType;
pLobbyRoom->SendToAll(&CGMsg, sizeof(CGMsg));
}
AgentPartyManager::Instance()->MigrateCHuntingRoom(pMasterUser, pLobbyRoom, pCHuntingRoom);
// 로비의 모든사람에게 로비 나감 SYN, 룸 들어가기 SYN
RoomMigrater<LobbyRoom, CHuntingRoom, TR_LEAVE_LOBBY_FOR_CHUNTING> op(pLobbyRoom, pCHuntingRoom);
pLobbyRoom->Foreach(op);
return RC::RC_ROOM_SUCCESS;
}
//_NA_000038_20100316_VIEW_TO_JOINABLE_ROOM_IN_LOBBY
RC::eROOM_RESULT ZoneManager::IsMoveableZone(CheckMoveZonePolicy* const check_move_zone_policy,
const RoomArgument& room_argument) const
{
const RC::eROOM_RESULT enable_check_result = check_move_zone_policy->EnableCheck();
if (enable_check_result != RC::RC_ROOM_SUCCESS)
{
return enable_check_result;
}
User* const user = check_move_zone_policy->Args->pUser;
ZoneInterface* const to_zone = check_move_zone_policy->Args->ToZonePtr;
const RC::eROOM_RESULT can_join_result = to_zone->CanJoin(user, room_argument.RoomExportLevel, room_argument.Password);
if (can_join_result != RC::RC_ROOM_SUCCESS)
{
return can_join_result;
}
return RC::RC_ROOM_SUCCESS;
}
//==================================================================================================
// <MoveZone>
//
// <COMMENT>
// - 현재 MoveZone의 사용사례로 볼 때, 각각이 제약조건을 검사해서 이동시키는 형태다.
// 즉, 존 이동 관련 정책이 제각각이라는 소리이며, 이는 일관성을 크게 악화시키는 요인으로 판단.
// (추가로 중복 코드 및 실수 유발 여지가 지극히 높다.)
// - 중앙 집중적인 관리로 전환한다면 어떨까? 음... 다소 난항은 있어도 정책적인 문제를 관리하는데는
// 매우 좋을 듯 하다.
RC::eROOM_RESULT ZoneManager::MoveZone(CheckMoveZonePolicy* const check_move_zone_policy,
const RoomArgument& room_argument)
{
// (CHANGES)(20100318)(hukim)(REQ_0038) 이동 가능 여부 검사를 일원화하기 위해 별도의 메서드로
// 분리했다.
const RC::eROOM_RESULT is_moveable_zone_result = IsMoveableZone(check_move_zone_policy, room_argument);
if (is_moveable_zone_result != RC::RC_ROOM_SUCCESS)
{
return is_moveable_zone_result;
}
User* const user = check_move_zone_policy->Args->pUser;
ZoneInterface* const from_zone = check_move_zone_policy->Args->FromZonePtr;
ZoneInterface* const to_zone = check_move_zone_policy->Args->ToZonePtr;
return MoveZone(from_zone, to_zone, user, room_argument);
}
RC::eROOM_RESULT
ZoneManager::MoveZone(ZoneInterface* const pFromZone,
ZoneInterface* const pToZone,
User* const pUser,
const RoomArgument& rRoomArg)
{
if(pFromZone->GetLinkedServer() == pToZone->GetLinkedServer())
{
pFromZone->LeaveUser(pUser, eSEND_CMD, pToZone->GetType(), pToZone->GetLinkedServerIndex());
pToZone->ReadyUser(pUser, eSEND_CMD, rRoomArg.ToFieldCode, rRoomArg.ToAreaID, rRoomArg.pStartPos);
}
else
{
pFromZone->LeaveUser(pUser, eSEND_SYN, pToZone->GetType(), pToZone->GetLinkedServerIndex());
}
return RC::RC_ROOM_SUCCESS;
}
RC::eROOM_RESULT
ZoneManager::KickUserFromLobby(User* pMaster, DWORD TargetPlayerKey, User*& OUT pTargetUser)
{
// 로비의 상태인가?
if(pMaster->GetZoneState() != ePRS_AT_LOBBY)
return RC::RC_ROOM_INVALIDROOMTYPE;
LobbyRoom* pLobbyRoom = FindLobby(pMaster->GetZoneKey());
if(!pLobbyRoom)
return RC::RC_ROOM_NOTEXISTLOBBY;
// 방장이어야한다.
if(pMaster != pLobbyRoom->GetMaster())
return RC::RC_ROOM_NOT_CMD_FOR_MEMBER;
pTargetUser = pLobbyRoom->FindUser(TargetPlayerKey);
if(!pTargetUser)
return RC::RC_ROOM_NOT_EXIST_MEMBER;
// 로비에서 나가기 전에 파티에 소속되어 있으면 강퇴부터 시킨다.
MAPCODE mcCode = pTargetUser->GetSelectedCharMapCode();
ZoneInterface* pZone = g_ZoneManager.FindStaticZone(mcCode);
if(!pZone) return RC::RC_ROOM_NOTEXISTVILLAGE;
const sMAPINFO* pMAPINFO = MapInfoParser::Instance()->FindMapInfo(mcCode);
if(!((eZONETYPE_VILLAGE == pMAPINFO->byMKind) || (eZONETYPE_TUTORIAL_FIELD == pMAPINFO->byMKind)))
return RC::RC_ROOM_NOTEXISTVILLAGE;
pLobbyRoom->LeaveUser(pTargetUser, eSEND_CMD, eZONETYPE_VILLAGE, pZone->GetLinkedServerIndex());
pZone->ReadyUser(pTargetUser, eSEND_CMD);
return RC::RC_ROOM_SUCCESS;
}
RC::eROOM_RESULT
ZoneManager::UserReadyInLobby(User* pUser, BOOL bReady)
{
// 로비의 상태인가?
if(pUser->GetZoneState() != ePRS_AT_LOBBY)
return RC::RC_ROOM_INVALIDROOMTYPE;
LobbyRoom* pLobbyRoom = FindLobby(pUser->GetZoneKey());
if(!pLobbyRoom)
return RC::RC_ROOM_NOTEXISTLOBBY;
// 방장이 아니어야 한다.
if(pUser == pLobbyRoom->GetMaster())
return RC::RC_ROOM_NOT_CMD_FOR_MASTER;
if(bReady == TRUE)
{
// 레디가 아니어야 한다.
if(pUser->IsReady())
{
return RC::RC_ROOM_ALREADY_READY_STATE;
}
pUser->SetReady(TRUE);
}
else
{
// 레디이어야 한다
if(!pUser->IsReady())
{
return RC::RC_ROOM_ALREADY_NOT_READY_STATE;
}
pUser->SetReady(FALSE);
}
return RC::RC_ROOM_SUCCESS;
}
RC::eROOM_RESULT
ZoneManager::ChangeTeamInLobby(User* pUser, BYTE team)
{
// 로비의 상태인가?
if(pUser->GetZoneState() != ePRS_AT_LOBBY)
return RC::RC_ROOM_INVALIDROOMTYPE;
LobbyRoom* pLobbyRoom = FindPVPLobby(pUser->GetZoneKey());
if(!pLobbyRoom)
return RC::RC_ROOM_NOTEXISTLOBBY;
if(!pLobbyRoom->IsPVPTeamMode())
return RC::RC_ROOM_INVALID_TEAM;
if(1 != team && 2 != team)
return RC::RC_ROOM_INVALID_TEAM;
if(pUser->GetTeam() == team)
return RC::RC_ROOM_INVALID_TEAM;
pUser->SetTeam(team);
return RC::RC_ROOM_SUCCESS;
}
RC::eROOM_RESULT
ZoneManager::SetNonblockSlotNumInLobby(User* pMaster, BYTE maxUser)
{
// 로비의 상태인가?
if(pMaster->GetZoneState() != ePRS_AT_LOBBY)
return RC::RC_ROOM_INVALIDROOMTYPE;
LobbyRoom* pLobbyRoom = FindLobby(pMaster->GetZoneKey());
if(!pLobbyRoom)
return RC::RC_ROOM_NOTEXISTLOBBY;
// 방장이어야한다.
if(pMaster!= pLobbyRoom->GetMaster())
return RC::RC_ROOM_NOT_CMD_FOR_MEMBER;
// 두번째 경쟁헌팅 로비인 경우 옵션을 바꾸지 못한다.
if(pLobbyRoom->GetAdditionalCHuntingInfo()->m_LinkHuntingKey)
return RC::RC_ROOM_CANNOT_CHANGE_OPTION_ROOMTYPE;
const sMAPINFO* pInfo = MapInfoParser::Instance()->FindMapInfo(pLobbyRoom->GetMapCode());
if(!pInfo) return RC::RC_ROOM_INVALID_MAPCODE;
if(pInfo->byMinUserNum > maxUser || pInfo->byMaxUserNum < maxUser)
return RC::RC_ROOM_INVALID_LIMITUSERNUM;
#ifdef __NA_000000_20070528_TAIWAN_GUILD_PVP
if(pLobbyRoom->GetRoomInfo()->IsSpecialType(eROOM_SPECIAL_GUILD_PVP))
return RC::RC_ROOM_INVALID_LIMITUSERNUM;
#endif
pLobbyRoom->SetLimitMaxUserNum(maxUser);
if(maxUser > 10)
SUNLOG(eCRITICAL_LOG, "방인원10명초과2(%u)\n", maxUser);
return RC::RC_ROOM_SUCCESS;
}
RC::eROOM_RESULT
ZoneManager::ChangeMapInLobby(User* pMaster, MAPCODE mapCode)
{
// 로비의 상태인가?
if(pMaster->GetZoneState() != ePRS_AT_LOBBY)
return RC::RC_ROOM_INVALIDROOMTYPE;
LobbyRoom* pLobbyRoom = FindLobby(pMaster->GetZoneKey());
if(!pLobbyRoom)
return RC::RC_ROOM_NOTEXISTLOBBY;
// 방장이어야한다.
if(pMaster != pLobbyRoom->GetMaster())
return RC::RC_ROOM_NOT_CMD_FOR_MEMBER;
return pLobbyRoom->ChangeMap(mapCode);
}
RC::eROOM_RESULT
ZoneManager::ConfigHuntingRoomInLobby(User* pMaster, ADDITIONAL_ROOMINFO& IN additionalInfo)
{
// 로비의 상태인가?
if(pMaster->GetZoneState() != ePRS_AT_LOBBY)
return RC::RC_ROOM_INVALIDROOMTYPE;
LobbyRoom* pLobbyRoom = FindHuntingLobby(pMaster->GetZoneKey());
if(!pLobbyRoom)
return RC::RC_ROOM_NOTEXISTLOBBY;
// 방장이어야한다.
if(pMaster != pLobbyRoom->GetMaster())
return RC::RC_ROOM_NOT_CMD_FOR_MEMBER;
// 정보값 유효한가 체크후 셋팅
if(additionalInfo.m_Bonus >= eHUNTING_BONUS_TYPE_MAX)
return RC::RC_ROOM_INVALID_BONUS_VALUE;
if(additionalInfo.m_Difficulty >= eHUNTING_MONSTER_DIFFICULT_MAX)
return RC::RC_ROOM_INVALID_DIFFICULTY_VALUE;
pLobbyRoom->SetAdditionalRoomInfo(&additionalInfo);
return RC::RC_ROOM_SUCCESS;
}
RC::eROOM_RESULT
ZoneManager::ConfigPVPRoomInLobby(User* pMaster, ADDITIONAL_PVPINFO& IN AdditionalPVPInfo)
{
// 로비의 상태인가?
if(pMaster->GetZoneState() != ePRS_AT_LOBBY)
return RC::RC_ROOM_INVALIDROOMTYPE;
LobbyRoom* pLobbyRoom = FindPVPLobby(pMaster->GetZoneKey());
if(!pLobbyRoom)
return RC::RC_ROOM_NOTEXISTLOBBY;
// 방장이어야한다.
if(pMaster != pLobbyRoom->GetMaster())
return RC::RC_ROOM_NOT_CMD_FOR_MEMBER;
// 정보값 유효한가 체크후 셋팅
if(AdditionalPVPInfo.m_Rule >= ePVP_RULE_MAX)
return RC::RC_ROOM_INVALID_RULE_VALUE;
if(AdditionalPVPInfo.m_Mode >= ePVP_MODE_MAX)
return RC::RC_ROOM_INVALID_MODE_VALUE;
if(pLobbyRoom->GetAdditionalPVPInfo()->m_Mode != AdditionalPVPInfo.m_Mode)//&&
// AdditionalPVPInfo.m_Mode == ePVP_TEAM_MODE)
{
pLobbyRoom->SetAdditionalPVPInfo(&AdditionalPVPInfo);
// 팀전이면
// 모든 팀원의 team을 나누고
// 팀정보에 대한 brd
pLobbyRoom->AssignTeam();
}
else
{
pLobbyRoom->SetAdditionalPVPInfo(&AdditionalPVPInfo);
}
return RC::RC_ROOM_SUCCESS;
}
RC::eROOM_RESULT
ZoneManager::ConfigCHuntingRoomInLobby(User* pMaster, ADDITIONAL_CHUNTINGINFO& IN additionalInfo)
{
// 로비의 상태인가?
if(pMaster->GetZoneState() != ePRS_AT_LOBBY)
return RC::RC_ROOM_INVALIDROOMTYPE;
LobbyRoom* pLobbyRoom = FindCHuntingLobby(pMaster->GetZoneKey());
if(!pLobbyRoom)
return RC::RC_ROOM_NOTEXISTLOBBY;
// 방장이어야한다.
if(pMaster != pLobbyRoom->GetMaster())
return RC::RC_ROOM_NOT_CMD_FOR_MEMBER;
// 두번째 경쟁헌팅 로비인 경우 옵션을 바꾸지 못한다.
if(pLobbyRoom->GetAdditionalCHuntingInfo()->m_LinkHuntingKey)
return RC::RC_ROOM_CANNOT_CHANGE_OPTION_ROOMTYPE;
// 정보값 유효한가 체크후 셋팅
if(additionalInfo.m_Bonus >= eHUNTING_BONUS_TYPE_MAX)
return RC::RC_ROOM_INVALID_BONUS_VALUE;
if(additionalInfo.m_Difficulty >= eHUNTING_MONSTER_DIFFICULT_MAX)
return RC::RC_ROOM_INVALID_DIFFICULTY_VALUE;
if(additionalInfo.m_Rule >= eCOMPETITION_RULE_MAX)
return RC::RC_ROOM_INVALID_RULE_VALUE;
if(additionalInfo.m_Mode >= eCOMPETITION_MODE_MAX)
return RC::RC_ROOM_INVALID_MODE_VALUE;
#ifdef __NA_000000_20070528_TAIWAN_GUILD_PVP
if(pLobbyRoom->GetRoomInfo()->IsSpecialType(eROOM_SPECIAL_GUILD_PVP))
{
if(additionalInfo.m_Rule != eCOMPETITION_RULE_DUAL_PARTY)
return RC::RC_ROOM_INVALID_RULE_VALUE;
}
#endif
pLobbyRoom->SetAdditionalCHuntingInfo(&additionalInfo);
return RC::RC_ROOM_SUCCESS;
}
struct SerializeLobbyRoomList
{
template< ZoneManager::eLOBBY_HASH_IDX _IDX, typename _ROOMINFO >
static VOID Execute(ZoneManager* const zone_manager,
User* const user,
const BYTE max_room_count,
BYTE& OUT room_count,
_ROOMINFO* OUT room_info_array)
{
BOOST_STATIC_ASSERT(static_cast<DWORD>(_IDX) < static_cast<DWORD>(ZoneManager::LHI_SIZE_MAX));
room_count = 0;
typedef typename ZoneManager::CACHE_LOBBY_LIST LOBBY_LIST;
const LOBBY_LIST& lobby_list = zone_manager->m_LobbyRoomPerType[_IDX];
FOREACH_CONTAINER(typename LOBBY_LIST::value_type& lobby_room_key, lobby_list, LOBBY_LIST)
{
const typename ZoneManager::ObjectKeyStream::sNode* lobby_room_node =
zone_manager->m_pObjectKeyStream->GetObjectInfo(lobby_room_key);
if (!(lobby_room_node && lobby_room_node->pObject))
{
continue;
}
// (CHANGES)(20100317)(hukim)(REQ_0038) 현재는 방 목록만 얻고 실제 방에 대한 입장은
// 다른 플로우이므로 방 타입에 따른 패스워드 검사는 통과시킨다.
// 패스워드를 포함한 검사는 실제 방에 입장할 때 검사된다.
const LobbyRoom_Info::pointer_r lobby_room = LobbyRoom_Info::downcast(lobby_room_node->pObject);
if (lobby_room->CanShowAtRoomList(user, lobby_room->GetZonePublic(), lobby_room->GetRoomPWD()) == TRUE)
{
lobby_room->SerializeLoad(room_info_array[room_count++]);
if (max_room_count == room_count)
{
return;
}
}
}
}
};
VOID
ZoneManager::_LobbyRoomListRefresh()
{
// (f100617.3L) change to a more cheap routine
m_LobbyRoomPerType[LHI_HUNTING ].resize(0);
m_LobbyRoomPerType[LHI_MISSION ].resize(0);
m_LobbyRoomPerType[LHI_PVP ].resize(0);
m_LobbyRoomPerType[LHI_CHUNTING ].resize(0);
if(m_LobbyRooms.empty())
return;
FOREACH_CONTAINER(const ZONE_LIST::value_type& rNode, m_LobbyRooms, ZONE_LIST)
{
const KEYTYPE key = rNode;
const ObjectKeyStream::sNode* pNode = m_pObjectKeyStream->GetObjectInfo(key);
if(!(pNode && pNode->pObject))
continue;
LobbyRoom_Info::pointer_r pLobbyRoom = LobbyRoom_Info::downcast(pNode->pObject);
switch(pLobbyRoom->GetLobbyType())
{
case eZONETYPE_HUNTING: m_LobbyRoomPerType[LHI_HUNTING ].push_back(key); break;
case eZONETYPE_MISSION: m_LobbyRoomPerType[LHI_MISSION ].push_back(key); break;
case eZONETYPE_PVP: m_LobbyRoomPerType[LHI_PVP ].push_back(key); break;
case eZONETYPE_CHUNTING:m_LobbyRoomPerType[LHI_CHUNTING ].push_back(key); break;
}
}
}
VOID
ZoneManager::GetMissionLobbyRoomList(User* pUser, BYTE, BYTE MaxCount, BYTE& OUT Count, MISSION_ROOMINFO* OUT pRoomInfoArray)
{
SerializeLobbyRoomList::Execute<ZoneManager::LHI_MISSION>(this, pUser, MaxCount, Count,
pRoomInfoArray);
}
VOID
ZoneManager::GetHuntingLobbyRoomList(User* pUser, BYTE, BYTE MaxCount, BYTE& OUT Count, HUNTING_ROOMINFO* OUT pRoomInfoArray)
{
SerializeLobbyRoomList::Execute<ZoneManager::LHI_HUNTING>(this, pUser, MaxCount, Count,
pRoomInfoArray);
}
VOID ZoneManager::GetPVPLobbyRoomList(User* pUser, BYTE, BYTE MaxCount, BYTE& OUT Count, PVP_ROOMINFO* OUT pRoomInfoArray)
{
SerializeLobbyRoomList::Execute<ZoneManager::LHI_PVP>(this, pUser, MaxCount, Count,
pRoomInfoArray);
}
VOID ZoneManager::GetCHuntingLobbyRoomList(User* pUser, BYTE, BYTE MaxCount, BYTE& OUT Count, CHUNTING_ROOMINFO* OUT pRoomInfoArray)
{
SerializeLobbyRoomList::Execute<ZoneManager::LHI_CHUNTING>(this, pUser, MaxCount, Count,
pRoomInfoArray);
}
// <사용 사례가 이상하다.>
//
VOID ZoneManager::GetCHuntingRoomList(User* pUser, BYTE, BYTE MaxCount, BYTE& OUT count, CHUNTING_ROOMINFO* OUT pRoomInfoArray)
{
count = 0;
FOREACH_CONTAINER(const ZONE_LIST::value_type& rNode, m_CHuntingRooms, ZONE_LIST)
{
const KEYTYPE key = rNode;
const ObjectKeyStream::sNode* pNode = m_pObjectKeyStream->GetObjectInfo(key);
if(!(pNode && pNode->pObject))
{
WAVERIX_ZONE_ASSERT(!"m_CHuntingRooms empty slot");
continue;
}
CHuntingRoom_Info::pointer_r pCHuntingRoom = CHuntingRoom_Info::downcast(pNode->pObject);
if(RC::RC_ROOM_SUCCESS != pCHuntingRoom->CanJoin(pUser, eZONEPUBLIC_PUBLIC, NULL))
continue;
// 이미 링크 로비방이 만들어 졌는지 체크
if(pCHuntingRoom->GetLinkedLobby())
continue;
pCHuntingRoom->SerializeLoad(pRoomInfoArray[count++]);
if(count == MaxCount)
return;
}
}
#ifdef __NA_000000_20070528_TAIWAN_GUILD_PVP
//현재 대기중인 길드 PVP의 방 리스트를 보여준다.
VOID
ZoneManager::GetGuildPVPRoomList(User* pUser, BYTE ReqCount, BYTE MaxCount, BYTE& OUT count, CHUNTING_ROOMINFO* OUT pRoomInfoArray)
{
count = 0;
FOREACH_CONTAINER(const ZONE_LIST::value_type& rNode, m_CHuntingRooms, ZONE_LIST)
{
const KEYTYPE key = rNode;
const ObjectKeyStream::sNode* pNode = m_pObjectKeyStream->GetObjectInfo(key);
if(!(pNode && pNode->pObject))
{
WAVERIX_ZONE_ASSERT(!"m_CHuntingRooms empty slot");
continue;
}
CHuntingRoom_Info::pointer_r pCHuntingRoom = CHuntingRoom_Info::downcast(pNode->pObject);
const RC::eROOM_RESULT rt = pCHuntingRoom->CanJoin(pUser, eZONEPUBLIC_PUBLIC, NULL);
if(RC::RC_ROOM_SUCCESS != rt)
{
//실패 하였어도, 리스트가 보여지는 것은 서로 다른 길드여도 보여 져야 하고, 입장권 수량이 모잘라도 보여져야 한다.
switch(rt)
{
case RC::RC_ROOM_CANNOT_JOIN_ROOM_FOR_DIFF_GUILD:
case RC::RC_ROOM_SHORT_ENTRANCE_CARD_OF_GUILD_PVP:
break;
default:
continue;
}
}
// 이미 링크 로비방이 만들어 졌는지 체크
if(pCHuntingRoom->GetLinkedLobby())
continue;
//길드 PVP방이 아니면 리스트를 보여주지 않는다.
if(!pCHuntingRoom->IsSpecialType(eROOM_SPECIAL_GUILD_PVP))
continue;
pCHuntingRoom->SerializeLoad(pRoomInfoArray[count++]);
if(count == MaxCount)
return;
}
}
#endif //__NA_000000_20070528_TAIWAN_GUILD_PVP
VOID
ZoneManager::GetHuntingRoomList(User* pUser, BYTE, BYTE MaxCount, BYTE& OUT Count,
HUNTING_ROOMINFO* OUT pRoomInfoArray)
{
SerializeLobbyRoomList::Execute<ZoneManager::LHI_HUNTING>(this, pUser, MaxCount, Count, pRoomInfoArray);
}
RoomInterface*
ZoneManager::FindRecommendRoom(User* pUser, eZONETYPE RoomType)
{
CACHE_LOBBY_LIST* pList = 0;
switch(RoomType)
{
case eZONETYPE_PVP: pList = &m_LobbyRoomPerType[ LHI_PVP ]; break;
case eZONETYPE_MISSION: pList = &m_LobbyRoomPerType[ LHI_MISSION ]; break;
case eZONETYPE_HUNTING: pList = &m_LobbyRoomPerType[ LHI_HUNTING ]; break;
case eZONETYPE_CHUNTING:pList = &m_LobbyRoomPerType[ LHI_CHUNTING ]; break;
default:
return NULL;
};
RoomInterface* pGeneralRoom = NULL;
CACHE_LOBBY_LIST& rList = *pList;
FOREACH_CONTAINER(const CACHE_LOBBY_LIST::value_type& rNode, rList, CACHE_LOBBY_LIST)
{
const KEYTYPE key = rNode;
const ObjectKeyStream::sNode* pNode = m_pObjectKeyStream->GetObjectInfo(key);
if(!(pNode && pNode->pObject))
continue;
LobbyRoom_Info::pointer_r pLobbyRoom = LobbyRoom_Info::downcast(pNode->pObject);
const RC::eROOM_RESULT rt = pLobbyRoom->IsRecommendRoom(pUser);
if(RC::RC_ROOM_SUCCESS_FOR_RECOMMEND_JOIN == rt)
return pLobbyRoom;
else if(RC::RC_ROOM_SUCCESS_FOR_GENERAL_JOIN == rt)
pGeneralRoom = pLobbyRoom;
}
return pGeneralRoom;
}
//─────────────────────────────────────────
//
//
VOID
ZoneManager::Process()
{
ZONE_LIST::iterator it=m_TotalZones.begin(), itend=m_TotalZones.end();
while(it != itend)
{
const KEYTYPE key = *it;
const ObjectKeyStream::sNode* pNode = m_pObjectKeyStream->GetObjectInfo(key);
if(!(pNode && pNode->pObject))
{
WAVERIX_ZONE_ASSERT(!"huh!");
++it;
continue;
}
ZoneInterface* const pZoneInterface = pNode->pObject;
if(FALSE == pZoneInterface->Process())
{
it = m_TotalZones.erase(it);
DestroyZone(pZoneInterface);
// iterator ++ 와 같은 연산자의 우선순위가 달라질 수 있다. 따라서 미리 제거해 버린다.
// 내부적으로 m_TotalZones에 대한 해당 키를 제거하려고 해도 이미 제거되었으므로 iterator의 위치는 동일하다.
continue;
}
++it;
}
if(m_UpdateTimer.IsExpired())
{
_LobbyRoomListRefresh();
}
}
VOID
ZoneManager::DestroyZone(ZoneInterface* pZone)
{
const KEYTYPE regedKey = (!pZone->IsReusedKey()) ? pZone->GetKey() : 0;
const eZONETYPE ztTYPE = pZone->GetType();
RemoveRoom(pZone);
pZone->Destroy();
switch(ztTYPE)
{
#undef REG_ZONE_NODE
#define REG_ZONE_NODE(_typeinfo) case _typeinfo::value:
REG_ZONE_LIST();
_FreeZone(pZone);
break;
case InstanceDungeon_Info::value: _FreeIndun(pZone); break;
};
if(regedKey)
FreeKey(regedKey);
}
VOID
ZoneManager::AddRoom(ZoneInterface* const pRoom)
{
const eZONETYPE ztTYPE = pRoom->GetType();
const KEYTYPE zoneKey = pRoom->GetKey();
if(!(zoneKey && ((DWORD)ztTYPE < eZONETYPE_MAX)))
{
WAVERIX_ZONE_ASSERT(!(zoneKey && ((DWORD)ztTYPE < eZONETYPE_MAX)));
return;
}
if(FALSE == m_pObjectKeyStream->AddObjectInfo(zoneKey, pRoom, ZoneKeyStreamAddin(pRoom)))
{
WAVERIX_ZONE_ASSERT(0);
return;
}
switch(ztTYPE)
{
case eZONETYPE_LOBBY:
{ // Lobby의 경우는 세부 타입으로 처리해야 한다.
m_LobbyRooms.insert(zoneKey);
LobbyRoom* const pLobbyRoom = LobbyRoom_Info::downcast(pRoom);
if(pLobbyRoom->GetLobbyType() == eZONETYPE_CHUNTING)
{
const KEYTYPE linkKey = pLobbyRoom->GetAdditionalCHuntingInfo()->m_LinkHuntingKey;
m_CHuntingLobbyByCKey.insert(std::make_pair(linkKey, zoneKey));
}
}
break;
case eZONETYPE_CHUNTING:
{
m_CHuntingRooms.insert(zoneKey);
}
break;
case eZONETYPE_VILLAGE:
case eZONETYPE_DOMINATION_FIELD:
case eZONETYPE_FIELD:
#ifdef _NA_008069_20150210_ADD_SPA_SYSTEM
case eZONETYPE_SPA_FIELD:
#endif //_NA_008069_20150210_ADD_SPA_SYSTEM
{
const MAPCODE mapCode = pRoom->GetMapCode();
m_StaticZones.insert(std::make_pair(mapCode, zoneKey));
}
break;
case eZONETYPE_INSTANCE:
{
InstanceDungeon* const pInstanceDungeon = InstanceDungeon_Info::downcast(pRoom);
switch(pInstanceDungeon->GetDungeonType())
{
//case INDUN_KIND_TOP_OF_TRIAL:
//case INDUN_KIND_100LEVEL_QUEST:
// break;
case INDUN_KIND_SS_QUEST:
{
const MAPCODE mapCode = pRoom->GetMapCode();
m_StaticDungeons.insert(std::make_pair(mapCode, zoneKey));
}
break;
}
}
break;
};
PortalManager::OnRoomEvent(pRoom, true);
//
++m_ZoneCounts[ztTYPE];
AddZone(zoneKey);
return;
}
VOID
ZoneManager::RemoveRoom(ZoneInterface* const pRoom)
{
const eZONETYPE ztTYPE = pRoom->GetType();
const KEYTYPE zoneKey = pRoom->GetKey();
if(!(zoneKey && ((DWORD)ztTYPE < eZONETYPE_MAX)))
{
WAVERIX_ZONE_ASSERT(!(zoneKey && ((DWORD)ztTYPE < eZONETYPE_MAX)));
return;
}
if(FALSE == m_pObjectKeyStream->RemoveObjectInfo(zoneKey))
{
WAVERIX_ZONE_ASSERT(0);
return;
}
switch(ztTYPE)
{
case eZONETYPE_LOBBY:
{ // Lobby의 경우는 세부 타입으로 처리해야 한다.
m_LobbyRooms.erase(zoneKey);
LobbyRoom* const pLobbyRoom = LobbyRoom_Info::downcast(pRoom);
if(pLobbyRoom->GetLobbyType() == eZONETYPE_CHUNTING)
{
const KEYTYPE linkKey = pLobbyRoom->GetAdditionalCHuntingInfo()->m_LinkHuntingKey;
m_CHuntingLobbyByCKey.erase(linkKey);
}
}
break;
case eZONETYPE_CHUNTING:
{
m_CHuntingRooms.erase(zoneKey);
}
break;
case eZONETYPE_VILLAGE:
case eZONETYPE_DOMINATION_FIELD:
case eZONETYPE_FIELD:
#ifdef _NA_008069_20150210_ADD_SPA_SYSTEM
case eZONETYPE_SPA_FIELD:
#endif //_NA_008069_20150210_ADD_SPA_SYSTEM
{
const MAPCODE mapCode = pRoom->GetMapCode();
m_StaticZones.erase(mapCode);
}
break;
case eZONETYPE_INSTANCE:
{
InstanceDungeon* const pInstanceDungeon = InstanceDungeon_Info::downcast(pRoom);
switch(pInstanceDungeon->GetDungeonType())
{
//case INDUN_KIND_TOP_OF_TRIAL:
//case INDUN_KIND_100LEVEL_QUEST:
// break;
case INDUN_KIND_SS_QUEST:
{
const MAPCODE mapCode = pRoom->GetMapCode();
m_StaticDungeons.erase(mapCode);
}
break;
}
}
break;
};
PortalManager::OnRoomEvent(pRoom, false);
RemoveZone(zoneKey);
--m_ZoneCounts[ztTYPE];
return;
}
void
ZoneManager::ChangeBattlePlayersCount(RoomInterface* pRoom, DWORD number_of_players)
{
if(pRoom == 0 || pRoom->IsRoomType() == 0)
return;
DWORD zone_type_flag = pRoom->GetType();
zone_type_flag = 1 << zone_type_flag;
if((PolicymentForRoom::MonsterAbilityChangableRoomsBit & zone_type_flag) == 0)
return;
MSG_AG_ZONE_CHANGE_MONSTER_ABILITY_CMD msg;
msg.roomKey = pRoom->GetKey();
msg.number_of_players = (WORD)number_of_players;
pRoom->SendToLinkedServer(&msg, sizeof(msg));
}
DWORD
ZoneManager::GetNumberOfHuntingRooms()
{
return /*GetCHuntingLobbyRoomCount() +*/ GetCHuntingRoomCount();
}
DWORD
ZoneManager::GetNumberOfMissionRooms()
{
return /*GetMissionLobbyRoomCount()+*/ GetMissionRoomCount();
}
VOID
ZoneManager::Display(BOOL bLog)
{
TCHAR* const format = _T("%-18s\t: (%3u) : User's# (%4u)%s");
const TCHAR* delimcode = bLog ? "" : "\n";
const CSunLog::eLOGOPTION option = bLog ? CSunLog::cOUTPUT_FILE : CSunLog::cOUTPUT_CONSOLE;
#undef REG_ZONE_NODE
#define REG_ZONE_NODE(_typeinfo) \
MessageOutEx(g_pSunLog, CSunLog::cCRITICAL_LOG, option, CSunLog::cCATE_DEFAULT, \
format, #_typeinfo, m_ZoneCounts[_typeinfo::value], m_ZoneUserCounts[_typeinfo::value], delimcode);
MessageOutEx(g_pSunLog, CSunLog::cCRITICAL_LOG, option, CSunLog::cCATE_DEFAULT,
"====================================================");
REG_ZONE_LIST();
// REG_INDUN_LIST(); <-인던은 종류별로 되어 있지 않다.
MessageOutEx(g_pSunLog, CSunLog::cCRITICAL_LOG, option, CSunLog::cCATE_DEFAULT, \
format, "InstanceDungeon_Info",
m_ZoneCounts[InstanceDungeon_Info::value],
m_ZoneUserCounts[InstanceDungeon_Info::value], delimcode);
MessageOutEx(g_pSunLog, CSunLog::cCRITICAL_LOG, option, CSunLog::cCATE_DEFAULT,
"====================================================");
}
VOID
ZoneManager::DisplayerZonePoolInfo()
{
typedef util::CMemoryPoolFactory<LobbyRoom> POOL_for_LOBBY;
util::IVMemoryPool* pPool = m_PoolRouter.GetPool(eZONETYPE_LOBBY);
POOL_for_LOBBY* pPF = DOWNCASTER_SELECT<POOL_for_LOBBY*>(pPool);
printf("LOBBY %u %u %u %u\n",
pPF->GetPoolBasicSize(), pPF->GetPoolExtendSize(),
pPF->GetNumberOfBands(), pPF->GetAvailableNumberOfTypes());
}
VOID
ZoneManager::CreateMissionByLobby(User* request_user,
const MSG_AG_ZONE_CAN_CREATE_ROOM_ACK* recv_msg)
{
MSG_AG_ZONE_CAN_CREATE_ROOM_ACK::CheckArgMembers check_member = recv_msg->m_CheckArgMembers;
MSG_CG_ZONE_MISSION_CREATE_NAK nak_msg;
ZoneInterface* zone_interface = NULL;
LobbyRoom* lobby_room = NULL;
if(check_member.roomKey == request_user->GetZoneKey())
{
zone_interface = g_ZoneManager.FindZone(check_member.roomKey);
}
if(zone_interface && zone_interface->GetType() == eZONETYPE_LOBBY)
{
lobby_room = static_cast<LobbyRoom*>(zone_interface);
}
if(FALSE == (lobby_room && lobby_room->GetLobbyType() == eZONETYPE_MISSION))
{
nak_msg.m_dwErrorCode = RC::RC_ROOM_INVALID_ROOM_TYPE;
request_user->SendPacket(&nak_msg, sizeof(nak_msg));
return;
}
if(lobby_room->IsAllReady() == FALSE)
{
nak_msg.m_dwErrorCode = RC::RC_ROOM_IS_NOT_ALL_READY;
request_user->SendPacket(&nak_msg, sizeof(nak_msg));
return;
}
RoomInterface* room_interface = static_cast<RoomInterface*>(zone_interface);
if (room_interface->ExceptionProcessByLobbyMember(recv_msg, request_user) == false)
{
SUNLOG(eCRITICAL_LOG, __FUNCTION__" : Fail mission start");
return;
}
request_user->BeginTransaction(TR_LEAVE_LOBBY_FOR_MISSION);
MissionRoom* pRoom = NULL;
RC::eROOM_RESULT rt = g_ZoneManager.CreateMissionRoom(check_member.roomKey, request_user, pRoom);
if (RC::RC_ROOM_SUCCESS == rt)
{
request_user->SetTRRoomKey(pRoom->GetKey());
RoomMigrater<LobbyRoom, MissionRoom, TR_LEAVE_LOBBY_FOR_MISSION> op(lobby_room, pRoom);
lobby_room->Foreach(op);
}
else
{
request_user->EndTransaction();
nak_msg.m_dwErrorCode = rt;
request_user->SendPacket(&nak_msg, sizeof(nak_msg));
}
}
//_NA_20110630_BATTLE_ZONE_RENEWAL
VOID
ZoneManager::ProcessCreatePVPRoom(User* request_user)
{
AgentPartyManager* party_manager = AgentPartyManager::Instance();
WORD party_key = request_user->GetPartyState().GetPartyKey();
const PartyRoom* party_room = party_manager->FindPartyRoom(party_key);
if (party_room == NULL)
{
SUNLOG(eCRITICAL_LOG, __FUNCTION__" : Not found party room : %d", party_key);
return;
}
BaseParty* party = const_cast<BaseParty*>(party_manager->FindParty(party_key));
if (party == NULL)
{
SUNLOG(eCRITICAL_LOG, __FUNCTION__" : Not found party : %d", party_key);
return;
}
PVPRoom* pvp_room = NULL;
ADDITIONAL_PVPINFO pvp_info;
pvp_info.m_Rule = static_cast<BYTE>(ePVP_RULE_INFINITY);
pvp_info.m_Mode = static_cast<BYTE>(party_room->GetPvPMode());
MAPCODE map_code = party_room->GetMapCode();
request_user->BeginTransaction(TR_LEAVE_FIELD_FOR_PARTY_PVP);
RC::eROOM_RESULT result_code = g_ZoneManager.CreatePVPRoomByParty(request_user,
pvp_room,
map_code,
party_room->GetPartyRoomType(),
&pvp_info);
if (result_code == RC::RC_ROOM_SUCCESS)
{
party_manager->ResetPartyRoomReadyState(request_user, party_key);
party_manager->SetIsMissionStart(party_key, true);
request_user->SetTRRoomKey(pvp_room->GetKey());
RoomMigraterByParty<PVPRoom, TR_LEAVE_FIELD_FOR_PARTY_PVP> op(pvp_room);
party->For_eachMembers(op);
}
else
{
MSG_CG_PARTY_ROOM_START_ACK nak_msg;
request_user->EndTransaction();
nak_msg.result_code_ = RC::RC_PARTY_FAIL_CREATE_ROOM;
party_manager->SendPacketAllMember(party_key, &nak_msg, sizeof(nak_msg));
party_manager->ResetPartyRoomReadyState(request_user, party_key);
SUNLOG(eCRITICAL_LOG,
__FUNCTION__" : CreatePVPRoom process result fail : %d",
result_code);
}
}
VOID
ZoneManager::ProcessCreateInstanceDungeonRoom(User* request_user)
{
AgentPartyManager* party_manager = AgentPartyManager::Instance();
WORD party_key = request_user->GetPartyState().GetPartyKey();
const PartyRoom* party_room = party_manager->FindPartyRoom(party_key);
if (party_room == NULL)
{
SUNLOG(eCRITICAL_LOG, __FUNCTION__" : Not found party room : %d", party_key);
return;
}
BaseParty* party = const_cast<BaseParty*>(party_manager->FindParty(party_key));
if (party == NULL)
{
SUNLOG(eCRITICAL_LOG, __FUNCTION__" : Not found party : %d", party_key);
return;
}
InstanceDungeon* Instance_dungeon = NULL;
BOOL need_check_open_time =
(party_room->GetPartyRoomType() == PartyOfTopOfTrialByNormal) ? true : false;
MAPCODE map_code = party_room->GetMapCode();
request_user->BeginTransaction(TR_LEAVE_FIELD_FOR_PARTY_INSTANCEDUNGEON);
RC::eROOM_RESULT result_code =
g_ZoneManager.CreateInstanceDungeonRoomByParty(request_user,
(InstanceDungeon *&)Instance_dungeon,
map_code,
party_room->GetPartyRoomType(),
INDUN_KIND_TOP_OF_TRIAL,
need_check_open_time);
if (result_code == RC::RC_ROOM_SUCCESS)
{
party_manager->ResetPartyRoomReadyState(request_user, party_key);
party_manager->SetIsMissionStart(party_key, true);
request_user->SetTRRoomKey(Instance_dungeon->GetKey());
g_ZoneManager.ChangeBattlePlayersCount(Instance_dungeon, party->GetMemberNum());
RoomMigraterByParty<InstanceDungeon, TR_LEAVE_FIELD_FOR_PARTY_INSTANCEDUNGEON> op(Instance_dungeon);
party->For_eachMembers(op);
}
else
{
MSG_CG_PARTY_ROOM_START_ACK nak_msg;
request_user->EndTransaction();
nak_msg.result_code_ = RC::RC_PARTY_FAIL_CREATE_ROOM;
party_manager->SendPacketAllMember(party_key, &nak_msg, sizeof(nak_msg));
party_manager->ResetPartyRoomReadyState(request_user, party_key);
SUNLOG(eCRITICAL_LOG,
__FUNCTION__" : CreateInstanceDungeonRoom process result fail : %d",
result_code);
}
}
VOID
ZoneManager::ProcessCreateMissionRoom(User* request_user)
{
AgentPartyManager* party_manager = AgentPartyManager::Instance();
WORD party_key = request_user->GetPartyState().GetPartyKey();
const PartyRoom* party_room = party_manager->FindPartyRoom(party_key);
if (party_room == NULL)
{
SUNLOG(eCRITICAL_LOG, __FUNCTION__" : Not found party room : %d", party_key);
return;
}
BaseParty* party = const_cast<BaseParty*>(party_manager->FindParty(party_key));
if (party == NULL)
{
SUNLOG(eCRITICAL_LOG, __FUNCTION__" : Not found party : %d", party_key);
return;
}
MissionRoom* party_mission_room = NULL;
MAPCODE map_code = party_room->GetMapCode();
request_user->BeginTransaction(TR_LEAVE_FIELD_FOR_PARTY_MISSION);
RC::eROOM_RESULT result_code =
g_ZoneManager.CreateMissionRoomByParty(request_user,
party_mission_room,
map_code,
party_room->GetPartyRoomType());
if (RC::RC_ROOM_SUCCESS == result_code)
{
party_manager->ResetPartyRoomReadyState(request_user, party_key);
party_manager->SetIsMissionStart(party_key, true);
request_user->SetTRRoomKey(party_mission_room->GetKey());
g_ZoneManager.ChangeBattlePlayersCount(party_mission_room, party->GetMemberNum());
RoomMigraterByParty<MissionRoom, TR_LEAVE_FIELD_FOR_PARTY_MISSION> op(party_mission_room);
party->For_eachMembers(op);
}
else
{
MSG_CG_PARTY_ROOM_START_ACK nak_msg;
request_user->EndTransaction();
nak_msg.result_code_ = RC::RC_PARTY_FAIL_CREATE_ROOM;
party_manager->SendPacketAllMember(party_key, &nak_msg, sizeof(nak_msg));
party_manager->ResetPartyRoomReadyState(request_user, party_key);
SUNLOG(eCRITICAL_LOG,
__FUNCTION__" : CreateMissionRoom process result fail : %d",
result_code);
}
}
RC::eROOM_RESULT
ZoneManager::CreatePVPRoomByParty(User* master_user,
PVPRoom*& OUT pvp_room,
MAPCODE map_code,
PartyZoneType party_room_type,
const ADDITIONAL_PVPINFO* additional_pvp_info)
{
ServerSessionManager* const server_session_manager = ServerSessionManager::Instance();
FlowControl flow;
ServerSessionEx* const pFieldSession = _CheckRoomCountLimit(flow);
if (pFieldSession == NULL)
{
return RC::RC_ROOM_CANNOT_CREATE_ROOM_FOR_LIMIT;
}
const DWORD server_session_index = server_session_manager->Incr_LOF_BattleServer();
if (server_session_index == 0)
{
return RC::RC_ROOM_FAILED;
}
ServerSession* server_session =
static_cast<ServerSession*>(ServerSessionManager::Instance()->FindServer(server_session_index));
if (!server_session || server_session->GetServerType() != BATTLE_SERVER)
{
return RC::RC_ROOM_FAILED;
}
KEYTYPE pvp_room_key = AllocKey();
pvp_room = PVPRoom_Info::downcast(_AllocZone(PVPRoom_Info::value));
RC::eROOM_RESULT result_code = pvp_room->Create(master_user,
map_code,
pvp_room_key,
server_session,
additional_pvp_info);
if(result_code != RC::RC_ROOM_SUCCESS)
{
FreeKey(pvp_room_key);
_FreeZone(pvp_room);
return result_code;
}
AddRoom(pvp_room);
ZoneInterface* current_zone = FindZone(master_user->GetZoneKey());
if (current_zone == NULL)
{
return RC::RC_ROOM_FAILED;
}
AgentPartyManager* const party_manager = AgentPartyManager::Instance();
const PartyRoom* party_room =
party_manager->FindPartyRoom(master_user->GetPartyState().GetPartyKey());
if (party_room == NULL)
{
SUNLOG(eCRITICAL_LOG,
__FUNCTION__" : Not found party room : key : %d",
master_user->GetPartyState().GetPartyKey());
return RC::RC_ROOM_NOT_EXIST_ROOM;
}
MSG_AG_PARTY_PARTYROOM_ITEM_DELETE_CMD cmd_msg;
cmd_msg.require_item_ = party_room->GetPartyRoomAdditionalInfo()->require_item_;
cmd_msg.member_key_ = master_user->GetPlayerKey();
#ifdef _NA_007734_20141027_ADD_ROOMKIND_SPECIALMISSION
cmd_msg.party_zone_type_ = BattlezoneMissionTreeParser::Instance()->GetType(map_code);
#endif //_NA_007734_20141027_ADD_ROOMKIND_SPECIALMISSION
master_user->SendToLinkedServer(&cmd_msg, sizeof(cmd_msg));
RoomArgument args(eZONEPUBLIC_PUBLIC);
result_code = MoveZone(current_zone, pvp_room, master_user, args);
if (result_code != RC::RC_ROOM_SUCCESS)
{
SUNLOG(eCRITICAL_LOG, __FUNCTION__" : Party master fail move to mission room");
return result_code;
}
return RC::RC_ROOM_SUCCESS;
}
RC::eROOM_RESULT
ZoneManager::CreateInstanceDungeonRoomByParty(User* master_user,
InstanceDungeon*& OUT Instance_dungeon,
MAPCODE map_code,
PartyZoneType party_room_type,
eINSTANCE_DUNGEON_KIND dungeon_kind,
BOOL need_check_open_time)
{
ServerSessionManager* const server_session_manager = ServerSessionManager::Instance();
FlowControl flow;
ServerSessionEx* const pFieldSession = _CheckRoomCountLimit(flow);
if (pFieldSession == NULL)
{
return RC::RC_ROOM_CANNOT_CREATE_ROOM_FOR_LIMIT;
}
const DWORD server_session_index = server_session_manager->Incr_LOF_BattleServer();
if (server_session_index == 0)
{
return RC::RC_ROOM_FAILED;
}
ServerSession* server_session =
static_cast<ServerSession*>(ServerSessionManager::Instance()->FindServer(server_session_index));
if (!server_session || server_session->GetServerType() != BATTLE_SERVER)
{
return RC::RC_ROOM_FAILED;
}
KEYTYPE alloc_key = AllocKey();
Instance_dungeon = InstanceDungeon_Info::downcast(_AllocIndun(dungeon_kind));
if (Instance_dungeon->RegisterRuleset(map_code) == false)
{
return RC::RC_ROOM_FAILED;
}
RC::eROOM_RESULT result_code = Instance_dungeon->Create(master_user,
map_code,
alloc_key,
server_session,
need_check_open_time);
if (result_code != RC::RC_ROOM_SUCCESS)
{
FreeKey(alloc_key);
_FreeIndun(Instance_dungeon);
return result_code;
}
AddRoom(Instance_dungeon);
ZoneInterface* const current_zone = FindZone(master_user->GetZoneKey());
if (current_zone == NULL)
{
return RC::RC_ROOM_FAILED;
}
AgentPartyManager* const party_manager = AgentPartyManager::Instance();
const PartyRoom* party_room =
party_manager->FindPartyRoom(master_user->GetPartyState().GetPartyKey());
if (party_room == NULL)
{
SUNLOG(eCRITICAL_LOG,
__FUNCTION__" : Not found party room : key : %d",
master_user->GetPartyState().GetPartyKey());
return RC::RC_ROOM_NOT_EXIST_ROOM;
}
MSG_AG_PARTY_PARTYROOM_ITEM_DELETE_CMD cmd_msg;
cmd_msg.require_item_ = party_room->GetPartyRoomAdditionalInfo()->require_item_;
cmd_msg.member_key_ = master_user->GetPlayerKey();
#ifdef _NA_007734_20141027_ADD_ROOMKIND_SPECIALMISSION
cmd_msg.party_zone_type_ = BattlezoneMissionTreeParser::Instance()->GetType(map_code);
#endif //_NA_007734_20141027_ADD_ROOMKIND_SPECIALMISSION
master_user->SendToLinkedServer(&cmd_msg, sizeof(cmd_msg));
RoomArgument args(eZONEPUBLIC_PUBLIC);
result_code = MoveZone(current_zone, Instance_dungeon, master_user, args);
if (result_code != RC::RC_ROOM_SUCCESS)
{
SUNLOG(eCRITICAL_LOG, __FUNCTION__" : Party master fail move to Instance room");
return result_code;
}
return RC::RC_ROOM_SUCCESS;
}
RC::eROOM_RESULT
ZoneManager::CreateMissionRoomByParty(User* master_user,
MissionRoom*& OUT party_mission_room,
MAPCODE map_code,
PartyZoneType party_room_type)
{
ServerSessionManager* const server_session_manager = ServerSessionManager::Instance();
FlowControl flow;
ServerSessionEx* const pFieldSession = _CheckRoomCountLimit(flow);
if (pFieldSession == NULL)
{
return RC::RC_ROOM_CANNOT_CREATE_ROOM_FOR_LIMIT;
}
const DWORD server_session_index = server_session_manager->Incr_LOF_BattleServer();
if (server_session_index == 0)
{
return RC::RC_ROOM_FAILED;
}
ServerSession* server_session =
static_cast<ServerSession*>(ServerSessionManager::Instance()->FindServer(server_session_index));
if (!server_session || server_session->GetServerType() != BATTLE_SERVER)
{
return RC::RC_ROOM_FAILED;
}
KEYTYPE mission_key = AllocKey();
party_mission_room = MissionRoom_Info::downcast(_AllocZone(MissionRoom_Info::value));
RC::eROOM_RESULT result_code = party_mission_room->Create(master_user, map_code,
mission_key, server_session);
if(result_code != RC::RC_ROOM_SUCCESS)
{
FreeKey(mission_key);
_FreeZone(party_mission_room);
return result_code;
}
AddRoom(party_mission_room);
ZoneInterface* current_zone = FindZone(master_user->GetZoneKey());
if (current_zone == NULL)
{
return RC::RC_ROOM_FAILED;
}
AgentPartyManager* const party_manager = AgentPartyManager::Instance();
const PartyRoom* party_room =
party_manager->FindPartyRoom(master_user->GetPartyState().GetPartyKey());
if (party_room == NULL)
{
SUNLOG(eCRITICAL_LOG,
__FUNCTION__" : Not found party room : key : %d",
master_user->GetPartyState().GetPartyKey());
return RC::RC_ROOM_NOT_EXIST_ROOM;
}
MSG_AG_PARTY_PARTYROOM_ITEM_DELETE_CMD cmd_msg;
cmd_msg.require_item_ = party_room->GetPartyRoomAdditionalInfo()->require_item_;
cmd_msg.member_key_ = master_user->GetPlayerKey();
#ifdef _NA_007734_20141027_ADD_ROOMKIND_SPECIALMISSION
cmd_msg.party_zone_type_ = BattlezoneMissionTreeParser::Instance()->GetType(map_code);
#endif //_NA_007734_20141027_ADD_ROOMKIND_SPECIALMISSION
master_user->SendToLinkedServer(&cmd_msg, sizeof(cmd_msg));
RoomArgument args(eZONEPUBLIC_PUBLIC);
result_code = MoveZone(current_zone, party_mission_room, master_user, args);
if (result_code != RC::RC_ROOM_SUCCESS)
{
SUNLOG(eCRITICAL_LOG, __FUNCTION__" : Party master fail move to mission room");
return result_code;
}
return RC::RC_ROOM_SUCCESS;
}
#ifdef _NA_008069_20150210_ADD_SPA_SYSTEM
SpaField* ZoneManager::FindSpaField( const MAPCODE map_code ) const
{
const DWORD STATIC_ZONE_MASK = (1<<eZONETYPE_SPA_FIELD);
ZoneInterface* const pZoneInterface = FindStaticZone(map_code);
if(pZoneInterface)
{
const DWORD zoneTypeBit = 1 << pZoneInterface->GetType();
if(STATIC_ZONE_MASK & zoneTypeBit)
return SpaField_Info::downcast(pZoneInterface);
}
return NULL;
}
RC::eROOM_RESULT ZoneManager::CreateSpaField( MAPCODE mapCode, ZoneInterface* OUT spa_field )
{
ServerSession* pServerSession = (ServerSession*)ServerSessionManager::Instance()->GetFieldServer();
if(!pServerSession)
{
SUNLOG(eFULL_LOG, "["__FUNCTION__"] 필드서버가 아닌 세션을 연결하려한다.!\n");
return RC::RC_ROOM_FAILED;
}
SpaField_Info::pointer_r pField = SpaField_Info::downcast(_AllocZone(SpaField_Info::value));
// NOTE: f110520.5L, static fields use the reserved unique key.
const MapInfoParser* const map_parser = MapInfoParser::Instance();
const sMAPINFO* map_info = map_parser->FindMapInfo(mapCode);
if (FlowControl::FCAssert(map_info != NULL) == false) {
return RC::RC_ROOM_FAILED;
};
const KEYTYPE alloced_key = map_info->reserved_key_index_;
pField->Create(alloced_key, mapCode, pServerSession);
AddRoom(pField);
if(spa_field)
spa_field = pField;
return RC::RC_ROOM_SUCCESS;
}
#endif //_NA_008069_20150210_ADD_SPA_SYSTEM