mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	network/room_member: Add moderation functions
To allow for passing moderation errors around without impacting the State, this commit also separates the previous State enum into two enums: State, and Error. The State enum now only contains generic states like disconnected or connected, and the Error enum describes the specific error happened.
citra_qt/multiplayer/{state, message} is changed accordingly.
			
			
This commit is contained in:
		
							parent
							
								
									38f86cce94
								
							
						
					
					
						commit
						7acd2664dd
					
				
					 6 changed files with 251 additions and 56 deletions
				
			
		|  | @ -31,6 +31,7 @@ public: | |||
| 
 | ||||
|     std::atomic<State> state{State::Idle}; ///< Current state of the RoomMember.
 | ||||
|     void SetState(const State new_state); | ||||
|     void SetError(const Error new_error); | ||||
|     bool IsConnected() const; | ||||
| 
 | ||||
|     std::string nickname; ///< The nickname of this member.
 | ||||
|  | @ -61,6 +62,8 @@ public: | |||
|         CallbackSet<StatusMessageEntry> callback_set_status_messages; | ||||
|         CallbackSet<RoomInformation> callback_set_room_information; | ||||
|         CallbackSet<State> callback_set_state; | ||||
|         CallbackSet<Error> callback_set_error; | ||||
|         CallbackSet<Room::BanList> callback_set_ban_list; | ||||
|     }; | ||||
|     Callbacks callbacks; ///< All CallbackSets to all events
 | ||||
| 
 | ||||
|  | @ -117,6 +120,12 @@ public: | |||
|      */ | ||||
|     void HandleStatusMessagePacket(const ENetEvent* event); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Extracts a ban list request response from a received ENet packet. | ||||
|      * @param event The ENet event that was received. | ||||
|      */ | ||||
|     void HandleModBanListResponsePacket(const ENetEvent* event); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Disconnects the RoomMember from the Room | ||||
|      */ | ||||
|  | @ -137,6 +146,10 @@ void RoomMember::RoomMemberImpl::SetState(const State new_state) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void RoomMember::RoomMemberImpl::SetError(const Error new_error) { | ||||
|     Invoke<Error>(new_error); | ||||
| } | ||||
| 
 | ||||
| bool RoomMember::RoomMemberImpl::IsConnected() const { | ||||
|     return state == State::Joining || state == State::Joined; | ||||
| } | ||||
|  | @ -170,32 +183,59 @@ void RoomMember::RoomMemberImpl::MemberLoop() { | |||
|                     HandleJoinPacket(&event); // Get the MAC Address for the client
 | ||||
|                     SetState(State::Joined); | ||||
|                     break; | ||||
|                 case IdModBanListResponse: | ||||
|                     HandleModBanListResponsePacket(&event); | ||||
|                     break; | ||||
|                 case IdRoomIsFull: | ||||
|                     SetState(State::RoomIsFull); | ||||
|                     SetState(State::Idle); | ||||
|                     SetError(Error::RoomIsFull); | ||||
|                     break; | ||||
|                 case IdNameCollision: | ||||
|                     SetState(State::NameCollision); | ||||
|                     SetState(State::Idle); | ||||
|                     SetError(Error::NameCollision); | ||||
|                     break; | ||||
|                 case IdMacCollision: | ||||
|                     SetState(State::MacCollision); | ||||
|                     SetState(State::Idle); | ||||
|                     SetError(Error::MacCollision); | ||||
|                     break; | ||||
|                 case IdConsoleIdCollision: | ||||
|                     SetState(State::ConsoleIdCollision); | ||||
|                     SetState(State::Idle); | ||||
|                     SetError(Error::ConsoleIdCollision); | ||||
|                     break; | ||||
|                 case IdVersionMismatch: | ||||
|                     SetState(State::WrongVersion); | ||||
|                     SetState(State::Idle); | ||||
|                     SetError(Error::WrongVersion); | ||||
|                     break; | ||||
|                 case IdWrongPassword: | ||||
|                     SetState(State::WrongPassword); | ||||
|                     SetState(State::Idle); | ||||
|                     SetError(Error::WrongPassword); | ||||
|                     break; | ||||
|                 case IdCloseRoom: | ||||
|                     SetState(State::LostConnection); | ||||
|                     SetState(State::Idle); | ||||
|                     SetError(Error::LostConnection); | ||||
|                     break; | ||||
|                 case IdHostKicked: | ||||
|                     SetState(State::Idle); | ||||
|                     SetError(Error::HostKicked); | ||||
|                     break; | ||||
|                 case IdHostBanned: | ||||
|                     SetState(State::Idle); | ||||
|                     SetError(Error::HostBanned); | ||||
|                     break; | ||||
|                 case IdModPermissionDenied: | ||||
|                     SetError(Error::PermissionDenied); | ||||
|                     break; | ||||
|                 case IdModNoSuchUser: | ||||
|                     SetError(Error::NoSuchUser); | ||||
|                     break; | ||||
|                 } | ||||
|                 enet_packet_destroy(event.packet); | ||||
|                 break; | ||||
|             case ENET_EVENT_TYPE_DISCONNECT: | ||||
|                 SetState(State::LostConnection); | ||||
|                 if (state == State::Joined) { | ||||
|                     SetState(State::Idle); | ||||
|                     SetError(Error::LostConnection); | ||||
|                 } | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | @ -251,11 +291,13 @@ void RoomMember::RoomMemberImpl::HandleRoomInformationPacket(const ENetEvent* ev | |||
|     packet >> info.member_slots; | ||||
|     packet >> info.port; | ||||
|     packet >> info.preferred_game; | ||||
|     packet >> info.host_username; | ||||
|     room_information.name = info.name; | ||||
|     room_information.description = info.description; | ||||
|     room_information.member_slots = info.member_slots; | ||||
|     room_information.port = info.port; | ||||
|     room_information.preferred_game = info.preferred_game; | ||||
|     room_information.host_username = info.host_username; | ||||
| 
 | ||||
|     u32 num_members; | ||||
|     packet >> num_members; | ||||
|  | @ -344,6 +386,19 @@ void RoomMember::RoomMemberImpl::HandleStatusMessagePacket(const ENetEvent* even | |||
|     Invoke<StatusMessageEntry>(status_message_entry); | ||||
| } | ||||
| 
 | ||||
| void RoomMember::RoomMemberImpl::HandleModBanListResponsePacket(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)); | ||||
| 
 | ||||
|     Room::BanList ban_list = {}; | ||||
|     packet >> ban_list.first; | ||||
|     packet >> ban_list.second; | ||||
|     Invoke<Room::BanList>(ban_list); | ||||
| } | ||||
| 
 | ||||
| void RoomMember::RoomMemberImpl::Disconnect() { | ||||
|     member_information.clear(); | ||||
|     room_information.member_slots = 0; | ||||
|  | @ -383,6 +438,12 @@ RoomMember::RoomMemberImpl::Callbacks::Get() { | |||
|     return callback_set_state; | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| RoomMember::RoomMemberImpl::CallbackSet<RoomMember::Error>& | ||||
| RoomMember::RoomMemberImpl::Callbacks::Get() { | ||||
|     return callback_set_error; | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| RoomMember::RoomMemberImpl::CallbackSet<RoomInformation>& | ||||
| RoomMember::RoomMemberImpl::Callbacks::Get() { | ||||
|  | @ -400,6 +461,12 @@ RoomMember::RoomMemberImpl::Callbacks::Get() { | |||
|     return callback_set_status_messages; | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| RoomMember::RoomMemberImpl::CallbackSet<Room::BanList>& | ||||
| RoomMember::RoomMemberImpl::Callbacks::Get() { | ||||
|     return callback_set_ban_list; | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| void RoomMember::RoomMemberImpl::Invoke(const T& data) { | ||||
|     std::lock_guard<std::mutex> lock(callback_mutex); | ||||
|  | @ -481,7 +548,8 @@ void RoomMember::Join(const std::string& nick, const std::string& console_id_has | |||
|         enet_host_connect(room_member_impl->client, &address, NumChannels, 0); | ||||
| 
 | ||||
|     if (!room_member_impl->server) { | ||||
|         room_member_impl->SetState(State::Error); | ||||
|         room_member_impl->SetState(State::Idle); | ||||
|         room_member_impl->SetError(Error::UnknownError); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|  | @ -494,7 +562,8 @@ void RoomMember::Join(const std::string& nick, const std::string& console_id_has | |||
|         SendGameInfo(room_member_impl->current_game_info); | ||||
|     } else { | ||||
|         enet_peer_disconnect(room_member_impl->server, 0); | ||||
|         room_member_impl->SetState(State::CouldNotConnect); | ||||
|         room_member_impl->SetState(State::Idle); | ||||
|         room_member_impl->SetError(Error::CouldNotConnect); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -532,11 +601,37 @@ void RoomMember::SendGameInfo(const GameInfo& game_info) { | |||
|     room_member_impl->Send(std::move(packet)); | ||||
| } | ||||
| 
 | ||||
| void RoomMember::SendModerationRequest(RoomMessageTypes type, const std::string& nickname) { | ||||
|     ASSERT_MSG(type == IdModKick || type == IdModBan || type == IdModUnban, | ||||
|                "type is not a moderation request"); | ||||
|     if (!IsConnected()) | ||||
|         return; | ||||
| 
 | ||||
|     Packet packet; | ||||
|     packet << static_cast<u8>(type); | ||||
|     packet << nickname; | ||||
|     room_member_impl->Send(std::move(packet)); | ||||
| } | ||||
| 
 | ||||
| void RoomMember::RequestBanList() { | ||||
|     if (!IsConnected()) | ||||
|         return; | ||||
| 
 | ||||
|     Packet packet; | ||||
|     packet << static_cast<u8>(IdModGetBanList); | ||||
|     room_member_impl->Send(std::move(packet)); | ||||
| } | ||||
| 
 | ||||
| RoomMember::CallbackHandle<RoomMember::State> RoomMember::BindOnStateChanged( | ||||
|     std::function<void(const RoomMember::State&)> callback) { | ||||
|     return room_member_impl->Bind(callback); | ||||
| } | ||||
| 
 | ||||
| RoomMember::CallbackHandle<RoomMember::Error> RoomMember::BindOnError( | ||||
|     std::function<void(const RoomMember::Error&)> callback) { | ||||
|     return room_member_impl->Bind(callback); | ||||
| } | ||||
| 
 | ||||
| RoomMember::CallbackHandle<WifiPacket> RoomMember::BindOnWifiPacketReceived( | ||||
|     std::function<void(const WifiPacket&)> callback) { | ||||
|     return room_member_impl->Bind(callback); | ||||
|  | @ -557,6 +652,11 @@ RoomMember::CallbackHandle<StatusMessageEntry> RoomMember::BindOnStatusMessageRe | |||
|     return room_member_impl->Bind(callback); | ||||
| } | ||||
| 
 | ||||
| RoomMember::CallbackHandle<Room::BanList> RoomMember::BindOnBanListReceived( | ||||
|     std::function<void(const Room::BanList&)> 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); | ||||
|  | @ -574,8 +674,10 @@ void RoomMember::Leave() { | |||
| 
 | ||||
| template void RoomMember::Unbind(CallbackHandle<WifiPacket>); | ||||
| template void RoomMember::Unbind(CallbackHandle<RoomMember::State>); | ||||
| template void RoomMember::Unbind(CallbackHandle<RoomMember::Error>); | ||||
| template void RoomMember::Unbind(CallbackHandle<RoomInformation>); | ||||
| template void RoomMember::Unbind(CallbackHandle<ChatEntry>); | ||||
| template void RoomMember::Unbind(CallbackHandle<StatusMessageEntry>); | ||||
| template void RoomMember::Unbind(CallbackHandle<Room::BanList>); | ||||
| 
 | ||||
| } // namespace Network
 | ||||
|  |  | |||
|  | @ -57,20 +57,30 @@ class RoomMember final { | |||
| public: | ||||
|     enum class State : u8 { | ||||
|         Uninitialized, ///< Not initialized
 | ||||
|         Idle,          ///< Default state
 | ||||
|         Error,         ///< Some error [permissions to network device missing or something]
 | ||||
|         Idle,          ///< Default state (i.e. not connected)
 | ||||
|         Joining,       ///< The client is attempting to join a room.
 | ||||
|         Joined, ///< The client is connected to the room and is ready to send/receive packets.
 | ||||
|     }; | ||||
| 
 | ||||
|     enum class Error : u8 { | ||||
|         // Reasons why connection was closed
 | ||||
|         LostConnection, ///< Connection closed
 | ||||
|         HostKicked,     ///< Kicked by the host
 | ||||
| 
 | ||||
|         // Reasons why connection was rejected
 | ||||
|         UnknownError,       ///< Some error [permissions to network device missing or something]
 | ||||
|         NameCollision,      ///< Somebody is already using this name
 | ||||
|         MacCollision,       ///< Somebody is already using that mac-address
 | ||||
|         ConsoleIdCollision, ///< Somebody in the room has the same Console ID
 | ||||
|         WrongVersion,       ///< The room version is not the same as for this RoomMember
 | ||||
|         WrongPassword,      ///< The password doesn't match the one from the Room
 | ||||
|         CouldNotConnect,    ///< The room is not responding to a connection attempt
 | ||||
|         RoomIsFull          ///< Room is already at the maximum number of players
 | ||||
|         RoomIsFull,         ///< Room is already at the maximum number of players
 | ||||
|         HostBanned,         ///< The user is banned by the host
 | ||||
| 
 | ||||
|         // Reasons why moderation request failed
 | ||||
|         PermissionDenied, ///< The user does not have mod permissions
 | ||||
|         NoSuchUser,       ///< The nickname the user attempts to kick/ban does not exist
 | ||||
|     }; | ||||
| 
 | ||||
|     struct MemberInformation { | ||||
|  | @ -161,6 +171,19 @@ public: | |||
|      */ | ||||
|     void SendGameInfo(const GameInfo& game_info); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Sends a moderation request to the room. | ||||
|      * @param type Moderation request type. | ||||
|      * @param nickname The subject of the request. (i.e. the user you want to kick/ban) | ||||
|      */ | ||||
|     void SendModerationRequest(RoomMessageTypes type, const std::string& nickname); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Attempts to retrieve ban list from the room. | ||||
|      * If success, the ban list callback would be called. Otherwise an error would be emitted. | ||||
|      */ | ||||
|     void RequestBanList(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Binds a function to an event that will be triggered every time the State of the member | ||||
|      * changed. The function wil be called every time the event is triggered. The callback function | ||||
|  | @ -170,6 +193,15 @@ public: | |||
|      */ | ||||
|     CallbackHandle<State> BindOnStateChanged(std::function<void(const State&)> callback); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Binds a function to an event that will be triggered every time an error happened. The | ||||
|      * function wil 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<Error> BindOnError(std::function<void(const Error&)> callback); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Binds a function to an event that will be triggered every time a WifiPacket is received. | ||||
|      * The function wil be called everytime the event is triggered. | ||||
|  | @ -210,6 +242,16 @@ public: | |||
|     CallbackHandle<StatusMessageEntry> BindOnStatusMessageReceived( | ||||
|         std::function<void(const StatusMessageEntry&)> callback); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Binds a function to an event that will be triggered every time a requested ban list | ||||
|      * 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<Room::BanList> BindOnBanListReceived( | ||||
|         std::function<void(const Room::BanList&)> callback); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Leaves the current room. | ||||
|      */ | ||||
|  | @ -224,24 +266,42 @@ static const char* GetStateStr(const RoomMember::State& s) { | |||
|     switch (s) { | ||||
|     case RoomMember::State::Idle: | ||||
|         return "Idle"; | ||||
|     case RoomMember::State::Error: | ||||
|         return "Error"; | ||||
|     case RoomMember::State::Joining: | ||||
|         return "Joining"; | ||||
|     case RoomMember::State::Joined: | ||||
|         return "Joined"; | ||||
|     case RoomMember::State::LostConnection: | ||||
|     } | ||||
|     return "Unknown"; | ||||
| } | ||||
| 
 | ||||
| static const char* GetErrorStr(const RoomMember::Error& e) { | ||||
|     switch (e) { | ||||
|     case RoomMember::Error::LostConnection: | ||||
|         return "LostConnection"; | ||||
|     case RoomMember::State::NameCollision: | ||||
|     case RoomMember::Error::HostKicked: | ||||
|         return "HostKicked"; | ||||
|     case RoomMember::Error::UnknownError: | ||||
|         return "UnknownError"; | ||||
|     case RoomMember::Error::NameCollision: | ||||
|         return "NameCollision"; | ||||
|     case RoomMember::State::MacCollision: | ||||
|         return "MacCollision"; | ||||
|     case RoomMember::State::WrongVersion: | ||||
|     case RoomMember::Error::MacCollision: | ||||
|         return "MaxCollision"; | ||||
|     case RoomMember::Error::ConsoleIdCollision: | ||||
|         return "ConsoleIdCollision"; | ||||
|     case RoomMember::Error::WrongVersion: | ||||
|         return "WrongVersion"; | ||||
|     case RoomMember::State::WrongPassword: | ||||
|     case RoomMember::Error::WrongPassword: | ||||
|         return "WrongPassword"; | ||||
|     case RoomMember::State::CouldNotConnect: | ||||
|     case RoomMember::Error::CouldNotConnect: | ||||
|         return "CouldNotConnect"; | ||||
|     case RoomMember::Error::RoomIsFull: | ||||
|         return "RoomIsFull"; | ||||
|     case RoomMember::Error::HostBanned: | ||||
|         return "HostBanned"; | ||||
|     case RoomMember::Error::PermissionDenied: | ||||
|         return "PermissionDenied"; | ||||
|     case RoomMember::Error::NoSuchUser: | ||||
|         return "NoSuchUser"; | ||||
|     } | ||||
|     return "Unknown"; | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue