Files
Leviathan/Server/GameServer/Game/Community/PartyManager.cpp
T
2026-06-01 12:46:52 +02:00

1738 lines
47 KiB
C++

#include <toolkit/XEnv.h>
#include <toolkit/XRandom.h>
#include <toolkit/XConsole.h>
#include "PartyManager.h"
#include "StructPlayer.h"
#include "StructSummon.h"
#include "DB_Commands.h"
#include "SendMessage.h"
#include "GameMessage.h"
#include "GameDBUtil.h"
#include "DB_Commands.h"
#include "HuntaholicManager.h"
#include "GuildManager.h"
#include "PartyMatchingManager.h"
static PartyManager _inst;
PartyManager & PartyManager::GetInstance()
{
return _inst;
}
bool PartyManager::Init()
{
InitUserDbConnection( m_DBConn.connection );
m_DBConn.CreateCommand( m_DBConn.command );
SCOPED_ENV( "stat.loading_party_info" );
m_nMaxPartyID = 0;
// DB 파티 리스트 주욱 읽어옴(m_IntfLock을 안 걸었는데, 로딩 과정 중에는 다른 쓰레드에서 PartyManager에 접근할 일이 없다고 간주하고 처리)
loadPartyMemberTagList(); // Character 테이블에서 먼저 파티 소속 아바타 정보를 읽어서 PartyMemberTag 벡터 생성
loadPartyList(); // 파티 정보 로딩 및 생성된 PartyMemberTag 벡터에서 해당 파티에 맞는 벡터 복사 및 소거
finishLoading(); // 쓰고 남은 떨거지 청소(떨거지가 있다면 해당 파티 ID인 캐릭터는 있으나 Party 는 없는 것)
return true;
}
bool PartyManager::DeInit()
{
SCOPED_ENV( "stat.saving_party_info" );
// 쿼리 다 완결될때까지 대기
while( !m_lQueryList.empty() )
{
Sleep( 100 );
}
return true;
}
const PartyManager::_PARTY_TYPE PartyManager::GetPartyType( int nPartyID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo )
{
assert( 0 );
return TYPE_UNKNOWN;
}
return pInfo->ePartyType;
}
bool PartyManager::IsLinkedParty( int nPartyID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return false;
return ( pInfo->pPartyLinkInfo != NULL );
}
bool PartyManager::IsAttackTeamParty( int nPartyID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return false;
return _isAttackTeamParty( pInfo );
}
bool PartyManager::IsBattleArenaTeamParty( int nPartyID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return false;
return _isBattleArenaTeamParty( pInfo );
}
bool PartyManager::IsJoinableLinkedParty( int nPartyID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return false;
if( !pInfo->pPartyLinkInfo ) return false;
return static_cast< int >( pInfo->pPartyLinkInfo->vPartyList.size() ) < pInfo->pPartyLinkInfo->nMaxPartyCount;
}
int PartyManager::GetLinkedPartyLeadPartyID( int nPartyID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return 0;
if( pInfo->pPartyLinkInfo )
return pInfo->pPartyLinkInfo->nLeadPartyID;
return 0;
}
bool PartyManager::IsExistAttackTeam( int nGuildID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
if( m_hshAttackTeamID.has( nGuildID ) )
return true;
return false;
}
int PartyManager::GetAttackTeamLeadPartyIDByGuildID( int nGuildID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
AttackTeamInfo * pAttackTeamInfo = NULL;
m_hshAttackTeamID.lookup( nGuildID, pAttackTeamInfo );
if( !pAttackTeamInfo )
return 0;
return pAttackTeamInfo->nLeadPartyID;
}
bool PartyManager::MakeAttackTeam( int nPartyID, int nGuildID, int nMaxGuildParty, bool bIsRaidParty )
{
THREAD_SYNCRONIZE( m_IntfLock );
PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return false;
if( pInfo->pPartyLinkInfo )
return false;
if( bIsRaidParty )
{
if( pInfo->ePartyType != TYPE_RAID_ATTACKTEAM )
{
assert( 0 );
pInfo->ePartyType = TYPE_RAID_ATTACKTEAM;
}
}
else if( pInfo->ePartyType != TYPE_SIEGE_ATTACKTEAM )
{
assert( 0 );
pInfo->ePartyType = TYPE_SIEGE_ATTACKTEAM;
}
if( makeAttackTeam( pInfo, nGuildID, nMaxGuildParty ) )
{
Push( new DB_UpdatePartyInfo( pInfo->nPartyID, pInfo->nLeaderSID, pInfo->eShareMode, pInfo->ePartyType, pInfo->nPartyID ) );
return true;
}
return false;
}
bool PartyManager::JoinAttackTeam( int nGuildID, int nPartyID )
{
THREAD_SYNCRONIZE( m_IntfLock );
PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return false;
if( pInfo->pPartyLinkInfo ) return false;
AttackTeamInfo * pAttackTeamInfo = NULL;
m_hshAttackTeamID.lookup( nGuildID, pAttackTeamInfo );
if( !pAttackTeamInfo )
return false;
if( joinLinkedParty( pAttackTeamInfo, pInfo ) )
{
Push( new DB_UpdatePartyInfo( pInfo->nPartyID, pInfo->nLeaderSID, pInfo->eShareMode, pInfo->ePartyType, pInfo->pPartyLinkInfo->nLeadPartyID ) );
return true;
}
return false;
}
int PartyManager::GetAttackTeamGuildID( int nPartyID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return 0;
if( !_isAttackTeamParty( pInfo ) ) return 0;
return static_cast< AttackTeamInfo * >( pInfo->pPartyLinkInfo )->nGuildID;
}
bool PartyManager::MakeBattleArenaTeam( int nLeadPartyID, int nMaxPartyCount )
{
THREAD_SYNCRONIZE( m_IntfLock );
PartyInfo *pInfo = getPartyInfo( nLeadPartyID );
if( !pInfo ) return false;
if( pInfo->pPartyLinkInfo )
return false;
if( pInfo->ePartyType != TYPE_BATTLE_ARENA_TEAM &&
pInfo->ePartyType != TYPE_BATTLE_ARENA_EXERCISE_TEAM )
return false;
// 배틀 아레나 파티 관련 내용이므로 DB 업데이트를 따로 하지 않음
return makeLinkedParty( pInfo, nMaxPartyCount );
}
bool PartyManager::JoinBattleArenaTeam( int nLeadPartyID, int nPartyID )
{
THREAD_SYNCRONIZE( m_IntfLock );
PartyInfo * pLeadPartyInfo = getPartyInfo( nLeadPartyID );
if( !pLeadPartyInfo ) return false;
PartyLinkInfo * pPartyLinkInfo = pLeadPartyInfo->pPartyLinkInfo;
if( !pPartyLinkInfo )
return false;
if( pLeadPartyInfo->ePartyType != TYPE_BATTLE_ARENA_TEAM &&
pLeadPartyInfo->ePartyType != TYPE_BATTLE_ARENA_EXERCISE_TEAM )
return false;
PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return false;
// 배틀 아레나 파티 관련 내용이므로 DB 업데이트를 따로 하지 않음
return joinLinkedParty( pPartyLinkInfo, pInfo );
}
bool PartyManager::ChangeBattleArenaExerciseTeamType( int nLeadPartyID, bool bToExerciseTeam )
{
THREAD_SYNCRONIZE( m_IntfLock );
PartyInfo * pLeadPartyInfo = getPartyInfo( nLeadPartyID );
if( !pLeadPartyInfo ) return false;
if( !_isBattleArenaTeamParty( pLeadPartyInfo ) )
return false;
PartyLinkInfo * pPartyLinkInfo = pLeadPartyInfo->pPartyLinkInfo;
if( !pPartyLinkInfo )
return false;
_PARTY_TYPE eSourceType = ( bToExerciseTeam ) ? TYPE_BATTLE_ARENA_TEAM : TYPE_BATTLE_ARENA_EXERCISE_TEAM;
_PARTY_TYPE eTargetType = ( bToExerciseTeam ) ? TYPE_BATTLE_ARENA_EXERCISE_TEAM : TYPE_BATTLE_ARENA_TEAM;
for( std::vector< PartyInfo * >::iterator it = pPartyLinkInfo->vPartyList.begin() ; it != pPartyLinkInfo->vPartyList.end() ; ++it )
{
PartyInfo * pInfo = (*it);
// 타입이 다른 파티 정보가 나왔으면 지금까지 바꾼 파티들 다 되돌려주고 실패
if( pInfo->ePartyType != eSourceType )
{
assert( 0 );
for( std::vector< PartyInfo * >::iterator itPrev = pPartyLinkInfo->vPartyList.begin() ; itPrev != it ; ++itPrev )
(*itPrev)->ePartyType = eSourceType;
return false;
}
pInfo->ePartyType = eTargetType;
}
return true;
}
int PartyManager::GetPartyPassword( int nPartyID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
// 파티 구조체 얻기
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return -1;
return pInfo->nPartyPassword;
}
int PartyManager::GetLinkedPartyPassword( int nPartyID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
// 파티 구조체 얻기
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return -1;
if( !pInfo->pPartyLinkInfo ) return -1;
return pInfo->pPartyLinkInfo->nPassword;
}
bool PartyManager::IsSomeoneInSiegeOrRaidDungeon( int nPartyID )
{
THREAD_SYNCRONIZE( m_IntfLock );
PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo || !_isAttackTeamParty( pInfo ) ) return false;
// 던전 내부에 한 명이라도 있으면 공대파티 파괴 불가능
struct myPartyCheckerFunctor : PartyManager::PartyFunctor
{
myPartyCheckerFunctor() : m_bSomeoneInDungeon(false) {}
virtual bool operator()( AR_HANDLE handle )
{
StructPlayer::iterator pit = StructPlayer::get( handle );
StructPlayer *pPlayer = *pit;
if( pPlayer && pPlayer->IsInSiegeOrRaidDungeon() )
m_bSomeoneInDungeon = true;
return true;
}
bool m_bSomeoneInDungeon;
} _foChecker;
for( std::vector< PartyInfo * >::iterator it = pInfo->pPartyLinkInfo->vPartyList.begin() ; it != pInfo->pPartyLinkInfo->vPartyList.end() && !_foChecker.m_bSomeoneInDungeon ; ++it )
{
doEachMember( (*it), _foChecker );
}
return _foChecker.m_bSomeoneInDungeon;
}
int PartyManager::MakeParty( const char *szPartyName, int nLeaderSID, const _PARTY_TYPE & ePartyType )
{
THREAD_SYNCRONIZE( m_IntfLock );
PartyInfo *pInfo = getPartyInfo( szPartyName );
if( pInfo ) return 0;
int nPartyID = allocPartyID();
if( nPartyID <= 0 )
{
return 0;
}
pInfo = makeParty( nPartyID, szPartyName, nLeaderSID, ITEM_SHARE_MONOPOLY, ePartyType );
if( pInfo == NULL )
{
return 0;
}
// DB에 추가해야 하는 타입의 파티인 경우에만 DB에 추가
if( isDBUpdateRequiredType( ePartyType ) )
Push( new DB_InsertParty( pInfo->strPartyName.c_str(), pInfo->nPartyID, pInfo->nLeaderSID, pInfo->ePartyType ) );
return pInfo->nPartyID;
}
bool PartyManager::DestroyParty( int nPartyID )
{
THREAD_SYNCRONIZE( m_IntfLock );
return destroyParty( getPartyInfo( nPartyID ) );
}
int PartyManager::GetMemberCount( int nPartyID )
{
THREAD_SYNCRONIZE( m_IntfLock );
// 파티 구조체 얻기
PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return 0;
return static_cast< int >( pInfo->vMemberNameList.size() );
}
int PartyManager::GetPartyID( const char * szPartyName ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo * pInfo = getPartyInfo( szPartyName );
if( !pInfo ) return 0;
return pInfo->nPartyID;
}
std::string PartyManager::GetPartyName( int nPartyID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return "";
return pInfo->strPartyName;
}
bool PartyManager::IsLeader( int nPartyID, PlayerUID nPlayerUID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return false;
return pInfo->nLeaderSID == nPlayerUID;
}
bool PartyManager::IsMember( int nPartyID, PlayerUID nPlayerUID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return false;
std::vector< PartyMemberTag >::const_iterator it;
for( it = pInfo->vMemberNameList.begin(); it != pInfo->vMemberNameList.end(); ++it )
{
if( (*it).sid == nPlayerUID )
return true;
}
return false;
}
std::string PartyManager::GetMemberDisplayName( int nPartyID, PlayerUID nPlayerUID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return "";
std::vector< PartyMemberTag >::const_iterator it;
for( it = pInfo->vMemberNameList.begin(); it != pInfo->vMemberNameList.end(); ++it )
{
if( (*it).sid == nPlayerUID )
return (*it).strDisplayName;
}
return "";
}
PlayerUID PartyManager::GetMemberUID( int nPartyID, const char * szPlayerName ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return 0;
std::vector< PartyMemberTag >::const_iterator it;
for( it = pInfo->vMemberNameList.begin(); it != pInfo->vMemberNameList.end(); ++it )
{
if( (*it).strName == szPlayerName )
return (*it).sid;
}
return 0;
}
bool PartyManager::Promote( int nPartyID, struct StructPlayer *pPtr )
{
THREAD_SYNCRONIZE( m_IntfLock );
// 파티 구조체 얻기
PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return false;
// 시즈/레이드 공대 파티에서는 파티장 인계 불가능(길드 내 권한 시스템이 추가됨에 따라 수정되어야 했던 부분인듯 한데...;;)
if( _isAttackTeamParty( pInfo ) )
return false;
PlayerUID nNewLeaderUID = pPtr->GetPlayerUID();
// 현재 파장에게 인계하려는 시도면 패스
if( nNewLeaderUID == pInfo->nLeaderSID )
{
assert( 0 );
return false;
}
const PartyMemberTag * pMemberTag = NULL;
for( std::vector< PartyMemberTag >::const_iterator it = pInfo->vMemberNameList.begin() ; it != pInfo->vMemberNameList.end() ; ++it )
{
const PartyMemberTag & memberTag = (*it);
if( memberTag.sid == nNewLeaderUID )
{
pMemberTag = &memberTag;
break;
}
}
// 파티 멤버가 아닌 유저에게 인계 시도?
if( !pMemberTag )
{
assert( 0 );
return false;
}
if( isDBUpdateRequiredType( pInfo->ePartyType ) )
Push( new DB_UpdatePartyInfo( nPartyID, pMemberTag->sid, pInfo->eShareMode, pInfo->ePartyType, 0 ) );
pInfo->strLeaderName = pMemberTag->strName;
pInfo->strLeaderDisplayName = pMemberTag->strDisplayName;
pInfo->nLeaderSID = pMemberTag->sid;
pInfo->nLeaderJobId = pMemberTag->nJobId;
CPartyMatchingManager::GetInstance()->ChangeMaster(*StructPlayer::get(StructPlayer::FindPlayer(pInfo->strLeaderName.c_str())), pPtr);
return true;
}
bool PartyManager::AutoPromote( int nPartyID, const bool bOnlyOnlinePlayer )
{
THREAD_SYNCRONIZE( m_IntfLock );
// 파티 구조체 얻기
PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return false;
// 시즈/레이드 공대 파티에서는 파티장 인계 불가능(길드 내 권한 시스템이 추가됨에 따라 수정되어야 했던 부분인듯 한데...;;)
if( pInfo->pPartyLinkInfo && ( pInfo->ePartyType == TYPE_RAID_ATTACKTEAM || pInfo->ePartyType == TYPE_SIEGE_ATTACKTEAM ) )
return false;
PartyMemberTag * pNewLeaderTag = NULL;
for( std::vector< PartyMemberTag >::iterator it = pInfo->vMemberNameList.begin() ; it != pInfo->vMemberNameList.end() ; ++it )
{
PartyMemberTag & memberTag = (*it);
// 필요하다면 온라인 유저 체크
if( bOnlyOnlinePlayer && !memberTag.bIsOnline )
continue;
// 현재 리더면 패스
if( memberTag.sid == pInfo->nLeaderSID )
continue;
pNewLeaderTag = &memberTag;
}
if( !pNewLeaderTag )
return false;
if( isDBUpdateRequiredType( pInfo->ePartyType ) )
Push( new DB_UpdatePartyInfo( nPartyID, pNewLeaderTag->sid, pInfo->eShareMode, pInfo->ePartyType, 0 ) );
pInfo->strLeaderName = pNewLeaderTag->strName;
pInfo->strLeaderDisplayName = pNewLeaderTag->strDisplayName;
pInfo->nLeaderSID = pNewLeaderTag->sid;
pInfo->nLeaderJobId = pNewLeaderTag->nJobId;
CPartyMatchingManager::GetInstance()->ChangeMaster(*StructPlayer::get(StructPlayer::FindPlayer(pInfo->strLeaderName.c_str())), *StructPlayer::get(StructPlayer::FindPlayer(pNewLeaderTag->strName.c_str())));
return true;
}
void PartyManager::OnChangeCharacterName( int nPartyID, PlayerUID nPlayerUID, const char * szNewName )
{
THREAD_SYNCRONIZE( m_IntfLock );
PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return;
for( std::vector< PartyMemberTag >::iterator it = pInfo->vMemberNameList.begin(); it != pInfo->vMemberNameList.end(); ++it )
{
PartyMemberTag & memberTag = (*it);
if( memberTag.sid == nPlayerUID )
{
std::string strPrevDisplayName = memberTag.strDisplayName;
bool bDisplayNameChanged = false;
// 실명이 다른 사람들에게 보여지고 있는 경우 표시 이름 변경 처리도 필요
if( memberTag.strName == memberTag.strDisplayName )
{
bDisplayNameChanged = true;
memberTag.strDisplayName = szNewName;
// 파장이었으면 파장 표시 이름 갱신
if( pInfo->nLeaderSID == nPlayerUID )
pInfo->strLeaderDisplayName = szNewName;
}
// 파장이었으면 파장 이름 갱신
if( pInfo->nLeaderSID == nPlayerUID )
pInfo->strLeaderName = szNewName;
memberTag.strName = szNewName;
if( bDisplayNameChanged )
PrintfLinkedPartyChatMessage( false, CHAT_PARTY_SYSTEM, "@PARTY", nPartyID, "CHANGE_NAME|%s|%s|", strPrevDisplayName.c_str(), szNewName );
break;
}
}
}
void PartyManager::OnChangeCharacterLevel( int nPartyID, PlayerUID nPlayerUID, const int nLevel )
{
THREAD_SYNCRONIZE( m_IntfLock );
PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return;
for( std::vector< PartyMemberTag >::iterator it = pInfo->vMemberNameList.begin(); it != pInfo->vMemberNameList.end(); ++it )
{
if( (*it).sid == nPlayerUID )
{
(*it).nLevel = nLevel;
PrintfPartyChatMessage( CHAT_PARTY_SYSTEM, nPartyID, "CHANGE_LEVEL|%s|%d|", (*it).strDisplayName.c_str(), nLevel );
break;
}
}
}
void PartyManager::OnChangeCharacterJob( int nPartyID, PlayerUID nPlayerUID, const int nJobId )
{
THREAD_SYNCRONIZE( m_IntfLock );
PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return;
for( std::vector< PartyMemberTag >::iterator it = pInfo->vMemberNameList.begin(); it != pInfo->vMemberNameList.end(); ++it )
{
if( (*it).sid == nPlayerUID )
{
(*it).nJobId = nJobId;
PrintfLinkedPartyChatMessage( false, CHAT_PARTY_SYSTEM, "@PARTY", nPartyID, "CHANGE_JOB|%s|%d|", (*it).strDisplayName.c_str(), nJobId );
break;
}
}
}
int PartyManager::GetMaxLevel( int nPartyID )
{
THREAD_SYNCRONIZE( m_IntfLock );
// 파티 구조체 얻기
PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return 0;
int nMaxLevel = 0;
std::vector< AR_HANDLE >::iterator it;
for( it = pInfo->vOnlineList.begin(); it != pInfo->vOnlineList.end(); ++it )
{
StructPlayer *pPlayer = static_cast< StructPlayer * >( GameObject::raw_get( *it ) );
if( !pPlayer ) continue;
if( nMaxLevel < pPlayer->GetLevel() ) nMaxLevel = pPlayer->GetLevel();
}
return nMaxLevel;
}
int PartyManager::GetMinLevel( int nPartyID )
{
THREAD_SYNCRONIZE( m_IntfLock );
// 파티 구조체 얻기
PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return 0;
int nMinLevel = 999;
std::vector< AR_HANDLE >::iterator it;
for( it = pInfo->vOnlineList.begin(); it != pInfo->vOnlineList.end(); ++it )
{
StructPlayer *pPlayer = static_cast< StructPlayer * >( GameObject::raw_get( *it ) );
if( !pPlayer ) continue;
if( nMinLevel > pPlayer->GetLevel() ) nMinLevel = pPlayer->GetLevel();
}
return nMinLevel;
}
int PartyManager::GetTotalLevel( int nPartyID )
{
THREAD_SYNCRONIZE( m_IntfLock );
// 파티 구조체 얻기
PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return 0;
int nTotalLevel = 0;
std::vector< AR_HANDLE >::iterator it;
for( it = pInfo->vOnlineList.begin(); it != pInfo->vOnlineList.end(); ++it )
{
StructPlayer *pPlayer = static_cast< StructPlayer * >( GameObject::raw_get( *it ) );
if( !pPlayer ) continue;
nTotalLevel += pPlayer->GetLevel();
}
return nTotalLevel;
}
std::string PartyManager::GetLeaderName( int nPartyID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
// 파티 구조체 얻기
const PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return "";
return pInfo->strLeaderName;
}
std::string PartyManager::GetLeaderDisplayName( int nPartyID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
// 파티 구조체 얻기
const PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return "";
return pInfo->strLeaderDisplayName;
}
PlayerUID PartyManager::GetLeaderSID( int nPartyID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
// 파티 구조체 얻기
const PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return 0;
return pInfo->nLeaderSID;
}
bool PartyManager::JoinParty( int nPartyID, struct StructPlayer *pPtr )
{
THREAD_SYNCRONIZE( m_IntfLock );
return joinParty( getPartyInfo( nPartyID ), pPtr );
}
bool PartyManager::LeaveParty( int nPartyID, PlayerUID nPlayerUID )
{
THREAD_SYNCRONIZE( m_IntfLock );
return leaveParty( getPartyInfo( nPartyID ), nPlayerUID );
}
bool PartyManager::onLogin( int nPartyID, struct StructPlayer *pPtr )
{
THREAD_SYNCRONIZE( m_IntfLock );
PartyInfo * pPartyInfo = getPartyInfo( nPartyID );
if( !pPartyInfo )
{
pPtr->SetPartyID( 0 );
return false;
}
// 유저가 오프라인 된 상태에서 기존의 파티가 해산되고 다른 파티가 생성되면서 파티ID가 재사용된 경우에는
// 실제로는 멤버가 아닌데 해당 파티에 다시 진입하려는 시도를 할 수도 있으므로 실제 멤버인지 체크 추가
// * 이 증상은 거의 발생하지 않지만, smp_login_character가 실행된 직후에 smp_delete_party가 실행되면
// 이미 DB에서 읽어들인 데이터는 party_id != 0 이 되지만 실제로 DB 상의 party_id = 0 이 되어있고,
// PartyManager::onLogin 함수가 호출되기 전에 다른 쓰레드에서 해당 파티ID를 사용해 새 파티가 생성되는
// 아주 절묘한 타이밍에는 발생할 수 있음... 거의 없음 -_ -;;;
// 그래도 유저 1회 로그인당 1번밖에 실행 안되는 함수이니 처리해주기...
PlayerUID nPlayerUID = pPtr->GetPlayerUID();
for( std::vector< PartyMemberTag >::const_iterator it = pPartyInfo->vMemberNameList.begin() ; it != pPartyInfo->vMemberNameList.end() ; ++it )
{
if( (*it).sid != nPlayerUID )
continue;
// 멤버라는 거 알려주는 걸 변수 딱히 따로 선언하기 뭣해서 기냥 nPlayerUID를 차용 'ㅠ 'ㅋ
nPlayerUID = -1;
break;
}
// 멤버가 아니네 'ㅠ ';
if( nPlayerUID != -1 )
{
pPtr->SetPartyID( 0 );
return false;
}
if( pPartyInfo->vMemberNameList.size() > MAX_PARTY_MEMBER )
{
bool bResult = false;
if( pPartyInfo->nLeaderSID == pPtr->GetPlayerUID() )
{
bResult = destroyParty( pPartyInfo );
}
else
{
bResult = leaveParty( pPartyInfo, pPtr->GetPlayerUID() );
}
// 탈퇴/해산이 불가능한 경우에는 그냥 로그인시켜 줌(어차피 배열도 아니고 벡터로 처리하므로 인덱싱 오류같은 건 안 생기므로... 클라에선 좀 문제될지도 ``;)
if( bResult )
{
pPtr->SetPartyID( 0 );
return false;
}
}
return signAsOnLine( pPartyInfo, pPtr );
}
bool PartyManager::onLogout( int nPartyID, struct StructPlayer *pPtr )
{
THREAD_SYNCRONIZE( m_IntfLock );
return signAsOffLine( getPartyInfo( nPartyID ), pPtr );
}
const PartyManager::_ITEM_SHARE_MODE PartyManager::GetShareMode( int nPartyID )
{
THREAD_SYNCRONIZE( m_IntfLock );
// 파티 구조체 얻기
PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return ITEM_SHARE_MONOPOLY;
return pInfo->eShareMode;
}
void PartyManager::SetShareMode( int nPartyID, const _ITEM_SHARE_MODE & eShareMode )
{
THREAD_SYNCRONIZE( m_IntfLock );
// 파티 구조체 얻기
PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return;
pInfo->eShareMode = eShareMode;
int nLeadPartyID = ( pInfo->pPartyLinkInfo ) ? pInfo->pPartyLinkInfo->nLeadPartyID : 0;
if( isDBUpdateRequiredType( pInfo->ePartyType ) )
Push( new DB_UpdatePartyInfo( nPartyID, pInfo->nLeaderSID, pInfo->eShareMode, pInfo->ePartyType, nLeadPartyID ) );
}
struct StructPlayer * PartyManager::GetNextItemAcquirer( struct StructPlayer * pFinder, const std::vector< struct StructPlayer * > & vPlayers )
{
THREAD_SYNCRONIZE( m_IntfLock );
// 파티 구조체 얻기
PartyInfo *pInfo = getPartyInfo( pFinder->GetPartyID() );
if( !pInfo ) return NULL;
switch( pInfo->eShareMode )
{
case ITEM_SHARE_MONOPOLY:
// 각자 분배(습득자 독점)면 습득자가 획득자
return pFinder;
case ITEM_SHARE_RANDOM:
// 랜덤 분배
return vPlayers[ XRandom() % static_cast< int >( vPlayers.size() ) ];
case ITEM_SHARE_LINEAR:
// 순차 분배
{
int nMemberCount = static_cast< int >( pInfo->vMemberNameList.size() );
if( pInfo->nLastItemAcquirerIdx == -1 )
{
pInfo->nLastItemAcquirerIdx = nMemberCount - 1;
}
int nThisItemAcquirerIdx = ( pInfo->nLastItemAcquirerIdx + 1 ) % nMemberCount;
while( nThisItemAcquirerIdx != pInfo->nLastItemAcquirerIdx )
{
if( !pInfo->vMemberNameList[ nThisItemAcquirerIdx ].bIsOnline )
{
nThisItemAcquirerIdx = ( nThisItemAcquirerIdx + 1 ) % nMemberCount;
continue;
}
for( std::vector< struct StructPlayer * >::const_iterator it = vPlayers.begin() ; it != vPlayers.end() ; ++it )
{
if( (*it)->GetSID() == pInfo->vMemberNameList[ nThisItemAcquirerIdx ].sid )
{
pInfo->nLastItemAcquirerIdx = nThisItemAcquirerIdx;
return (*it);
}
}
nThisItemAcquirerIdx = ( nThisItemAcquirerIdx + 1 ) % nMemberCount;
}
}
break;
}
return pFinder;
}
std::string PartyManager::GetLinkedPartyInfo( int nPartyID ) const
{
char buf[1024];
std::string strResult;
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo || !pInfo->pPartyLinkInfo ) return strResult;
if( _isAttackTeamParty( pInfo ) )
{
int nRaidDungeonID = GuildManager::GetInstance().GetRaidDungeonID( static_cast< AttackTeamInfo * >( pInfo->pPartyLinkInfo )->nGuildID );
s_sprintf( buf, _countof( buf ), "RAID_INFO|%d|%d|%d|%d|", pInfo->pPartyLinkInfo->nLeadPartyID,
pInfo->pPartyLinkInfo->nMaxPartyCount, nRaidDungeonID + 70000000, pInfo->ePartyType == TYPE_RAID_ATTACKTEAM );
}
// 기존의 시즈/레이드용 공대 파티 외의 파티는 모두 아래의 형식으로 보내지만,
// 차후에라도 BattleArenaTeamParty 외의 타입이 추가되고 아래의 정보 외에 추가 정보를 보내야 하게 되면
// 아래의 내용이 else 로 분류되지 않고 else if ... else if ... else 로 갈라져야 함
else
{
// 배틀 아레나 연습 경기용 파티의 경우 경기 시작과 함께 실제 경기용 파티로 변경되므로 클라에는 무조건 실제 경기용 파티 타입으로 방송
s_sprintf( buf, _countof( buf ), "LPINFO|%d|%d|%d|", pInfo->pPartyLinkInfo->nLeadPartyID, pInfo->pPartyLinkInfo->nMaxPartyCount,
( pInfo->ePartyType != TYPE_BATTLE_ARENA_EXERCISE_TEAM ) ? pInfo->ePartyType : TYPE_BATTLE_ARENA_TEAM );
}
strResult = buf;
for( std::vector< PartyInfo * >::iterator it = pInfo->pPartyLinkInfo->vPartyList.begin(); it != pInfo->pPartyLinkInfo->vPartyList.end(); ++it )
{
int nSubPartyID = (*it)->nPartyID;
if( nPartyID == nSubPartyID )
continue;
std::string strMemberInfo;
// 멤버당 최대 정보 길이를 예상해보면 34 Bytes 쯤 되니 미리 공간을 할당해둬서 그나마 빈번한 메모리 재할당을 방지
strMemberInfo.reserve( (*it)->vMemberNameList.size() * 34 );
int nPartyLevel = 0;
for( std::vector< PartyManager::PartyMemberTag >::iterator itMember = (*it)->vMemberNameList.begin() ; itMember != (*it)->vMemberNameList.end() ; ++itMember )
{
PartyManager::PartyMemberTag *pMemberTag = &(*itMember);
bool bIsProc = false;
// 파티장의 레벨을 파티의 대표 레벨로 설정
if( pMemberTag->sid == (*it)->nLeaderSID )
nPartyLevel = pMemberTag->nLevel;
do
{
if( !pMemberTag->bIsOnline )
break;
StructPlayer::iterator pit = StructPlayer::get( StructPlayer::FindPlayer( pMemberTag->strName.c_str() ) );
StructPlayer * pPlayer = *pit;
if( !pPlayer )
break;
char buf[512];
s_sprintf( buf, _countof( buf ), "%u|%s|%d|%d|", pPlayer->GetHandle(),
pMemberTag->strDisplayName.c_str(), pPlayer->GetJobId(), pPlayer->GetHPPercentage() != 0 );
strMemberInfo += buf;
bIsProc = true;
} while( false );
if( !bIsProc )
{
char buf[512];
s_sprintf( buf, _countof( buf ), "0|%s|%d|1|", pMemberTag->strDisplayName.c_str(), pMemberTag->nJobId );
strMemberInfo += buf;
}
}
s_sprintf( buf, _countof( buf ), "%d|%s|%s|%d|%d|%d|", (*it)->nPartyID, (*it)->strPartyName.c_str(), (*it)->strLeaderDisplayName.c_str(),
nPartyLevel, (*it)->nLeaderJobId, (*it)->vMemberNameList.size() );
strResult += buf;
strResult += strMemberInfo;
}
return strResult;
}
std::string PartyManager::GetSummonInfo( int nPartyID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return "";
return "SINFO|" + getSummonInfo( nPartyID );
}
std::string PartyManager::GetLinkedPartySummonInfo( int nPartyID ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return "";
if( !pInfo->pPartyLinkInfo ) return "";
std::string strResult = "SINFO|";
for( std::vector< PartyInfo * >::iterator it = pInfo->pPartyLinkInfo->vPartyList.begin(); it != pInfo->pPartyLinkInfo->vPartyList.end(); ++it )
{
strResult += getSummonInfo( (*it)->nPartyID );
}
return strResult;
}
size_t PartyManager::DoEachLinkedPartyMember( int nPartyID, PartyFunctor & _fo )
{
THREAD_SYNCRONIZE( m_IntfLock );
PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return 0;
if( !pInfo->pPartyLinkInfo ) return 0;
size_t nRet = 0;
for( std::vector< PartyInfo * >::iterator it = pInfo->pPartyLinkInfo->vPartyList.begin(); it != pInfo->pPartyLinkInfo->vPartyList.end(); ++it )
{
nRet += doEachMember( (*it), _fo );
}
return nRet;
}
size_t PartyManager::DoEachAttackTeamMemberByGuildId( int nGuildID, PartyFunctor & _fo )
{
THREAD_SYNCRONIZE( m_IntfLock );
AttackTeamInfo * pAttackTeamInfo = NULL;
m_hshAttackTeamID.lookup( nGuildID, pAttackTeamInfo );
if( !pAttackTeamInfo )
return 0;
int nRet = 0;
for( std::vector< PartyInfo * >::iterator it = pAttackTeamInfo->vPartyList.begin(); it != pAttackTeamInfo->vPartyList.end(); ++it )
{
nRet += static_cast<int>( doEachMember( (*it), _fo ) );
}
return nRet;
}
size_t PartyManager::DoEachMember( int nPartyID, PartyFunctor & _fo )
{
THREAD_SYNCRONIZE( m_IntfLock );
PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return 0;
return doEachMember( pInfo, _fo );
}
size_t PartyManager::DoEachMember( int nPartyID, PartyFunctor & _fo ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return 0;
return doEachMember( pInfo, _fo );
}
size_t PartyManager::DoEachMemberTag( int nPartyID, PartyMemberTagFunctor & _fo )
{
THREAD_SYNCRONIZE( m_IntfLock );
PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return 0;
return doEachMemberTag( pInfo, _fo );
}
size_t PartyManager::DoEachParty( int nPartyID, LinkedPartyFunctor & _fo )
{
THREAD_SYNCRONIZE( m_IntfLock );
PartyInfo *pInfo = getPartyInfo( nPartyID );
if( !pInfo || !pInfo->pPartyLinkInfo ) return 0;
return doEachParty( pInfo->pPartyLinkInfo, _fo );
}
void PartyManager::GetNearMember( struct StructPlayer *pPtr, AR_UNIT distance, std::vector< StructPlayer* > & vList ) const
{
AR_TIME t = GetArTime();
struct myPartyFunctor : PartyManager::PartyFunctor
{
myPartyFunctor( const ArPosition & _pos, unsigned char _layer, AR_TIME _t, AR_UNIT _dist, std::vector< StructPlayer* > * pList ) : pos( _pos ), layer( _layer ), t( _t ), distance( _dist ), pvList( pList )
{
}
virtual bool operator()( AR_HANDLE handle )
{
StructPlayer::iterator pit = StructPlayer::get( handle );
StructPlayer *pPlayer = *pit;
if( !pPlayer || !pPlayer->IsInWorld() ) return true;
// 멀리 떨어져 있으면 KIN
if( layer != pPlayer->GetLayer() )
return true;
AR_UNIT d = pos.GetDistance( pPlayer->GetPos() );
if( d > distance ) return true;
pvList->push_back( pPlayer );
return true;
}
ArPosition pos;
unsigned char layer;
AR_TIME t;
AR_UNIT distance;
std::vector< StructPlayer* > *pvList;
} _tmp( pPtr->GetPos(), pPtr->GetLayer(), t, distance, &vList );
DoEachMember( pPtr->GetPartyID(), _tmp );
}
void PartyManager::GetOfflineMember( int nPartyID, std::vector< PartyMemberTag > & vList ) const
{
THREAD_SYNCRONIZE( m_IntfLock );
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return;
for( std::vector< PartyMemberTag >::const_iterator it = pInfo->vMemberNameList.begin(); it != pInfo->vMemberNameList.end(); ++it )
{
if( !(*it).bIsOnline ) vList.push_back( *it );
}
}
void PartyManager::Push( GameDBManager::DBProc* pWork )
{
THREAD_SYNCRONIZE( m_QueryLock );
if( m_lQueryList.empty() )
{
DB().Push( pWork );
}
m_lQueryList.push_back( pWork );
}
void PartyManager::onEndQuery()
{
THREAD_SYNCRONIZE( m_QueryLock );
m_lQueryList.pop_front();
if( !m_lQueryList.empty() )
{
DB().Push( m_lQueryList.front() );
}
}
PartyManager::PartyManager()
: m_QueryLock( "PartyManager::m_QueryLock" )
, m_IntfLock( "PartyManager::m_IntfLock" )
{
m_nMaxPartyID = 0;
}
PartyManager::~PartyManager()
{
}
bool PartyManager::leaveParty( PartyInfo *pInfo, PlayerUID nPlayerUID )
{
if( !pInfo ) return false;
// 파티장이 파티 탈퇴를 하면 덤프 남김(파티장은 leaveParty 함수가 아니라 destroyParty 함수로 들어가도록 호출부에서 처리되어 있어야 함)
if( pInfo->nLeaderSID == nPlayerUID )
{
assert( 0 );
XSEH::InvokeUnhandledException( 0xC000000DL );
return false;
}
// 파티원이 1명인데 파티 탈퇴가 시도되면 해산 처리 시도
// 파티장이 탈퇴를 할 수 있었기에 이런 상황이 발생하는 것이므로 이 경우에는 덤프를 남기지 않고 어떻게든 처리해서 넘김
if( pInfo->vMemberNameList.size() == 1 )
{
assert( 0 );
switch( pInfo->ePartyType )
{
// 공대 관련 파티일 경우에는 파티장 인계처리만 하여 파티 해산을 유저가 시도 할 수 있도록 허용
// 멤버로서 탈퇴는 가능하지만 해산은 하면 안되는 경우가 많음
case TYPE_RAID_ATTACKTEAM:
case TYPE_SIEGE_ATTACKTEAM:
{
const PartyMemberTag * pMemberTag = &pInfo->vMemberNameList.front();
int nLeadPartyID = ( pInfo->pPartyLinkInfo ) ? pInfo->pPartyLinkInfo->nLeadPartyID : 0;
Push( new DB_UpdatePartyInfo( pInfo->nPartyID, pMemberTag->sid, pInfo->eShareMode, pInfo->ePartyType, nLeadPartyID ) );
pInfo->strLeaderName = pMemberTag->strName;
pInfo->strLeaderDisplayName = pMemberTag->strDisplayName;
pInfo->nLeaderSID = pMemberTag->sid;
pInfo->nLeaderJobId = pMemberTag->nJobId;
}
return false;
// 일반 파티 또는 헌터홀릭 관련 파티면 해산함(탈퇴 시도가 사냥 종료를 뜻하는 경우가 대부분이므로)
default:
return destroyParty( pInfo );
}
}
int nIdx = 0;
for( std::vector< PartyMemberTag >::iterator it = pInfo->vMemberNameList.begin(); it != pInfo->vMemberNameList.end(); ++it, ++nIdx )
{
if( it->sid == nPlayerUID )
{
// 멤버 리스트에서 제거(이름은 아래에서 사용해야 하므로 임시 보관)
std::string strName = it->strName;
pInfo->vMemberNameList.erase( it );
// 온라인 상태라면 제거
StructPlayer::iterator pit = StructPlayer::get( StructPlayer::FindPlayer( strName.c_str() ) );
StructPlayer *pPtr = *pit;
if( pPtr )
{
pPtr->SetPartyID( 0 );
signAsOffLine( pInfo, pPtr );
}
else
{
// DB의 해당 캐릭터의 파티 ID 를 0으로 설정함.
// 파티 ID는 무조건 저장해 줌
// * 파티 타입에 따라 DB에 파티 정보를 저장하지 않는 경우도 있지만 파티 데이터가 유지되는 상태에서
// 유저만 재접속하는 경우에는 해당 파티에 가입된 상태를 유지시켜야 하는 경우가 있기 때문
Push( new DB_SetParty( strName.c_str(), 0 ) );
}
// 순차 분배일 경우 파티 탈퇴 인원 발생 시 다음 아이템 습득할 유저 인덱스가 탈퇴 유저 인덱스보다 뒤면 하나 당겨줌
if( nIdx < pInfo->nLastItemAcquirerIdx )
--pInfo->nLastItemAcquirerIdx;
pInfo->nLastItemAcquirerIdx = pInfo->nLastItemAcquirerIdx % static_cast< int >( pInfo->vMemberNameList.size() );
CPartyMatchingManager::GetInstance()->SendMemberAsChange(*StructPlayer::get(StructPlayer::FindPlayer(pInfo->strLeaderName.c_str())));
return true;
}
}
return false;
}
bool PartyManager::joinParty( PartyInfo *pInfo, struct StructPlayer *pPtr )
{
if( !pInfo ) return false;
if( pInfo->vMemberNameList.size() >= MAX_PARTY_MEMBER )
return false;
// 파티매칭에 등록된 인원제한.
//if(false == CPartyMatchingManager::GetInstance()->CheckNumber(pInfo->nPartyID))
//{
// return false;
//}
// 파티 리스트에 추가
// * 가명 기능 사용 가능 타입의 파티에만 가명 정보 반영
pInfo->vMemberNameList.push_back( PartyMemberTag( pPtr->GetPlayerUID(), pPtr->GetName(),
getDisplayNameForPartyType( pInfo->ePartyType, pPtr ), pPtr->GetLevel(), pPtr->GetJobId() ) );
// 온라인으로 설정
signAsOnLine( pInfo, pPtr );
pPtr->SetPartyID( pInfo->nPartyID );
pPtr->ReleaseItemPriority();
// 파티 ID는 무조건 저장해 줌
// * 파티 타입에 따라 DB에 파티 정보를 저장하지 않는 경우도 있지만 파티 데이터가 유지되는 상태에서
// 유저만 재접속하는 경우에는 해당 파티에 가입된 상태를 유지시켜야 하는 경우가 있기 때문
Push( new DB_SetParty( pPtr->GetName(), pInfo->nPartyID ) );
CPartyMatchingManager::GetInstance()->SendMemberAsChange(*StructPlayer::get(StructPlayer::FindPlayer(pInfo->strLeaderName.c_str())));
return true;
}
bool PartyManager::destroyParty( PartyInfo *pInfo )
{
if( !pInfo ) return false;
CPartyMatchingManager::GetInstance()->Remove(*StructPlayer::get(StructPlayer::FindPlayer(pInfo->strLeaderName.c_str())));
// 연결된 파티가 있는 파티 해산 시
if( pInfo->pPartyLinkInfo )
{
// 연결된 파티의 마스터 파티가 해산될 경우
if( pInfo->pPartyLinkInfo->nLeadPartyID == pInfo->nPartyID )
{
// 시즈/레이드 공대 파티일 경우
if( pInfo->ePartyType == TYPE_RAID_ATTACKTEAM || pInfo->ePartyType == TYPE_SIEGE_ATTACKTEAM )
{
// destroy all raid party
for( std::vector< PartyInfo * >::iterator it = pInfo->pPartyLinkInfo->vPartyList.begin(); it != pInfo->pPartyLinkInfo->vPartyList.end(); )
{
if( (*it) != pInfo )
{
destroyParty( (*it) );
it = pInfo->pPartyLinkInfo->vPartyList.begin();
}
else
{
++it;
}
}
m_hshAttackTeamID.erase( static_cast< AttackTeamInfo * >( pInfo->pPartyLinkInfo )->nGuildID );
delete pInfo->pPartyLinkInfo;
pInfo->pPartyLinkInfo = NULL;
}
// 배틀 아레나 파티인 경우
else if( pInfo->ePartyType == TYPE_BATTLE_ARENA_TEAM || pInfo->ePartyType == TYPE_BATTLE_ARENA_EXERCISE_TEAM )
{
// 마지막 남은 파티인 경우
if( pInfo->pPartyLinkInfo->vPartyList.size() <= 1 )
{
delete pInfo->pPartyLinkInfo;
pInfo->pPartyLinkInfo = NULL;
}
// 현재 파티 외에 남은 파티가 있다면 마스터 파티를 남은 파티 중 첫 번째 파티로 변경
// * 마스터 파티가 배틀 아레나에선 별 의미가 없으므로 막 바꿔 줌
else
{
// 해산될 파티를 링크 파티 목록에서 제거
std::vector< PartyInfo * >::iterator it = std::find( pInfo->pPartyLinkInfo->vPartyList.begin(), pInfo->pPartyLinkInfo->vPartyList.end(), pInfo );
if( it != pInfo->pPartyLinkInfo->vPartyList.end() )
{
it = pInfo->pPartyLinkInfo->vPartyList.erase( it );
pInfo->pPartyLinkInfo->nLeadPartyID = pInfo->pPartyLinkInfo->vPartyList.front()->nPartyID;
}
else
{
// 멤버 파티가 아닌데 해산하려고 보니 현재 링크 파티 정보로 온 것이므로
// pPartyLinkInfo 가 엉뚱한 놈으로 세팅된 것이거나, 아니면 두 번 이상 destroyParty가 호출된 경우.
assert( 0 );
}
pInfo->pPartyLinkInfo = NULL;
}
}
else
{
// 연결된 파티 정보는 있으나 해당 타입의 파티에 대한 해산 처리 대한 코드 작업이 되지 않은 경우...
assert( 0 );
}
}
// 멤버 파티의 해산인 경우
else
{
for( std::vector< PartyInfo * >::iterator it = pInfo->pPartyLinkInfo->vPartyList.begin(); it != pInfo->pPartyLinkInfo->vPartyList.end(); ++it)
{
if( (*it) == pInfo )
{
pInfo->pPartyLinkInfo->vPartyList.erase( it );
break;
}
}
pInfo->pPartyLinkInfo = NULL;
}
}
struct myPartyFunctor : PartyFunctor
{
virtual bool operator()( AR_HANDLE handle )
{
StructPlayer::iterator pit = StructPlayer::get( handle );
StructPlayer *pPlayer = *pit;
if( !pPlayer ) return true;
pPlayer->SetPartyID( 0 );
return true;
}
} _fo;
// 각 플레이어들 파티 정보 클리어
doEachMember( pInfo, _fo );
// DB 에서 파티 제거(DB에 저장되지 않은 타입의 파티여도 이건 처리해 줌으로써
// Party 테이블의 데이터 삭제는 어차피 이루어지지 않지만
// Character.party_id == pInfo->nPartyID 인 것들을 0 으로 설정하는 처리를 하도록 함
Push( new DB_DeleteParty( pInfo->nPartyID ) );
m_hshPartyName.erase( pInfo->strPartyName.c_str() );
m_hshPartyID.erase( pInfo->nPartyID );
// 파티 정보 지움
delete pInfo;
return true;
}
PartyManager::PartyLinkInfo * PartyManager::makeLinkedParty( PartyInfo * pInfo, int nMaxPartyCount )
{
if( pInfo->pPartyLinkInfo )
return NULL;
PartyLinkInfo * pLinkInfo = new PartyLinkInfo();
pLinkInfo->vPartyList.push_back( pInfo );
pLinkInfo->nLeadPartyID = pInfo->nPartyID;
pLinkInfo->nMaxPartyCount = nMaxPartyCount;
pLinkInfo->nPassword = XRandom();
pInfo->pPartyLinkInfo = pLinkInfo;
return pLinkInfo;
}
bool PartyManager::joinLinkedParty( PartyLinkInfo * pLinkInfo, PartyInfo * pInfo )
{
if( static_cast< int >( pLinkInfo->vPartyList.size() ) >= pLinkInfo->nMaxPartyCount )
return false;
pLinkInfo->vPartyList.push_back( pInfo );
pInfo->pPartyLinkInfo = pLinkInfo;
return true;
}
PartyManager::AttackTeamInfo * PartyManager::makeAttackTeam( PartyInfo * pInfo, int nGuildID, int nMaxGuildParty )
{
if( m_hshAttackTeamID.has( nGuildID ) )
return NULL;
AttackTeamInfo * pAttackTeamInfo = new AttackTeamInfo;
pAttackTeamInfo->nPassword = XRandom();
pAttackTeamInfo->nLeadPartyID = pInfo->nPartyID;
pAttackTeamInfo->nGuildID = nGuildID;
pAttackTeamInfo->nMaxPartyCount = nMaxGuildParty;
pAttackTeamInfo->vPartyList.push_back( pInfo );
pInfo->pPartyLinkInfo = pAttackTeamInfo;
m_hshAttackTeamID.add( pAttackTeamInfo->nGuildID, pAttackTeamInfo );
return pAttackTeamInfo;
}
PartyManager::PartyInfo * PartyManager::makeParty( int nPartyID, const char *szPartyName, int nLeaderSID, const _ITEM_SHARE_MODE & eShareMode, const _PARTY_TYPE & ePartyType )
{
if( ePartyType == TYPE_UNKNOWN )
{
assert( 0 );
return NULL;
}
// 파티 구조체 생성
PartyInfo * pInfo = new PartyInfo;
pInfo->strPartyName = szPartyName;
pInfo->nPartyID = nPartyID;
pInfo->nPartyPassword = XRandom();
pInfo->nLeaderSID = nLeaderSID;
pInfo->eShareMode = eShareMode;
pInfo->nLastItemAcquirerIdx = -1;
pInfo->ePartyType = ePartyType;
pInfo->pPartyLinkInfo = NULL;
// 해쉬에 등록
if( registerParty( pInfo ) == false )
{
delete pInfo;
return NULL;
}
return pInfo;
}
bool PartyManager::registerParty( PartyInfo* pInfo )
{
if( m_hshPartyID.add( pInfo->nPartyID, pInfo ) == NULL )
{
return false;
}
if( m_hshPartyName.add( pInfo->strPartyName.c_str(), pInfo ) == NULL )
{
int nHas = (m_hshPartyName.has( pInfo->strPartyName.c_str() ) ? 1 : 0);
FILELOG( "(register) KHash add failed PartyID: %d, PartyName: %s(has: %d)", pInfo->nPartyID, pInfo->strPartyName.c_str(), nHas );
_cprint( "(register) KHash add failed PartyID: %d, PartyName: %s(has: %d)\n", pInfo->nPartyID, pInfo->strPartyName.c_str(), nHas );
m_hshPartyID.erase( pInfo->nPartyID );
return false;
}
return true;
}
int PartyManager::allocPartyID()
{
return InterlockedIncrement( &m_nMaxPartyID );
}
PartyManager::PartyInfo * PartyManager::getPartyInfo( const char *szPartyName )
{
PartyInfo * p = NULL;
m_hshPartyName.lookup( szPartyName, p );
return p;
}
const char * PartyManager::getDisplayNameForPartyType( _PARTY_TYPE ePartyType, struct StructPlayer * pPlayer )
{
return ( isAliasUsableParty( ePartyType ) ) ? pPlayer->GetAlias() : pPlayer->GetName();
}
const PartyManager::PartyInfo * PartyManager::getPartyInfo( const char *szPartyName ) const
{
PartyInfo * p = NULL;
m_hshPartyName.lookup( szPartyName, p );
return p;
}
PartyManager::PartyInfo * PartyManager::getPartyInfo( int nPartyID )
{
PartyInfo * p = NULL;
m_hshPartyID.lookup( nPartyID, p );
return p;
}
const PartyManager::PartyInfo * PartyManager::getPartyInfo( int nPartyID ) const
{
PartyInfo * p = NULL;
m_hshPartyID.lookup( nPartyID, p );
return p;
}
const std::string PartyManager::getSummonInfo( int nPartyID ) const
{
const PartyInfo * pInfo = getPartyInfo( nPartyID );
if( !pInfo ) return "";
struct myPartyFunctor : PartyFunctor
{
myPartyFunctor() : count( 0 ) {}
virtual bool operator()( AR_HANDLE handle )
{
StructPlayer::iterator pit = StructPlayer::get( handle );
StructPlayer *pPlayer = *pit;
if( !pPlayer ) return true;
AR_HANDLE nMainSummonHandle = pPlayer->GetMainSummon() ? pPlayer->GetMainSummon()->GetHandle() : 0;
AR_HANDLE nSubSummonHandle = pPlayer->GetSubSummon() ? pPlayer->GetSubSummon()->GetHandle() : 0;
if( !nMainSummonHandle && !nSubSummonHandle ) return true;
char buf[50];
s_sprintf( buf, _countof( buf ), "%u|%u|%u|", handle, nMainSummonHandle, nSubSummonHandle );
count++;
strPartyInfo += buf;
return true;
}
int count;
std::string strPartyInfo;
} _fo;
doEachMember( pInfo, _fo );
std::string strResult;
XStringUtil::Format( strResult, "%d|%d|%s", nPartyID, _fo.count, _fo.strPartyInfo.c_str() );
return strResult;
}
size_t PartyManager::doEachMember( PartyInfo * pInfo, PartyFunctor & _fo )
{
size_t cnt = 0;
std::vector< AR_HANDLE >::iterator it;
for( it = pInfo->vOnlineList.begin(); it != pInfo->vOnlineList.end(); ++it )
{
_fo( *it );
++cnt;
}
return cnt;
}
size_t PartyManager::doEachMember( const PartyInfo * pInfo, PartyFunctor & _fo ) const
{
size_t cnt = 0;
std::vector< AR_HANDLE >::const_iterator it;
for( it = pInfo->vOnlineList.begin(); it != pInfo->vOnlineList.end(); ++it )
{
_fo( *it );
++cnt;
}
return cnt;
}
size_t PartyManager::doEachMemberTag( PartyInfo * pInfo, PartyMemberTagFunctor & _fo )
{
size_t cnt = 0;
for( std::vector< PartyMemberTag >::iterator it = pInfo->vMemberNameList.begin() ; it != pInfo->vMemberNameList.end() ; ++it )
{
_fo( &(*it) );
++cnt;
}
return cnt;
}
size_t PartyManager::doEachParty( PartyLinkInfo * pLinkInfo, LinkedPartyFunctor & _fo )
{
size_t cnt = 0;
for( std::vector< PartyInfo * >::iterator it = pLinkInfo->vPartyList.begin() ; it != pLinkInfo->vPartyList.end() ; ++it )
{
_fo( (*it)->nPartyID );
++cnt;
}
return cnt;
}
bool PartyManager::signAsOnLine( PartyInfo *pInfo, struct StructPlayer *pPtr )
{
if( !pInfo ) return false;
pInfo->vOnlineList.push_back( pPtr->GetHandle() );
if( pInfo->nLeaderSID == pPtr->GetPlayerUID() )
{
pInfo->strLeaderName = pPtr->GetName();
pInfo->strLeaderDisplayName = getDisplayNameForPartyType( pInfo->ePartyType, pPtr );
pInfo->nLeaderJobId = pPtr->GetJobId();
}
for( std::vector< PartyMemberTag >::iterator it = pInfo->vMemberNameList.begin(); it != pInfo->vMemberNameList.end(); ++it )
{
if( (*it).sid == pPtr->GetPlayerUID() )
{
(*it).bIsOnline = true;
(*it).nJobId = pPtr->GetJobId();
(*it).nLevel = pPtr->GetLevel();
break;
}
}
return true;
}
bool PartyManager::signAsOffLine( PartyInfo *pInfo, struct StructPlayer *pPtr )
{
if( !pInfo ) return false;
for( std::vector< AR_HANDLE >::iterator it = pInfo->vOnlineList.begin(); it != pInfo->vOnlineList.end(); ++it )
{
if( *it == pPtr->GetHandle() )
{
pInfo->vOnlineList.erase( it );
break;
}
}
if( pInfo->nLeaderSID == pPtr->GetPlayerUID() )
{
pInfo->nLeaderJobId = pPtr->GetJobId();
}
for( std::vector< PartyMemberTag >::iterator it = pInfo->vMemberNameList.begin(); it != pInfo->vMemberNameList.end(); ++it )
{
if( (*it).sid == pPtr->GetPlayerUID() )
{
(*it).bIsOnline = false;
(*it).nJobId = pPtr->GetJobId();
(*it).nLevel = pPtr->GetLevel();
break;
}
}
return false;
}