mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	multiplayer: Add status message for user joining/leaving
The room server is now able to send a new type of packet: IdStatusMessage which is parsed and displayed by the client.
This commit is contained in:
		
							parent
							
								
									386bf5c861
								
							
						
					
					
						commit
						0319e51960
					
				
					 6 changed files with 134 additions and 7 deletions
				
			
		|  | @ -127,6 +127,12 @@ public: | |||
|      */ | ||||
|     void SendCloseMessage(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Sends a system message to all the connected clients. | ||||
|      */ | ||||
|     void SendStatusMessage(StatusMessageTypes type, const std::string& nickname, | ||||
|                            const std::string& username); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Sends the information about the room, along with the list of members | ||||
|      * to every connected client in the room. | ||||
|  | @ -290,6 +296,9 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) { | |||
|     } | ||||
|     member.user_data = verify_backend->LoadUserData(uid, token); | ||||
| 
 | ||||
|     // Notify everyone that the user has joined.
 | ||||
|     SendStatusMessage(IdMemberJoin, member.nickname, member.user_data.username); | ||||
| 
 | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(member_mutex); | ||||
|         members.push_back(std::move(member)); | ||||
|  | @ -415,6 +424,24 @@ void Room::RoomImpl::SendCloseMessage() { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void Room::RoomImpl::SendStatusMessage(StatusMessageTypes type, const std::string& nickname, | ||||
|                                        const std::string& username) { | ||||
|     Packet packet; | ||||
|     packet << static_cast<u8>(IdStatusMessage); | ||||
|     packet << static_cast<u8>(type); | ||||
|     packet << nickname; | ||||
|     packet << username; | ||||
|     std::lock_guard<std::mutex> lock(member_mutex); | ||||
|     if (!members.empty()) { | ||||
|         ENetPacket* enet_packet = | ||||
|             enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE); | ||||
|         for (auto& member : members) { | ||||
|             enet_peer_send(member.peer, 0, enet_packet); | ||||
|         } | ||||
|     } | ||||
|     enet_host_flush(server); | ||||
| } | ||||
| 
 | ||||
