summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/core.cpp5
-rw-r--r--src/core/loader/ncch.cpp8
-rw-r--r--src/network/packet.cpp38
-rw-r--r--src/network/packet.h4
-rw-r--r--src/network/room.cpp84
-rw-r--r--src/network/room.h19
-rw-r--r--src/network/room_member.cpp128
-rw-r--r--src/network/room_member.h59
9 files changed, 310 insertions, 37 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 360f407f3..0a6f97e4b 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -388,7 +388,7 @@ set(HEADERS
388 388
389create_directory_groups(${SRCS} ${HEADERS}) 389create_directory_groups(${SRCS} ${HEADERS})
390add_library(core STATIC ${SRCS} ${HEADERS}) 390add_library(core STATIC ${SRCS} ${HEADERS})
391target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) 391target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core)
392target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp dynarmic fmt) 392target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp dynarmic fmt)
393if (ENABLE_WEB_SERVICE) 393if (ENABLE_WEB_SERVICE)
394 target_link_libraries(core PUBLIC json-headers web_service) 394 target_link_libraries(core PUBLIC json-headers web_service)
diff --git a/src/core/core.cpp b/src/core/core.cpp
index d08f18623..5332318cf 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -19,6 +19,7 @@
19#include "core/loader/loader.h" 19#include "core/loader/loader.h"
20#include "core/memory_setup.h" 20#include "core/memory_setup.h"
21#include "core/settings.h" 21#include "core/settings.h"
22#include "network/network.h"
22#include "video_core/video_core.h" 23#include "video_core/video_core.h"
23 24
24namespace Core { 25namespace Core {
@@ -188,6 +189,10 @@ void System::Shutdown() {
188 cpu_core = nullptr; 189 cpu_core = nullptr;
189 app_loader = nullptr; 190 app_loader = nullptr;
190 telemetry_session = nullptr; 191 telemetry_session = nullptr;
192 if (auto room_member = Network::GetRoomMember().lock()) {
193 Network::GameInfo game_info{};
194 room_member->SendGameInfo(game_info);
195 }
191 196
192 LOG_DEBUG(Core, "Shutdown OK"); 197 LOG_DEBUG(Core, "Shutdown OK");
193} 198}
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index c007069a9..7aff7f29b 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -20,6 +20,7 @@
20#include "core/loader/ncch.h" 20#include "core/loader/ncch.h"
21#include "core/loader/smdh.h" 21#include "core/loader/smdh.h"
22#include "core/memory.h" 22#include "core/memory.h"
23#include "network/network.h"
23 24
24//////////////////////////////////////////////////////////////////////////////////////////////////// 25////////////////////////////////////////////////////////////////////////////////////////////////////
25// Loader namespace 26// Loader namespace
@@ -350,6 +351,13 @@ ResultStatus AppLoader_NCCH::Load() {
350 351
351 Core::Telemetry().AddField(Telemetry::FieldType::Session, "ProgramId", program_id); 352 Core::Telemetry().AddField(Telemetry::FieldType::Session, "ProgramId", program_id);
352 353
354 if (auto room_member = Network::GetRoomMember().lock()) {
355 Network::GameInfo game_info;
356 ReadTitle(game_info.name);
357 game_info.id = ncch_header.program_id;
358 room_member->SendGameInfo(game_info);
359 }
360
353 is_loaded = true; // Set state to loaded 361 is_loaded = true; // Set state to loaded
354 362
355 result = LoadExec(); // Load the executable into memory for booting 363 result = LoadExec(); // Load the executable into memory for booting
diff --git a/src/network/packet.cpp b/src/network/packet.cpp
index 660e92c0d..cc60f2fbc 100644
--- a/src/network/packet.cpp
+++ b/src/network/packet.cpp
@@ -13,6 +13,18 @@
13 13
14namespace Network { 14namespace Network {
15 15
16#ifndef htonll
17u64 htonll(u64 x) {
18 return ((1 == htonl(1)) ? (x) : ((uint64_t)htonl((x)&0xFFFFFFFF) << 32) | htonl((x) >> 32));
19}
20#endif
21
22#ifndef ntohll
23u64 ntohll(u64 x) {
24 return ((1 == ntohl(1)) ? (x) : ((uint64_t)ntohl((x)&0xFFFFFFFF) << 32) | ntohl((x) >> 32));
25}
26#endif
27
16void Packet::Append(const void* in_data, std::size_t size_in_bytes) { 28void Packet::Append(const void* in_data, std::size_t size_in_bytes) {
17 if (in_data && (size_in_bytes > 0)) { 29 if (in_data && (size_in_bytes > 0)) {
18 std::size_t start = data.size(); 30 std::size_t start = data.size();
@@ -100,6 +112,20 @@ Packet& Packet::operator>>(u32& out_data) {
100 return *this; 112 return *this;
101} 113}
102 114
115Packet& Packet::operator>>(s64& out_data) {
116 s64 value;
117 Read(&value, sizeof(value));
118 out_data = ntohll(value);
119 return *this;
120}
121
122Packet& Packet::operator>>(u64& out_data) {
123 u64 value;
124 Read(&value, sizeof(value));
125 out_data = ntohll(value);
126 return *this;
127}
128
103Packet& Packet::operator>>(float& out_data) { 129Packet& Packet::operator>>(float& out_data) {
104 Read(&out_data, sizeof(out_data)); 130 Read(&out_data, sizeof(out_data));
105 return *this; 131 return *this;
@@ -183,6 +209,18 @@ Packet& Packet::operator<<(u32 in_data) {
183 return *this; 209 return *this;
184} 210}
185 211
212Packet& Packet::operator<<(s64 in_data) {
213 s64 toWrite = htonll(in_data);
214 Append(&toWrite, sizeof(toWrite));
215 return *this;
216}
217
218Packet& Packet::operator<<(u64 in_data) {
219 u64 toWrite = htonll(in_data);
220 Append(&toWrite, sizeof(toWrite));
221 return *this;
222}
223
186Packet& Packet::operator<<(float in_data) { 224Packet& Packet::operator<<(float in_data) {
187 Append(&in_data, sizeof(in_data)); 225 Append(&in_data, sizeof(in_data));
188 return *this; 226 return *this;
diff --git a/src/network/packet.h b/src/network/packet.h
index 94b351ab1..5a2e58dc2 100644
--- a/src/network/packet.h
+++ b/src/network/packet.h
@@ -72,6 +72,8 @@ public:
72 Packet& operator>>(u16& out_data); 72 Packet& operator>>(u16& out_data);
73 Packet& operator>>(s32& out_data); 73 Packet& operator>>(s32& out_data);
74 Packet& operator>>(u32& out_data); 74 Packet& operator>>(u32& out_data);
75 Packet& operator>>(s64& out_data);
76 Packet& operator>>(u64& out_data);
75 Packet& operator>>(float& out_data); 77 Packet& operator>>(float& out_data);
76 Packet& operator>>(double& out_data); 78 Packet& operator>>(double& out_data);
77 Packet& operator>>(char* out_data); 79 Packet& operator>>(char* out_data);
@@ -89,6 +91,8 @@ public:
89 Packet& operator<<(u16 in_data); 91 Packet& operator<<(u16 in_data);
90 Packet& operator<<(s32 in_data); 92 Packet& operator<<(s32 in_data);
91 Packet& operator<<(u32 in_data); 93 Packet& operator<<(u32 in_data);
94 Packet& operator<<(s64 in_data);
95 Packet& operator<<(u64 in_data);
92 Packet& operator<<(float in_data); 96 Packet& operator<<(float in_data);
93 Packet& operator<<(double in_data); 97 Packet& operator<<(double in_data);
94 Packet& operator<<(const char* in_data); 98 Packet& operator<<(const char* in_data);
diff --git a/src/network/room.cpp b/src/network/room.cpp
index fbbaf8b93..261049ab0 100644
--- a/src/network/room.cpp
+++ b/src/network/room.cpp
@@ -4,9 +4,9 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <atomic> 6#include <atomic>
7#include <mutex>
7#include <random> 8#include <random>
8#include <thread> 9#include <thread>
9#include <vector>
10#include "enet/enet.h" 10#include "enet/enet.h"
11#include "network/packet.h" 11#include "network/packet.h"
12#include "network/room.h" 12#include "network/room.h"
@@ -29,12 +29,14 @@ public:
29 29
30 struct Member { 30 struct Member {
31 std::string nickname; ///< The nickname of the member. 31 std::string nickname; ///< The nickname of the member.
32 std::string game_name; ///< The current game of the member 32 GameInfo game_info; ///< The current game of the member
33 MacAddress mac_address; ///< The assigned mac address of the member. 33 MacAddress mac_address; ///< The assigned mac address of the member.
34 ENetPeer* peer; ///< The remote peer. 34 ENetPeer* peer; ///< The remote peer.
35 }; 35 };
36 using MemberList = std::vector<Member>; 36 using MemberList = std::vector<Member>;
37 MemberList members; ///< Information about the members of this room. 37 MemberList members; ///< Information about the members of this room
38 mutable std::mutex member_mutex; ///< Mutex for locking the members list
39 /// This should be a std::shared_mutex as soon as C++17 is supported
38 40
39 RoomImpl() 41 RoomImpl()
40 : random_gen(std::random_device()()), NintendoOUI{0x00, 0x1F, 0x32, 0x00, 0x00, 0x00} {} 42 : random_gen(std::random_device()()), NintendoOUI{0x00, 0x1F, 0x32, 0x00, 0x00, 0x00} {}
@@ -147,7 +149,7 @@ void Room::RoomImpl::ServerLoop() {
147 case IdJoinRequest: 149 case IdJoinRequest:
148 HandleJoinRequest(&event); 150 HandleJoinRequest(&event);
149 break; 151 break;
150 case IdSetGameName: 152 case IdSetGameInfo:
151 HandleGameNamePacket(&event); 153 HandleGameNamePacket(&event);
152 break; 154 break;
153 case IdWifiPacket: 155 case IdWifiPacket:
@@ -213,7 +215,10 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) {
213 member.nickname = nickname; 215 member.nickname = nickname;
214 member.peer = event->peer; 216 member.peer = event->peer;
215 217
216 members.push_back(std::move(member)); 218 {
219 std::lock_guard<std::mutex> lock(member_mutex);
220 members.push_back(std::move(member));
221 }
217 222
218 // Notify everyone that the room information has changed. 223 // Notify everyone that the room information has changed.
219 BroadcastRoomInformation(); 224 BroadcastRoomInformation();
@@ -223,12 +228,14 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) {
223bool Room::RoomImpl::IsValidNickname(const std::string& nickname) const { 228bool Room::RoomImpl::IsValidNickname(const std::string& nickname) const {
224 // A nickname is valid if it is not already taken by anybody else in the room. 229 // A nickname is valid if it is not already taken by anybody else in the room.
225 // TODO(B3N30): Check for empty names, spaces, etc. 230 // TODO(B3N30): Check for empty names, spaces, etc.
231 std::lock_guard<std::mutex> lock(member_mutex);
226 return std::all_of(members.begin(), members.end(), 232 return std::all_of(members.begin(), members.end(),
227 [&nickname](const auto& member) { return member.nickname != nickname; }); 233 [&nickname](const auto& member) { return member.nickname != nickname; });
228} 234}
229 235
230bool Room::RoomImpl::IsValidMacAddress(const MacAddress& address) const { 236bool Room::RoomImpl::IsValidMacAddress(const MacAddress& address) const {
231 // A MAC address is valid if it is not already taken by anybody else in the room. 237 // A MAC address is valid if it is not already taken by anybody else in the room.
238 std::lock_guard<std::mutex> lock(member_mutex);
232 return std::all_of(members.begin(), members.end(), 239 return std::all_of(members.begin(), members.end(),
233 [&address](const auto& member) { return member.mac_address != address; }); 240 [&address](const auto& member) { return member.mac_address != address; });
234} 241}
@@ -279,6 +286,7 @@ void Room::RoomImpl::SendCloseMessage() {
279 packet << static_cast<u8>(IdCloseRoom); 286 packet << static_cast<u8>(IdCloseRoom);
280 ENetPacket* enet_packet = 287 ENetPacket* enet_packet =
281 enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE); 288 enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
289 std::lock_guard<std::mutex> lock(member_mutex);
282 for (auto& member : members) { 290 for (auto& member : members) {
283 enet_peer_send(member.peer, 0, enet_packet); 291 enet_peer_send(member.peer, 0, enet_packet);
284 } 292 }
@@ -295,10 +303,14 @@ void Room::RoomImpl::BroadcastRoomInformation() {
295 packet << room_information.member_slots; 303 packet << room_information.member_slots;
296 304
297 packet << static_cast<u32>(members.size()); 305 packet << static_cast<u32>(members.size());
298 for (const auto& member : members) { 306 {
299 packet << member.nickname; 307 std::lock_guard<std::mutex> lock(member_mutex);
300 packet << member.mac_address; 308 for (const auto& member : members) {
301 packet << member.game_name; 309 packet << member.nickname;
310 packet << member.mac_address;
311 packet << member.game_info.name;
312 packet << member.game_info.id;
313 }
302 } 314 }
303 315
304 ENetPacket* enet_packet = 316 ENetPacket* enet_packet =
@@ -335,11 +347,13 @@ void Room::RoomImpl::HandleWifiPacket(const ENetEvent* event) {
335 ENET_PACKET_FLAG_RELIABLE); 347 ENET_PACKET_FLAG_RELIABLE);
336 348
337 if (destination_address == BroadcastMac) { // Send the data to everyone except the sender 349 if (destination_address == BroadcastMac) { // Send the data to everyone except the sender
350 std::lock_guard<std::mutex> lock(member_mutex);
338 for (const auto& member : members) { 351 for (const auto& member : members) {
339 if (member.peer != event->peer) 352 if (member.peer != event->peer)
340 enet_peer_send(member.peer, 0, enet_packet); 353 enet_peer_send(member.peer, 0, enet_packet);
341 } 354 }
342 } else { // Send the data only to the destination client 355 } else { // Send the data only to the destination client
356 std::lock_guard<std::mutex> lock(member_mutex);
343 auto member = std::find_if(members.begin(), members.end(), 357 auto member = std::find_if(members.begin(), members.end(),
344 [destination_address](const Member& member) -> bool { 358 [destination_address](const Member& member) -> bool {
345 return member.mac_address == destination_address; 359 return member.mac_address == destination_address;
@@ -361,6 +375,8 @@ void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) {
361 auto CompareNetworkAddress = [event](const Member member) -> bool { 375 auto CompareNetworkAddress = [event](const Member member) -> bool {
362 return member.peer == event->peer; 376 return member.peer == event->peer;
363 }; 377 };
378
379 std::lock_guard<std::mutex> lock(member_mutex);
364 const auto sending_member = std::find_if(members.begin(), members.end(), CompareNetworkAddress); 380 const auto sending_member = std::find_if(members.begin(), members.end(), CompareNetworkAddress);
365 if (sending_member == members.end()) { 381 if (sending_member == members.end()) {
366 return; // Received a chat message from a unknown sender 382 return; // Received a chat message from a unknown sender
@@ -385,22 +401,32 @@ void Room::RoomImpl::HandleGameNamePacket(const ENetEvent* event) {
385 in_packet.Append(event->packet->data, event->packet->dataLength); 401 in_packet.Append(event->packet->data, event->packet->dataLength);
386 402
387 in_packet.IgnoreBytes(sizeof(u8)); // Igonore the message type 403 in_packet.IgnoreBytes(sizeof(u8)); // Igonore the message type
388 std::string game_name; 404 GameInfo game_info;
389 in_packet >> game_name; 405 in_packet >> game_info.name;
390 auto member = 406 in_packet >> game_info.id;
391 std::find_if(members.begin(), members.end(), 407
392 [event](const Member& member) -> bool { return member.peer == event->peer; }); 408 {
393 if (member != members.end()) { 409 std::lock_guard<std::mutex> lock(member_mutex);
394 member->game_name = game_name; 410 auto member =
395 BroadcastRoomInformation(); 411 std::find_if(members.begin(), members.end(), [event](const Member& member) -> bool {
412 return member.peer == event->peer;
413 });
414 if (member != members.end()) {
415 member->game_info = game_info;
416 }
396 } 417 }
418 BroadcastRoomInformation();
397} 419}
398 420
399void Room::RoomImpl::HandleClientDisconnection(ENetPeer* client) { 421void Room::RoomImpl::HandleClientDisconnection(ENetPeer* client) {
400 // Remove the client from the members list. 422 // Remove the client from the members list.
401 members.erase(std::remove_if(members.begin(), members.end(), 423 {
402 [client](const Member& member) { return member.peer == client; }), 424 std::lock_guard<std::mutex> lock(member_mutex);
403 members.end()); 425 members.erase(
426 std::remove_if(members.begin(), members.end(),
427 [client](const Member& member) { return member.peer == client; }),
428 members.end());
429 }
404 430
405 // Announce the change to all clients. 431 // Announce the change to all clients.
406 enet_peer_disconnect(client, 0); 432 enet_peer_disconnect(client, 0);
@@ -437,6 +463,19 @@ const RoomInformation& Room::GetRoomInformation() const {
437 return room_impl->room_information; 463 return room_impl->room_information;
438} 464}
439 465
466std::vector<Room::Member> Room::GetRoomMemberList() const {
467 std::vector<Room::Member> member_list;
468 std::lock_guard<std::mutex> lock(room_impl->member_mutex);
469 for (const auto& member_impl : room_impl->members) {
470 Member member;
471 member.nickname = member_impl.nickname;
472 member.mac_address = member_impl.mac_address;
473 member.game_info = member_impl.game_info;
474 member_list.push_back(member);
475 }
476 return member_list;
477};
478
440void Room::Destroy() { 479void Room::Destroy() {
441 room_impl->state = State::Closed; 480 room_impl->state = State::Closed;
442 room_impl->room_thread->join(); 481 room_impl->room_thread->join();
@@ -447,7 +486,10 @@ void Room::Destroy() {
447 } 486 }
448 room_impl->room_information = {}; 487 room_impl->room_information = {};
449 room_impl->server = nullptr; 488 room_impl->server = nullptr;
450 room_impl->members.clear(); 489 {
490 std::lock_guard<std::mutex> lock(room_impl->member_mutex);
491 room_impl->members.clear();
492 }
451 room_impl->room_information.member_slots = 0; 493 room_impl->room_information.member_slots = 0;
452 room_impl->room_information.name.clear(); 494 room_impl->room_information.name.clear();
453} 495}
diff --git a/src/network/room.h b/src/network/room.h
index 65b0d008a..8285a4d0c 100644
--- a/src/network/room.h
+++ b/src/network/room.h
@@ -7,6 +7,7 @@
7#include <array> 7#include <array>
8#include <memory> 8#include <memory>
9#include <string> 9#include <string>
10#include <vector>
10#include "common/common_types.h" 11#include "common/common_types.h"
11 12
12namespace Network { 13namespace Network {
@@ -21,6 +22,11 @@ struct RoomInformation {
21 u32 member_slots; ///< Maximum number of members in this room 22 u32 member_slots; ///< Maximum number of members in this room
22}; 23};
23 24
25struct GameInfo {
26 std::string name{""};
27 u64 id{0};
28};
29
24using MacAddress = std::array<u8, 6>; 30using MacAddress = std::array<u8, 6>;
25/// A special MAC address that tells the room we're joining to assign us a MAC address 31/// A special MAC address that tells the room we're joining to assign us a MAC address
26/// automatically. 32/// automatically.
@@ -34,7 +40,7 @@ enum RoomMessageTypes : u8 {
34 IdJoinRequest = 1, 40 IdJoinRequest = 1,
35 IdJoinSuccess, 41 IdJoinSuccess,
36 IdRoomInformation, 42 IdRoomInformation,
37 IdSetGameName, 43 IdSetGameInfo,
38 IdWifiPacket, 44 IdWifiPacket,
39 IdChatMessage, 45 IdChatMessage,
40 IdNameCollision, 46 IdNameCollision,
@@ -51,6 +57,12 @@ public:
51 Closed, ///< The room is not opened and can not accept connections. 57 Closed, ///< The room is not opened and can not accept connections.
52 }; 58 };
53 59
60 struct Member {
61 std::string nickname; ///< The nickname of the member.
62 GameInfo game_info; ///< The current game of the member
63 MacAddress mac_address; ///< The assigned mac address of the member.
64 };
65
54 Room(); 66 Room();
55 ~Room(); 67 ~Room();
56 68
@@ -65,6 +77,11 @@ public:
65 const RoomInformation& GetRoomInformation() const; 77 const RoomInformation& GetRoomInformation() const;
66 78
67 /** 79 /**
80 * Gets a list of the mbmers connected to the room.
81 */
82 std::vector<Member> GetRoomMemberList() const;
83
84 /**
68 * Creates the socket for this room. Will bind to default address if 85 * Creates the socket for this room. Will bind to default address if
69 * server is empty string. 86 * server is empty string.
70 */ 87 */
diff --git a/src/network/room_member.cpp b/src/network/room_member.cpp
index dac9bacae..f229ec6fd 100644
--- a/src/network/room_member.cpp
+++ b/src/network/room_member.cpp
@@ -5,6 +5,7 @@
5#include <atomic> 5#include <atomic>
6#include <list> 6#include <list>
7#include <mutex> 7#include <mutex>
8#include <set>
8#include <thread> 9#include <thread>
9#include "common/assert.h" 10#include "common/assert.h"
10#include "enet/enet.h" 11#include "enet/enet.h"
@@ -25,6 +26,9 @@ public:
25 /// Information about the room we're connected to. 26 /// Information about the room we're connected to.
26 RoomInformation room_information; 27 RoomInformation room_information;
27 28
29 /// The current game name, id and version
30 GameInfo current_game_info;
31
28 std::atomic<State> state{State::Idle}; ///< Current state of the RoomMember. 32 std::atomic<State> state{State::Idle}; ///< Current state of the RoomMember.
29 void SetState(const State new_state); 33 void SetState(const State new_state);
30 bool IsConnected() const; 34 bool IsConnected() const;
@@ -37,6 +41,24 @@ public:
37 std::unique_ptr<std::thread> loop_thread; 41 std::unique_ptr<std::thread> loop_thread;
38 std::mutex send_list_mutex; ///< Mutex that controls access to the `send_list` variable. 42 std::mutex send_list_mutex; ///< Mutex that controls access to the `send_list` variable.
39 std::list<Packet> send_list; ///< A list that stores all packets to send the async 43 std::list<Packet> send_list; ///< A list that stores all packets to send the async
44
45 template <typename T>
46 using CallbackSet = std::set<CallbackHandle<T>>;
47 std::mutex callback_mutex; ///< The mutex used for handling callbacks
48
49 class Callbacks {
50 public:
51 template <typename T>
52 CallbackSet<T>& Get();
53
54 private:
55 CallbackSet<WifiPacket> callback_set_wifi_packet;
56 CallbackSet<ChatEntry> callback_set_chat_messages;
57 CallbackSet<RoomInformation> callback_set_room_information;
58 CallbackSet<State> callback_set_state;
59 };
60 Callbacks callbacks; ///< All CallbackSets to all events
61
40 void MemberLoop(); 62 void MemberLoop();
41 63
42 void StartLoop(); 64 void StartLoop();
@@ -84,12 +106,20 @@ public:
84 * Disconnects the RoomMember from the Room 106 * Disconnects the RoomMember from the Room
85 */ 107 */
86 void Disconnect(); 108 void Disconnect();
109
110 template <typename T>
111 void Invoke(const T& data);
112
113 template <typename T>
114 CallbackHandle<T> Bind(std::function<void(const T&)> callback);
87}; 115};
88 116
89// RoomMemberImpl 117// RoomMemberImpl
90void RoomMember::RoomMemberImpl::SetState(const State new_state) { 118void RoomMember::RoomMemberImpl::SetState(const State new_state) {
91 state = new_state; 119 if (state != new_state) {
92 // TODO(B3N30): Invoke the callback functions 120 state = new_state;
121 Invoke<State>(state);
122 }
93} 123}
94 124
95bool RoomMember::RoomMemberImpl::IsConnected() const { 125bool RoomMember::RoomMemberImpl::IsConnected() const {
@@ -195,9 +225,10 @@ void RoomMember::RoomMemberImpl::HandleRoomInformationPacket(const ENetEvent* ev
195 for (auto& member : member_information) { 225 for (auto& member : member_information) {
196 packet >> member.nickname; 226 packet >> member.nickname;
197 packet >> member.mac_address; 227 packet >> member.mac_address;
198 packet >> member.game_name; 228 packet >> member.game_info.name;
229 packet >> member.game_info.id;
199 } 230 }
200 // TODO(B3N30): Invoke callbacks 231 Invoke(room_information);
201} 232}
202 233
203void RoomMember::RoomMemberImpl::HandleJoinPacket(const ENetEvent* event) { 234void RoomMember::RoomMemberImpl::HandleJoinPacket(const ENetEvent* event) {
@@ -209,7 +240,7 @@ void RoomMember::RoomMemberImpl::HandleJoinPacket(const ENetEvent* event) {
209 240
210 // Parse the MAC Address from the packet 241 // Parse the MAC Address from the packet
211 packet >> mac_address; 242 packet >> mac_address;
212 // TODO(B3N30): Invoke callbacks 243 SetState(State::Joined);
213} 244}
214 245
215void RoomMember::RoomMemberImpl::HandleWifiPackets(const ENetEvent* event) { 246void RoomMember::RoomMemberImpl::HandleWifiPackets(const ENetEvent* event) {
@@ -235,7 +266,7 @@ void RoomMember::RoomMemberImpl::HandleWifiPackets(const ENetEvent* event) {
235 266
236 packet >> wifi_packet.data; 267 packet >> wifi_packet.data;
237 268
238 // TODO(B3N30): Invoke callbacks 269 Invoke<WifiPacket>(wifi_packet);
239} 270}
240 271
241void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) { 272void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) {
@@ -248,7 +279,7 @@ void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) {
248 ChatEntry chat_entry{}; 279 ChatEntry chat_entry{};
249 packet >> chat_entry.nickname; 280 packet >> chat_entry.nickname;
250 packet >> chat_entry.message; 281 packet >> chat_entry.message;
251 // TODO(B3N30): Invoke callbacks 282 Invoke<ChatEntry>(chat_entry);
252} 283}
253 284
254void RoomMember::RoomMemberImpl::Disconnect() { 285void RoomMember::RoomMemberImpl::Disconnect() {
@@ -276,6 +307,46 @@ void RoomMember::RoomMemberImpl::Disconnect() {
276 server = nullptr; 307 server = nullptr;
277} 308}
278 309
310template <>
311RoomMember::RoomMemberImpl::CallbackSet<WifiPacket>& RoomMember::RoomMemberImpl::Callbacks::Get() {
312 return callback_set_wifi_packet;
313}
314
315template <>
316RoomMember::RoomMemberImpl::CallbackSet<RoomMember::State>&
317RoomMember::RoomMemberImpl::Callbacks::Get() {
318 return callback_set_state;
319}
320
321template <>
322RoomMember::RoomMemberImpl::CallbackSet<RoomInformation>&
323RoomMember::RoomMemberImpl::Callbacks::Get() {
324 return callback_set_room_information;
325}
326
327template <>
328RoomMember::RoomMemberImpl::CallbackSet<ChatEntry>& RoomMember::RoomMemberImpl::Callbacks::Get() {
329 return callback_set_chat_messages;
330}
331
332template <typename T>
333void RoomMember::RoomMemberImpl::Invoke(const T& data) {
334 std::lock_guard<std::mutex> lock(callback_mutex);
335 CallbackSet<T> callback_set = callbacks.Get<T>();
336 for (auto const& callback : callback_set)
337 (*callback)(data);
338}
339
340template <typename T>
341RoomMember::CallbackHandle<T> RoomMember::RoomMemberImpl::Bind(
342 std::function<void(const T&)> callback) {
343 std::lock_guard<std::mutex> lock(callback_mutex);
344 CallbackHandle<T> handle;
345 handle = std::make_shared<std::function<void(const T&)>>(callback);
346 callbacks.Get<T>().insert(handle);
347 return handle;
348}
349
279// RoomMember 350// RoomMember
280RoomMember::RoomMember() : room_member_impl{std::make_unique<RoomMemberImpl>()} { 351RoomMember::RoomMember() : room_member_impl{std::make_unique<RoomMemberImpl>()} {
281 room_member_impl->client = enet_host_create(nullptr, 1, NumChannels, 0, 0); 352 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
339 room_member_impl->SetState(State::Joining); 410 room_member_impl->SetState(State::Joining);
340 room_member_impl->StartLoop(); 411 room_member_impl->StartLoop();
341 room_member_impl->SendJoinRequest(nick, preferred_mac); 412 room_member_impl->SendJoinRequest(nick, preferred_mac);
413 SendGameInfo(room_member_impl->current_game_info);
342 } else { 414 } else {
343 room_member_impl->SetState(State::CouldNotConnect); 415 room_member_impl->SetState(State::CouldNotConnect);
344 } 416 }
@@ -366,17 +438,53 @@ void RoomMember::SendChatMessage(const std::string& message) {
366 room_member_impl->Send(std::move(packet)); 438 room_member_impl->Send(std::move(packet));
367} 439}
368 440
369void RoomMember::SendGameName(const std::string& game_name) { 441void RoomMember::SendGameInfo(const GameInfo& game_info) {
442 room_member_impl->current_game_info = game_info;
443 if (!IsConnected())
444 return;
445
370 Packet packet; 446 Packet packet;
371 packet << static_cast<u8>(IdSetGameName); 447 packet << static_cast<u8>(IdSetGameInfo);
372 packet << game_name; 448 packet << game_info.name;
449 packet << game_info.id;
373 room_member_impl->Send(std::move(packet)); 450 room_member_impl->Send(std::move(packet));
374} 451}
375 452
453RoomMember::CallbackHandle<RoomMember::State> RoomMember::BindOnStateChanged(
454 std::function<void(const RoomMember::State&)> callback) {
455 return room_member_impl->Bind(callback);
456}
457
458RoomMember::CallbackHandle<WifiPacket> RoomMember::BindOnWifiPacketReceived(
459 std::function<void(const WifiPacket&)> callback) {
460 return room_member_impl->Bind(callback);
461}
462
463RoomMember::CallbackHandle<RoomInformation> RoomMember::BindOnRoomInformationChanged(
464 std::function<void(const RoomInformation&)> callback) {
465 return room_member_impl->Bind(callback);
466}
467
468RoomMember::CallbackHandle<ChatEntry> RoomMember::BindOnChatMessageRecieved(
469 std::function<void(const ChatEntry&)> callback) {
470 return room_member_impl->Bind(callback);
471}
472
473template <typename T>
474void RoomMember::Unbind(CallbackHandle<T> handle) {
475 std::lock_guard<std::mutex> lock(room_member_impl->callback_mutex);
476 room_member_impl->callbacks.Get<T>().erase(handle);
477}
478
376void RoomMember::Leave() { 479void RoomMember::Leave() {
377 room_member_impl->SetState(State::Idle); 480 room_member_impl->SetState(State::Idle);
378 room_member_impl->loop_thread->join(); 481 room_member_impl->loop_thread->join();
379 room_member_impl->loop_thread.reset(); 482 room_member_impl->loop_thread.reset();
380} 483}
381 484
485template void RoomMember::Unbind(CallbackHandle<WifiPacket>);
486template void RoomMember::Unbind(CallbackHandle<RoomMember::State>);
487template void RoomMember::Unbind(CallbackHandle<RoomInformation>);
488template void RoomMember::Unbind(CallbackHandle<ChatEntry>);
489
382} // namespace Network 490} // namespace Network
diff --git a/src/network/room_member.h b/src/network/room_member.h
index bc1af3a7e..98770a234 100644
--- a/src/network/room_member.h
+++ b/src/network/room_member.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <functional>
7#include <memory> 8#include <memory>
8#include <string> 9#include <string>
9#include <vector> 10#include <vector>
@@ -53,12 +54,23 @@ public:
53 54
54 struct MemberInformation { 55 struct MemberInformation {
55 std::string nickname; ///< Nickname of the member. 56 std::string nickname; ///< Nickname of the member.
56 std::string game_name; ///< Name of the game they're currently playing, or empty if they're 57 GameInfo game_info; ///< Name of the game they're currently playing, or empty if they're
57 /// not playing anything. 58 /// not playing anything.
58 MacAddress mac_address; ///< MAC address associated with this member. 59 MacAddress mac_address; ///< MAC address associated with this member.
59 }; 60 };
60 using MemberList = std::vector<MemberInformation>; 61 using MemberList = std::vector<MemberInformation>;
61 62
63 // The handle for the callback functions
64 template <typename T>
65 using CallbackHandle = std::shared_ptr<std::function<void(const T&)>>;
66
67 /**
68 * Unbinds a callback function from the events.
69 * @param handle The connection handle to disconnect
70 */
71 template <typename T>
72 void Unbind(CallbackHandle<T> handle);
73
62 RoomMember(); 74 RoomMember();
63 ~RoomMember(); 75 ~RoomMember();
64 76
@@ -113,10 +125,49 @@ public:
113 void SendChatMessage(const std::string& message); 125 void SendChatMessage(const std::string& message);
114 126
115 /** 127 /**
116 * Sends the current game name to the room. 128 * Sends the current game info to the room.
117 * @param game_name The game name. 129 * @param game_info The game information.
130 */
131 void SendGameInfo(const GameInfo& game_info);
132
133 /**
134 * Binds a function to an event that will be triggered every time the State of the member
135 * changed. The function wil be called every time the event is triggered. The callback function
136 * must not bind or unbind a function. Doing so will cause a deadlock
137 * @param callback The function to call
138 * @return A handle used for removing the function from the registered list
139 */
140 CallbackHandle<State> BindOnStateChanged(std::function<void(const State&)> callback);
141
142 /**
143 * Binds a function to an event that will be triggered every time a WifiPacket is received.
144 * The function wil be called everytime the event is triggered.
145 * The callback function must not bind or unbind a function. Doing so will cause a deadlock
146 * @param callback The function to call
147 * @return A handle used for removing the function from the registered list
148 */
149 CallbackHandle<WifiPacket> BindOnWifiPacketReceived(
150 std::function<void(const WifiPacket&)> callback);
151
152 /**
153 * Binds a function to an event that will be triggered every time the RoomInformation changes.
154 * The function wil be called every time the event is triggered.
155 * The callback function must not bind or unbind a function. Doing so will cause a deadlock
156 * @param callback The function to call
157 * @return A handle used for removing the function from the registered list
158 */
159 CallbackHandle<RoomInformation> BindOnRoomInformationChanged(
160 std::function<void(const RoomInformation&)> callback);
161
162 /**
163 * Binds a function to an event that will be triggered every time a ChatMessage is received.
164 * The function wil be called every time the event is triggered.
165 * The callback function must not bind or unbind a function. Doing so will cause a deadlock
166 * @param callback The function to call
167 * @return A handle used for removing the function from the registered list
118 */ 168 */
119 void SendGameName(const std::string& game_name); 169 CallbackHandle<ChatEntry> BindOnChatMessageRecieved(
170 std::function<void(const ChatEntry&)> callback);
120 171
121 /** 172 /**
122 * Leaves the current room. 173 * Leaves the current room.