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})
|
||||
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;
|
||||
|
||||
{
|
||||
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());
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(member_mutex);
|
||||
for (const auto& member : members) {
|
||||
packet << member.nickname;
|
||||
packet << member.mac_address;
|
||||
packet << member.game_name;
|
||||
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;
|
||||
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; });
|
||||
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();
|
||||
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(),
|
||||
{
|
||||
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;
|
||||
{
|
||||
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) {
|
||||
if (state != new_state) {
|
||||
state = new_state;
|
||||
// TODO(B3N30): Invoke the callback functions
|
||||
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.
|
||||
|
|
Reference in New Issue