Reorganized and cleaned up the solution.

This commit is contained in:
HikikoMarmy
2026-03-02 12:37:07 +00:00
parent 8012f30170
commit d4dfbddf69
175 changed files with 1516 additions and 1136 deletions

View File

@@ -0,0 +1,17 @@
#include "Network\Event\NotifyClientDiscovered.hpp"
#include "Game/RealmUser.hpp"
NotifyClientDiscovered::NotifyClientDiscovered( sptr_user user ) : GenericMessage( 0x40 )
{
this->m_clientIp = user->m_discoveryAddr;
this->m_clientPort = user->m_discoveryPort;
}
void NotifyClientDiscovered::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( 0 );
out.write_sz_utf8( m_clientIp );
out.write_u32( m_clientPort );
}

View File

@@ -0,0 +1,19 @@
#include "Network\Event\NotifyClientDiscovered_RTA.hpp"
#include "Common/Constant.hpp"
#include "Game/RealmUser.hpp"
NotifyClientDiscovered_RTA::NotifyClientDiscovered_RTA( sptr_user user ) : GenericMessage( 0x40 )
{
this->m_clientIp = user->m_discoveryAddr;
this->m_clientPort = user->m_discoveryPort;
}
void NotifyClientDiscovered_RTA::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( 0 );
out.write_utf8( m_clientIp );
out.write_u32( m_clientPort );
}

View File

@@ -0,0 +1,18 @@
#include "NotifyClientReqConnect.h"
NotifyClientRequestConnect::NotifyClientRequestConnect( std::string clientIp, int32_t clientPort ) : GenericMessage( 0x3F )
{
this->m_clientIp = std::move( clientIp );
this->m_clientPort = clientPort;
}
ByteBuffer &NotifyClientRequestConnect::Serialize()
{
m_stream.write_u16( m_packetId );
m_stream.write_u32( 0 );
m_stream.write_sz_utf8( m_clientIp );
m_stream.write_u32( m_clientPort );
return m_stream;
}

View File

@@ -0,0 +1,17 @@
#include "Network/Event/NotifyClientRequestConnect.hpp"
#include "Game/RealmUser.hpp"
NotifyClientRequestConnect::NotifyClientRequestConnect( sptr_user user ) : GenericMessage( 0x3F )
{
this->m_clientIp = user->m_discoveryAddr;
this->m_clientPort = user->m_discoveryPort;
}
void NotifyClientRequestConnect::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( 0 );
out.write_sz_utf8( m_clientIp );
out.write_u32( m_clientPort );
}

View File

@@ -0,0 +1,25 @@
#include "Network\Event\NotifyClientRequestConnect_RTA.hpp"
#include "Game/RealmUser.hpp"
NotifyClientRequestConnect_RTA::NotifyClientRequestConnect_RTA( sptr_user user ) : GenericMessage( 0x65 )
{
this->m_remoteAddr = user->m_discoveryAddr;
this->m_remotePort = user->m_discoveryPort;
this->m_localAddr = user->m_localAddr;
this->m_localPort = user->m_localPort;
}
void NotifyClientRequestConnect_RTA::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( 0 );
out.write_utf8( this->m_localAddr );
out.write_u32( this->m_localPort );
out.write_utf8( this->m_remoteAddr );
out.write_u32( this->m_remotePort );
}

View File

@@ -0,0 +1,12 @@
#include "Network/Event/NotifyForcedLogout.hpp"
NotifyForcedLogout::NotifyForcedLogout() : GenericMessage( 0x41 )
{
}
void NotifyForcedLogout::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( 0 );
out.write_u32( 0 );
}

View File

@@ -0,0 +1,16 @@
#include "Network\Event\NotifyFriendStatus.hpp"
NotifyFriendStatus::NotifyFriendStatus( std::wstring handle, bool status ) : GenericMessage( 0x2F )
{
m_handle = handle;
m_status = status;
}
void NotifyFriendStatus::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( 0 );
out.write_utf16( m_handle );
out.write_u8( m_status ? 1 : 0 );
}

View File

@@ -0,0 +1,22 @@
#include "Network/Event/NotifyGameDiscovered.hpp"
#include "Game/RealmUser.hpp"
NotifyGameDiscovered::NotifyGameDiscovered( sptr_user user ) : GenericMessage( 0x3E )
{
this->m_clientIp = user->m_discoveryAddr;
this->m_clientPort = user->m_discoveryPort;
this->m_clientType = user->m_gameType;
}
void NotifyGameDiscovered::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( 0 );
if( m_clientType == RealmGameType::RETURN_TO_ARMS )
out.write_utf8( m_clientIp );
else
out.write_sz_utf8( m_clientIp );
out.write_u32( m_clientPort );
}

View File

@@ -0,0 +1,16 @@
#include "Network\Event\NotifyInstantMessage.hpp"
NotifyInstantMessage::NotifyInstantMessage( std::wstring chatHandle, std::wstring message ) : GenericMessage( 0x30 )
{
m_chatHandle = chatHandle;
m_message = message;
}
void NotifyInstantMessage::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( 0 );
out.write_utf16( m_chatHandle );
out.write_utf16( m_message );
}

View File

@@ -0,0 +1,19 @@
#include "NotifyReserveUserSlot_RTA.h"
NotifyReserveUserSlot_RTA::NotifyReserveUserSlot_RTA( int32_t memberId, std::string discoveryAddr, int32_t discoveryPort ) : GenericMessage( 0x51 )
{
this->m_discoveryAddr = discoveryAddr;
this->m_port = discoveryPort;
this->m_memberId = memberId;
}
// This notification is nullsub.
void NotifyReserveUserSlot_RTA::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( 0 );
out.write_u32( 0 );
out.write_utf8( "" );
out.write_u32( 0 );
}

View File

@@ -0,0 +1,18 @@
#include "Network\Event\NotifyRoomMessage.hpp"
NotifyRoomMessage::NotifyRoomMessage( std::wstring roomName, std::wstring chatHandle, std::wstring message ) : GenericMessage( 0x3D )
{
m_roomName = roomName;
m_chatHandle = chatHandle;
m_message = message;
}
void NotifyRoomMessage::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( 0 );
out.write_utf16( m_roomName );
out.write_utf16( m_chatHandle );
out.write_utf16( m_message );
}

View File

@@ -0,0 +1,49 @@
#include "Notify_4C.h"
Notify_4C::Notify_4C() : GenericMessage( 0x4C )
{
}
void Notify_4C::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( 0 );
out.write_u32( 0 ); // Unknown
out.write_u32( 1 ); // Unknown
{
out.write_utf16( L"Dummy 1" );
}
out.write_u32( 1 ); // Unknown
{
out.write_u32( 0 );
// Blob
}
out.write_u32( 1 ); // Unknown
{
out.write_u32( 0 );
}
out.write_u16( 0 ); // Unknown
out.write_u32( 1 ); // Unknown
{
out.write_u16( 0 );
out.write_u32( 0 );
out.write_utf16( L"Dummy 2" );
out.write_u32( 0 );
out.write_u32( 0 );
out.write_u32( 0 );
out.write_u16( 1 );
}
out.write_u32( 0 ); // Unknown
out.write_utf8( "127.0.0.1" );
out.write_u32( 0 ); // Unknown
out.write_u32( 0 ); // Unknown
}

View File

@@ -0,0 +1,22 @@
#include "Notify_65.h"
NotifyClientRequestsConnect2::NotifyClientRequestsConnect2( std::string discoveryAddr, std::string localAddr, int32_t port ) : GenericMessage( 0x65 )
{
m_discoveryAddr = std::move( discoveryAddr );
m_localAddr = std::move( localAddr );
m_port = port;
}
ByteBuffer &NotifyClientRequestsConnect2::Serialize()
{
m_stream.write_u16( m_packetId );
m_stream.write_u32( 0 );
m_stream.write_utf8( m_discoveryAddr );
m_stream.write_u32( m_port );
m_stream.write_utf8( m_localAddr );
m_stream.write_u32( m_port );
return m_stream;
}

View File

@@ -0,0 +1,61 @@
#include "Network/Event/RequestAddFriend.hpp"
#include "Game/RealmUserManager.hpp"
#include "Database/Database.hpp"
#include "logging.hpp"
void RequestAddFriend::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
m_chatHandle = stream->read_utf16();
}
sptr_generic_response RequestAddFriend::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
return std::make_shared< ResultAddFriend >( this, FATAL_ERROR );
}
if( user->IsFriend( m_chatHandle ) )
{
return std::make_shared< ResultAddFriend >( this, FRIEND_DUPLICATE );
}
auto targetUser = UserManager::Get().FindUserByChatHandle( m_chatHandle );
if( targetUser == nullptr )
{
return std::make_shared< ResultAddFriend >( this, FRIEND_INVALID );
}
if( targetUser->IsIgnored( user->m_chatHandle ) )
{
return std::make_shared< ResultAddFriend >( this, FRIEND_IGNORING );
}
if( !Database::Get().SaveFriend( user->m_accountId, targetUser->m_chatHandle ) )
{
return std::make_shared< ResultAddFriend >( this, DATABASE_ERROR );
}
user->m_friendList.push_back( targetUser->m_chatHandle );
return std::make_shared< ResultAddFriend >( this, SUCCESS );
}
ResultAddFriend::ResultAddFriend( GenericRequest *request, int32_t reply ) : GenericResponse( *request )
{
m_reply = reply;
}
void ResultAddFriend::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
}

View File

@@ -0,0 +1,61 @@
#include "Network/Event/RequestAddIgnore.hpp"
#include "Game/RealmUserManager.hpp"
#include "Database/Database.hpp"
#include "logging.hpp"
void RequestAddIgnore::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
m_chatHandle = stream->read_utf16();
}
sptr_generic_response RequestAddIgnore::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
return std::make_shared< ResultAddIgnore >( this, FATAL_ERROR );
}
if( user->IsFriend( m_chatHandle ) )
{
return std::make_shared< ResultAddIgnore >( this, IGNORE_FRIEND );
}
if( user->IsIgnored( m_chatHandle ) )
{
return std::make_shared< ResultAddIgnore >( this, IGNORE_DUPLICATE );
}
auto targetUser = UserManager::Get().FindUserByChatHandle( m_chatHandle );
if( targetUser == nullptr )
{
return std::make_shared< ResultAddIgnore >( this, IGNORE_INVALID );
}
if( !Database::Get().SaveIgnore( user->m_accountId, targetUser->m_chatHandle ) )
{
return std::make_shared< ResultAddIgnore >( this, DATABASE_ERROR );
}
user->m_ignoreList.push_back( targetUser->m_chatHandle );
return std::make_shared< ResultAddIgnore >( this, SUCCESS );
}
ResultAddIgnore::ResultAddIgnore( GenericRequest *request, int32_t reply ) : GenericResponse( *request )
{
m_reply = reply;
}
void ResultAddIgnore::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
}

View File

@@ -0,0 +1,45 @@
#include "Network/Event/RequestAppendCharacterData.hpp"
#include "Game/CharacterSaveManager.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/RealmUser.hpp"
#include "Database/Database.hpp"
#include "logging.hpp"
void RequestAppendCharacterData::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
auto sessionId = stream->read_encrypted_utf16();
auto length = stream->read_u32();
m_data = stream->read_bytes( length );
m_endOfData = stream->read_u32();
}
sptr_generic_response RequestAppendCharacterData::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
return std::make_shared< ResultAppendCharacterData >( this, FATAL_ERROR );
}
CharacterSaveManager::Get().AppendSaveData( user->m_sessionId, m_data, m_endOfData );
return std::make_shared< ResultAppendCharacterData >( this, SUCCESS );
}
ResultAppendCharacterData::ResultAppendCharacterData( GenericRequest *request, int32_t reply ) : GenericResponse( *request )
{
m_reply = reply;
}
void ResultAppendCharacterData::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
}

View File

@@ -0,0 +1,47 @@
#include "Network/Event/RequestCancelGame.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/GameSessionManager.hpp"
#include "logging.hpp"
void RequestCancelGame::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
}
sptr_generic_response RequestCancelGame::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
Log::Error( "User not found! [{}]", m_sessionId );
return std::make_shared< ResultCancelGame >( this );
}
if( user->m_gameType != RealmGameType::CHAMPIONS_OF_NORRATH )
{
return std::make_shared< ResultCancelGame >( this );
}
if( !GameSessionManager::Get().RequestCancel( user ) )
{
Log::Error( "Failed to cancel game session for user [{}]", user->m_sessionId );
}
return std::make_shared< ResultCancelGame >( this );
}
ResultCancelGame::ResultCancelGame( GenericRequest *request ) : GenericResponse( *request )
{
}
void ResultCancelGame::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( 0 );
}

View File

@@ -0,0 +1,61 @@
#include "Network/Event/RequestCancelGame_RTA.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/GameSessionManager.hpp"
#include "Game/ChatRoomManager.hpp"
#include "logging.hpp"
void RequestCancelGame_RTA::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
}
sptr_generic_response RequestCancelGame_RTA::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
Log::Error( "User not found! [{}]", m_sessionId );
return std::make_shared< ResultCancelGame_RTA >( this );
}
if( user->m_gameType != RealmGameType::RETURN_TO_ARMS )
{
return std::make_shared< ResultCancelGame_RTA >( this );
}
const auto &gameSession = GameSessionManager::Get().FindGame( user->m_gameId, user->m_gameType );
if( gameSession == nullptr )
{
Log::Error( "Game session not found for user [{}]", user->m_sessionId );
return std::make_shared< ResultCancelGame_RTA >( this );
}
if( !GameSessionManager::Get().RequestCancel( user ) )
{
Log::Error( "Failed to cancel game session for user [{}]", user->m_sessionId );
}
if( !ChatRoomManager::Get().LeaveRoom( user, user->m_privateRoomId ) )
{
Log::Error( "Failed to leave private chat room for user [{}]", user->m_username );
}
return std::make_shared< ResultCancelGame_RTA >( this );
}
ResultCancelGame_RTA::ResultCancelGame_RTA( GenericRequest *request ) : GenericResponse( *request )
{
}
void ResultCancelGame_RTA::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( 0 );
}

View File

@@ -0,0 +1,97 @@
#include "Network/Event/RequestCreateAccount.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/RealmUser.hpp"
#include "Common/Constant.hpp"
#include "Crypto/PasswordHash.hpp"
#include "Database/Database.hpp"
#include "logging.hpp"
void RequestCreateAccount::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_username = stream->read_encrypted_utf16();
m_password = stream->read_encrypted_utf16();
m_emailAddress = stream->read_encrypted_utf16();
m_dateOfBirth = stream->read_encrypted_utf16();
m_chatHandle = stream->read_encrypted_utf16();
}
bool RequestCreateAccount::VerifyUserData()
{
if( m_username.empty() || m_password.empty() || m_emailAddress.empty() || m_dateOfBirth.empty() || m_chatHandle.empty() )
{
Log::Error( "RequestCreateAccount::VerifyUserData() - Missing required fields for account creation." );
return false;
}
if( m_username.length() < 3 || m_username.length() > 20 )
{
Log::Error( "RequestCreateAccount::VerifyUserData() - Username must be between 3 and 20 characters." );
return false;
}
if( m_password.length() < 6 || m_password.length() > 32 )
{
Log::Error( "RequestCreateAccount::VerifyUserData() - Password must be between 6 and 32 characters." );
return false;
}
return true;
}
sptr_generic_response RequestCreateAccount::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( nullptr == user || user->m_gameType != RealmGameType::RETURN_TO_ARMS )
{
return std::make_shared< ResultCreateAccount >( this, ERROR_FATAL, L"" );
}
if( m_username.empty() || m_password.empty() || m_emailAddress.empty() || m_dateOfBirth.empty() || m_chatHandle.empty() )
{
Log::Error( "RequestCreateAccount::ProcessRequest() - Missing required fields for account creation." );
return std::make_shared< ResultCreateAccount >( this, ERROR_FATAL, L"" );
}
auto result = Database::Get().CreateNewAccount
(
Util::WideToUTF8( m_username ),
Util::WideToUTF8( m_password ),
Util::WideToUTF8( m_emailAddress ),
Util::WideToUTF8( m_dateOfBirth ),
Util::WideToUTF8( m_chatHandle )
);
if( !result )
{
Log::Error( "RequestCreateAccount::ProcessRequest() - Failed to create account for user: {}", m_username );
return std::make_shared< ResultCreateAccount >( this, ERROR_FATAL, L"" );
}
user->m_isLoggedIn = true;
user->m_sessionId = UserManager::Get().GenerateSessionId();
user->m_accountId = result;
user->m_username = m_username;
user->m_chatHandle = m_chatHandle;
return std::make_shared< ResultCreateAccount >( this, SUCCESS, user->m_sessionId );
}
ResultCreateAccount::ResultCreateAccount( GenericRequest *request, int32_t reply, std::wstring sessionId ) : GenericResponse( *request )
{
m_reply = reply;
m_sessionId = sessionId;
}
void ResultCreateAccount::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
out.write_encrypted_utf16( m_sessionId );
}

View File

@@ -0,0 +1,64 @@
#include "Network/Event/RequestCreateNewCharacter_RTA.hpp"
#include "Database/Database.hpp"
#include "Game/CharacterSaveManager.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/RealmUser.hpp"
#include "Game/RealmCharacter.hpp"
#include "logging.hpp"
void RequestCreateNewCharacter_RTA::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
auto a = stream->read_u32();
auto b = stream->read_u32();
m_metaData.Deserialize( stream );
auto characterDataSize = stream->read_u32();
m_characterData = stream->read_bytes( characterDataSize );
}
sptr_generic_response RequestCreateNewCharacter_RTA::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
Log::Error( "User not found! [{}]", m_sessionId );
return std::make_shared< ResultCreateNewCharacter_RTA >( this, FATAL_ERROR );
}
if( user->m_gameType != RealmGameType::RETURN_TO_ARMS )
{
Log::Error( "Invalid game type for CreateNewCharacter_RTA request! [{}]", m_sessionId );
return std::make_shared< ResultCreateNewCharacter_RTA >( this, FATAL_ERROR );
}
auto &saveManager = CharacterSaveManager::Get();
if( !saveManager.BeginSaveTask( user, user, 0, m_metaData, CharacterSaveType::NEW_CHARACTER ) )
{
Log::Error( "Failed to begin save task for new character! [{}]", m_sessionId );
return std::make_shared< ResultCreateNewCharacter_RTA >( this, FATAL_ERROR );
}
saveManager.AppendSaveData( user->m_sessionId, m_characterData, false );
return std::make_shared< ResultCreateNewCharacter_RTA >( this, SUCCESS );
}
ResultCreateNewCharacter_RTA::ResultCreateNewCharacter_RTA( GenericRequest *request, int32_t reply ) : GenericResponse( *request )
{
m_reply = reply;
}
void ResultCreateNewCharacter_RTA::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
}

View File

@@ -0,0 +1,61 @@
#include "Network/Event/RequestCreatePrivateGame.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/GameSessionManager.hpp"
#include "configuration.hpp"
#include "logging.hpp"
void RequestCreatePrivateGame::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
m_gameName = stream->read_utf16();
}
sptr_generic_response RequestCreatePrivateGame::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
Log::Error( "User not found! [{}]", m_sessionId );
return std::make_shared< ResultCreatePrivateGame >( this, FATAL_ERROR, "", 0 );
}
if( nullptr != GameSessionManager::Get().FindGame( m_gameName, user->m_gameType ) )
{
Log::Error( "Game name is already in use! [{}]", m_gameName );
return std::make_shared< ResultCreatePrivateGame >( this, GAME_NAME_IN_USE, "", 0 );
}
auto result = GameSessionManager::Get().CreateGameSession_CON( user, L"", m_gameName, L"", true);
if( !result )
{
Log::Error( "RequestCreatePrivateGame::ProcessRequest() - Failed to create private game session!" );
return std::make_shared< ResultCreatePrivateGame >( this, GENERAL_ERROR, "", 0 );
}
Log::Info( "[{}] Create Private Game: {}", m_sessionId, m_gameName );
return std::make_shared< ResultCreatePrivateGame >( this, SUCCESS, Config::service_ip, Config::discovery_port );
}
ResultCreatePrivateGame::ResultCreatePrivateGame( GenericRequest *request, int32_t reply, std::string discoveryIp, int32_t discoveryPort ) : GenericResponse( *request )
{
m_reply = reply;
m_discoveryIp = discoveryIp;
m_discoveryPort = discoveryPort;
}
void ResultCreatePrivateGame::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
out.write_sz_utf8( m_discoveryIp );
out.write( m_discoveryPort );
}

View File

@@ -0,0 +1,59 @@
#include "Network/Event/RequestCreatePrivateGame_RTA.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/GameSessionManager.hpp"
#include "configuration.hpp"
#include "logging.hpp"
void RequestCreatePrivateGame_RTA::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
m_gameName = stream->read_utf16();
m_localAddr = Util::WideToUTF8( stream->read_utf16() );
m_localPort = stream->read_u32();
}
sptr_generic_response RequestCreatePrivateGame_RTA::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
Log::Error( "User not found! [{}]", m_sessionId );
return std::make_shared< ResultCreatePrivateGame_RTA >( this, FATAL_ERROR, "", 0 );
}
auto result = GameSessionManager::Get().CreateGameSession_RTA( user, L"", m_gameName, {}, true);
if( !result )
{
Log::Error( "RequestCreatePrivateGame2::ProcessRequest() - Failed to create private game session!" );
return std::make_shared< ResultCreatePrivateGame_RTA >( this, GENERAL_ERROR, "", 0 );
}
user->m_localAddr = m_localAddr;
user->m_localPort = m_localPort;
Log::Info( "[{}] Create Private Game: {}", m_sessionId, m_gameName );
return std::make_shared< ResultCreatePrivateGame_RTA >( this, SUCCESS, Config::service_ip, Config::discovery_port );
}
ResultCreatePrivateGame_RTA::ResultCreatePrivateGame_RTA( GenericRequest *request, int32_t reply, std::string discoveryIp, int32_t discoveryPort ) : GenericResponse( *request )
{
m_reply = reply;
m_discoveryIp = discoveryIp;
m_discoveryPort = discoveryPort;
}
void ResultCreatePrivateGame_RTA::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
out.write_utf8( m_discoveryIp );
out.write( m_discoveryPort );
}

View File

@@ -0,0 +1,45 @@
#include "Network/Event/RequestCreatePrivateRoom.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/ChatRoomManager.hpp"
#include "logging.hpp"
void RequestCreatePrivateRoom::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
m_roomName = stream->read_utf16();
}
sptr_generic_response RequestCreatePrivateRoom::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
return std::make_shared< ResultCreatePrivateRoom >( this );
}
auto result = ChatRoomManager::Get().CreateGameChatSession( user, m_roomName );
if( !result )
{
Log::Error( "RequestCreatePrivateRoom::ProcessRequest() - Failed to create private room!" );
return std::make_shared< ResultCreatePrivateRoom >( this );
}
return std::make_shared< ResultCreatePrivateRoom >( this );
}
ResultCreatePrivateRoom::ResultCreatePrivateRoom( GenericRequest *request ) : GenericResponse( *request )
{
}
void ResultCreatePrivateRoom::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( 0 );
}

View File

@@ -0,0 +1,96 @@
#include "Network/Event/RequestCreatePublicGame.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/GameSessionManager.hpp"
#include "configuration.hpp"
#include "logging.hpp"
// Request
void RequestCreatePublicGame::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
// Some kind of match attributes
auto unknown_a = stream->read_u16();
auto unknown_b = stream->read_u32();
auto unknown_c = stream->read_u32();
auto unknown_d = stream->read_u32();
m_gameInfo = stream->read_utf16();
auto [name, stage] = ParseNameAndStage( m_gameInfo );
m_gameName = name;
m_stageName = stage;
}
std::tuple<std::wstring, std::wstring> RequestCreatePublicGame::ParseNameAndStage( const std::wstring &gameInfo )
{
const size_t open = gameInfo.find( L'[' );
const size_t close = gameInfo.find( L']' );
if( open == std::wstring::npos || close == std::wstring::npos || close < open )
return { L"", L"" };
std::wstring name = gameInfo.substr( 0, open );
std::wstring stage = gameInfo.substr( open + 1, close - open - 1 );
if( !name.empty() && iswspace( name.back() ) )
name.pop_back();
return { name, stage };
}
sptr_generic_response RequestCreatePublicGame::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
Log::Error( "User not found! [{}]", m_sessionId );
return std::make_shared< ResultCreatePublicGame >( this, FATAL_ERROR, "", 0 );
}
if( nullptr != GameSessionManager::Get().FindGame( m_gameName, user->m_gameType ) )
{
Log::Error( "Game name is already in use! [{}]", m_gameName );
return std::make_shared< ResultCreatePublicGame >( this, GAME_NAME_IN_USE, "", 0 );
}
auto result = GameSessionManager::Get().CreateGameSession_CON( user, m_gameInfo, m_gameName, m_stageName, false );
if( !result )
{
Log::Error( "RequestCreatePublicGame::ProcessRequest() - Failed to create public game session!" );
return std::make_shared< ResultCreatePublicGame >( this, GENERAL_ERROR, "", 0 );
}
Log::Info( "[{}] Create Public Game: {}", m_sessionId, m_gameInfo );
user->m_isHost = true;
user->m_discoveryAddr = "";
user->m_discoveryPort = 0;
return std::make_shared< ResultCreatePublicGame >( this, SUCCESS, Config::service_ip, Config::discovery_port );
}
// Result
ResultCreatePublicGame::ResultCreatePublicGame( GenericRequest *request, int32_t reply, std::string discoveryIp, int32_t discoveryPort ) : GenericResponse( *request )
{
m_reply = reply;
m_discoveryIp = discoveryIp;
m_discoveryPort = discoveryPort;
}
void ResultCreatePublicGame::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
out.write_sz_utf8( m_discoveryIp );
out.write( m_discoveryPort );
}

View File

@@ -0,0 +1,114 @@
#include "Network/Event/RequestCreatePublicGame_RTA.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/GameSessionManager.hpp"
#include "Game/ChatRoomManager.hpp"
#include "configuration.hpp"
#include "logging.hpp"
void RequestCreatePublicGame_RTA::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
auto unknown_a = stream->read_u16();
auto unknown_b = stream->read_u32();
auto unknown_c = stream->read_u32();
auto unknown_d = stream->read_u32();
m_gameInfo = stream->read_utf16();
auto unknown_e = stream->read_u32();
auto unknown_f = stream->read_u32();
m_localAddr = Util::WideToUTF8( stream->read_utf16() );
m_localPort = stream->read_u32();
if( !ParseGameInfo() )
{
Log::Error( "Failed to parse game info: {}", m_gameInfo );
}
}
bool RequestCreatePublicGame_RTA::ParseGameInfo()
{
if( m_gameInfo.empty() )
{
Log::Error( "Game info is empty!" );
return false;
}
size_t pipePos = m_gameInfo.find( L'|' );
if( pipePos == std::wstring::npos )
{
Log::Error( "Invalid game info format!" );
return false;
}
std::wstring numbersPart = m_gameInfo.substr( 0, pipePos );
m_gameName = m_gameInfo.substr( pipePos + 1 );
std::wstringstream ss( numbersPart );
std::wstring numStr;
std::array<int8_t, 5> fields = { 0, 0, 0, 0, 0 };
for( size_t i = 0; i < fields.size(); ++i )
{
if( !std::getline( ss, numStr, L',' ) )
return false;
try
{
fields[ i ] = std::stoi( numStr );
}
catch( ... )
{
return false;
}
}
return true;
}
sptr_generic_response RequestCreatePublicGame_RTA::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
Log::Error( "User not found! [{}]", m_sessionId );
return std::make_shared< ResultCreatePublicGame_RTA >( this, GENERAL_ERROR, "", 0 );
}
auto result = GameSessionManager::Get().CreateGameSession_RTA( user, m_gameInfo, m_gameName, m_attributes, false );
if( !result )
{
Log::Error( "RequestCreatePublicGame::ProcessRequest() - Failed to create public game session!" );
return std::make_shared< ResultCreatePublicGame_RTA >( this, GENERAL_ERROR, "", 0 );
}
user->m_localAddr = m_localAddr;
user->m_localPort = m_localPort;
Log::Info( "[{}] Create Public Game: {}", user->m_username, m_gameInfo );
return std::make_shared< ResultCreatePublicGame_RTA >( this, SUCCESS, Config::service_ip, Config::discovery_port );
}
// Result
ResultCreatePublicGame_RTA::ResultCreatePublicGame_RTA( GenericRequest *request, int32_t reply, std::string discoveryIp, int32_t discoveryPort ) : GenericResponse( *request )
{
m_reply = reply;
m_discoveryIp = discoveryIp;
m_discoveryPort = discoveryPort;
}
void ResultCreatePublicGame_RTA::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
out.write_utf8( m_discoveryIp );
out.write( m_discoveryPort );
}

View File

@@ -0,0 +1,58 @@
#include "Network/Event/RequestDoClientDiscovery.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/GameSessionManager.hpp"
#include "configuration.hpp"
#include "logging.hpp"
void RequestDoClientDiscovery::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
m_gameId = stream->read_u32();
}
sptr_generic_response RequestDoClientDiscovery::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
return std::make_shared< ResultDoClientDiscovery >( this, DISCOVERY_REPLY::FATAL_ERROR, "", 0 );
}
auto session = GameSessionManager::Get().FindGame( m_gameId, user->m_gameType );
if( session == nullptr )
{
return std::make_shared< ResultDoClientDiscovery >( this, DISCOVERY_REPLY::FATAL_ERROR, "", 0 );
}
if( !session->IsJoinable( user ) )
{
return std::make_shared< ResultDoClientDiscovery >( this, DISCOVERY_REPLY::GAME_FULL, "", 0 );
}
user->m_gameId = m_gameId;
user->m_isHost = false;
return std::make_shared< ResultDoClientDiscovery >( this, DISCOVERY_REPLY::SUCCESS, Config::service_ip, Config::discovery_port );
}
ResultDoClientDiscovery::ResultDoClientDiscovery( GenericRequest *request, int32_t reply, std::string ip, int32_t port ) : GenericResponse( *request )
{
m_reply = reply;
m_discoveryIP = ip;
m_discoveryPort = port;
}
void ResultDoClientDiscovery::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
out.write_sz_utf8( m_discoveryIP );
out.write( m_discoveryPort );
}

View File

@@ -0,0 +1,59 @@
#include "Network/Event/RequestDoClientDiscovery_RTA.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/GameSessionManager.hpp"
#include "configuration.hpp"
#include "logging.hpp"
void RequestDoClientDiscovery_RTA::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
m_gameId = stream->read_u32();
m_localAddr = stream->read_utf16();
m_localPort = stream->read_u32();
}
sptr_generic_response RequestDoClientDiscovery_RTA::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
Log::Error( "User not found! [{}]", m_sessionId );
return std::make_shared< ResultDoClientDiscovery_RTA >( this, TIMEOUT );
}
auto session = GameSessionManager::Get().FindGame( m_gameId, user->m_gameType );
if( session == nullptr )
{
Log::Error( "Game session not found! [{}]", m_gameId );
return std::make_shared< ResultDoClientDiscovery_RTA >( this, NOT_FOUND );
}
user->m_isHost = false;
user->m_gameId = session->m_gameId;
user->m_localAddr = Util::WideToUTF8(m_localAddr);
user->m_localPort = m_localPort;
return std::make_shared< ResultDoClientDiscovery_RTA >( this, SUCCESS, Config::service_ip, Config::discovery_port );
}
ResultDoClientDiscovery_RTA::ResultDoClientDiscovery_RTA( GenericRequest *request, int32_t reply, std::string discoveryIp, int32_t discoveryPort ) : GenericResponse( *request )
{
m_reply = reply;
m_discoveryIp = discoveryIp;
m_discoveryPort = discoveryPort;
}
void ResultDoClientDiscovery_RTA::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
out.write_utf8( m_discoveryIp );
out.write_u32( m_discoveryPort );
}

View File

@@ -0,0 +1,85 @@
#include "Network/Event/RequestEnterRoom.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/ChatRoomManager.hpp"
#include "logging.hpp"
void RequestEnterRoom::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
auto sessionId = stream->read_encrypted_utf16();
m_roomName = stream->read_utf16();
}
sptr_generic_response RequestEnterRoom::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
const auto user = UserManager::Get().FindUserBySocket( socket );
if( !user )
{
Log::Error( "User not found for socket!" );
return std::make_shared< ResultEnterRoom >( this, GENERAL_ERROR, nullptr );
}
if( !ChatRoomManager::Get().JoinRoom( user, m_roomName ) )
{
Log::Error( "Failed to join room [{}] for user [{}]", m_roomName, user->m_username );
return std::make_shared< ResultEnterRoom >( this, GENERAL_ERROR, nullptr );
}
const auto room = ChatRoomManager::Get().FindRoom( m_roomName );
if( !room )
{
Log::Error( "Chat room [{}] not found after joining", m_roomName );
return std::make_shared< ResultEnterRoom >( this, GENERAL_ERROR, nullptr );
}
return std::make_shared< ResultEnterRoom >( this, SUCCESS, room );
}
ResultEnterRoom::ResultEnterRoom( GenericRequest *request, int32_t reply, sptr_chat_room_session room ) : GenericResponse( *request )
{
m_reply = reply;
m_room = room;
}
void ResultEnterRoom::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
if( m_room )
{
out.write_utf16( m_room->m_name );
out.write_utf16( m_room->m_banner );
out.write_u32( static_cast< uint32_t >( m_room->m_members.size() ) );
for( const auto &m : m_room->m_members )
{
if( auto member = m.lock() )
{
out.write_utf16( member->m_chatHandle );
}
else
{
out.write_utf16( L"Unknown" );
}
}
out.write_u32( static_cast< uint32_t >( m_room->m_moderators.size() ) );
for( const auto &m : m_room->m_moderators )
{
if( auto member = m.lock() )
{
out.write_utf16( member->m_chatHandle );
}
else
{
out.write_utf16( L"" );
}
}
}
}

View File

@@ -0,0 +1,113 @@
#include "Network/Event/RequestGetCharacterData_RTA.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/RealmUser.hpp"
#include "Database/Database.hpp"
#include "logging.hpp"
void RequestGetNetCharacterData_RTA::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
auto sessionId = stream->read_encrypted_utf16();
m_characterId = stream->read_u32();
}
sptr_generic_response RequestGetNetCharacterData_RTA::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
return std::make_shared< ResultGetNetCharacterData_RTA >( this, FATAL_ERROR );
}
auto result = Database::Get().LoadCharacterData( user->m_accountId, m_characterId );
if( !result )
{
Log::Error( "Failed to load character data for account ID: " + std::to_string( user->m_accountId ) + ", character ID: " + std::to_string( m_characterId ) );
return std::make_shared< ResultGetNetCharacterData_RTA >( this, FATAL_ERROR );
}
user->m_characterId = result->m_characterId;
user->m_character = result;
return SendCharacterData( socket, result );
}
sptr_generic_response RequestGetNetCharacterData_RTA::SendCharacterData( sptr_socket socket, sptr_realm_character character )
{
const auto &data = character->m_data;
const auto data_size = data.size();
size_t position = 0;
sptr_generic_response finalChunk = nullptr;
while( position < data_size )
{
const size_t chunk_size = std::min<size_t>( 1024, data_size - position );
std::vector<uint8_t> chunk_data( data.begin() + position, data.begin() + position + chunk_size );
const int32_t isFinalChunk = ( position + chunk_size >= data_size );
if( isFinalChunk && chunk_data.size() < 1024 )
{
chunk_data.resize( 1024, 0 );
}
auto response = std::make_shared<ResultGetNetCharacterData_RTA>( this, SUCCESS, std::move( chunk_data ), isFinalChunk );
if( isFinalChunk )
{
finalChunk = response;
}
else
{
socket->send( response );
}
position += chunk_size;
}
return finalChunk;
}
ResultGetNetCharacterData_RTA::ResultGetNetCharacterData_RTA( GenericRequest *request, int32_t reply, std::optional<std::vector<uint8_t>> data, std::optional<int32_t> endOfData ) : GenericResponse( *request )
{
m_reply = reply;
if( !data.has_value() )
{
m_chunk.clear();
}
else
{
m_chunk = data.value();
}
if( !endOfData.has_value() )
{
m_endOfData = 0;
}
else
{
m_endOfData = endOfData.value();
}
}
void ResultGetNetCharacterData_RTA::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
if( !m_reply )
{
out.write_u32( static_cast< uint32_t >( m_chunk.size() ) );
out.write_bytes( m_chunk );
out.write_u32( m_endOfData );
}
}

View File

@@ -0,0 +1,34 @@
#include "Network/Event/RequestGetEncryptionKey.hpp"
void RequestGetEncryptionKey::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
}
sptr_generic_response RequestGetEncryptionKey::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto publicKey = stream->read_utf8();
auto unknown = stream->read_u32();
return std::make_shared< ResultGetEncryptionKey >( this );
}
ResultGetEncryptionKey::ResultGetEncryptionKey( GenericRequest *request ) : GenericResponse( *request )
{
m_symKey = RealmCrypt::getSymmetricKey();
}
void ResultGetEncryptionKey::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( 0 );
const auto encrypted = RealmCrypt::encryptSymmetric( m_symKey );
out.write_u32( static_cast<uint32_t>( encrypted.size() ) + 4 );
out.write_u32( static_cast<uint32_t>( m_symKey.size() ) );
out.write_bytes( encrypted );
}

View File

@@ -0,0 +1,38 @@
#include "RequestGetFriendList.h"
void RequestGetFriendList::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
}
sptr_generic_response RequestGetFriendList::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto publicKey = stream->read_utf8();
auto unknown = stream->read_u32();
return std::make_shared< ResultGetFriendList >( this );
}
ResultGetFriendList::ResultGetFriendList( GenericRequest *request ) : GenericResponse( *request )
{
}
void ResultGetFriendList::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( 0 );
// Friends
out.write_u32(1);
out.write_utf16(L"String_1");
out.write_u32(1);
out.write_utf16(L"String_2");
// Ignore
out.write_u32(1);
out.write_utf16(L"String_3");
}

View File

@@ -0,0 +1,72 @@
#include "Network/Event/RequestGetGame.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/GameSessionManager.hpp"
#include "Game/RealmUser.hpp"
#include "logging.hpp"
void RequestGetGame::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
m_gameName = stream->read_utf16();
}
sptr_generic_response RequestGetGame::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
Log::Error( "User not found! [{}]", m_sessionId );
return std::make_shared< ResultGetGame >( this, TIMEOUT );
}
auto session = GameSessionManager::Get().FindGame( m_gameName, user->m_gameType );
if( session == nullptr )
{
Log::Error( "Game session not found! [{}]", m_gameName );
return std::make_shared< ResultGetGame >( this, NOT_FOUND );
}
if( session->m_currentPlayers >= session->m_maximumPlayers )
{
Log::Error( "Game session is full! [{}]", m_gameName );
return std::make_shared< ResultGetGame >( this, TIMEOUT );
}
auto host_user = session->GetOwner();
if( host_user == nullptr )
{
Log::Error( "Game session owner not found! [{}]", m_gameName );
return std::make_shared< ResultGetGame >( this, TIMEOUT );
}
user->m_isHost = false;
user->m_gameId = session->m_gameId;
return std::make_shared< ResultGetGame >( this, SUCCESS, session->m_gameId );
}
ResultGetGame::ResultGetGame( GenericRequest *request, int32_t reply, int32_t gameId ) : GenericResponse( *request )
{
m_reply = reply;
m_gameId = gameId;
}
void ResultGetGame::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
// TODO: These may come in from the UpdateGameData event
out.write_utf16( L"Kelethin" );
out.write_utf16( L"OwnerName" );
out.write_u32( m_gameId );
}

View File

@@ -0,0 +1,78 @@
#include "Network/Event/RequestGetGame_RTA.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/GameSessionManager.hpp"
#include "Game/RealmUser.hpp"
#include "logging.hpp"
void RequestGetGame_RTA::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
m_gameName = stream->read_utf16();
}
sptr_generic_response RequestGetGame_RTA::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
Log::Error( "User not found! [{}]", m_sessionId );
return std::make_shared< ResultGetGame_RTA >( this, TIMEOUT );
}
auto session = GameSessionManager::Get().FindGame( m_gameName, user->m_gameType );
if( session == nullptr )
{
Log::Error( "Game session not found! [{}]", m_gameName );
return std::make_shared< ResultGetGame_RTA >( this, NOT_FOUND );
}
if( session->m_currentPlayers >= session->m_maximumPlayers )
{
Log::Error( "Game session is full! [{}]", m_gameName );
return std::make_shared< ResultGetGame_RTA >( this, TIMEOUT );
}
auto host_user = session->GetOwner();
if( host_user == nullptr )
{
Log::Error( "Game session owner not found! [{}]", m_gameName );
return std::make_shared< ResultGetGame_RTA >( this, TIMEOUT );
}
user->m_isHost = false;
user->m_gameId = session->m_gameId;
return std::make_shared< ResultGetGame_RTA >( this, SUCCESS, session->m_gameId, host_user->m_discoveryAddr, host_user->m_localAddr, host_user->m_discoveryPort );
}
ResultGetGame_RTA::ResultGetGame_RTA( GenericRequest *request, int32_t reply, int32_t gameId, std::string discoveryAddr, std::string localAddr, int32_t discoveryPort ) : GenericResponse( *request )
{
m_reply = reply;
m_gameId = gameId;
m_discoveryAddr = Util::UTF8ToWide( discoveryAddr );
m_localAddr = Util::UTF8ToWide( localAddr );
m_port = discoveryPort;
}
void ResultGetGame_RTA::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
out.write_utf16( L"Test" );
out.write_u32( m_gameId );
out.write_utf16( m_discoveryAddr );
out.write_u32( m_port );
out.write_utf16( m_localAddr );
out.write_u32( m_port );
}

View File

@@ -0,0 +1,65 @@
#include "Network/Event/RequestGetNetCharacterList_RTA.hpp"
#include "Game/RealmUser.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/RealmCharacterMetaKV.hpp"
#include "Database/Database.hpp"
#include "logging.hpp"
void RequestGetNetCharacterList_RTA::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
}
sptr_generic_response RequestGetNetCharacterList_RTA::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( !user )
{
return std::make_shared< ResultGetNetCharacterList_RTA >( this, FATAL_ERROR, std::nullopt );
}
auto result = Database::Get().LoadCharacterSlots( user->m_accountId );
return std::make_shared< ResultGetNetCharacterList_RTA >( this, SUCCESS, result );
}
ResultGetNetCharacterList_RTA::ResultGetNetCharacterList_RTA( GenericRequest *request, int32_t reply, std::optional< std::map< uint32_t, CharacterSlotData > > list ) : GenericResponse( *request )
{
m_reply = reply;
if( list != std::nullopt )
{
m_characterList = list.value();
}
}
void ResultGetNetCharacterList_RTA::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
// Character Count
out.write_u32( static_cast< int >( m_characterList.size() ) );
// Character List
for( auto &character : m_characterList )
{
const auto &KV = character.second.GetMetaData();
// Character ID
out.write_u32( character.first );
// Number of Key-Value pairs
out.write_u32( static_cast< uint32_t >( KV.size() ) );
for( auto &pair : KV )
{
out.write_utf16( pair.first );
out.write_utf16( pair.second );
}
}
}

View File

@@ -0,0 +1,55 @@
#include "Network/Event/RequestGetPublicRooms.hpp"
#include "Game/ChatRoomManager.hpp"
void RequestGetPublicRooms::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
}
sptr_generic_response RequestGetPublicRooms::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
const auto publicRooms = ChatRoomManager::Get().GetPublicRoomList();
return std::make_shared< ResultGetPublicRooms >( this, publicRooms );
}
ResultGetPublicRooms::ResultGetPublicRooms( GenericRequest *request, std::vector< sptr_chat_room_session > rooms ) : GenericResponse( *request )
{
m_rooms = std::move( rooms );
}
void ResultGetPublicRooms::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( 0 );
const auto numRoom = static_cast< uint32_t >( m_rooms.size() );
out.write_u32( numRoom );
for( const auto &room : m_rooms )
{
out.write_utf16( room->m_name );
}
out.write_u32( numRoom );
for( const auto &room : m_rooms )
{
out.write_utf16( L"UNKNOWN" );
}
out.write_u32( numRoom );
for( const auto &room : m_rooms )
{
out.write_u32( 88 );
}
out.write_u32( numRoom );
for( const auto &room : m_rooms )
{
out.write_u32( 99 );
}
}

View File

@@ -0,0 +1,39 @@
#include "Network/Event/RequestGetRealmStats.hpp"
#include "Game/RealmUserManager.hpp"
void RequestGetRealmStats::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
}
sptr_generic_response RequestGetRealmStats::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
return std::make_shared< ResultGetRealmStats >( this );
}
ResultGetRealmStats::ResultGetRealmStats( GenericRequest *request ) : GenericResponse( *request )
{
}
void ResultGetRealmStats::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( 0 );
// Player count on the game page.
out.write_u32( UserManager::Get().GetUserCount() ); // Users Logged In Game
// I'm not sure this appears anywhere in the game.
out.write_u32( 0 ); // Users Logged In Realm
out.write_u32( 0 ); // Users Running Game
out.write_u32( 0 ); // Users Running Realm
out.write_u32( 0 ); // Users Playing Game
out.write_u32( 0 ); // Users Playing Realm
out.write_u32( 0 ); // unmatchedGamesGame
out.write_u32( 0 ); // unmatchedGamesRealm
}

View File

@@ -0,0 +1,86 @@
#include "Network/Event/RequestGetRoom.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/ChatRoomManager.hpp"
#include "logging.hpp"
void RequestGetRoom::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
m_roomName = stream->read_utf16();
}
sptr_generic_response RequestGetRoom::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
const auto user = UserManager::Get().FindUserBySocket( socket );
if( !user )
{
return std::make_shared< ResultGetRoom >( this, GENERAL_ERROR );
}
sptr_chat_room_session targetRoom = nullptr;
if( m_roomName.empty() )
{
targetRoom = ChatRoomManager::Get().FindRoom( user->m_privateRoomId );
}
else
{
targetRoom = ChatRoomManager::Get().FindRoom( user->m_publicRoomId );
}
return std::make_shared< ResultGetRoom >( this, SUCCESS, targetRoom );
}
ResultGetRoom::ResultGetRoom( GenericRequest *request, int32_t reply, sptr_chat_room_session room ) : GenericResponse( *request )
{
m_reply = reply;
m_room = room;
}
void ResultGetRoom::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
if( m_room )
{
out.write_utf16( m_room->m_name );
out.write_utf16( m_room->m_banner );
out.write_u32( static_cast< uint32_t >( m_room->m_members.size() ) );
for( const auto &m : m_room->m_members )
{
const auto &member = m.lock();
if( member )
{
out.write_utf16( member->m_chatHandle );
}
else
{
out.write_utf16( L"" );
}
}
out.write_u32( static_cast< uint32_t >( m_room->m_moderators.size() ) );
for( const auto &m : m_room->m_moderators )
{
if( auto member = m.lock() )
{
out.write_utf16( member->m_chatHandle );
}
else
{
out.write_utf16( L"" );
}
}
}
}

View File

@@ -0,0 +1,62 @@
#include "Network/Event/RequestGetRules.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/RealmUser.hpp"
#include "Common/Constant.hpp"
#include "logging.hpp"
void RequestGetRules::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_language = stream->read_sz_utf8();
}
sptr_generic_response RequestGetRules::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
return std::make_shared< ResultGetRules >( this, L"" );
}
// TODO: Get rules/eula based on language
// and move it info a MOTD file.
std::wstring rules;
if( user->m_gameType == RealmGameType::RETURN_TO_ARMS )
{
rules = L"Welcome to the Champions Emulated Server!\n\n"
L"RETURN TO ARMS network support is currently a\n"
L"work in progress and can not guarantee stability.\n\n"
L"[IMPORTANT]:\n"
L"Please note that ONLINE character saves may be unstable.\n"
L"Use them at your own risk.\n";
}
else
{
rules = L"Welcome to the Champions Emulated Server!\n\n"
L"This server is currently in development\n"
L"and may not be fully functional.\n\n";
}
return std::make_shared< ResultGetRules >( this, rules );
}
ResultGetRules::ResultGetRules( GenericRequest *request, std::wstring rules ) : GenericResponse( *request )
{
m_rules = rules;
}
void ResultGetRules::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( 0 );
out.write_utf16( m_rules );
}

View File

@@ -0,0 +1,47 @@
#include "Network/Event/RequestGetServerAddress.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/RealmUser.hpp"
#include "Common/Constant.hpp"
#include "configuration.hpp"
#include "logging.hpp"
void RequestGetServerAddress::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
}
sptr_generic_response RequestGetServerAddress::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
if( socket->gameType == RealmGameType::RETURN_TO_ARMS )
{
return std::make_shared< ResultGetServerAddress >( this, Config::service_ip, Config::rta_lobby_port, socket->gameType );
}
else
{
return std::make_shared< ResultGetServerAddress >( this, Config::service_ip, Config::con_lobby_port, socket->gameType );
}
}
ResultGetServerAddress::ResultGetServerAddress( GenericRequest *request, std::string ip, int32_t port, RealmGameType gameType ) : GenericResponse( *request )
{
m_ip = ip;
m_port = port;
m_gameType = gameType;
}
void ResultGetServerAddress::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( 0 );
if( m_gameType == RealmGameType::RETURN_TO_ARMS )
out.write_utf8( m_ip );
else
out.write_sz_utf8( m_ip );
out.write( m_port );
}

View File

@@ -0,0 +1,54 @@
#include "Network/Event/RequestGetSocialListInitial.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/RealmUser.hpp"
#include "logging.hpp"
void RequestGetSocialListInitial::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
}
sptr_generic_response RequestGetSocialListInitial::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
Log::Error( "RequestGetFriendList::ProcessRequest() - User not found" );
return std::make_shared< ResultGetSocialListInitial >( this );
}
return std::make_shared< ResultGetSocialListInitial >( this, user );
}
ResultGetSocialListInitial::ResultGetSocialListInitial( GenericRequest *request, sptr_user user ) : GenericResponse( *request )
{
m_user = user;
}
void ResultGetSocialListInitial::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( 0 );
// Friends
out.write_u32( static_cast< uint32_t >( m_user->m_friendList.size() ) );
for( const auto &friendHandle : m_user->m_friendList )
{
out.write_utf16( friendHandle );
}
// ?
out.write_u32(1);
out.write_utf16(L"String_2");
// Ignore
out.write_u32( static_cast< uint32_t >( m_user->m_ignoreList.size() ) );
for( const auto &ignoreHandle : m_user->m_ignoreList )
{
out.write_utf16( ignoreHandle );
}
}

View File

@@ -0,0 +1,50 @@
#include "Network/Event/RequestGetSocialListUpdate.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/RealmUser.hpp"
#include "logging.hpp"
void RequestGetSocialListUpdate::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
}
sptr_generic_response RequestGetSocialListUpdate::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
Log::Error( "RequestGetFriendList::ProcessRequest() - User not found" );
return std::make_shared< ResultGetSocialListUpdate >( this );
}
return std::make_shared< ResultGetSocialListUpdate >( this, user );
}
ResultGetSocialListUpdate::ResultGetSocialListUpdate( GenericRequest *request, sptr_user user ) : GenericResponse( *request )
{
m_user = user;
}
void ResultGetSocialListUpdate::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( 0 );
// Friends
out.write_u32( static_cast< uint32_t >( m_user->m_friendList.size() ) );
for( const auto &friendHandle : m_user->m_friendList )
{
out.write_utf16( friendHandle );
}
// Ignore
out.write_u32( static_cast< uint32_t >( m_user->m_ignoreList.size() ) );
for( const auto &ignoreHandle : m_user->m_ignoreList )
{
out.write_utf16( ignoreHandle );
}
}

View File

@@ -0,0 +1,45 @@
#include "Network/Event/RequestLeaveRoom.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/ChatRoomManager.hpp"
#include "logging.hpp"
void RequestLeaveRoom::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
auto sessionId = stream->read_encrypted_utf16();
m_roomName = stream->read_utf16();
}
sptr_generic_response RequestLeaveRoom::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
const auto user = UserManager::Get().FindUserBySocket( socket );
if( !user )
{
Log::Error( "User not found for socket!" );
return std::make_shared< ResultLeaveRoom >( this, GENERAL_ERROR );
}
if( !ChatRoomManager::Get().LeaveRoom( user, m_roomName ) )
{
Log::Error( "Could not remove user [{}] from room [{}]", user->m_username, m_roomName );
return std::make_shared< ResultLeaveRoom >( this, GENERAL_ERROR );
}
return std::make_shared< ResultLeaveRoom >( this, SUCCESS );
}
ResultLeaveRoom::ResultLeaveRoom( GenericRequest *request, int32_t reply ) : GenericResponse( *request )
{
m_reply = reply;
}
void ResultLeaveRoom::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
}

View File

@@ -0,0 +1,122 @@
#include "Network/Event/RequestLogin.hpp"
#include "Database/Database.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/RealmUser.hpp"
#include "Common/Constant.hpp"
#include "logging.hpp"
void RequestLogin::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_username = stream->read_encrypted_utf16();
m_password = stream->read_encrypted_utf16();
}
sptr_generic_response RequestLogin::ProcessLoginCON( sptr_user user )
{
if( m_username != L"foo" && m_password != L"bar" )
{
// Network Beta CoN uses login information, but it's invalid because of version 2.0
// which used "foo" and "bar" as the login credentials.
Log::Debug( "RequestLogin : Champions of Norrath v1.0" );
// TODO: Either block this, or add support for the network beta.
return std::make_shared< ResultLogin >( this, LOGIN_REPLY::ACCOUNT_INVALID, L"" );
}
user->m_isLoggedIn = true;
user->m_accountId = -1;
user->m_sessionId = UserManager::Get().GenerateSessionId();
return std::make_shared< ResultLogin >( this, SUCCESS, user->m_sessionId );
}
sptr_generic_response RequestLogin::ProcessLoginRTA( sptr_user user )
{
// Return to Arms uses login information.
Log::Debug( "RequestLogin : Return to Arms" );
auto &UserManager = UserManager::Get();
auto &Database = Database::Get();
// Verify the account exists
auto [ result, accountId, chatHandle ] = Database.VerifyAccount( m_username, m_password );
if( accountId < 0 )
{
Log::Error( "RequestLogin::ProcessRequest() - Invalid account ID: " + std::to_string( accountId ) );
return std::make_shared< ResultLogin >( this, ACCOUNT_INVALID, L"" );
}
// Check if the user is already logged in
for( const auto &existingUser : UserManager.GetUserList() )
{
if( existingUser->m_username == m_username || existingUser->m_accountId == accountId )
{
return std::make_shared< ResultLogin >( this, FATAL_ERROR, L"" );
}
}
// Login Success
user->m_isLoggedIn = true;
user->m_username = m_username;
user->m_accountId = accountId;
user->m_chatHandle = chatHandle;
user->m_sessionId = UserManager.GenerateSessionId();
// Load Friend List
user->m_friendList = Database.LoadFriends( accountId );
// Load Ignore List
user->m_ignoreList = Database.LoadIgnores( accountId );
// Notify friends about the user's online status
UserManager.NotifyFriendsOnlineStatus( user, true );
return std::make_shared< ResultLogin >( this, SUCCESS, user->m_sessionId );
}
sptr_generic_response RequestLogin::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
Log::Error( "RequestLogin::ProcessRequest() - User not found" );
return std::make_shared< ResultLogin >( this, ACCOUNT_INVALID, L"" );
}
if( m_username.empty() || m_password.empty() )
{
Log::Error( "RequestLogin::ProcessRequest() - Username or password is empty" );
return std::make_shared< ResultLogin >( this, ACCOUNT_INVALID, L"" );
}
if( user->m_gameType == RealmGameType::CHAMPIONS_OF_NORRATH )
{
return ProcessLoginCON( user );
}
else
{
return ProcessLoginRTA( user );
}
}
ResultLogin::ResultLogin( GenericRequest *request, int32_t reply, std::wstring sessionId ) : GenericResponse( *request )
{
m_reply = reply;
m_sessionId = sessionId;
}
void ResultLogin::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
out.write_encrypted_utf16( m_sessionId );
out.write_encrypted_utf16( L"UNKNOWN DUMMY STRING" );
}

View File

@@ -0,0 +1,33 @@
#include "Network/Event/RequestLogout.hpp"
#include "Game/RealmUserManager.hpp"
#include "logging.hpp"
void RequestLogout::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
}
sptr_generic_response RequestLogout::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
UserManager::Get().RemoveUser( socket );
Log::Debug( "[{}] Logout", m_sessionId );
return std::make_shared< ResultLogout >( this, 0 );
}
ResultLogout::ResultLogout( GenericRequest *request, int32_t reply ) : GenericResponse( *request )
{
m_reply = reply;
}
void ResultLogout::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
}

View File

@@ -0,0 +1,97 @@
#include "Network/Event/RequestMatchGame.hpp"
#include <format>
#include "Common/Constant.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/GameSessionManager.hpp"
#include "Game/RealmUser.hpp"
void RequestMatchGame::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
auto unknown_a = stream->read_u16();
auto unknown_b = stream->read_u32();
auto unknown_c = stream->read_u32();
auto unknown_d = stream->read_u32();
auto unknown_e = stream->read_u32();
// Match Game Node Count
for( uint32_t i = 0; i < unknown_e; i++ )
{
auto node_a = stream->read_u16();
auto node_b = stream->read_u32();
auto node_c = stream->read_utf16();
auto node_d = stream->read_u32();
auto node_e = stream->read_u32();
auto node_f = stream->read_u32();
auto node_g = stream->read_u16();
}
auto unknown_f = stream->read_u8();
auto unknown_g = stream->read_u32();
auto unknown_h = stream->read_u32();
}
sptr_generic_response RequestMatchGame::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
return std::make_shared< ResultMatchGame >( this, socket->remote_ip );
}
ResultMatchGame::ResultMatchGame( GenericRequest *request, std::string userIp ) : GenericResponse( *request )
{
m_userIp = userIp;
}
void ResultMatchGame::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( 0 );
const auto publicGameList = GameSessionManager::Get().GetAvailableGameSessionList( RealmGameType::CHAMPIONS_OF_NORRATH );
const auto publicGameCount = static_cast< uint32_t >( publicGameList.size() );
out.write_u32( publicGameCount );
{
for( const auto &game : publicGameList )
{
if( m_userIp == game->m_hostExternalAddr )
out.write_utf16( std::format( L"{}:{}", Util::UTF8ToWide( game->m_hostLocalAddr ), game->m_hostNatPort ) );
else
out.write_utf16( std::format( L"{}:{}", Util::UTF8ToWide( game->m_hostExternalAddr ), game->m_hostNatPort ) );
}
}
out.write_u32( publicGameCount );
{
for( const auto &game : publicGameList )
out.write_utf16( game->m_gameName );
}
out.write_u32( publicGameCount );
{
for( const auto &game : publicGameList )
out.write_utf16( game->m_ownerName );
}
out.write_u32( publicGameCount );
{
for( const auto &game : publicGameList )
out.write_u32( game->m_gameId );
}
out.write_u32( publicGameCount );
{
for( const auto &game : publicGameList )
out.write_utf8( game->m_gameData );
}
}

View File

@@ -0,0 +1,93 @@
#include "Network/Event/RequestMatchGame_RTA.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/GameSessionManager.hpp"
#include "logging.hpp"
void RequestMatchGame_RTA::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
}
sptr_generic_response RequestMatchGame_RTA::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
UserManager::Get().Disconnect( socket, "User not found!" );
return std::make_shared< ResultMatchGame_RTA >( this, "" );
}
if( !user->m_isLoggedIn )
{
UserManager::Get().Disconnect( user, "User is not logged in!" );
return std::make_shared< ResultMatchGame_RTA >( this, "" );
}
return std::make_shared< ResultMatchGame_RTA >( this, socket->remote_ip );
}
ResultMatchGame_RTA::ResultMatchGame_RTA( GenericRequest *request, std::string userIp ) : GenericResponse( *request )
{
m_userIp = userIp;
}
void ResultMatchGame_RTA::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( 0 );
const auto publicGameList = GameSessionManager::Get().GetAvailableGameSessionList( RealmGameType::RETURN_TO_ARMS );
const auto publicGameCount = static_cast< uint32_t >( publicGameList.size() );
out.write_u32( publicGameCount );
{
for( const auto &game : publicGameList )
out.write_utf16( Util::UTF8ToWide( game->m_gameData ) );
}
out.write_u32( publicGameCount );
{
for( const auto &game : publicGameList )
out.write_utf16( game->m_playerCount );
}
out.write_u32( publicGameCount );
{
for( const auto &game : publicGameList )
out.write_u32( game->m_gameId );
}
// Something about filtering.
out.write_u32( publicGameCount );
{
out.write_u32( 0 ); // Size
}
out.write_u32( publicGameCount );
{
for( const auto &game : publicGameList )
out.write_utf16( Util::UTF8ToWide( game->m_hostLocalAddr ) );
}
out.write_u32( publicGameCount );
{
for( const auto &game : publicGameList )
out.write_u32( game->m_hostLocalPort );
}
out.write_u32( publicGameCount );
{
for( const auto &game : publicGameList )
out.write_utf16( Util::UTF8ToWide( game->m_hostExternalAddr ) );
}
out.write_u32( publicGameCount );
{
for( const auto &game : publicGameList )
out.write_u32( game->m_hostNatPort );
}
}

View File

@@ -0,0 +1,56 @@
#include "Network/Event/RequestRemoveFriend.hpp"
#include "Game/RealmUserManager.hpp"
#include "Database/Database.hpp"
#include "logging.hpp"
void RequestRemoveFriend::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
m_chatHandle = stream->read_utf16();
}
sptr_generic_response RequestRemoveFriend::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
return std::make_shared< ResultRemoveFriend >( this, FATAL_ERROR );
}
if( !user->IsFriend( m_chatHandle ) )
{
return std::make_shared< ResultRemoveFriend >( this, FRIEND_INVALID );
}
if( !Database::Get().RemoveFriend( user->m_accountId, m_chatHandle ) )
{
return std::make_shared< ResultRemoveFriend >( this, DATABASE_ERROR );
}
const auto iter = std::find( user->m_friendList.begin(), user->m_friendList.end(), m_chatHandle );
if( iter == user->m_friendList.end() )
{
return std::make_shared< ResultRemoveFriend >( this, FRIEND_INVALID );
}
user->m_friendList.erase( iter );
return std::make_shared< ResultRemoveFriend >( this, SUCCESS );
}
ResultRemoveFriend::ResultRemoveFriend( GenericRequest *request, int32_t reply ) : GenericResponse( *request )
{
m_reply = reply;
}
void ResultRemoveFriend::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
}

View File

@@ -0,0 +1,56 @@
#include "Network/Event/RequestRemoveIgnore.hpp"
#include "Game/RealmUserManager.hpp"
#include "Database/Database.hpp"
#include "logging.hpp"
void RequestRemoveIgnore::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
m_chatHandle = stream->read_utf16();
}
sptr_generic_response RequestRemoveIgnore::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
return std::make_shared< ResultRemoveIgnore >( this, FATAL_ERROR );
}
if( !user->IsIgnored( m_chatHandle ) )
{
return std::make_shared< ResultRemoveIgnore >( this, IGNORE_INVALID );
}
if( !Database::Get().RemoveIgnore( user->m_accountId, m_chatHandle ) )
{
return std::make_shared< ResultRemoveIgnore >( this, DATABASE_ERROR );
}
const auto iter = std::find( user->m_ignoreList.begin(), user->m_ignoreList.end(), m_chatHandle );
if( iter == user->m_ignoreList.end() )
{
return std::make_shared< ResultRemoveIgnore >( this, IGNORE_INVALID );
}
user->m_ignoreList.erase( iter );
return std::make_shared< ResultRemoveIgnore >( this, SUCCESS );
}
ResultRemoveIgnore::ResultRemoveIgnore( GenericRequest *request, int32_t reply ) : GenericResponse( *request )
{
m_reply = reply;
}
void ResultRemoveIgnore::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
}

View File

@@ -0,0 +1,75 @@
#include "Network/Event/RequestSaveCharacter_RTA.hpp"
#include "Database/Database.hpp"
#include "Game/GameSessionManager.hpp"
#include "Game/CharacterSaveManager.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/RealmUser.hpp"
#include "Game/RealmCharacter.hpp"
#include "logging.hpp"
#include "Common/RLEZ.hpp"
void RequestSaveCharacter_RTA::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
m_memberSessionId = stream->read_encrypted_utf16();
m_targetCharacterId = stream->read_u32();
auto a = stream->read_u32();
auto b = stream->read_u32();
m_metaData.Deserialize( stream );
auto characterDataSize = stream->read_u32();
m_characterData = stream->read_bytes( characterDataSize );
}
sptr_generic_response RequestSaveCharacter_RTA::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto &userManager = UserManager::Get();
auto user = userManager.FindUserBySocket( socket );
if( user == nullptr || user->m_accountId == -1 )
{
return std::make_shared< ResultSaveCharacter_RTA >( this, FATAL_ERROR );
}
sptr_user targetUser = user;
if( m_sessionId != m_memberSessionId )
{
targetUser = userManager.FindUserBySessionId( m_memberSessionId );
}
if( targetUser == nullptr || targetUser->m_accountId == -1 )
{
Log::Error( "Target user not found or invalid account ID for session: {}", m_memberSessionId );
return std::make_shared< ResultSaveCharacter_RTA >( this, FATAL_ERROR );
}
auto characterId = targetUser->m_characterId;
auto &saveManager = CharacterSaveManager::Get();
if( saveManager.BeginSaveTask( user, targetUser, characterId, m_metaData, CharacterSaveType::SAVE_CHARACTER ) )
{
saveManager.AppendSaveData( user->m_sessionId, m_characterData, false );
}
return std::make_shared< ResultSaveCharacter_RTA >( this, SUCCESS );
}
ResultSaveCharacter_RTA::ResultSaveCharacter_RTA( GenericRequest *request, int32_t reply ) : GenericResponse( *request )
{
m_reply = reply;
}
void ResultSaveCharacter_RTA::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
}

View File

@@ -0,0 +1,54 @@
#include "Network/Event/RequestSendInstantMessage.hpp"
#include "Network\Event\NotifyInstantMessage.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/ChatRoomManager.hpp"
#include "logging.hpp"
void RequestSendInstantMessage::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
auto sessionId = stream->read_encrypted_utf16();
m_chatHandle = stream->read_utf16();
m_message = stream->read_utf16();
}
sptr_generic_response RequestSendInstantMessage::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
const auto user = UserManager::Get().FindUserBySocket( socket );
if( !user )
{
Log::Error( "User not found for socket!" );
return std::make_shared< ResultSendInstantMessage >( this, GENERAL_ERROR );
}
auto targetUser = UserManager::Get().FindUserByChatHandle( m_chatHandle );
if( !targetUser )
{
return std::make_shared< ResultSendInstantMessage >( this, GENERAL_ERROR );
}
if( targetUser->IsIgnored( user->m_chatHandle ) )
{
return std::make_shared< ResultSendInstantMessage >( this, USER_IGNORED );
}
targetUser->sock->send( NotifyInstantMessage( user->m_chatHandle, m_message ) );
return std::make_shared< ResultSendInstantMessage >( this, SUCCESS );
}
ResultSendInstantMessage::ResultSendInstantMessage( GenericRequest *request, int32_t reply ) : GenericResponse( *request )
{
m_reply = reply;
}
void ResultSendInstantMessage::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
}

View File

@@ -0,0 +1,72 @@
#include "Network/Event/RequestSendRoomMessage.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/ChatRoomManager.hpp"
#include "Network\Event\NotifyRoomMessage.hpp"
#include "logging.hpp"
void RequestSendRoomMessage::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
auto sessionId = stream->read_encrypted_utf16();
m_roomName = stream->read_utf16();
m_message = stream->read_utf16();
}
sptr_generic_response RequestSendRoomMessage::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
const auto user = UserManager::Get().FindUserBySocket( socket );
if( !user )
{
Log::Error( "User not found for socket!" );
return std::make_shared< ResultSendRoomMessage >( this, GENERAL_ERROR );
}
const auto room = ChatRoomManager::Get().FindRoom( m_roomName );
if( !room )
{
Log::Error( "Chat room not found: {}", m_roomName );
return std::make_shared< ResultSendRoomMessage >( this, GENERAL_ERROR );
}
if( !room->IsMember( user ) )
{
Log::Error( "User [{}] is not a member of chat room [{}]", user->m_chatHandle, m_roomName );
return std::make_shared< ResultSendRoomMessage >( this, GENERAL_ERROR );
}
NotifyRoomMessage msg( m_roomName, user->m_chatHandle, m_message );
for( const auto &member : room->m_members )
{
auto memberUser = member.lock();
if( !memberUser )
continue;
if( memberUser->IsIgnored( user->m_chatHandle ) )
{
continue; // Skip sending to ignored users
}
memberUser->sock->send( msg );
}
return std::make_shared< ResultSendRoomMessage >( this, SUCCESS );
}
ResultSendRoomMessage::ResultSendRoomMessage( GenericRequest *request, int32_t reply ) : GenericResponse( *request )
{
m_reply = reply;
}
void ResultSendRoomMessage::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
}

View File

@@ -0,0 +1,57 @@
#include "Network/Event/RequestStartGame.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/GameSessionManager.hpp"
#include "Game/ChatRoomManager.hpp"
#include "Game/RealmUser.hpp"
#include "logging.hpp"
void RequestStartGame::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
auto sessionId = stream->read_encrypted_utf16();
}
sptr_generic_response RequestStartGame::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
return std::make_shared< ResultStartGame >( this, FATAL_ERROR );
}
auto session = GameSessionManager::Get().FindGame( user->m_gameId, user->m_gameType );
if( session == nullptr )
{
Log::Error( "Game session not found! [%d]", user->m_gameId );
return std::make_shared< ResultStartGame >( this, FATAL_ERROR );
}
if( !GameSessionManager::Get().RequestStart( user ) )
{
Log::Error( "Failed to start game session [{}]", user->m_gameId );
return std::make_shared< ResultStartGame >( this, FATAL_ERROR );
}
if( !ChatRoomManager::Get().CloseGameChatSession( session->m_gameName ) )
{
Log::Error( "Failed to close chat room for game session [{}]", session->m_gameName );
}
return std::make_shared< ResultStartGame >( this, SUCCESS );
}
ResultStartGame::ResultStartGame( GenericRequest *request, int32_t reply ) : GenericResponse( *request )
{
m_reply = reply;
}
void ResultStartGame::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
}

View File

@@ -0,0 +1,38 @@
#include "Network/Event/RequestTouchSession.hpp"
#include "Game/RealmUserManager.hpp"
#include "logging.hpp"
void RequestTouchSession::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
}
sptr_generic_response RequestTouchSession::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
Log::Error( "User not found! [{}]", m_sessionId );
return std::make_shared< ResultTouchSession >( this );
}
return std::make_shared< ResultTouchSession >( this );
}
ResultTouchSession::ResultTouchSession( GenericRequest *request ) : GenericResponse( *request )
{
}
void ResultTouchSession::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( 0 );
}

View File

@@ -0,0 +1,91 @@
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4996)
#endif
#include "Network/Event/RequestUpdateGameData.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/GameSessionManager.hpp"
#include "Game/RealmUser.hpp"
#include "logging.hpp"
void RequestUpdateGameData::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
m_gameData = stream->read_utf8();
}
bool RequestUpdateGameData::ParseGameData( sptr_game_session session )
{
if( session == nullptr || m_gameData.size() < 256 )
{
Log::Error( "Invalid game session or game data size! [{}]", m_sessionId );
return false;
}
session->m_gameData = m_gameData;
int8_t currentPlayers = 0;
int8_t maxPlayers = 0;
char description[ 200 ] = { 0 };
int result = sscanf( m_gameData.c_str(), " %hhd / %hhd :%199[^\r\n]", &currentPlayers, &maxPlayers, description );
if( result >= 2 )
{
session->m_currentPlayers = currentPlayers;
session->m_maximumPlayers = maxPlayers;
session->m_description = ( result == 3 ) ? description : "";
}
else
{
Log::Debug( "Failed to parse game info from: {}", m_gameData );
}
return true;
}
sptr_generic_response RequestUpdateGameData::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
Log::Error( "User not found! [{}]", m_sessionId );
return std::make_shared< ResultUpdateGameData >( this );
}
auto gameSession = GameSessionManager::Get().FindGame( user->m_gameId, user->m_gameType );
if( !ParseGameData( gameSession ) )
{
Log::Error( "Failed to parse game data! [{}]", m_sessionId );
return std::make_shared< ResultUpdateGameData >( this );
}
const auto localAddr = std::string( m_gameData.c_str() + 220, 24 );
user->m_localAddr = localAddr;
return std::make_shared< ResultUpdateGameData >( this );
}
ResultUpdateGameData::ResultUpdateGameData( GenericRequest *request ) : GenericResponse( *request )
{
}
void ResultUpdateGameData::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( 0 );
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif

View File

@@ -0,0 +1,59 @@
#include "Network/Event/RequestUserJoinSuccess.hpp"
#include "Game/GameSessionManager.hpp"
#include "Game/RealmUserManager.hpp"
#include "Game/RealmUser.hpp"
#include "Database/Database.hpp"
#include "logging.hpp"
void RequestUserJoinSuccess::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
m_ownerSessionId = stream->read_encrypted_utf16();
}
sptr_generic_response RequestUserJoinSuccess::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto user = UserManager::Get().FindUserBySocket( socket );
if( user == nullptr )
{
return std::make_shared< ResultUserJoinSuccess >( this, FATAL_ERROR );
}
auto gameSession = GameSessionManager::Get().FindGame( user->m_gameId, user->m_gameType );
if( gameSession == nullptr )
{
Log::Error( "Game session not found for user: {}", user->m_username );
return std::make_shared< ResultUserJoinSuccess >( this, FATAL_ERROR );
}
if( !gameSession->IsJoinable() )
{
Log::Error( "Game session is not open for user: {}", user->m_username );
return std::make_shared< ResultUserJoinSuccess >( this, FATAL_ERROR );
}
if( !gameSession->AddMember( user ) )
{
Log::Error( "Failed to add user {} to game session {}", user->m_username, gameSession->m_gameId );
return std::make_shared< ResultUserJoinSuccess >( this, FATAL_ERROR );
}
return std::make_shared< ResultUserJoinSuccess >( this, SUCCESS );
}
ResultUserJoinSuccess::ResultUserJoinSuccess( GenericRequest *request, int32_t reply ) : GenericResponse( *request )
{
m_reply = reply;
}
void ResultUserJoinSuccess::Serialize( ByteBuffer &out ) const
{
out.write_u16( m_packetId );
out.write_u32( m_trackId );
out.write_u32( m_reply );
}

View File

@@ -0,0 +1,72 @@
#include "Request_5F.h"
#include "../../Game/GameSessionManager.h"
#include "../../Game/RealmUserManager.h"
#include "../../Game/RealmUser.h"
#include "../../Database/Database.h"
#include "../../logging.h"
void Request_5F::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
m_sessionId = stream->read_encrypted_utf16();
m_memberSessionId = stream->read_encrypted_utf16();
}
sptr_generic_response Request_5F::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
Log::Packet( stream->get_buffer(), stream->get_length(), false );
//auto user = UserManager::Get().FindUserBySocket( socket );
//if( user == nullptr )
//{
// return std::make_shared< Result_5F >( this, FATAL_ERROR );
//}
//
//auto targetUser = UserManager::Get().FindUserBySessionId( m_memberSessionId );
//if( targetUser == nullptr || targetUser->m_accountId == -1 )
//{
// Log::Error( "Target user not found or invalid account ID for session: %S", m_memberSessionId.c_str() );
// return std::make_shared< Result_5F >( this, FATAL_ERROR );
//}
//
//auto gameSession = GameSessionManager::Get().FindGame( user->m_gameId, user->m_gameType );
//if( gameSession == nullptr )
//{
// Log::Error( "Game session not found for user: %S", user->m_sessionId.c_str() );
// return std::make_shared< Result_5F >( this, FATAL_ERROR );
//}
//
//if( !gameSession->IsJoinable() )
//{
// Log::Error( "Game session is not open for user: %S", user->m_sessionId.c_str() );
// return std::make_shared< Result_5F >( this, FATAL_ERROR );
//}
//
//if( !gameSession->AddMember( targetUser ) )
//{
// Log::Error( "Failed to add user %S to game session %d", targetUser->m_sessionId.c_str(), gameSession->m_gameIndex );
// return std::make_shared< Result_5F >( this, FATAL_ERROR );
//}
// TODO: Here is more like finalize/confirm joined
return std::make_shared< Result_5F >( this, SUCCESS );
}
Result_5F::Result_5F( GenericRequest *request, int32_t reply ) : GenericResponse( *request )
{
m_reply = reply;
}
ByteBuffer& Result_5F::Serialize()
{
m_stream.write_u16( m_packetId );
m_stream.write_u32( m_trackId );
m_stream.write_u32( m_reply );
return m_stream;
}

View File

@@ -0,0 +1,40 @@
#include "Request_61.h"
void Request_61::Deserialize( sptr_byte_stream stream )
{
DeserializeHeader( stream );
}
sptr_generic_response Request_61::ProcessRequest( sptr_socket socket, sptr_byte_stream stream )
{
Deserialize( stream );
auto publicKey = stream->read_utf8();
auto unknown = stream->read_u32();
return std::make_shared< Result_61 >( this );
}
Result_61::Result_61( GenericRequest *request ) : GenericResponse( *request )
{
}
ByteBuffer&Result_61::Serialize()
{
m_stream.write_u16( m_packetId );
m_stream.write_u32( m_trackId );
m_stream.write_u32( 0 );
// Friends
m_stream.write_u32(1);
m_stream.write_utf16(L"String_1");
m_stream.write_u32(1);
m_stream.write_utf16(L"String_2");
// Ignore
m_stream.write_u32(1);
m_stream.write_utf16(L"String_3");
return m_stream;
}