mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu.git
				synced 2025-05-12 00:45:25 +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
					
				| @ -388,7 +388,7 @@ set(HEADERS | |||||||
| 
 | 
 | ||||||
| create_directory_groups(${SRCS} ${HEADERS}) | create_directory_groups(${SRCS} ${HEADERS}) | ||||||
| add_library(core STATIC ${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) | target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp dynarmic fmt) | ||||||
| if (ENABLE_WEB_SERVICE) | if (ENABLE_WEB_SERVICE) | ||||||
|     target_link_libraries(core PUBLIC json-headers web_service) |     target_link_libraries(core PUBLIC json-headers web_service) | ||||||
|  | |||||||
| @ -19,6 +19,7 @@ | |||||||
| #include "core/loader/loader.h" | #include "core/loader/loader.h" | ||||||
| #include "core/memory_setup.h" | #include "core/memory_setup.h" | ||||||
| #include "core/settings.h" | #include "core/settings.h" | ||||||
|  | #include "network/network.h" | ||||||
| #include "video_core/video_core.h" | #include "video_core/video_core.h" | ||||||
| 
 | 
 | ||||||
| namespace Core { | namespace Core { | ||||||
| @ -188,6 +189,10 @@ void System::Shutdown() { | |||||||
|     cpu_core = nullptr; |     cpu_core = nullptr; | ||||||
|     app_loader = nullptr; |     app_loader = nullptr; | ||||||
|     telemetry_session = 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"); |     LOG_DEBUG(Core, "Shutdown OK"); | ||||||
| } | } | ||||||
|  | |||||||
| @ -20,6 +20,7 @@ | |||||||
| #include "core/loader/ncch.h" | #include "core/loader/ncch.h" | ||||||
| #include "core/loader/smdh.h" | #include "core/loader/smdh.h" | ||||||
| #include "core/memory.h" | #include "core/memory.h" | ||||||
|  | #include "network/network.h" | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| // Loader namespace
 | // Loader namespace
 | ||||||
| @ -350,6 +351,13 @@ ResultStatus AppLoader_NCCH::Load() { | |||||||
| 
 | 
 | ||||||
|     Core::Telemetry().AddField(Telemetry::FieldType::Session, "ProgramId", program_id); |     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
 |     is_loaded = true; // Set state to loaded
 | ||||||
| 
 | 
 | ||||||
|     result = LoadExec(); // Load the executable into memory for booting
 |     result = LoadExec(); // Load the executable into memory for booting
 | ||||||
|  | |||||||
| @ -13,6 +13,18 @@ | |||||||
| 
 | 
 | ||||||
| namespace Network { | 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) { | void Packet::Append(const void* in_data, std::size_t size_in_bytes) { | ||||||
|     if (in_data && (size_in_bytes > 0)) { |     if (in_data && (size_in_bytes > 0)) { | ||||||
|         std::size_t start = data.size(); |         std::size_t start = data.size(); | ||||||
| @ -100,6 +112,20 @@ Packet& Packet::operator>>(u32& out_data) { | |||||||
|     return *this; |     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) { | Packet& Packet::operator>>(float& out_data) { | ||||||
|     Read(&out_data, sizeof(out_data)); |     Read(&out_data, sizeof(out_data)); | ||||||
|     return *this; |     return *this; | ||||||
| @ -183,6 +209,18 @@ Packet& Packet::operator<<(u32 in_data) { | |||||||
|     return *this; |     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) { | Packet& Packet::operator<<(float in_data) { | ||||||
|     Append(&in_data, sizeof(in_data)); |     Append(&in_data, sizeof(in_data)); | ||||||
|     return *this; |     return *this; | ||||||
|  | |||||||
| @ -72,6 +72,8 @@ public: | |||||||
|     Packet& operator>>(u16& out_data); |     Packet& operator>>(u16& out_data); | ||||||
|     Packet& operator>>(s32& out_data); |     Packet& operator>>(s32& out_data); | ||||||
|     Packet& operator>>(u32& out_data); |     Packet& operator>>(u32& out_data); | ||||||
|  |     Packet& operator>>(s64& out_data); | ||||||
|  |     Packet& operator>>(u64& out_data); | ||||||
|     Packet& operator>>(float& out_data); |     Packet& operator>>(float& out_data); | ||||||
|     Packet& operator>>(double& out_data); |     Packet& operator>>(double& out_data); | ||||||
|     Packet& operator>>(char* out_data); |     Packet& operator>>(char* out_data); | ||||||
| @ -89,6 +91,8 @@ public: | |||||||
|     Packet& operator<<(u16 in_data); |     Packet& operator<<(u16 in_data); | ||||||
|     Packet& operator<<(s32 in_data); |     Packet& operator<<(s32 in_data); | ||||||
|     Packet& operator<<(u32 in_data); |     Packet& operator<<(u32 in_data); | ||||||
|  |     Packet& operator<<(s64 in_data); | ||||||
|  |     Packet& operator<<(u64 in_data); | ||||||
|     Packet& operator<<(float in_data); |     Packet& operator<<(float in_data); | ||||||
|     Packet& operator<<(double in_data); |     Packet& operator<<(double in_data); | ||||||
|     Packet& operator<<(const char* in_data); |     Packet& operator<<(const char* in_data); | ||||||
|  | |||||||
| @ -4,9 +4,9 @@ | |||||||
| 
 | 
 | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <atomic> | #include <atomic> | ||||||
|  | #include <mutex> | ||||||
| #include <random> | #include <random> | ||||||
| #include <thread> | #include <thread> | ||||||
| #include <vector> |  | ||||||
| #include "enet/enet.h" | #include "enet/enet.h" | ||||||
| #include "network/packet.h" | #include "network/packet.h" | ||||||
| #include "network/room.h" | #include "network/room.h" | ||||||
| @ -29,12 +29,14 @@ public: | |||||||
| 
 | 
 | ||||||
|     struct Member { |     struct Member { | ||||||
|         std::string nickname;   ///< The nickname of the 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.
 |         MacAddress mac_address; ///< The assigned mac address of the member.
 | ||||||
|         ENetPeer* peer;         ///< The remote peer.
 |         ENetPeer* peer;         ///< The remote peer.
 | ||||||
|     }; |     }; | ||||||
|     using MemberList = std::vector<Member>; |     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() |     RoomImpl() | ||||||
|         : random_gen(std::random_device()()), NintendoOUI{0x00, 0x1F, 0x32, 0x00, 0x00, 0x00} {} |         : random_gen(std::random_device()()), NintendoOUI{0x00, 0x1F, 0x32, 0x00, 0x00, 0x00} {} | ||||||
| @ -147,7 +149,7 @@ void Room::RoomImpl::ServerLoop() { | |||||||
|                 case IdJoinRequest: |                 case IdJoinRequest: | ||||||
|                     HandleJoinRequest(&event); |                     HandleJoinRequest(&event); | ||||||
|                     break; |                     break; | ||||||
|                 case IdSetGameName: |                 case IdSetGameInfo: | ||||||
|                     HandleGameNamePacket(&event); |                     HandleGameNamePacket(&event); | ||||||
|                     break; |                     break; | ||||||
|                 case IdWifiPacket: |                 case IdWifiPacket: | ||||||
| @ -213,7 +215,10 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) { | |||||||
|     member.nickname = nickname; |     member.nickname = nickname; | ||||||
|     member.peer = event->peer; |     member.peer = event->peer; | ||||||
| 
 | 
 | ||||||
|  |     { | ||||||
|  |         std::lock_guard<std::mutex> lock(member_mutex); | ||||||
|         members.push_back(std::move(member)); |         members.push_back(std::move(member)); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     // Notify everyone that the room information has changed.
 |     // Notify everyone that the room information has changed.
 | ||||||
|     BroadcastRoomInformation(); |     BroadcastRoomInformation(); | ||||||
| @ -223,12 +228,14 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) { | |||||||
| bool Room::RoomImpl::IsValidNickname(const std::string& nickname) const { | 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.
 |     // A nickname is valid if it is not already taken by anybody else in the room.
 | ||||||
|     // TODO(B3N30): Check for empty names, spaces, etc.
 |     // TODO(B3N30): Check for empty names, spaces, etc.
 | ||||||
|  |     std::lock_guard<std::mutex> lock(member_mutex); | ||||||
|     return std::all_of(members.begin(), members.end(), |     return std::all_of(members.begin(), members.end(), | ||||||
|                        [&nickname](const auto& member) { return member.nickname != nickname; }); |                        [&nickname](const auto& member) { return member.nickname != nickname; }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool Room::RoomImpl::IsValidMacAddress(const MacAddress& address) const { | 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.
 |     // 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(), |     return std::all_of(members.begin(), members.end(), | ||||||
|                        [&address](const auto& member) { return member.mac_address != address; }); |                        [&address](const auto& member) { return member.mac_address != address; }); | ||||||
| } | } | ||||||
| @ -279,6 +286,7 @@ void Room::RoomImpl::SendCloseMessage() { | |||||||
|     packet << static_cast<u8>(IdCloseRoom); |     packet << static_cast<u8>(IdCloseRoom); | ||||||
|     ENetPacket* enet_packet = |     ENetPacket* enet_packet = | ||||||
|         enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE); |         enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE); | ||||||
|  |     std::lock_guard<std::mutex> lock(member_mutex); | ||||||
|     for (auto& member : members) { |     for (auto& member : members) { | ||||||
|         enet_peer_send(member.peer, 0, enet_packet); |         enet_peer_send(member.peer, 0, enet_packet); | ||||||
|     } |     } | ||||||
| @ -295,10 +303,14 @@ void Room::RoomImpl::BroadcastRoomInformation() { | |||||||
|     packet << room_information.member_slots; |     packet << room_information.member_slots; | ||||||
| 
 | 
 | ||||||
|     packet << static_cast<u32>(members.size()); |     packet << static_cast<u32>(members.size()); | ||||||
|  |     { | ||||||
|  |         std::lock_guard<std::mutex> lock(member_mutex); | ||||||
|         for (const auto& member : members) { |         for (const auto& member : members) { | ||||||
|             packet << member.nickname; |             packet << member.nickname; | ||||||
|             packet << member.mac_address; |             packet << member.mac_address; | ||||||
|         packet << member.game_name; |             packet << member.game_info.name; | ||||||
|  |             packet << member.game_info.id; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ENetPacket* enet_packet = |     ENetPacket* enet_packet = | ||||||
| @ -335,11 +347,13 @@ void Room::RoomImpl::HandleWifiPacket(const ENetEvent* event) { | |||||||
|                                                  ENET_PACKET_FLAG_RELIABLE); |                                                  ENET_PACKET_FLAG_RELIABLE); | ||||||
| 
 | 
 | ||||||
|     if (destination_address == BroadcastMac) { // Send the data to everyone except the sender
 |     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) { |         for (const auto& member : members) { | ||||||
|             if (member.peer != event->peer) |             if (member.peer != event->peer) | ||||||
|                 enet_peer_send(member.peer, 0, enet_packet); |                 enet_peer_send(member.peer, 0, enet_packet); | ||||||
|         } |         } | ||||||
|     } else { // Send the data only to the destination client
 |     } 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(), |         auto member = std::find_if(members.begin(), members.end(), | ||||||
|                                    [destination_address](const Member& member) -> bool { |                                    [destination_address](const Member& member) -> bool { | ||||||
|                                        return member.mac_address == destination_address; |                                        return member.mac_address == destination_address; | ||||||
| @ -361,6 +375,8 @@ void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) { | |||||||
|     auto CompareNetworkAddress = [event](const Member member) -> bool { |     auto CompareNetworkAddress = [event](const Member member) -> bool { | ||||||
|         return member.peer == event->peer; |         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); |     const auto sending_member = std::find_if(members.begin(), members.end(), CompareNetworkAddress); | ||||||
|     if (sending_member == members.end()) { |     if (sending_member == members.end()) { | ||||||
|         return; // Received a chat message from a unknown sender
 |         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.Append(event->packet->data, event->packet->dataLength); | ||||||
| 
 | 
 | ||||||
|     in_packet.IgnoreBytes(sizeof(u8)); // Igonore the message type
 |     in_packet.IgnoreBytes(sizeof(u8)); // Igonore the message type
 | ||||||
|     std::string game_name; |     GameInfo game_info; | ||||||
|     in_packet >> game_name; |     in_packet >> game_info.name; | ||||||
|  |     in_packet >> game_info.id; | ||||||
|  | 
 | ||||||
|  |     { | ||||||
|  |         std::lock_guard<std::mutex> lock(member_mutex); | ||||||
|         auto member = |         auto member = | ||||||
|         std::find_if(members.begin(), members.end(), |             std::find_if(members.begin(), members.end(), [event](const Member& member) -> bool { | ||||||
|                      [event](const Member& member) -> bool { return member.peer == event->peer; }); |                 return member.peer == event->peer; | ||||||
|  |             }); | ||||||
|         if (member != members.end()) { |         if (member != members.end()) { | ||||||
|         member->game_name = game_name; |             member->game_info = game_info; | ||||||
|         BroadcastRoomInformation(); |  | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  |     BroadcastRoomInformation(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Room::RoomImpl::HandleClientDisconnection(ENetPeer* client) { | void Room::RoomImpl::HandleClientDisconnection(ENetPeer* client) { | ||||||
|     // Remove the client from the members list.
 |     // Remove the client from the members list.
 | ||||||
|     members.erase(std::remove_if(members.begin(), 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; }), |                            [client](const Member& member) { return member.peer == client; }), | ||||||
|             members.end()); |             members.end()); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     // Announce the change to all clients.
 |     // Announce the change to all clients.
 | ||||||
|     enet_peer_disconnect(client, 0); |     enet_peer_disconnect(client, 0); | ||||||
| @ -437,6 +463,19 @@ const RoomInformation& Room::GetRoomInformation() const { | |||||||
|     return room_impl->room_information; |     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() { | void Room::Destroy() { | ||||||
|     room_impl->state = State::Closed; |     room_impl->state = State::Closed; | ||||||
|     room_impl->room_thread->join(); |     room_impl->room_thread->join(); | ||||||
| @ -447,7 +486,10 @@ void Room::Destroy() { | |||||||
|     } |     } | ||||||
|     room_impl->room_information = {}; |     room_impl->room_information = {}; | ||||||
|     room_impl->server = nullptr; |     room_impl->server = nullptr; | ||||||
|  |     { | ||||||
|  |         std::lock_guard<std::mutex> lock(room_impl->member_mutex); | ||||||
|         room_impl->members.clear(); |         room_impl->members.clear(); | ||||||
|  |     } | ||||||
|     room_impl->room_information.member_slots = 0; |     room_impl->room_information.member_slots = 0; | ||||||
|     room_impl->room_information.name.clear(); |     room_impl->room_information.name.clear(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ | |||||||
| #include <array> | #include <array> | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <string> | #include <string> | ||||||
|  | #include <vector> | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| 
 | 
 | ||||||
| namespace Network { | namespace Network { | ||||||
| @ -21,6 +22,11 @@ struct RoomInformation { | |||||||
|     u32 member_slots; ///< Maximum number of members in this room
 |     u32 member_slots; ///< Maximum number of members in this room
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct GameInfo { | ||||||
|  |     std::string name{""}; | ||||||
|  |     u64 id{0}; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| using MacAddress = std::array<u8, 6>; | using MacAddress = std::array<u8, 6>; | ||||||
| /// A special MAC address that tells the room we're joining to assign us a MAC address
 | /// A special MAC address that tells the room we're joining to assign us a MAC address
 | ||||||
| /// automatically.
 | /// automatically.
 | ||||||
| @ -34,7 +40,7 @@ enum RoomMessageTypes : u8 { | |||||||
|     IdJoinRequest = 1, |     IdJoinRequest = 1, | ||||||
|     IdJoinSuccess, |     IdJoinSuccess, | ||||||
|     IdRoomInformation, |     IdRoomInformation, | ||||||
|     IdSetGameName, |     IdSetGameInfo, | ||||||
|     IdWifiPacket, |     IdWifiPacket, | ||||||
|     IdChatMessage, |     IdChatMessage, | ||||||
|     IdNameCollision, |     IdNameCollision, | ||||||
| @ -51,6 +57,12 @@ public: | |||||||
|         Closed, ///< The room is not opened and can not accept connections.
 |         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(); | ||||||
|     ~Room(); |     ~Room(); | ||||||
| 
 | 
 | ||||||
| @ -64,6 +76,11 @@ public: | |||||||
|      */ |      */ | ||||||
|     const RoomInformation& GetRoomInformation() const; |     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 |      * Creates the socket for this room. Will bind to default address if | ||||||
|      * server is empty string. |      * server is empty string. | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ | |||||||
| #include <atomic> | #include <atomic> | ||||||
| #include <list> | #include <list> | ||||||
| #include <mutex> | #include <mutex> | ||||||
|  | #include <set> | ||||||
| #include <thread> | #include <thread> | ||||||
| #include "common/assert.h" | #include "common/assert.h" | ||||||
| #include "enet/enet.h" | #include "enet/enet.h" | ||||||
| @ -25,6 +26,9 @@ public: | |||||||
|     /// Information about the room we're connected to.
 |     /// Information about the room we're connected to.
 | ||||||
|     RoomInformation room_information; |     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.
 |     std::atomic<State> state{State::Idle}; ///< Current state of the RoomMember.
 | ||||||
|     void SetState(const State new_state); |     void SetState(const State new_state); | ||||||
|     bool IsConnected() const; |     bool IsConnected() const; | ||||||
| @ -37,6 +41,24 @@ public: | |||||||
|     std::unique_ptr<std::thread> loop_thread; |     std::unique_ptr<std::thread> loop_thread; | ||||||
|     std::mutex send_list_mutex;  ///< Mutex that controls access to the `send_list` variable.
 |     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
 |     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 MemberLoop(); | ||||||
| 
 | 
 | ||||||
|     void StartLoop(); |     void StartLoop(); | ||||||
| @ -84,12 +106,20 @@ public: | |||||||
|      * Disconnects the RoomMember from the Room |      * Disconnects the RoomMember from the Room | ||||||
|      */ |      */ | ||||||
|     void Disconnect(); |     void Disconnect(); | ||||||
|  | 
 | ||||||
|  |     template <typename T> | ||||||
|  |     void Invoke(const T& data); | ||||||
|  | 
 | ||||||
|  |     template <typename T> | ||||||
|  |     CallbackHandle<T> Bind(std::function<void(const T&)> callback); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // RoomMemberImpl
 | // RoomMemberImpl
 | ||||||
| void RoomMember::RoomMemberImpl::SetState(const State new_state) { | void RoomMember::RoomMemberImpl::SetState(const State new_state) { | ||||||
|  |     if (state != new_state) { | ||||||
|         state = new_state; |         state = new_state; | ||||||
|     // TODO(B3N30): Invoke the callback functions
 |         Invoke<State>(state); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool RoomMember::RoomMemberImpl::IsConnected() const { | bool RoomMember::RoomMemberImpl::IsConnected() const { | ||||||
| @ -195,9 +225,10 @@ void RoomMember::RoomMemberImpl::HandleRoomInformationPacket(const ENetEvent* ev | |||||||
|     for (auto& member : member_information) { |     for (auto& member : member_information) { | ||||||
|         packet >> member.nickname; |         packet >> member.nickname; | ||||||
|         packet >> member.mac_address; |         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) { | 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
 |     // Parse the MAC Address from the packet
 | ||||||
|     packet >> mac_address; |     packet >> mac_address; | ||||||
|     // TODO(B3N30): Invoke callbacks
 |     SetState(State::Joined); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RoomMember::RoomMemberImpl::HandleWifiPackets(const ENetEvent* event) { | void RoomMember::RoomMemberImpl::HandleWifiPackets(const ENetEvent* event) { | ||||||
| @ -235,7 +266,7 @@ void RoomMember::RoomMemberImpl::HandleWifiPackets(const ENetEvent* event) { | |||||||
| 
 | 
 | ||||||
|     packet >> wifi_packet.data; |     packet >> wifi_packet.data; | ||||||
| 
 | 
 | ||||||
|     // TODO(B3N30): Invoke callbacks
 |     Invoke<WifiPacket>(wifi_packet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) { | void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) { | ||||||
| @ -248,7 +279,7 @@ void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) { | |||||||
|     ChatEntry chat_entry{}; |     ChatEntry chat_entry{}; | ||||||
|     packet >> chat_entry.nickname; |     packet >> chat_entry.nickname; | ||||||
|     packet >> chat_entry.message; |     packet >> chat_entry.message; | ||||||
|     // TODO(B3N30): Invoke callbacks
 |     Invoke<ChatEntry>(chat_entry); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RoomMember::RoomMemberImpl::Disconnect() { | void RoomMember::RoomMemberImpl::Disconnect() { | ||||||
| @ -276,6 +307,46 @@ void RoomMember::RoomMemberImpl::Disconnect() { | |||||||
|     server = nullptr; |     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::RoomMember() : room_member_impl{std::make_unique<RoomMemberImpl>()} { | RoomMember::RoomMember() : room_member_impl{std::make_unique<RoomMemberImpl>()} { | ||||||
|     room_member_impl->client = enet_host_create(nullptr, 1, NumChannels, 0, 0); |     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->SetState(State::Joining); | ||||||
|         room_member_impl->StartLoop(); |         room_member_impl->StartLoop(); | ||||||
|         room_member_impl->SendJoinRequest(nick, preferred_mac); |         room_member_impl->SendJoinRequest(nick, preferred_mac); | ||||||
|  |         SendGameInfo(room_member_impl->current_game_info); | ||||||
|     } else { |     } else { | ||||||
|         room_member_impl->SetState(State::CouldNotConnect); |         room_member_impl->SetState(State::CouldNotConnect); | ||||||
|     } |     } | ||||||
| @ -366,17 +438,53 @@ void RoomMember::SendChatMessage(const std::string& message) { | |||||||
|     room_member_impl->Send(std::move(packet)); |     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 packet; | ||||||
|     packet << static_cast<u8>(IdSetGameName); |     packet << static_cast<u8>(IdSetGameInfo); | ||||||
|     packet << game_name; |     packet << game_info.name; | ||||||
|  |     packet << game_info.id; | ||||||
|     room_member_impl->Send(std::move(packet)); |     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() { | void RoomMember::Leave() { | ||||||
|     room_member_impl->SetState(State::Idle); |     room_member_impl->SetState(State::Idle); | ||||||
|     room_member_impl->loop_thread->join(); |     room_member_impl->loop_thread->join(); | ||||||
|     room_member_impl->loop_thread.reset(); |     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
 | } // namespace Network
 | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ | |||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include <functional> | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <string> | #include <string> | ||||||
| #include <vector> | #include <vector> | ||||||
| @ -53,12 +54,23 @@ public: | |||||||
| 
 | 
 | ||||||
|     struct MemberInformation { |     struct MemberInformation { | ||||||
|         std::string nickname;   ///< Nickname of the member.
 |         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.
 |                                 /// not playing anything.
 | ||||||
|         MacAddress mac_address; ///< MAC address associated with this member.
 |         MacAddress mac_address; ///< MAC address associated with this member.
 | ||||||
|     }; |     }; | ||||||
|     using MemberList = std::vector<MemberInformation>; |     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(); | ||||||
|     ~RoomMember(); |     ~RoomMember(); | ||||||
| 
 | 
 | ||||||
| @ -113,10 +125,49 @@ public: | |||||||
|     void SendChatMessage(const std::string& message); |     void SendChatMessage(const std::string& message); | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Sends the current game name  to the room. |      * Sends the current game info to the room. | ||||||
|      * @param game_name The game name. |      * @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. |      * Leaves the current room. | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 B3n30
						B3n30