| void Room::RoomImpl::BroadcastRoomInformation() { | ||||
|     Packet packet; | ||||
|     packet << static_cast<u8>(IdRoomInformation); | ||||
|  | @ -571,16 +598,23 @@ void Room::RoomImpl::HandleGameNamePacket(const ENetEvent* event) { | |||
| 
 | ||||
| void Room::RoomImpl::HandleClientDisconnection(ENetPeer* client) { | ||||
|     // Remove the client from the members list.
 | ||||
|     std::string nickname, username; | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(member_mutex); | ||||
|         members.erase( | ||||
|             std::remove_if(members.begin(), members.end(), | ||||
|                            [client](const Member& member) { return member.peer == client; }), | ||||
|             members.end()); | ||||
|         auto member = std::find_if(members.begin(), members.end(), [client](const Member& member) { | ||||
|             return member.peer == client; | ||||
|         }); | ||||
|         if (member != members.end()) { | ||||
|             nickname = member->nickname; | ||||
|             username = member->user_data.username; | ||||
|             members.erase(member); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Announce the change to all clients.
 | ||||
|     enet_peer_disconnect(client, 0); | ||||
|     if (!nickname.empty()) | ||||
|         SendStatusMessage(IdMemberLeave, nickname, username); | ||||
|     BroadcastRoomInformation(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -61,6 +61,13 @@ enum RoomMessageTypes : u8 { | |||
|     IdCloseRoom, | ||||
|     IdRoomIsFull, | ||||
|     IdConsoleIdCollision, | ||||
|     IdStatusMessage, | ||||
| }; | ||||
| 
 | ||||
| /// Types of system status messages
 | ||||
| enum StatusMessageTypes : u8 { | ||||
|     IdMemberJoin = 1, ///< Member joining
 | ||||
|     IdMemberLeave,    ///< Member leaving
 | ||||
| }; | ||||
| 
 | ||||
| /// This is what a server [person creating a server] would use.
 | ||||
|  |  | |||
|  | @ -58,6 +58,7 @@ public: | |||
|     private: | ||||
|         CallbackSet<WifiPacket> callback_set_wifi_packet; | ||||
|         CallbackSet<ChatEntry> callback_set_chat_messages; | ||||
|         CallbackSet<StatusMessageEntry> callback_set_status_messages; | ||||
|         CallbackSet<RoomInformation> callback_set_room_information; | ||||
|         CallbackSet<State> callback_set_state; | ||||
|     }; | ||||
|  | @ -109,6 +110,13 @@ public: | |||
|      */ | ||||
|     void HandleChatPacket(const ENetEvent* event); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Extracts a system message entry from a received ENet packet and adds it to the system message | ||||
|      * queue. | ||||
|      * @param event The ENet event that was received. | ||||
|      */ | ||||
|     void HandleStatusMessagePacket(const ENetEvent* event); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Disconnects the RoomMember from the Room | ||||
|      */ | ||||
|  | @ -148,6 +156,9 @@ void RoomMember::RoomMemberImpl::MemberLoop() { | |||
|                 case IdChatMessage: | ||||
|                     HandleChatPacket(&event); | ||||
|                     break; | ||||
|                 case IdStatusMessage: | ||||
|                     HandleStatusMessagePacket(&event); | ||||
|                     break; | ||||
|                 case IdRoomInformation: | ||||
|                     HandleRoomInformationPacket(&event); | ||||
|                     break; | ||||
|  | @ -317,6 +328,22 @@ void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) { | |||
|     Invoke<ChatEntry>(chat_entry); | ||||
| } | ||||
| 
 | ||||
| void RoomMember::RoomMemberImpl::HandleStatusMessagePacket(const ENetEvent* event) { | ||||
|     Packet packet; | ||||
|     packet.Append(event->packet->data, event->packet->dataLength); | ||||
| 
 | ||||
|     // Ignore the first byte, which is the message id.
 | ||||
|     packet.IgnoreBytes(sizeof(u8)); | ||||
| 
 | ||||
|     StatusMessageEntry status_message_entry{}; | ||||
|     u8 type{}; | ||||
|     packet >> type; | ||||
|     status_message_entry.type = static_cast<StatusMessageTypes>(type); | ||||
|     packet >> status_message_entry.nickname; | ||||
|     packet >> status_message_entry.username; | ||||
|     Invoke<StatusMessageEntry>(status_message_entry); | ||||
| } | ||||
| 
 | ||||
| void RoomMember::RoomMemberImpl::Disconnect() { | ||||
|     member_information.clear(); | ||||
|     room_information.member_slots = 0; | ||||
|  | @ -367,6 +394,12 @@ RoomMember::RoomMemberImpl::CallbackSet<ChatEntry>& RoomMember::RoomMemberImpl:: | |||
|     return callback_set_chat_messages; | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| RoomMember::RoomMemberImpl::CallbackSet<StatusMessageEntry>& | ||||
| RoomMember::RoomMemberImpl::Callbacks::Get() { | ||||
|     return callback_set_status_messages; | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| void RoomMember::RoomMemberImpl::Invoke(const T& data) { | ||||
|     std::lock_guard<std::mutex> lock(callback_mutex); | ||||
|  | @ -519,6 +552,11 @@ RoomMember::CallbackHandle<ChatEntry> RoomMember::BindOnChatMessageRecieved( | |||
|     return room_member_impl->Bind(callback); | ||||
| } | ||||
| 
 | ||||
| RoomMember::CallbackHandle<StatusMessageEntry> RoomMember::BindOnStatusMessageReceived( | ||||
|     std::function<void(const StatusMessageEntry&)> callback) { | ||||
|     return room_member_impl->Bind(callback); | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| void RoomMember::Unbind(CallbackHandle<T> handle) { | ||||
|     std::lock_guard<std::mutex> lock(room_member_impl->callback_mutex); | ||||
|  | @ -538,5 +576,6 @@ template void RoomMember::Unbind(CallbackHandle<WifiPacket>); | |||
| template void RoomMember::Unbind(CallbackHandle<RoomMember::State>); | ||||
| template void RoomMember::Unbind(CallbackHandle<RoomInformation>); | ||||
| template void RoomMember::Unbind(CallbackHandle<ChatEntry>); | ||||
| template void RoomMember::Unbind(CallbackHandle<StatusMessageEntry>); | ||||
| 
 | ||||
| } // namespace Network
 | ||||
|  |  | |||
|  | @ -40,6 +40,14 @@ struct ChatEntry { | |||
|     std::string message; ///< Body of the message.
 | ||||
| }; | ||||
| 
 | ||||
| /// Represents a system status message.
 | ||||
| struct StatusMessageEntry { | ||||
|     StatusMessageTypes type; ///< Type of the message
 | ||||
|     /// Subject of the message. i.e. the user who is joining/leaving/being banned, etc.
 | ||||
|     std::string nickname; | ||||
|     std::string username; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * This is what a client [person joining a server] would use. | ||||
|  * It also has to be used if you host a game yourself (You'd create both, a Room and a | ||||
|  | @ -192,6 +200,16 @@ public: | |||
|     CallbackHandle<ChatEntry> BindOnChatMessageRecieved( | ||||
|         std::function<void(const ChatEntry&)> callback); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Binds a function to an event that will be triggered every time a StatusMessage is | ||||
|      * received. The function will be called every time the event is triggered. The callback | ||||
|      * function must not bind or unbind a function. Doing so will cause a deadlock | ||||
|      * @param callback The function to call | ||||
|      * @return A handle used for removing the function from the registered list | ||||
|      */ | ||||
|     CallbackHandle<StatusMessageEntry> BindOnStatusMessageReceived( | ||||
|         std::function<void(const StatusMessageEntry&)> callback); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Leaves the current room. | ||||
|      */ | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue