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:
B3n30 2017-08-19 19:14:33 +02:00 committed by James Rowe
parent 21204ba488
commit 5d0a1e7efd
9 changed files with 310 additions and 37 deletions

View file

@ -5,6 +5,7 @@
#include <atomic>
#include <list>
#include <mutex>
#include <set>
#include <thread>
#include "common/assert.h"
#include "enet/enet.h"
@ -25,6 +26,9 @@ public:
/// Information about the room we're connected to.
RoomInformation room_information;
/// The current game name, id and version
GameInfo current_game_info;
std::atomic<State> state{State::Idle}; ///< Current state of the RoomMember.
void SetState(const State new_state);
bool IsConnected() const;
@ -37,6 +41,24 @@ public:
std::unique_ptr<std::thread> loop_thread;
std::mutex send_list_mutex; ///< Mutex that controls access to the `send_list` variable.
std::list<Packet> send_list; ///< A list that stores all packets to send the async
template <typename T>
using CallbackSet = std::set<CallbackHandle<T>>;
std::mutex callback_mutex; ///< The mutex used for handling callbacks
class Callbacks {
public:
template <typename T>
CallbackSet<T>& Get();
private:
CallbackSet<WifiPacket> callback_set_wifi_packet;
CallbackSet<ChatEntry> callback_set_chat_messages;
CallbackSet<RoomInformation> callback_set_room_information;
CallbackSet<State> callback_set_state;
};
Callbacks callbacks; ///< All CallbackSets to all events
void MemberLoop();
void StartLoop();
@ -84,12 +106,20 @@ public:
* Disconnects the RoomMember from the Room
*/
void Disconnect();
template <typename T>
void Invoke(const T& data);
template <typename T>
CallbackHandle<T> Bind(std::function<void(const T&)> callback);
};
// RoomMemberImpl
void RoomMember::RoomMemberImpl::SetState(const State new_state) {
state = new_state;
// TODO(B3N30): Invoke the callback functions
if (state != new_state) {
state = new_state;
Invoke<State>(state);
}
}
bool RoomMember::RoomMemberImpl::IsConnected() const {
@ -195,9 +225,10 @@ void RoomMember::RoomMemberImpl::HandleRoomInformationPacket(const ENetEvent* ev
for (auto& member : member_information) {
packet >> member.nickname;
packet >> member.mac_address;
packet >> member.game_name;
packet >> member.game_info.name;
packet >> member.game_info.id;
}
// TODO(B3N30): Invoke callbacks
Invoke(room_information);
}
void RoomMember::RoomMemberImpl::HandleJoinPacket(const ENetEvent* event) {
@ -209,7 +240,7 @@ void RoomMember::RoomMemberImpl::HandleJoinPacket(const ENetEvent* event) {
// Parse the MAC Address from the packet
packet >> mac_address;
// TODO(B3N30): Invoke callbacks
SetState(State::Joined);
}
void RoomMember::RoomMemberImpl::HandleWifiPackets(const ENetEvent* event) {
@ -235,7 +266,7 @@ void RoomMember::RoomMemberImpl::HandleWifiPackets(const ENetEvent* event) {
packet >> wifi_packet.data;
// TODO(B3N30): Invoke callbacks
Invoke<WifiPacket>(wifi_packet);
}
void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) {
@ -248,7 +279,7 @@ void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) {
ChatEntry chat_entry{};
packet >> chat_entry.nickname;
packet >> chat_entry.message;
// TODO(B3N30): Invoke callbacks
Invoke<ChatEntry>(chat_entry);
}
void RoomMember::RoomMemberImpl::Disconnect() {
@ -276,6 +307,46 @@ void RoomMember::RoomMemberImpl::Disconnect() {
server = nullptr;
}
template <>
RoomMember::RoomMemberImpl::CallbackSet<WifiPacket>& RoomMember::RoomMemberImpl::Callbacks::Get() {
return callback_set_wifi_packet;
}
template <>
RoomMember::RoomMemberImpl::CallbackSet<RoomMember::State>&
RoomMember::RoomMemberImpl::Callbacks::Get() {
return callback_set_state;
}
template <>
RoomMember::RoomMemberImpl::CallbackSet<RoomInformation>&
RoomMember::RoomMemberImpl::Callbacks::Get() {
return callback_set_room_information;
}
template <>
RoomMember::RoomMemberImpl::CallbackSet<ChatEntry>& RoomMember::RoomMemberImpl::Callbacks::Get() {
return callback_set_chat_messages;
}
template <typename T>
void RoomMember::RoomMemberImpl::Invoke(const T& data) {
std::lock_guard<std::mutex> lock(callback_mutex);
CallbackSet<T> callback_set = callbacks.Get<T>();
for (auto const& callback : callback_set)
(*callback)(data);
}
template <typename T>
RoomMember::CallbackHandle<T> RoomMember::RoomMemberImpl::Bind(
std::function<void(const T&)> callback) {
std::lock_guard<std::mutex> lock(callback_mutex);
CallbackHandle<T> handle;
handle = std::make_shared<std::function<void(const T&)>>(callback);
callbacks.Get<T>().insert(handle);
return handle;
}
// RoomMember
RoomMember::RoomMember() : room_member_impl{std::make_unique<RoomMemberImpl>()} {
room_member_impl->client = enet_host_create(nullptr, 1, NumChannels, 0, 0);
@ -339,6 +410,7 @@ void RoomMember::Join(const std::string& nick, const char* server_addr, u16 serv
room_member_impl->SetState(State::Joining);
room_member_impl->StartLoop();
room_member_impl->SendJoinRequest(nick, preferred_mac);
SendGameInfo(room_member_impl->current_game_info);
} else {
room_member_impl->SetState(State::CouldNotConnect);
}
@ -366,17 +438,53 @@ void RoomMember::SendChatMessage(const std::string& message) {
room_member_impl->Send(std::move(packet));
}
void RoomMember::SendGameName(const std::string& game_name) {
void RoomMember::SendGameInfo(const GameInfo& game_info) {
room_member_impl->current_game_info = game_info;
if (!IsConnected())
return;
Packet packet;
packet << static_cast<u8>(IdSetGameName);
packet << game_name;
packet << static_cast<u8>(IdSetGameInfo);
packet << game_info.name;
packet << game_info.id;
room_member_impl->Send(std::move(packet));
}
RoomMember::CallbackHandle<RoomMember::State> RoomMember::BindOnStateChanged(
std::function<void(const RoomMember::State&)> callback) {
return room_member_impl->Bind(callback);
}
RoomMember::CallbackHandle<WifiPacket> RoomMember::BindOnWifiPacketReceived(
std::function<void(const WifiPacket&)> callback) {
return room_member_impl->Bind(callback);
}
RoomMember::CallbackHandle<RoomInformation> RoomMember::BindOnRoomInformationChanged(
std::function<void(const RoomInformation&)> callback) {
return room_member_impl->Bind(callback);
}
RoomMember::CallbackHandle<ChatEntry> RoomMember::BindOnChatMessageRecieved(
std::function<void(const ChatEntry&)> callback) {
return room_member_impl->Bind(callback);
}
template <typename T>
void RoomMember::Unbind(CallbackHandle<T> handle) {
std::lock_guard<std::mutex> lock(room_member_impl->callback_mutex);
room_member_impl->callbacks.Get<T>().erase(handle);
}
void RoomMember::Leave() {
room_member_impl->SetState(State::Idle);
room_member_impl->loop_thread->join();
room_member_impl->loop_thread.reset();
}
template void RoomMember::Unbind(CallbackHandle<WifiPacket>);
template void RoomMember::Unbind(CallbackHandle<RoomMember::State>);
template void RoomMember::Unbind(CallbackHandle<RoomInformation>);
template void RoomMember::Unbind(CallbackHandle<ChatEntry>);
} // namespace Network