Miscellaneous RTA support

This commit is contained in:
HikikoMarmy
2025-06-15 00:19:35 +01:00
parent f54870cc1a
commit fec6eccae4
12 changed files with 305 additions and 169 deletions

View File

@@ -1,4 +1,4 @@
#include "../global_define.h" #include "ChatRoomSession.h"
ChatRoomSession::ChatRoomSession() ChatRoomSession::ChatRoomSession()
{ {

View File

@@ -1,7 +1,9 @@
#include "../global_define.h"
#include "ChatRoomManager.h" #include "ChatRoomManager.h"
#include "RealmUser.h"
#include "../logging.h"
ChatRoomManager::ChatRoomManager() ChatRoomManager::ChatRoomManager()
{ {
m_chatIndex = 0; m_chatIndex = 0;

View File

@@ -1,5 +1,10 @@
#pragma once #pragma once
#include <memory>
#include <mutex>
#include <vector>
#include <string>
#include "ChatRoomSession.h" #include "ChatRoomSession.h"
class ChatRoomManager { class ChatRoomManager {

View File

@@ -1,5 +1,9 @@
#pragma once #pragma once
#include <memory>
#include <string>
#include "RealmUser.h"
class ChatRoomSession { class ChatRoomSession {
public: public:
ChatRoomSession(); ChatRoomSession();

View File

@@ -1,11 +1,11 @@
#include "../global_define.h"
#include "GameSession.h"
GameSession::GameSession() GameSession::GameSession()
{ {
m_owner.reset(); m_owner.reset();
m_gameIndex = 0; m_gameIndex = 0;
m_clientType = RealmClientType::UNKNOWN;
m_type = GameType::Public; m_type = GameType::Public;
m_state = GameState::NotReady; m_state = GameState::NotReady;
m_currentPlayers = 0; m_currentPlayers = 0;
@@ -25,7 +25,6 @@ GameSession::~GameSession()
m_owner.reset(); m_owner.reset();
m_gameIndex = 0; m_gameIndex = 0;
m_clientType = RealmClientType::UNKNOWN;
m_type = GameType::Public; m_type = GameType::Public;
m_state = GameState::NotReady; m_state = GameState::NotReady;
m_currentPlayers = 0; m_currentPlayers = 0;

View File

@@ -1,5 +1,10 @@
#pragma once #pragma once
#include <string>
#include <memory>
#include "RealmUser.h"
class GameSession { class GameSession {
public: public:
GameSession(); GameSession();
@@ -14,12 +19,12 @@ public:
enum class GameState enum class GameState
{ {
NotReady, NotReady,
Open Open,
Started
}; };
GameType m_type; GameType m_type;
GameState m_state; GameState m_state;
RealmClientType m_clientType;
std::weak_ptr< RealmUser > m_owner; std::weak_ptr< RealmUser > m_owner;
@@ -32,8 +37,8 @@ public:
std::string m_gameData; std::string m_gameData;
std::string m_description; std::string m_description;
std::wstring m_hostLocalAddr; std::string m_hostLocalAddr;
std::wstring m_hostExternalAddr; std::string m_hostExternalAddr;
int32_t m_hostPort; int32_t m_hostPort;
int8_t m_currentPlayers; int8_t m_currentPlayers;

View File

@@ -1,16 +1,19 @@
#include "../global_define.h"
#include "GameSessionManager.h" #include "GameSessionManager.h"
#include "../Network/Event/NotifyClientDiscovered.h"
#include "../Network/Event/NotifyClientReqConnect.h"
#include "../Network/Event/NotifyGameDiscovered.h"
#include "RealmUser.h"
#include "../Network/Event/NotifyClientDiscovered.h"
#include "../Network/Event/NotifyClientDiscovered_RTA.h"
#include "../Network/Event/NotifyClientRequestConnect.h"
#include "../Network/Event/NotifyClientRequestConnect_RTA.h" #include "../Network/Event/NotifyClientRequestConnect_RTA.h"
#include "../Network/Event/NotifyGameDiscovered.h"
#include "../Network/Event/NotifyReserveUserSlot_RTA.h"
#include "../../logging.h"
GameSessionManager::GameSessionManager() GameSessionManager::GameSessionManager()
{ {
m_gameIndex = 0; m_gameIndex = 0;
m_gameSessionList.clear(); m_gameSessionList[ 0 ].clear();
m_gameSessionList[ 1 ].clear();
} }
GameSessionManager::~GameSessionManager() GameSessionManager::~GameSessionManager()
@@ -23,8 +26,9 @@ void GameSessionManager::OnDisconnectUser( sptr_user user )
return; return;
const auto gameId = user->m_gameId; const auto gameId = user->m_gameId;
const auto gameType = user->m_gameType;
auto session = FindGame( gameId ); auto session = FindGame( gameId, gameType );
if( !session ) if( !session )
return; return;
@@ -32,25 +36,25 @@ void GameSessionManager::OnDisconnectUser( sptr_user user )
if( !owner ) if( !owner )
{ {
Log::Error( "Game session owner not found! [%d]", gameId ); Log::Error( "Game session owner not found! [%d]", gameId );
ForceTerminateGame( gameId ); ForceTerminateGame( gameId, gameType );
return; return;
} }
if( owner->m_sessionId == user->m_sessionId ) if( owner->m_sessionId == user->m_sessionId )
{ {
Log::Info( "Game session owner disconnected! [%d]", gameId ); Log::Info( "Game session owner disconnected! [%d]", gameId );
ForceTerminateGame( gameId ); ForceTerminateGame( gameId, gameType );
} }
} }
bool GameSessionManager::CreatePublicGameSession( sptr_user owner, std::wstring gameName, RealmClientType clientType ) bool GameSessionManager::CreatePublicGameSession( sptr_user owner, std::wstring gameName, RealmGameType clientType )
{ {
auto new_session = std::make_shared< GameSession >(); auto new_session = std::make_shared< GameSession >();
new_session->m_type = GameSession::GameType::Public; new_session->m_type = GameSession::GameType::Public;
new_session->m_clientType = clientType;
new_session->m_gameIndex = m_gameIndex; new_session->m_gameIndex = m_gameIndex;
new_session->m_hostLocalAddr = L""; new_session->m_hostLocalAddr.clear();
new_session->m_hostExternalAddr.clear();
new_session->m_gameName = gameName; new_session->m_gameName = gameName;
new_session->m_currentPlayers = 1; new_session->m_currentPlayers = 1;
new_session->m_maximumPlayers = 4; new_session->m_maximumPlayers = 4;
@@ -64,17 +68,17 @@ bool GameSessionManager::CreatePublicGameSession( sptr_user owner, std::wstring
new_session->m_owner = owner; new_session->m_owner = owner;
std::lock_guard< std::mutex > lock( m_dataMutex ); std::lock_guard< std::mutex > lock( m_dataMutex );
m_gameSessionList.push_back( new_session ); m_gameSessionList[ clientType ].push_back( new_session );
m_gameIndex++; m_gameIndex++;
return true; return true;
} }
bool GameSessionManager::CreatePrivateGameSession( sptr_user owner, std::wstring gameName, RealmClientType clientType ) bool GameSessionManager::CreatePrivateGameSession( sptr_user owner, std::wstring gameName, RealmGameType clientType )
{ {
// Check if the game name or host session id is already in use // Check if the game name or host session id is already in use
for( auto &gameSession : m_gameSessionList ) for( const auto &gameSession : m_gameSessionList[ clientType ] )
{ {
if( gameSession->m_type != GameSession::GameType::Private ) if( gameSession->m_type != GameSession::GameType::Private )
continue; continue;
@@ -89,9 +93,9 @@ bool GameSessionManager::CreatePrivateGameSession( sptr_user owner, std::wstring
auto new_session = std::make_shared< GameSession >(); auto new_session = std::make_shared< GameSession >();
new_session->m_type = GameSession::GameType::Private; new_session->m_type = GameSession::GameType::Private;
new_session->m_clientType = clientType;
new_session->m_gameIndex = m_gameIndex; new_session->m_gameIndex = m_gameIndex;
new_session->m_hostLocalAddr = L""; new_session->m_hostLocalAddr.clear();
new_session->m_hostExternalAddr.clear();
new_session->m_gameName = gameName; new_session->m_gameName = gameName;
new_session->m_currentPlayers = 1; new_session->m_currentPlayers = 1;
new_session->m_maximumPlayers = 4; new_session->m_maximumPlayers = 4;
@@ -105,14 +109,14 @@ bool GameSessionManager::CreatePrivateGameSession( sptr_user owner, std::wstring
new_session->m_owner = owner; new_session->m_owner = owner;
std::lock_guard< std::mutex > lock( m_dataMutex ); std::lock_guard< std::mutex > lock( m_dataMutex );
m_gameSessionList.push_back( new_session ); m_gameSessionList[ clientType ].push_back( new_session );
m_gameIndex++; m_gameIndex++;
return true; return true;
} }
bool GameSessionManager::ForceTerminateGame( int32_t gameId ) bool GameSessionManager::ForceTerminateGame( int32_t gameId, RealmGameType clientType )
{ {
if( gameId < 0 ) if( gameId < 0 )
{ {
@@ -121,27 +125,28 @@ bool GameSessionManager::ForceTerminateGame( int32_t gameId )
std::lock_guard< std::mutex > lock( m_dataMutex ); std::lock_guard< std::mutex > lock( m_dataMutex );
auto it = std::find_if( m_gameSessionList.begin(), m_gameSessionList.end(), [ &gameId ]( sptr_game_session gameSession ) const auto &gameList = m_gameSessionList[ clientType ];
const auto it = std::find_if( gameList.begin(), gameList.end(), [ &gameId ]( sptr_game_session gameSession )
{ {
return gameSession->m_gameIndex == gameId; return gameSession->m_gameIndex == gameId;
} ); } );
if( it != m_gameSessionList.end() ) if( it != m_gameSessionList[ clientType ].end() )
{ {
m_gameSessionList.erase( it ); m_gameSessionList[ clientType ].erase( it );
return true; return true;
} }
return false; return false;
} }
sptr_game_session GameSessionManager::FindGame( const int32_t gameId ) sptr_game_session GameSessionManager::FindGame( const int32_t gameId, const RealmGameType gameType )
{ {
if( gameId < 0 ) return nullptr; if( gameId < 0 ) return nullptr;
std::lock_guard< std::mutex > lock( m_dataMutex ); std::lock_guard< std::mutex > lock( m_dataMutex );
for( auto &gameSession : m_gameSessionList ) for( auto &gameSession : m_gameSessionList[ gameType ] )
{ {
if( gameSession->m_gameIndex == gameId ) if( gameSession->m_gameIndex == gameId )
{ {
@@ -152,13 +157,13 @@ sptr_game_session GameSessionManager::FindGame( const int32_t gameId )
return nullptr; return nullptr;
} }
sptr_game_session GameSessionManager::FindGame( const std::wstring &gameName ) sptr_game_session GameSessionManager::FindGame( const std::wstring &gameName, const RealmGameType gameType )
{ {
if( gameName.empty() ) return nullptr; if( gameName.empty() ) return nullptr;
std::lock_guard< std::mutex > lock( m_dataMutex ); std::lock_guard< std::mutex > lock( m_dataMutex );
for( auto &gameSession : m_gameSessionList ) for( auto &gameSession : m_gameSessionList[ gameType ] )
{ {
if( gameSession->m_gameName == gameName ) if( gameSession->m_gameName == gameName )
{ {
@@ -172,7 +177,8 @@ sptr_game_session GameSessionManager::FindGame( const std::wstring &gameName )
bool GameSessionManager::RequestOpen( sptr_user user ) bool GameSessionManager::RequestOpen( sptr_user user )
{ {
auto gameId = user->m_gameId; auto gameId = user->m_gameId;
auto session = FindGame( gameId ); auto gameType = user->m_gameType;
auto session = FindGame( gameId, gameType );
if( session == nullptr ) if( session == nullptr )
{ {
@@ -191,15 +197,14 @@ bool GameSessionManager::RequestOpen( sptr_user user )
return false; return false;
} }
// Very cool that they couldn't agree on ASCII or UTF-16 session->m_hostExternalAddr = user->m_discoveryAddr;
session->m_hostLocalAddr = std::wstring( user->m_localAddr.begin(), user->m_localAddr.end() ); session->m_hostLocalAddr = user->m_localAddr;
session->m_hostExternalAddr = std::wstring( user->m_localAddr.begin(), user->m_localAddr.end() );
session->m_hostPort = user->m_discoveryPort; session->m_hostPort = user->m_discoveryPort;
session->m_state = GameSession::GameState::Open; session->m_state = GameSession::GameState::Open;
// Tell the host its own address. // Tell the host its own address.
NotifyGameDiscovered msg( user->m_discoveryAddr, user->m_discoveryPort, user->m_clientType ); NotifyGameDiscovered msg( user->m_discoveryAddr, user->m_discoveryPort, user->m_gameType );
user->sock->send( msg ); user->sock->send( msg );
Log::Info( "Game Session [%d] Discoverable on %s", gameId, user->m_discoveryAddr.c_str() ); Log::Info( "Game Session [%d] Discoverable on %s", gameId, user->m_discoveryAddr.c_str() );
@@ -207,22 +212,27 @@ bool GameSessionManager::RequestOpen( sptr_user user )
return true; return true;
} }
// NOTE:
// This might solely be for a user that is LEAVING the game (I.E "CancelJoining")
// instead of a game being cancelled overall. RTA has a dedicated endgame event.
bool GameSessionManager::RequestCancel( sptr_user user ) bool GameSessionManager::RequestCancel( sptr_user user )
{ {
if( !user || user->m_gameId < 0 ) if( !user || user->m_gameId < 0 )
return false; return false;
const int gameId = user->m_gameId;
std::lock_guard<std::mutex> lock( m_dataMutex ); std::lock_guard<std::mutex> lock( m_dataMutex );
auto it = std::find_if( m_gameSessionList.begin(), m_gameSessionList.end(), const auto gameId = user->m_gameId;
[ gameId ]( const sptr_game_session &gameSession ) const auto gameType = user->m_gameType;
auto &gameList = m_gameSessionList[ gameType ];
const auto it = std::find_if( gameList.begin(), gameList.end(),
[ gameId ]( const sptr_game_session &gameSession )
{ {
return gameSession->m_gameIndex == gameId; return gameSession->m_gameIndex == gameId;
} ); } );
if( it == m_gameSessionList.end() ) if( it == gameList.end() )
return false; return false;
const auto &session = *it; const auto &session = *it;
@@ -231,7 +241,7 @@ bool GameSessionManager::RequestCancel( sptr_user user )
if( !owner ) if( !owner )
{ {
Log::Error( "Game session owner not found! [%d]", gameId ); Log::Error( "Game session owner not found! [%d]", gameId );
ForceTerminateGame( gameId ); ForceTerminateGame( gameId, gameType );
return false; return false;
} }
@@ -241,14 +251,15 @@ bool GameSessionManager::RequestCancel( sptr_user user )
return false; return false;
} }
m_gameSessionList.erase( it ); gameList.erase( it );
return true; return true;
} }
bool GameSessionManager::RequestJoin( sptr_user join_user ) bool GameSessionManager::RequestJoin( sptr_user join_user )
{ {
const auto gameId = join_user->m_gameId; const auto gameId = join_user->m_gameId;
auto session = FindGame( gameId ); const auto gameType = join_user->m_gameType;
auto session = FindGame( gameId, gameType );
if( session == nullptr ) if( session == nullptr )
{ {
@@ -267,59 +278,79 @@ bool GameSessionManager::RequestJoin( sptr_user join_user )
if( host_user == nullptr ) if( host_user == nullptr )
{ {
Log::Error( "Host not found! [%d]", gameId ); Log::Error( "Host not found! [%d]", gameId );
ForceTerminateGame( gameId ); ForceTerminateGame( gameId, gameType );
return false; return false;
} }
if( host_user->m_discoveryAddr.empty() ) if( host_user->m_discoveryAddr.empty() )
{ {
Log::Error( "User discovery address is empty! [%d]", gameId ); Log::Error( "User discovery address is empty! [%d]", gameId );
ForceTerminateGame( gameId ); ForceTerminateGame( gameId, gameType );
return false; return false;
} }
join_user->m_isHost = false; join_user->m_isHost = false;
// Tell the joiner its own address. if( host_user->m_gameType == RealmGameType::CHAMPIONS_OF_NORRATH )
NotifyClientDiscovered msgClientDiscovered( host_user->m_discoveryAddr, host_user->m_discoveryPort, host_user->m_clientType );
join_user->sock->send( msgClientDiscovered );
// Notify the host that a client is trying to connect.
if( host_user->m_clientType == RealmClientType::CHAMPIONS_OF_NORRATH )
{ {
NotifyClientRequestConnect msgNotifyReqConnect( ProcessJoinNorrath( join_user, host_user );
join_user->m_discoveryAddr,
join_user->m_discoveryPort
);
host_user->sock->send( msgNotifyReqConnect );
} }
else else
{ {
NotifyClientRequestConnect_RTA msgNotifyReqConnect( ProcessJoinArms( join_user, host_user );
join_user->m_discoveryAddr,
join_user->m_localAddr,
join_user->m_discoveryPort
);
host_user->sock->send( msgNotifyReqConnect );
} }
Log::Info( "User [%S] Joining game session... [%d]", join_user->m_sessionId.c_str(), gameId ); Log::Info( "User [%S] Joining game session... [%d]", join_user->m_sessionId.c_str(), gameId );
return true; return true;
} }
std::vector<sptr_game_session> GameSessionManager::GetAvailableGameSessionList( RealmClientType clientType ) const // NOTE:
// Request Start seems to be for RTA only.
// CON will disconnect from the server at start time.
bool GameSessionManager::RequestStart(sptr_user user)
{
const auto gameId = user->m_gameId;
const auto gameType = user->m_gameType;
auto session = FindGame( gameId, gameType );
if( session == nullptr )
{
Log::Error( "Game session not found! [%d]", gameId );
return false;
}
std::lock_guard<std::mutex> lock( m_dataMutex );
session->m_state = GameSession::GameState::Started;
// Temp (or permanent) remove the game from the list.
auto &gameList = m_gameSessionList[ gameType ];
const auto it = std::find_if( gameList.begin(), gameList.end(),
[ gameId ]( const sptr_game_session &gameSession )
{
return gameSession->m_gameIndex == gameId;
} );
if( it != gameList.end() )
{
gameList.erase( it );
}
Log::Info( "Game session [%d] started", gameId );
return true;
}
std::vector<sptr_game_session> GameSessionManager::GetAvailableGameSessionList( const RealmGameType gameType ) const
{ {
std::lock_guard<std::mutex> lock( m_dataMutex ); std::lock_guard<std::mutex> lock( m_dataMutex );
std::vector<sptr_game_session> list; std::vector<sptr_game_session> list;
for( const auto &game : m_gameSessionList ) for( const auto &game : m_gameSessionList[ gameType ] )
{ {
if( game->m_clientType != clientType )
continue;
if( game->m_type == GameSession::GameType::Public && if( game->m_type == GameSession::GameType::Public &&
game->m_state == GameSession::GameState::Open ) game->m_state == GameSession::GameState::Open )
{ {
@@ -329,34 +360,82 @@ std::vector<sptr_game_session> GameSessionManager::GetAvailableGameSessionList(
return list; return list;
} }
std::vector<sptr_game_session> GameSessionManager::GetPublicGameSessionList( RealmClientType clientType ) const std::vector<sptr_game_session> GameSessionManager::GetPublicGameSessionList( const RealmGameType gameType ) const
{ {
std::lock_guard<std::mutex> lock( m_dataMutex ); std::lock_guard<std::mutex> lock( m_dataMutex );
std::vector<sptr_game_session> list; std::vector<sptr_game_session> list;
for( const auto &game : m_gameSessionList ) for( const auto &game : m_gameSessionList[ gameType ] )
{ {
if( game->m_clientType != clientType )
continue;
if( game->m_type == GameSession::GameType::Public ) if( game->m_type == GameSession::GameType::Public )
list.push_back( game ); list.push_back( game );
} }
return list; return list;
} }
std::vector<sptr_game_session> GameSessionManager::GetPrivateGameSessionList( RealmClientType clientType ) const std::vector<sptr_game_session> GameSessionManager::GetPrivateGameSessionList( const RealmGameType gameType ) const
{ {
std::lock_guard<std::mutex> lock( m_dataMutex ); std::lock_guard<std::mutex> lock( m_dataMutex );
std::vector<sptr_game_session> list; std::vector<sptr_game_session> list;
for( const auto &game : m_gameSessionList ) for( const auto &game : m_gameSessionList[ gameType ] )
{ {
if( game->m_clientType != clientType )
continue;
if( game->m_type == GameSession::GameType::Private ) if( game->m_type == GameSession::GameType::Private )
list.push_back( game ); list.push_back( game );
} }
return list; return list;
} }
void GameSessionManager::ProcessJoinNorrath(sptr_user join, sptr_user host)
{
std::string hostAddr = host->m_discoveryAddr;
std::string joinAddr = join->m_discoveryAddr;
if (hostAddr == joinAddr)
{
hostAddr = host->m_localAddr;
// I don't think the joiner ever reports its local address for CON.
// At best, we can report the hosts local IP and hope communication works.
}
// Tell the joining user the hosts address.
NotifyClientDiscovered msgClientDiscovered( hostAddr, host->m_discoveryPort );
join->sock->send(msgClientDiscovered);
// Tell the host the joining user's address.
NotifyClientRequestConnect msgNotifyReqConnect(
joinAddr,
join->m_discoveryPort
);
host->sock->send(msgNotifyReqConnect);
}
void GameSessionManager::ProcessJoinArms(sptr_user join, sptr_user host)
{
std::string hostAddr = host->m_discoveryAddr;
std::string joinAddr = join->m_discoveryAddr;
if (hostAddr == joinAddr)
{
hostAddr = host->m_localAddr;
joinAddr = join->m_localAddr;
}
// Tell the joining user the hosts address.
NotifyClientDiscovered_RTA msgClientDiscovered(hostAddr, host->m_discoveryPort);
join->sock->send(msgClientDiscovered);
// Reserve a slot for the joining user.
NotifyReserveUserSlot_RTA msgNotifyReserveUser(joinAddr, join->m_discoveryPort);
host->sock->send(msgNotifyReserveUser);
// Tell the host the joining user's address.
NotifyClientRequestConnect_RTA msgNotifyReqConnect(
joinAddr,
join->m_discoveryAddr,
join->m_discoveryPort
);
host->sock->send(msgNotifyReqConnect);
}

View File

@@ -1,5 +1,9 @@
#pragma once #pragma once
#include <memory>
#include <mutex>
#include <vector>
#include "GameSession.h" #include "GameSession.h"
class GameSessionManager { class GameSessionManager {
@@ -9,7 +13,7 @@ private:
static inline std::mutex m_dataMutex; static inline std::mutex m_dataMutex;
int32_t m_gameIndex; int32_t m_gameIndex;
std::vector< sptr_game_session > m_gameSessionList; std::vector< sptr_game_session > m_gameSessionList[ 2 ];
public: public:
GameSessionManager(); GameSessionManager();
@@ -30,17 +34,22 @@ public:
void OnDisconnectUser( sptr_user user ); void OnDisconnectUser( sptr_user user );
bool CreatePublicGameSession( sptr_user user, std::wstring gameName, RealmClientType clientType ); bool CreatePublicGameSession( sptr_user user, const std::wstring gameName, const RealmGameType clientType );
bool CreatePrivateGameSession( sptr_user user, std::wstring gameName, RealmClientType clientType ); bool CreatePrivateGameSession( sptr_user user, const std::wstring gameName, const RealmGameType clientType );
bool ForceTerminateGame( const int32_t gameId ); bool ForceTerminateGame( const int32_t gameId, RealmGameType clientType );
sptr_game_session FindGame( const int32_t gameId ); sptr_game_session FindGame( const int32_t gameId, RealmGameType clientType );
sptr_game_session FindGame( const std::wstring &gameName ); sptr_game_session FindGame( const std::wstring &gameName, RealmGameType clientType );
bool RequestOpen( sptr_user user ); bool RequestOpen( sptr_user user );
bool RequestCancel( sptr_user user ); bool RequestCancel( sptr_user user );
bool RequestJoin( sptr_user user ); bool RequestJoin( sptr_user user );
bool RequestStart( sptr_user user );
std::vector< sptr_game_session > GetAvailableGameSessionList( RealmClientType clientType ) const; std::vector< sptr_game_session > GetAvailableGameSessionList( const RealmGameType clientType ) const;
std::vector< sptr_game_session > GetPublicGameSessionList( RealmClientType clientType ) const; std::vector< sptr_game_session > GetPublicGameSessionList( const RealmGameType clientType ) const;
std::vector< sptr_game_session > GetPrivateGameSessionList( RealmClientType clientType ) const; std::vector< sptr_game_session > GetPrivateGameSessionList( const RealmGameType clientType ) const;
private:
void ProcessJoinNorrath( sptr_user join, sptr_user host );
void ProcessJoinArms( sptr_user join, sptr_user host );
}; };

View File

@@ -1,11 +1,13 @@
#include "../global_define.h" #include "RealmUser.h"
RealmUser::RealmUser() RealmUser::RealmUser()
{ {
sock = nullptr; sock = nullptr;
m_clientType = RealmClientType::UNKNOWN; m_gameType = RealmGameType::CHAMPIONS_OF_NORRATH;
m_accountId = -1;
m_characterId = -1;
m_sessionId = L""; m_sessionId = L"";
m_localAddr = ""; m_localAddr = "";
@@ -20,12 +22,14 @@ RealmUser::~RealmUser()
{ {
if( sock ) if( sock )
{ {
sock->flag.disconnected = true; sock->flag.disconnected_wait = true;
sock.reset(); sock.reset();
} }
m_clientType = RealmClientType::UNKNOWN; m_gameType = RealmGameType::CHAMPIONS_OF_NORRATH;
m_accountId = 0;
m_characterId = 0;
m_sessionId = L""; m_sessionId = L"";
m_localAddr = ""; m_localAddr = "";

View File

@@ -1,23 +1,34 @@
#pragma once #pragma once
#include <string>
#include <memory>
#include <array>
#include "RealmCharacter.h"
#include "../Common/Constant.h"
#include "../Network/RealmSocket.h"
class RealmUser { class RealmUser {
public: public:
RealmUser(); RealmUser();
~RealmUser(); ~RealmUser();
public: public:
sptr_socket sock; // For Realm Lobby sptr_socket sock; // For Realm Lobby
RealmClientType m_clientType; RealmGameType m_gameType; // Champions of Norrath or Return to Arms
std::wstring m_sessionId; // Temporary Session ID
int64_t m_accountId; // Unique ID of the account
std::wstring m_sessionId; // Unique Session ID for the user (Generated at login) int32_t m_characterId; // ID of selected Net Character
sptr_realm_character m_character; // Currently selected character
bool m_isHost; // True if this user is the host of a realm bool m_isHost; // True if this user is the host of a realm
int32_t m_gameId; // Unique ID of the realm int32_t m_gameId; // Unique ID of the realm
std::string m_localAddr; // Local IP address of the user, passed from the client during realm creation. std::string m_localAddr; // Local IP address of the user, passed from the client during Realm creation.
std::string m_discoveryAddr; std::string m_discoveryAddr;
int32_t m_discoveryPort; int32_t m_discoveryPort;
}; };
typedef std::shared_ptr< RealmUser > sptr_user; using sptr_user = std::shared_ptr< RealmUser >;

View File

@@ -1,7 +1,16 @@
#include "../global_define.h" #include "RealmUserManager.h"
#include "GameSessionManager.h"
#include "../Network/Event/NotifyForcedLogout.h"
#include "../Common/Constant.h"
#include "../Database/Database.h"
#include "../logging.h"
RealmUserManager::RealmUserManager() RealmUserManager::RealmUserManager()
{ {
std::random_device rd;
rng.seed( rd() );
m_users.clear(); m_users.clear();
} }
@@ -11,27 +20,30 @@ RealmUserManager::~RealmUserManager()
std::wstring RealmUserManager::GenerateSessionId() std::wstring RealmUserManager::GenerateSessionId()
{ {
// TODO : Maybe use something better than rand() static const wchar_t charset[] = L"0123456789ABCDEF";
// but it is just a temporary ID std::uniform_int_distribution<int> dist( 0, 15 );
std::wstring sessionId; std::wstring sessionId;
for( int i = 0; i < MAX_SESSION_ID_LENGTH; i++ ) sessionId.reserve( MAX_SESSION_ID_LENGTH );
for( int i = 0; i < MAX_SESSION_ID_LENGTH; ++i )
{ {
sessionId += L"0123456789ABCDEF"[ rand() % 16 ]; sessionId += charset[ dist( rng ) ];
} }
return sessionId; return sessionId;
} }
sptr_user RealmUserManager::CreateUser( sptr_socket socket, RealmClientType clientType ) sptr_user RealmUserManager::CreateUser( sptr_socket socket, RealmGameType clientType )
{ {
Log::Debug( "ClientManager::CreateUser() - Created new user" ); Log::Debug( "ClientManager::CreateUser() - Created new user" );
auto user = std::make_shared< RealmUser >(); auto user = std::make_shared< RealmUser >();
user->m_sessionId = GenerateSessionId();
user->sock = socket; user->sock = socket;
user->m_clientType = clientType; user->m_gameType = clientType;
std::lock_guard< std::mutex > lock( m_mutex );
m_users.push_back( user ); m_users.push_back( user );
return user; return user;
@@ -45,72 +57,77 @@ void RealmUserManager::RemoveUser( sptr_user user )
Log::Error( "RemoveUser : [%S] not found", user->m_sessionId.c_str() ); Log::Error( "RemoveUser : [%S] not found", user->m_sessionId.c_str() );
return; return;
} }
Database::Get().DeleteSession( user->m_sessionId );
GameSessionManager::Get().OnDisconnectUser( user ); GameSessionManager::Get().OnDisconnectUser( user );
Log::Debug( "RemoveUser : [%S]", user->m_sessionId.c_str() ); Log::Debug( "RemoveUser : [%S]", user->m_sessionId.c_str() );
std::lock_guard< std::mutex > lock( m_mutex );
m_users.erase( it ); m_users.erase( it );
} }
void RealmUserManager::RemoveUser( const std::wstring &sessionId ) void RealmUserManager::RemoveUser( const std::wstring &sessionId )
{ {
auto it = std::find_if( m_users.begin(), m_users.end(), [ &sessionId ]( sptr_user user ) auto user = FindUserBySessionId( sessionId );
{ if( !user )
return user->m_sessionId == sessionId;
} );
if( it == m_users.end() )
{ {
Log::Error( "RemoveUser : [%S] not found", sessionId.c_str() ); Log::Error( "RemoveUser : [%S] not found", sessionId.c_str() );
return; return;
} }
RemoveUser((*it)); RemoveUser( user );
} }
void RealmUserManager::RemoveUser( const sptr_socket socket ) void RealmUserManager::RemoveUser( const sptr_socket socket )
{ {
auto it = std::find_if( m_users.begin(), m_users.end(), [ &socket ]( sptr_user user ) auto user = FindUserBySocket( socket );
{ if( !user )
return user->sock == socket;
} );
if( it == m_users.end() )
{ {
Log::Error( "RemoveUser : [%S] not found", socket->remote_ip.c_str() ); Log::Error( "RemoveUser : [%S] not found", socket->remote_ip.c_str() );
return; return;
} }
RemoveUser((*it)); RemoveUser( user );
} }
sptr_user RealmUserManager::GetUser( const std::wstring &sessionId ) void RealmUserManager::DisconnectUser( sptr_user user, const std::string reason )
{ {
for( auto &user : m_users ) if( nullptr == user )
{ {
if( user->m_sessionId == sessionId ) return;
{
return user;
}
} }
return nullptr; if( user->sock != nullptr )
{
NotifyForcedLogout notifyLogout;
user->sock->send( notifyLogout );
user->sock->flag.disconnected_wait = true;
}
Log::Debug( "DisconnectUser : [%S]. Reason: %s", user->m_sessionId.c_str(), reason.c_str() );
RemoveUser( user );
} }
sptr_user RealmUserManager::GetUser( const sptr_socket socket ) sptr_user RealmUserManager::FindUserBySessionId( const std::wstring &sessionId )
{ {
auto it = std::find_if(m_users.begin(), m_users.end(), [&socket](sptr_user user) std::lock_guard<std::mutex> lock( m_mutex );
auto it = std::find_if( m_users.begin(), m_users.end(), [ & ]( const sptr_user &user )
{
return user->m_sessionId == sessionId;
} );
return ( it != m_users.end() ) ? *it : nullptr;
}
sptr_user RealmUserManager::FindUserBySocket( const sptr_socket &socket )
{
std::lock_guard<std::mutex> lock( m_mutex );
auto it = std::find_if( m_users.begin(), m_users.end(), [ & ]( const sptr_user &user )
{ {
return user->sock == socket; return user->sock == socket;
}); } );
return ( it != m_users.end() ) ? *it : nullptr;
if (it == m_users.end())
{
Log::Error("GetUser : [%S] not found", socket->remote_ip.c_str());
return nullptr;
}
return (*it);
} }
int32_t RealmUserManager::GetUserCount() const int32_t RealmUserManager::GetUserCount() const

View File

@@ -1,24 +1,21 @@
#pragma once #pragma once
#include <memory>
#include <mutex>
#include <vector>
#include <string>
#include <random>
#include "RealmUser.h" #include "RealmUser.h"
class RealmUserManager { class RealmUserManager {
private: private:
static const int MAX_SESSION_ID_LENGTH = 16;
static inline std::unique_ptr< RealmUserManager > m_instance;
static inline std::mutex m_mutex;
std::vector< sptr_user > m_users;
public: public:
static RealmUserManager& Get() static RealmUserManager &Get()
{ {
std::lock_guard< std::mutex > lock( m_mutex ); static RealmUserManager instance;
if( m_instance == nullptr ) return instance;
{
m_instance.reset( new RealmUserManager() );
}
return *m_instance;
} }
RealmUserManager( const RealmUserManager & ) = delete; RealmUserManager( const RealmUserManager & ) = delete;
@@ -26,15 +23,19 @@ public:
RealmUserManager(); RealmUserManager();
~RealmUserManager(); ~RealmUserManager();
public: std::wstring GenerateSessionId();
static std::wstring GenerateSessionId(); sptr_user CreateUser( sptr_socket socket, RealmGameType clientType );
sptr_user CreateUser( sptr_socket socket, RealmClientType clientType );
void RemoveUser( sptr_user user ); void RemoveUser( sptr_user user );
void RemoveUser( const std::wstring &sessionId ); void RemoveUser( const std::wstring &sessionId );
void RemoveUser( const sptr_socket socket ); void RemoveUser( const sptr_socket socket );
void DisconnectUser( sptr_user user, const std::string reason );
sptr_user GetUser( const std::wstring &sessionId ); sptr_user FindUserBySessionId( const std::wstring &sessionId );
sptr_user GetUser( const sptr_socket socket ); sptr_user FindUserBySocket( const sptr_socket &socket );
int32_t GetUserCount() const; int32_t GetUserCount() const;
private:
std::mutex m_mutex;
std::vector< sptr_user > m_users;
std::mt19937 rng;
}; };