mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Added missing parts in libnetwork (#2838)
* Network: Set and send the game information over enet Added Callbacks for RoomMember and GetMemberList to Room in preparation for web_services.
This commit is contained in:
		
							parent
							
								
									21204ba488
								
							
						
					
					
						commit
						5d0a1e7efd
					
				
					 9 changed files with 310 additions and 37 deletions
				
			
		|  | @ -388,7 +388,7 @@ set(HEADERS | |||
| 
 | ||||
| create_directory_groups(${SRCS} ${HEADERS}) | ||||
| add_library(core STATIC ${SRCS} ${HEADERS}) | ||||
| target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) | ||||
| target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core) | ||||
| target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp dynarmic fmt) | ||||
| if (ENABLE_WEB_SERVICE) | ||||
|     target_link_libraries(core PUBLIC json-headers web_service) | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ | |||
| #include "core/loader/loader.h" | ||||
| #include "core/memory_setup.h" | ||||
| #include "core/settings.h" | ||||
| #include "network/network.h" | ||||
| #include "video_core/video_core.h" | ||||
| 
 | ||||
| namespace Core { | ||||
|  | @ -188,6 +189,10 @@ void System::Shutdown() { | |||
|     cpu_core = nullptr; | ||||
|     app_loader = nullptr; | ||||
|     telemetry_session = nullptr; | ||||
|     if (auto room_member = Network::GetRoomMember().lock()) { | ||||
|         Network::GameInfo game_info{}; | ||||
|         room_member->SendGameInfo(game_info); | ||||
|     } | ||||
| 
 | ||||
|     LOG_DEBUG(Core, "Shutdown OK"); | ||||
| } | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ | |||
| #include "core/loader/ncch.h" | ||||
| #include "core/loader/smdh.h" | ||||
| #include "core/memory.h" | ||||
| #include "network/network.h" | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Loader namespace
 | ||||
|  | @ -350,6 +351,13 @@ ResultStatus AppLoader_NCCH::Load() { | |||
| 
 | ||||
|     Core::Telemetry().AddField(Telemetry::FieldType::Session, "ProgramId", program_id); | ||||
| 
 | ||||
|     if (auto room_member = Network::GetRoomMember().lock()) { | ||||
|         Network::GameInfo game_info; | ||||
|         ReadTitle(game_info.name); | ||||
|         game_info.id = ncch_header.program_id; | ||||
|         room_member->SendGameInfo(game_info); | ||||
|     } | ||||
| 
 | ||||
|     is_loaded = true; // Set state to loaded
 | ||||
| 
 | ||||
|     result = LoadExec(); // Load the executable into memory for booting
 | ||||
|  |  | |||
|  | @ -13,6 +13,18 @@ | |||
| 
 | ||||
| namespace Network { | ||||
| 
 | ||||
| #ifndef htonll | ||||
| u64 htonll(u64 x) { | ||||
|     return ((1 == htonl(1)) ? (x) : ((uint64_t)htonl((x)&0xFFFFFFFF) << 32) | htonl((x) >> 32)); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifndef ntohll | ||||
| u64 ntohll(u64 x) { | ||||
|     return ((1 == ntohl(1)) ? (x) : ((uint64_t)ntohl((x)&0xFFFFFFFF) << 32) | ntohl((x) >> 32)); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| void Packet::Append(const void* in_data, std::size_t size_in_bytes) { | ||||
|     if (in_data && (size_in_bytes > 0)) { | ||||
|         std::size_t start = data.size(); | ||||
|  | @ -100,6 +112,20 @@ Packet& Packet::operator>>(u32& out_data) { | |||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| Packet& Packet::operator>>(s64& out_data) { | ||||
|     s64 value; | ||||
|     Read(&value, sizeof(value)); | ||||
|     out_data = ntohll(value); | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| Packet& Packet::operator>>(u64& out_data) { | ||||
|     u64 value; | ||||
|     Read(&value, sizeof(value)); | ||||
|     out_data = ntohll(value); | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| Packet& Packet::operator>>(float& out_data) { | ||||
|     Read(&out_data, sizeof(out_data)); | ||||
|     return *this; | ||||
|  | @ -183,6 +209,18 @@ Packet& Packet::operator<<(u32 in_data) { | |||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| Packet& Packet::operator<<(s64 in_data) { | ||||
|     s64 toWrite = htonll(in_data); | ||||
|     Append(&toWrite, sizeof(toWrite)); | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| Packet& Packet::operator<<(u64 in_data) { | ||||
|     u64 toWrite = htonll(in_data); | ||||
|     Append(&toWrite, sizeof(toWrite)); | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| Packet& Packet::operator<<(float in_data) { | ||||
|     Append(&in_data, sizeof(in_data)); | ||||
|     return *this; | ||||
|  |  | |||
|  | @ -72,6 +72,8 @@ public: | |||
|     Packet& operator>>(u16& out_data); | ||||
|     Packet& operator>>(s32& out_data); | ||||
|     Packet& operator>>(u32& out_data); | ||||
|     Packet& operator>>(s64& out_data); | ||||
|     Packet& operator>>(u64& out_data); | ||||
|     Packet& operator>>(float& out_data); | ||||
|     Packet& operator>>(double& out_data); | ||||
|     Packet& operator>>(char* out_data); | ||||
|  | @ -89,6 +91,8 @@ public: | |||
|     Packet& operator<<(u16 in_data); | ||||
|     Packet& operator<<(s32 in_data); | ||||
|     Packet& operator<<(u32 in_data); | ||||
|     Packet& operator<<(s64 in_data); | ||||
|     Packet& operator<<(u64 in_data); | ||||
|     Packet& operator<<(float in_data); | ||||
|     Packet& operator<<(double in_data); | ||||
|     Packet& operator<<(const char* in_data); | ||||
|  |  | |||
|  | @ -4,9 +4,9 @@ | |||
| 
 | ||||
| #include <algorithm> | ||||
| #include <atomic> | ||||
| #include <mutex> | ||||
| #include <random> | ||||
| #include <thread> | ||||
| #include <vector> | ||||
| #include "enet/enet.h" | ||||
| #include "network/packet.h" | ||||
| #include "network/room.h" | ||||
|  | @ -29,12 +29,14 @@ public: | |||
| 
 | ||||
|     struct Member { | ||||
|         std::string nickname;   ///< The nickname of the member.
 | ||||
|         std::string game_name;  ///< The current game of the member
 | ||||
|         GameInfo game_info;     ///< The current game of the member
 | ||||
|         MacAddress mac_address; ///< The assigned mac address of the member.
 | ||||
|         ENetPeer* peer;         ///< The remote peer.
 | ||||
|     }; | ||||
|     using MemberList = std::vector<Member>; | ||||
|     MemberList members; ///< Information about the members of this room.
 | ||||
|     MemberList members;              ///< Information about the members of this room
 | ||||
|     mutable std::mutex member_mutex; ///< Mutex for locking the members list
 | ||||
|     /// This should be a std::shared_mutex as soon as C++17 is supported
 | ||||
| 
 | ||||
|     RoomImpl() | ||||
|         : random_gen(std::random_device()()), NintendoOUI{0x00, 0x1F, 0x32, 0x00, 0x00, 0x00} {} | ||||
|  | @ -147,7 +149,7 @@ void Room::RoomImpl::ServerLoop() { | |||
|                 case IdJoinRequest: | ||||
|                     HandleJoinRequest(&event); | ||||
|                     break; | ||||
|                 case IdSetGameName: | ||||
|                 case IdSetGameInfo: | ||||
|                     HandleGameNamePacket(&event); | ||||
|                     break; | ||||
|                 case IdWifiPacket: | ||||
|  | @ -213,7 +215,10 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) { | |||
|     member.nickname = nickname; | ||||
|     member.peer = event->peer; | ||||
| 
 | ||||
|     members.push_back(std::move(member)); | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(member_mutex); | ||||
|         members.push_back(std::move(member)); | ||||
|     } | ||||
| 
 | ||||
|     // Notify everyone that the room information has changed.
 | ||||
|     BroadcastRoomInformation(); | ||||
|  | @ -223,12 +228,14 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) { | |||
| bool Room::RoomImpl::IsValidNickname(const std::string& nickname) const { | ||||
|     // A nickname is valid if it is not already taken by anybody else in the room.
 | ||||
|     // TODO(B3N30): Check for empty names, spaces, etc.
 | ||||
|     std::lock_guard<std::mutex> lock(member_mutex); | ||||
|     return std::all_of(members.begin(), members.end(), | ||||
|                        [&nickname](const auto& member) { return member.nickname != nickname; }); | ||||
| } | ||||
| 
 | ||||
| bool Room::RoomImpl::IsValidMacAddress(const MacAddress& address) const { | ||||
|     // A MAC address is valid if it is not already taken by anybody else in the room.
 | ||||
|     std::lock_guard<std::mutex> lock(member_mutex); | ||||
|     return std::all_of(members.begin(), members.end(), | ||||
|                        [&address](const auto& member) { return member.mac_address != address; }); | ||||
| } | ||||
|  | @ -279,6 +286,7 @@ void Room::RoomImpl::SendCloseMessage() { | |||
|     packet << static_cast<u8>(IdCloseRoom); | ||||
|     ENetPacket* enet_packet = | ||||
|         enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE); | ||||
|     std::lock_guard<std::mutex> lock(member_mutex); | ||||
|     for (auto& member : members) { | ||||
|         enet_peer_send(member.peer, 0, enet_packet); | ||||
|     } | ||||
|  | @ -295,10 +303,14 @@ void Room::RoomImpl::BroadcastRoomInformation() { | |||
|     packet << room_information.member_slots; | ||||
| 
 | ||||
|     packet << static_cast<u32>(members.size()); | ||||
|     for (const auto& member : members) { | ||||
|         packet << member.nickname; | ||||
|         packet << member.mac_address; | ||||
|         packet << member.game_name; | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(member_mutex); | ||||
|         for (const auto& member : members) { | ||||
|             packet << member.nickname; | ||||
|             packet << member.mac_address; | ||||
|             packet << member.game_info.name; | ||||
|             packet << member.game_info.id; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     ENetPacket* enet_packet = | ||||
|  | @ -335,11 +347,13 @@ void Room::RoomImpl::HandleWifiPacket(const ENetEvent* event) { | |||
|                                                  ENET_PACKET_FLAG_RELIABLE); | ||||
| 
 | ||||
|     if (destination_address == BroadcastMac) { // Send the data to everyone except the sender
 | ||||
|         std::lock_guard<std::mutex> lock(member_mutex); | ||||
|         for (const auto& member : members) { | ||||
|             if (member.peer != event->peer) | ||||
|                 enet_peer_send(member.peer, 0, enet_packet); | ||||
|         } | ||||
|     } else { // Send the data only to the destination client
 | ||||
|         std::lock_guard<std::mutex> lock(member_mutex); | ||||
|         auto member = std::find_if(members.begin(), members.end(), | ||||
|                                    [destination_address](const Member& member) -> bool { | ||||
|                                        return member.mac_address == destination_address; | ||||
|  | @ -361,6 +375,8 @@ void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) { | |||
|     auto CompareNetworkAddress = [event](const Member member) -> bool { | ||||
|         return member.peer == event->peer; | ||||
|     }; | ||||
| 
 | ||||
|     std::lock_guard<std::mutex> lock(member_mutex); | ||||
|     const auto sending_member = std::find_if(members.begin(), members.end(), CompareNetworkAddress); | ||||
|     if (sending_member == members.end()) { | ||||
|         return; // Received a chat message from a unknown sender
 | ||||
|  | @ -385,22 +401,32 @@ void Room::RoomImpl::HandleGameNamePacket(const ENetEvent* event) { | |||
|     in_packet.Append(event->packet->data, event->packet->dataLength); | ||||
| 
 | ||||
|     in_packet.IgnoreBytes(sizeof(u8)); // Igonore the message type
 | ||||
|     std::string game_name; | ||||
|     in_packet >> game_name; | ||||
|     auto member = | ||||
|         std::find_if(members.begin(), members.end(), | ||||
|                      [event](const Member& member) -> bool { return member.peer == event->peer; }); | ||||
|     if (member != members.end()) { | ||||
|         member->game_name = game_name; | ||||
|         BroadcastRoomInformation(); | ||||
|     GameInfo game_info; | ||||
|     in_packet >> game_info.name; | ||||
|     in_packet >> game_info.id; | ||||
| 
 | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(member_mutex); | ||||
|         auto member = | ||||
|             std::find_if(members.begin(), members.end(), [event](const Member& member) -> bool { | ||||
|                 return member.peer == event->peer; | ||||
|             }); | ||||
|         if (member != members.end()) { | ||||
|             member->game_info = game_info; | ||||
|         } | ||||
|     } | ||||
|     BroadcastRoomInformation(); | ||||
| } | ||||
| 
 | ||||
| void Room::RoomImpl::HandleClientDisconnection(ENetPeer* client) { | ||||
|     // Remove the client from the members list.
 | ||||
|     members.erase(std::remove_if(members.begin(), members.end(), | ||||
|                                  [client](const Member& member) { return member.peer == client; }), | ||||
|                   members.end()); | ||||
|     { | ||||
|         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()); | ||||
|     } | ||||
| 
 | ||||
|     // Announce the change to all clients.
 | ||||
|     enet_peer_disconnect(client, 0); | ||||
|  | @ -437,6 +463,19 @@ const RoomInformation& Room::GetRoomInformation() const { | |||
|     return room_impl->room_information; | ||||
| } | ||||
| 
 | ||||
| std::vector<Room::Member> Room::GetRoomMemberList() const { | ||||
|     std::vector<Room::Member> member_list; | ||||
|     std::lock_guard<std::mutex> lock(room_impl->member_mutex); | ||||
|     for (const auto& member_impl : room_impl->members) { | ||||
|         Member member; | ||||
|         member.nickname = member_impl.nickname; | ||||
|         member.mac_address = member_impl.mac_address; | ||||
|         member.game_info = member_impl.game_info; | ||||
|         member_list.push_back(member); | ||||
|     } | ||||
|     return member_list; | ||||
| }; | ||||
| 
 | ||||
| void Room::Destroy() { | ||||
|     room_impl->state = State::Closed; | ||||
|     room_impl->room_thread->join(); | ||||
|  | @ -447,7 +486,10 @@ void Room::Destroy() { | |||
|     } | ||||
|     room_impl->room_information = {}; | ||||
|     room_impl->server = nullptr; | ||||
|     room_impl->members.clear(); | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(room_impl->member_mutex); | ||||
|         room_impl->members.clear(); | ||||
|     } | ||||
|     room_impl->room_information.member_slots = 0; | ||||
|     room_impl->room_information.name.clear(); | ||||
| } | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
| #include <array> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| namespace Network { | ||||
|  | @ -21,6 +22,11 @@ struct RoomInformation { | |||
|     u32 member_slots; ///< Maximum number of members in this room
 | ||||
| }; | ||||
| 
 | ||||
| struct GameInfo { | ||||
|     std::string name{""}; | ||||
|     u64 id{0}; | ||||
| }; | ||||
| 
 | ||||
| using MacAddress = std::array<u8, 6>; | ||||
| /// A special MAC address that tells the room we're joining to assign us a MAC address
 | ||||
| /// automatically.
 | ||||
|  | @ -34,7 +40,7 @@ enum RoomMessageTypes : u8 { | |||
|     IdJoinRequest = 1, | ||||
|     IdJoinSuccess, | ||||
|     IdRoomInformation, | ||||
|     IdSetGameName, | ||||
|     IdSetGameInfo, | ||||
|     IdWifiPacket, | ||||
|     IdChatMessage, | ||||
|     IdNameCollision, | ||||
|  | @ -51,6 +57,12 @@ public: | |||
|         Closed, ///< The room is not opened and can not accept connections.
 | ||||
|     }; | ||||
| 
 | ||||
|     struct Member { | ||||
|         std::string nickname;   ///< The nickname of the member.
 | ||||
|         GameInfo game_info;     ///< The current game of the member
 | ||||
|         MacAddress mac_address; ///< The assigned mac address of the member.
 | ||||
|     }; | ||||
| 
 | ||||
|     Room(); | ||||
|     ~Room(); | ||||
| 
 | ||||
|  | @ -64,6 +76,11 @@ public: | |||
|      */ | ||||
|     const RoomInformation& GetRoomInformation() const; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Gets a list of the mbmers connected to the room. | ||||
|      */ | ||||
|     std::vector<Member> GetRoomMemberList() const; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Creates the socket for this room. Will bind to default address if | ||||
|      * server is empty string. | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
| #include <atomic> | ||||
| #include <list> | ||||
| #include <mutex> | ||||
| #include <set> | ||||
| #include <thread> | ||||
| #include "common/assert.h" | ||||
| #include "enet/enet.h" | ||||
|  | @ -25,6 +26,9 @@ public: | |||
|     /// Information about the room we're connected to.
 | ||||
|     RoomInformation room_information; | ||||
| 
 | ||||
|     /// The current game name, id and version
 | ||||
|     GameInfo current_game_info; | ||||
| 
 | ||||
|     std::atomic<State> state{State::Idle}; ///< Current state of the RoomMember.
 | ||||
|     void SetState(const State new_state); | ||||
|     bool IsConnected() const; | ||||
|  | @ -37,6 +41,24 @@ public: | |||
|     std::unique_ptr<std::thread> loop_thread; | ||||
|     std::mutex send_list_mutex;  ///< Mutex that controls access to the `send_list` variable.
 | ||||
|     std::list<Packet> send_list; ///< A list that stores all packets to send the async
 | ||||
| 
 | ||||
|     template <typename T> | ||||
|     using CallbackSet = std::set<CallbackHandle<T>>; | ||||
|     std::mutex callback_mutex; ///< The mutex used for handling callbacks
 | ||||
| 
 | ||||
|     class Callbacks { | ||||
|     public: | ||||
|         template <typename T> | ||||
|         CallbackSet<T>& Get(); | ||||
| 
 | ||||
|     private: | ||||
|         CallbackSet<WifiPacket> callback_set_wifi_packet; | ||||
|         CallbackSet<ChatEntry> callback_set_chat_messages; | ||||
|         CallbackSet<RoomInformation> callback_set_room_information; | ||||
|         CallbackSet<State> callback_set_state; | ||||
|     }; | ||||
|     Callbacks callbacks; ///< All CallbackSets to all events
 | ||||
| 
 | ||||
|     void MemberLoop(); | ||||
| 
 | ||||
|     void StartLoop(); | ||||
|  | @ -84,12 +106,20 @@ public: | |||
|      * Disconnects the RoomMember from the Room | ||||
|      */ | ||||
|     void Disconnect(); | ||||
| 
 | ||||
|     template <typename T> | ||||
|     void Invoke(const T& data); | ||||
| 
 | ||||
|     template <typename T> | ||||
|     CallbackHandle<T> Bind(std::function<void(const T&)> callback); | ||||
| }; | ||||
| 
 | ||||
| // RoomMemberImpl
 | ||||
| void RoomMember::RoomMemberImpl::SetState(const State new_state) { | ||||
|     state = new_state; | ||||
|     // TODO(B3N30): Invoke the callback functions
 | ||||
|     if (state != new_state) { | ||||
|         state = new_state; | ||||
|         Invoke<State>(state); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool RoomMember::RoomMemberImpl::IsConnected() const { | ||||
|  | @ -195,9 +225,10 @@ void RoomMember::RoomMemberImpl::HandleRoomInformationPacket(const ENetEvent* ev | |||
|     for (auto& member : member_information) { | ||||
|         packet >> member.nickname; | ||||
|         packet >> member.mac_address; | ||||
|         packet >> member.game_name; | ||||
|         packet >> member.game_info.name; | ||||
|         packet >> member.game_info.id; | ||||
|     } | ||||
|     // TODO(B3N30): Invoke callbacks
 | ||||
|     Invoke(room_information); | ||||
| } | ||||
| 
 | ||||
| void RoomMember::RoomMemberImpl::HandleJoinPacket(const ENetEvent* event) { | ||||
|  | @ -209,7 +240,7 @@ void RoomMember::RoomMemberImpl::HandleJoinPacket(const ENetEvent* event) { | |||
| 
 | ||||
|     // Parse the MAC Address from the packet
 | ||||
|     packet >> mac_address; | ||||
|     // TODO(B3N30): Invoke callbacks
 | ||||
|     SetState(State::Joined); | ||||
| } | ||||
| 
 | ||||
| void RoomMember::RoomMemberImpl::HandleWifiPackets(const ENetEvent* event) { | ||||
|  | @ -235,7 +266,7 @@ void RoomMember::RoomMemberImpl::HandleWifiPackets(const ENetEvent* event) { | |||
| 
 | ||||
|     packet >> wifi_packet.data; | ||||
| 
 | ||||
|     // TODO(B3N30): Invoke callbacks
 | ||||
|     Invoke<WifiPacket>(wifi_packet); | ||||
| } | ||||
| 
 | ||||
| void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) { | ||||
|  | @ -248,7 +279,7 @@ void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) { | |||
|     ChatEntry chat_entry{}; | ||||
|     packet >> chat_entry.nickname; | ||||
|     packet >> chat_entry.message; | ||||
|     // TODO(B3N30): Invoke callbacks
 | ||||
|     Invoke<ChatEntry>(chat_entry); | ||||
| } | ||||
| 
 | ||||
| void RoomMember::RoomMemberImpl::Disconnect() { | ||||
|  | @ -276,6 +307,46 @@ void RoomMember::RoomMemberImpl::Disconnect() { | |||
|     server = nullptr; | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| RoomMember::RoomMemberImpl::CallbackSet<WifiPacket>& RoomMember::RoomMemberImpl::Callbacks::Get() { | ||||
|     return callback_set_wifi_packet; | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| RoomMember::RoomMemberImpl::CallbackSet<RoomMember::State>& | ||||
| RoomMember::RoomMemberImpl::Callbacks::Get() { | ||||
|     return callback_set_state; | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| RoomMember::RoomMemberImpl::CallbackSet<RoomInformation>& | ||||
| RoomMember::RoomMemberImpl::Callbacks::Get() { | ||||
|     return callback_set_room_information; | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| RoomMember::RoomMemberImpl::CallbackSet<ChatEntry>& RoomMember::RoomMemberImpl::Callbacks::Get() { | ||||
|     return callback_set_chat_messages; | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| void RoomMember::RoomMemberImpl::Invoke(const T& data) { | ||||
|     std::lock_guard<std::mutex> lock(callback_mutex); | ||||
|     CallbackSet<T> callback_set = callbacks.Get<T>(); | ||||
|     for (auto const& callback : callback_set) | ||||
|         (*callback)(data); | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| RoomMember::CallbackHandle<T> RoomMember::RoomMemberImpl::Bind( | ||||
|     std::function<void(const T&)> callback) { | ||||
|     std::lock_guard<std::mutex> lock(callback_mutex); | ||||
|     CallbackHandle<T> handle; | ||||
|     handle = std::make_shared<std::function<void(const T&)>>(callback); | ||||
|     callbacks.Get<T>().insert(handle); | ||||
|     return handle; | ||||
| } | ||||
| 
 | ||||
| // RoomMember
 | ||||
| RoomMember::RoomMember() : room_member_impl{std::make_unique<RoomMemberImpl>()} { | ||||
|     room_member_impl->client = enet_host_create(nullptr, 1, NumChannels, 0, 0); | ||||
|  | @ -339,6 +410,7 @@ void RoomMember::Join(const std::string& nick, const char* server_addr, u16 serv | |||
|         room_member_impl->SetState(State::Joining); | ||||
|         room_member_impl->StartLoop(); | ||||
|         room_member_impl->SendJoinRequest(nick, preferred_mac); | ||||
|         SendGameInfo(room_member_impl->current_game_info); | ||||
|     } else { | ||||
|         room_member_impl->SetState(State::CouldNotConnect); | ||||
|     } | ||||
|  | @ -366,17 +438,53 @@ void RoomMember::SendChatMessage(const std::string& message) { | |||
|     room_member_impl->Send(std::move(packet)); | ||||
| } | ||||
| 
 | ||||
| void RoomMember::SendGameName(const std::string& game_name) { | ||||
| void RoomMember::SendGameInfo(const GameInfo& game_info) { | ||||
|     room_member_impl->current_game_info = game_info; | ||||
|     if (!IsConnected()) | ||||
|         return; | ||||
| 
 | ||||
|     Packet packet; | ||||
|     packet << static_cast<u8>(IdSetGameName); | ||||
|     packet << game_name; | ||||
|     packet << static_cast<u8>(IdSetGameInfo); | ||||
|     packet << game_info.name; | ||||
|     packet << game_info.id; | ||||
|     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<WifiPacket> RoomMember::BindOnWifiPacketReceived( | ||||
|     std::function<void(const WifiPacket&)> callback) { | ||||
|     return room_member_impl->Bind(callback); | ||||
| } | ||||
| 
 | ||||
| RoomMember::CallbackHandle<RoomInformation> RoomMember::BindOnRoomInformationChanged( | ||||
|     std::function<void(const RoomInformation&)> callback) { | ||||
|     return room_member_impl->Bind(callback); | ||||
| } | ||||
| 
 | ||||
| RoomMember::CallbackHandle<ChatEntry> RoomMember::BindOnChatMessageRecieved( | ||||
|     std::function<void(const ChatEntry&)> 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); | ||||
|     room_member_impl->callbacks.Get<T>().erase(handle); | ||||
| } | ||||
| 
 | ||||
| void RoomMember::Leave() { | ||||
|     room_member_impl->SetState(State::Idle); | ||||
|     room_member_impl->loop_thread->join(); | ||||
|     room_member_impl->loop_thread.reset(); | ||||
| } | ||||
| 
 | ||||
| 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>); | ||||
| 
 | ||||
| } // namespace Network
 | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <functional> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <vector> | ||||
|  | @ -53,12 +54,23 @@ public: | |||
| 
 | ||||
|     struct MemberInformation { | ||||
|         std::string nickname;   ///< Nickname of the member.
 | ||||
|         std::string game_name;  ///< Name of the game they're currently playing, or empty if they're
 | ||||
|         GameInfo game_info;     ///< Name of the game they're currently playing, or empty if they're
 | ||||
|                                 /// not playing anything.
 | ||||
|         MacAddress mac_address; ///< MAC address associated with this member.
 | ||||
|     }; | ||||
|     using MemberList = std::vector<MemberInformation>; | ||||
| 
 | ||||
|     // The handle for the callback functions
 | ||||
|     template <typename T> | ||||
|     using CallbackHandle = std::shared_ptr<std::function<void(const T&)>>; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Unbinds a callback function from the events. | ||||
|      * @param handle The connection handle to disconnect | ||||
|      */ | ||||
|     template <typename T> | ||||
|     void Unbind(CallbackHandle<T> handle); | ||||
| 
 | ||||
|     RoomMember(); | ||||
|     ~RoomMember(); | ||||
| 
 | ||||
|  | @ -113,10 +125,49 @@ public: | |||
|     void SendChatMessage(const std::string& message); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Sends the current game name  to the room. | ||||
|      * @param game_name The game name. | ||||
|      * Sends the current game info to the room. | ||||
|      * @param game_info The game information. | ||||
|      */ | ||||
|     void SendGameName(const std::string& game_name); | ||||
|     void SendGameInfo(const GameInfo& game_info); | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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 | ||||
|      * 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<State> BindOnStateChanged(std::function<void(const State&)> 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. | ||||
|      * 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<WifiPacket> BindOnWifiPacketReceived( | ||||
|         std::function<void(const WifiPacket&)> callback); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Binds a function to an event that will be triggered every time the RoomInformation changes. | ||||
|      * 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<RoomInformation> BindOnRoomInformationChanged( | ||||
|         std::function<void(const RoomInformation&)> callback); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Binds a function to an event that will be triggered every time a ChatMessage is received. | ||||
|      * 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<ChatEntry> BindOnChatMessageRecieved( | ||||
|         std::function<void(const ChatEntry&)> callback); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Leaves the current room. | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue