Chat Room Support

This commit is contained in:
HikikoMarmy
2025-07-01 13:56:24 +01:00
parent 8f029d4c72
commit 57c256b008
4 changed files with 334 additions and 107 deletions

View File

@@ -1,15 +1,77 @@
#include "ChatRoomSession.h" #include "ChatRoomSession.h"
#include "RealmUser.h"
ChatRoomSession::ChatRoomSession() ChatRoomSession::ChatRoomSession()
{ {
m_type = GameType::Public; m_type = RoomType::Public;
m_gameIndex = 0; m_index = 0;
m_gameName.clear(); m_name.clear();
} }
ChatRoomSession::~ChatRoomSession() ChatRoomSession::~ChatRoomSession()
{ {
m_type = GameType::Public; m_type = RoomType::Public;
m_gameIndex = 0; m_index = 0;
m_gameName.clear(); m_name.clear();
}
bool ChatRoomSession::AddMember( sptr_user user )
{
if( !user )
return false;
for( const auto &member : m_members )
{
if( member.lock() == user )
return false; // User already in the room.
}
m_members.push_back( user );
return true;
}
bool ChatRoomSession::RemoveMember( sptr_user user )
{
if( !user )
return false;
auto it = std::remove_if( m_members.begin(), m_members.end(),
[ &user ]( const std::weak_ptr< RealmUser > &member )
{
return member.lock() == user;
} );
if( it == m_members.end() )
{
return false;
}
m_members.erase( it, m_members.end() );
return true;
}
bool ChatRoomSession::IsMember( sptr_user user )
{
if( !user )
return false;
for( const auto &member : m_members )
{
if( member.lock() == user )
return true;
}
return false;
}
bool ChatRoomSession::IsPublic() const
{
return m_type == RoomType::Public;
}
bool ChatRoomSession::IsPrivate() const
{
return m_type == RoomType::Private;
} }

View File

@@ -2,141 +2,294 @@
#include "RealmUser.h" #include "RealmUser.h"
#include "../Network/Event/NotifyRoomMessage.h"
#include "../logging.h" #include "../logging.h"
ChatRoomManager::ChatRoomManager() ChatRoomManager::ChatRoomManager()
{ {
m_chatIndex = 0;
m_chatSessionList.clear(); m_chatSessionList.clear();
m_roomIndex = 0;
CreatePublicRooms();
} }
ChatRoomManager::~ChatRoomManager() ChatRoomManager::~ChatRoomManager()
{ {
} }
void ChatRoomManager::OnDisconnectUser( sptr_user user ) void ChatRoomManager::CreatePublicRooms()
{ {
if( !user || user->m_gameId < 0 ) std::vector< std::wstring > RoomNames = {
return; L"Champions Reborn",
L"Adventurous",
L"Courageous",
L"Champion",
L"Legendary",
L"Epic"
};
const auto gameId = user->m_gameId; for( const auto &name : RoomNames )
{
auto new_session = std::make_shared< ChatRoomSession >();
auto session = FindRoom( gameId ); new_session->m_name = name;
if( !session ) new_session->m_type = ChatRoomSession::RoomType::Public;
return; new_session->m_index = m_roomIndex;
new_session->m_banner = L"";
//auto owner = session->m_owner.lock(); m_chatSessionList[ m_roomIndex++ ] = new_session;
//if( !owner ) }
//{
// Log::Error( "Game session owner not found! [%d]", gameId );
// ForceTerminateChat( gameId );
// return;
//}
//
//if( owner->m_sessionId == user->m_sessionId )
//{
// Log::Info( "Game session owner disconnected! [%d]", gameId );
// ForceTerminateChat( gameId );
//}
} }
bool ChatRoomManager::CreatePublicChatSession( sptr_user owner, std::wstring gameName ) std::vector<sptr_chat_room_session> ChatRoomManager::GetPublicRoomList() const
{ {
auto new_session = std::make_shared< ChatRoomSession >(); std::vector< sptr_chat_room_session > result;
new_session->m_type = ChatRoomSession::GameType::Public; for( const auto &chatSession : m_chatSessionList )
new_session->m_gameIndex = m_chatIndex; {
new_session->m_gameName = L""; if( chatSession.second->m_type == ChatRoomSession::RoomType::Public )
{
result.push_back( chatSession.second );
}
}
std::lock_guard< std::mutex > lock( m_mutex ); return result;
m_chatSessionList.push_back( new_session ); }
m_chatIndex++; bool ChatRoomManager::JoinRoom( sptr_user user, const std::wstring &roomName )
{
if( roomName.empty() || !user )
return false;
auto chatSession = FindRoom( roomName );
if( !chatSession )
{
Log::Error( "Chat room [{}] not found", roomName );
return false;
}
if( !chatSession->AddMember( user ) )
{
Log::Error( "Failed to add user [{}] to chat room [{}]", user->m_username, roomName );
return false;
}
if( chatSession->m_type == ChatRoomSession::RoomType::Public )
{
user->m_publicRoomId = chatSession->m_index;
}
else
{
user->m_privateRoomId = chatSession->m_index;
SendMessageToRoom( roomName, L"", L"User '" + user->m_chatHandle + L"' has joined the room." );
}
Log::Info( "User [{}] joined chat room [{}]", user->m_username, roomName );
return true; return true;
} }
bool ChatRoomManager::CreatePrivateChatSession( sptr_user owner, std::wstring roomName ) bool ChatRoomManager::LeaveRoom( sptr_user user, const std::wstring &roomName )
{ {
for( auto &chatSession : m_chatSessionList ) if( !user || roomName.empty() )
{ return false;
if( chatSession->m_type != ChatRoomSession::GameType::Private )
continue;
if( chatSession->m_gameName == roomName ) auto chatSession = FindRoom( roomName );
if( !chatSession )
{
Log::Error( "Chat room [{}] not found", roomName );
return false;
}
if( !chatSession->RemoveMember( user ) )
{
Log::Error( "Failed to remove user [{}] from chat room [{}]", user->m_username, roomName );
return false;
}
if( chatSession->m_type == ChatRoomSession::RoomType::Private )
{
if( chatSession->m_members.empty() && chatSession->m_moderators.empty() )
{ {
Log::Error( "Game name is already in use! [%S]", roomName.c_str() ); m_chatSessionList.erase( chatSession->m_index );
Log::Debug( "Private chat room [{}] deleted", roomName );
}
user->m_privateRoomId = -1;
}
else
{
user->m_publicRoomId = -1;
}
Log::Info( "User [{}] left chat room [{}]", user->m_username, roomName );
return true;
}
bool ChatRoomManager::LeaveRoom( sptr_user user, const int32_t roomId )
{
if( !user || roomId < 0 )
return false;
const auto chatSession = FindRoom( roomId );
if( !chatSession )
{
Log::Error( "Chat room with ID [{}] not found", roomId );
return false;
}
if( !chatSession->RemoveMember( user ) )
{
Log::Error( "Failed to remove user [{}] from chat room with ID [{}]", user->m_username, roomId );
return false;
}
if( chatSession->m_type == ChatRoomSession::RoomType::Private )
{
if( chatSession->m_members.empty() && chatSession->m_moderators.empty() )
{
m_chatSessionList.erase( roomId );
Log::Info( "Private chat room with ID [{}] deleted", roomId );
}
user->m_privateRoomId = -1;
}
else
{
user->m_publicRoomId = -1;
}
Log::Info( "User [{}] left chat room with ID [{}]", user->m_username, roomId );
return true;
}
void ChatRoomManager::OnDisconnectUser( sptr_user user )
{
if( !user ) return;
LeaveRoom( user, user->m_publicRoomId );
LeaveRoom( user, user->m_privateRoomId );
}
bool ChatRoomManager::CreateGameChatSession( sptr_user owner, std::wstring roomName )
{
for( const auto &chatSession : m_chatSessionList )
{
if( chatSession.second->m_name == roomName )
{
Log::Error( "Chat Room name is already in use! [{}]", roomName );
return false; return false;
} }
} }
auto new_session = std::make_shared< ChatRoomSession >(); auto new_session = std::make_shared< ChatRoomSession >();
new_session->m_type = ChatRoomSession::GameType::Private; new_session->m_type = ChatRoomSession::RoomType::Private;
new_session->m_gameIndex = m_chatIndex; new_session->m_name = roomName;
new_session->m_gameName = roomName; new_session->m_owner = owner;
new_session->m_banner = L"";
new_session->m_index = m_roomIndex;
std::lock_guard< std::mutex > lock( m_mutex ); new_session->AddMember( owner );
m_chatSessionList.push_back( new_session ); owner->m_privateRoomId = m_roomIndex;
m_chatIndex++; m_chatSessionList[ m_roomIndex++ ] = new_session;
return true; return true;
} }
bool ChatRoomManager::ForceTerminateChat( const int32_t gameId ) bool ChatRoomManager::CloseGameChatSession( const std::wstring roomName )
{ {
if( gameId < 0 ) if( roomName.empty() )
return false;
const auto it = std::find_if( m_chatSessionList.begin(), m_chatSessionList.end(),
[ &roomName ]( const auto &pair )
{ {
return pair.second->m_name == roomName;
} );
if( it == m_chatSessionList.end() )
{
Log::Error( "Chat room [{}] not found", roomName );
return false; return false;
} }
std::lock_guard< std::mutex > lock( m_mutex ); auto &chatSession = it->second;
if( chatSession->m_type != ChatRoomSession::RoomType::Private )
auto it = std::find_if( m_chatSessionList.begin(), m_chatSessionList.end(), [ &gameId ]( sptr_chat_room_session chatSession )
{ {
return chatSession->m_gameIndex == gameId; Log::Error( "Chat room [{}] is not a private room", roomName );
} ); return false;
if( it != m_chatSessionList.end() )
{
m_chatSessionList.erase( it );
return true;
} }
return false; for( const auto &member : chatSession->m_members )
}
sptr_chat_room_session ChatRoomManager::FindRoom( const int32_t gameId )
{
if( gameId < 0 ) return nullptr;
std::lock_guard< std::mutex > lock( m_mutex );
for( auto &chatSession : m_chatSessionList )
{ {
if( chatSession->m_gameIndex == gameId ) if( auto user = member.lock() )
{ {
return chatSession; user->m_privateRoomId = -1;
} }
} }
return nullptr; m_chatSessionList.erase( it );
Log::Info( "Chat room [{}] closed", roomName );
return true;
}
void ChatRoomManager::SendMessageToRoom( std::wstring roomName, std::wstring handle, std::wstring message )
{
if( roomName.empty() || message.empty() )
return;
auto chatSession = FindRoom( roomName );
if( !chatSession )
{
Log::Error( "Chat room [{}] not found", roomName );
return;
}
NotifyRoomMessage notifyMessage( roomName, handle, message );
for( const auto &m : chatSession->m_members )
{
if( auto member = m.lock() )
{
member->sock->send( notifyMessage );
}
}
} }
sptr_chat_room_session ChatRoomManager::FindRoom( const std::wstring &gameName ) sptr_chat_room_session ChatRoomManager::FindRoom( const std::wstring &gameName )
{ {
if( gameName.empty() ) return nullptr; if( gameName.empty() )
return nullptr;
std::lock_guard< std::mutex > lock( m_mutex ); for( const auto &chatSession : m_chatSessionList )
for( auto &chatSession : m_chatSessionList )
{ {
if( chatSession->m_gameName == gameName ) if( chatSession.second->m_name == gameName )
{ {
return chatSession; return chatSession.second;
} }
} }
return nullptr; return nullptr;
} }
sptr_chat_room_session ChatRoomManager::FindRoom( const int32_t roomId )
{
if( roomId < 0 )
return nullptr;
auto it = m_chatSessionList.find( roomId );
if( it != m_chatSessionList.end() )
{
return it->second;
}
Log::Error( "Chat room with ID [{}] not found", roomId );
return nullptr;
}

View File

@@ -2,19 +2,17 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <vector>
#include <string> #include <string>
#include <map>
#include "ChatRoomSession.h" #include "ChatRoomSession.h"
class ChatRoomManager { class ChatRoomManager {
private: private:
static inline std::unique_ptr< ChatRoomManager > m_instance; int32_t m_roomIndex = 0;
static inline std::mutex m_mutex; std::map< int32_t, sptr_chat_room_session > m_chatSessionList;
int32_t m_chatIndex;
std::vector< sptr_chat_room_session > m_chatSessionList;
void CreatePublicRooms();
public: public:
ChatRoomManager(); ChatRoomManager();
~ChatRoomManager(); ~ChatRoomManager();
@@ -23,20 +21,22 @@ public:
static ChatRoomManager &Get() static ChatRoomManager &Get()
{ {
std::lock_guard< std::mutex > lock( m_mutex ); static ChatRoomManager instance;
if( m_instance == nullptr ) return instance;
{
m_instance.reset( new ChatRoomManager() );
}
return *m_instance;
} }
void OnDisconnectUser( sptr_user user ); std::vector< sptr_chat_room_session > GetPublicRoomList() const;
bool JoinRoom( sptr_user user, const std::wstring &roomName );
bool LeaveRoom( sptr_user user, const std::wstring &roomName );
bool LeaveRoom( sptr_user user, const int32_t roomId );
void OnDisconnectUser( sptr_user user );
bool CreateGameChatSession( sptr_user user, const std::wstring roomName );
bool CloseGameChatSession( const std::wstring roomName );
void SendMessageToRoom( const std::wstring roomName, const std::wstring handle, const std::wstring message );
bool CreatePublicChatSession( sptr_user user, std::wstring roomName );
bool CreatePrivateChatSession( sptr_user user, std::wstring roomName );
bool ForceTerminateChat( const int32_t gameId );
sptr_chat_room_session FindRoom( const int32_t gameId );
sptr_chat_room_session FindRoom( const std::wstring &roomName ); sptr_chat_room_session FindRoom( const std::wstring &roomName );
sptr_chat_room_session FindRoom( const int32_t roomId );
}; };

View File

@@ -2,6 +2,8 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector>
#include "RealmUser.h" #include "RealmUser.h"
class ChatRoomSession { class ChatRoomSession {
@@ -9,16 +11,26 @@ public:
ChatRoomSession(); ChatRoomSession();
~ChatRoomSession(); ~ChatRoomSession();
enum class GameType bool AddMember( sptr_user user );
{ bool RemoveMember( sptr_user user );
bool IsMember( sptr_user user );
bool IsPublic() const;
bool IsPrivate() const;
enum class RoomType {
Public, Public,
Private Private
} m_type; };
int32_t m_gameIndex; RoomType m_type;
std::wstring m_gameName; int32_t m_index;
std::weak_ptr< RealmUser > m_owner; std::wstring m_name;
std::wstring m_banner;
wptr_user m_owner;
std::vector< wptr_user > m_members;
std::vector< wptr_user > m_moderators;
}; };
typedef std::shared_ptr< ChatRoomSession > sptr_chat_room_session; typedef std::shared_ptr< ChatRoomSession > sptr_chat_room_session;