Эх сурвалжийг харах

Network: Send JoinRequest and handle the answer in RoomMember

B3n30 9 жил өмнө
parent
commit
77677e205e

+ 107 - 2
src/network/room_member.cpp

@@ -7,6 +7,7 @@
 #include <thread>
 #include "common/assert.h"
 #include "enet/enet.h"
+#include "network/packet.h"
 #include "network/room_member.h"
 
 namespace Network {
@@ -18,17 +19,49 @@ public:
     ENetHost* client = nullptr; ///< ENet network interface.
     ENetPeer* server = nullptr; ///< The server peer the client is connected to
 
+    /// Information about the clients connected to the same room as us.
+    MemberList member_information;
+    /// Information about the room we're connected to.
+    RoomInformation room_information;
+
     std::atomic<State> state{State::Idle}; ///< Current state of the RoomMember.
     void SetState(const State new_state);
     bool IsConnected() const;
 
-    std::string nickname; ///< The nickname of this member.
+    std::string nickname;   ///< The nickname of this member.
+    MacAddress mac_address; ///< The mac_address of this member.
 
     std::mutex network_mutex; ///< Mutex that controls access to the `client` variable.
     /// Thread that receives and dispatches network packets
     std::unique_ptr<std::thread> receive_thread;
     void ReceiveLoop();
     void StartLoop();
+
+    /**
+     * Sends data to the room. It will be send on channel 0 with flag RELIABLE
+     * @param packet The data to send
+     */
+    void Send(Packet& packet);
+    /**
+     * Sends a request to the server, asking for permission to join a room with the specified
+     * nickname and preferred mac.
+     * @params nickname The desired nickname.
+     * @params preferred_mac The preferred MAC address to use in the room, the NoPreferredMac tells
+     * the server to assign one for us.
+     */
+    void SendJoinRequest(const std::string& nickname,
+                         const MacAddress& preferred_mac = NoPreferredMac);
+
+    /**
+     * Extracts a MAC Address from a received ENet packet.
+     * @param event The ENet event that was received.
+     */
+    void HandleJoinPacket(const ENetEvent* event);
+    /**
+     * Extracts RoomInformation and MemberInformation from a received RakNet packet.
+     * @param event The ENet event that was received.
+     */
+    void HandleRoomInformationPacket(const ENetEvent* event);
 };
 
 // RoomMemberImpl
@@ -50,6 +83,17 @@ void RoomMember::RoomMemberImpl::ReceiveLoop() {
             if (event.type == ENET_EVENT_TYPE_RECEIVE) {
                 switch (event.packet->data[0]) {
                 // TODO(B3N30): Handle the other message types
+                case IdRoomInformation:
+                    HandleRoomInformationPacket(&event);
+                    break;
+                case IdJoinSuccess:
+                    // The join request was successful, we are now in the room.
+                    // If we joined successfully, there must be at least one client in the room: us.
+                    ASSERT_MSG(member_information.size() > 0,
+                               "We have not yet received member information.");
+                    HandleJoinPacket(&event); // Get the MAC Address for the client
+                    SetState(State::Joined);
+                    break;
                 case IdNameCollision:
                     SetState(State::NameCollision);
                     enet_packet_destroy(event.packet);
@@ -77,6 +121,59 @@ void RoomMember::RoomMemberImpl::StartLoop() {
     receive_thread = std::make_unique<std::thread>(&RoomMember::RoomMemberImpl::ReceiveLoop, this);
 }
 
+void RoomMember::RoomMemberImpl::Send(Packet& packet) {
+    ENetPacket* enetPacket =
+        enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
+    enet_peer_send(server, 0, enetPacket);
+    enet_host_flush(client);
+}
+
+void RoomMember::RoomMemberImpl::SendJoinRequest(const std::string& nickname,
+                                                 const MacAddress& preferred_mac) {
+    Packet packet;
+    packet << static_cast<MessageID>(IdJoinRequest);
+    packet << nickname;
+    packet << preferred_mac;
+    Send(packet);
+}
+
+void RoomMember::RoomMemberImpl::HandleRoomInformationPacket(const ENetEvent* event) {
+    Packet packet;
+    packet.Append(event->packet->data, event->packet->dataLength);
+
+    // Ignore the first byte, which is the message id.
+    packet.IgnoreBytes(sizeof(MessageID));
+
+    RoomInformation info{};
+    packet >> info.name;
+    packet >> info.member_slots;
+    room_information.name = info.name;
+    room_information.member_slots = info.member_slots;
+
+    uint32_t num_members;
+    packet >> num_members;
+    member_information.resize(num_members);
+
+    for (auto& member : member_information) {
+        packet >> member.nickname;
+        packet >> member.mac_address;
+        packet >> member.game_name;
+    }
+    // TODO(B3N30): Invoke callbacks
+}
+
+void RoomMember::RoomMemberImpl::HandleJoinPacket(const ENetEvent* event) {
+    Packet packet;
+    packet.Append(event->packet->data, event->packet->dataLength);
+
+    // Ignore the first byte, which is the message id.
+    packet.IgnoreBytes(sizeof(MessageID));
+
+    // Parse the MAC Address from the BitStream
+    packet >> mac_address;
+    // TODO(B3N30): Invoke callbacks
+}
+
 // RoomMember
 RoomMember::RoomMember() : room_member_impl{std::make_unique<RoomMemberImpl>()} {
     room_member_impl->client = enet_host_create(nullptr, 1, NumChannels, 0, 0);
@@ -92,6 +189,14 @@ RoomMember::State RoomMember::GetState() const {
     return room_member_impl->state;
 }
 
+const RoomMember::MemberList& RoomMember::GetMemberInformation() const {
+    return room_member_impl->member_information;
+}
+
+RoomInformation RoomMember::GetRoomInformation() const {
+    return room_member_impl->room_information;
+}
+
 void RoomMember::Join(const std::string& nick, const char* server_addr, u16 server_port,
                       u16 client_port) {
     ENetAddress address{};
@@ -112,7 +217,7 @@ void RoomMember::Join(const std::string& nick, const char* server_addr, u16 serv
         room_member_impl->nickname = nick;
         room_member_impl->SetState(State::Joining);
         room_member_impl->StartLoop();
-        // TODO(B3N30): Send a join request with the nickname to the server
+        room_member_impl->SendJoinRequest(nick);
     } else {
         room_member_impl->SetState(State::CouldNotConnect);
     }

+ 18 - 0
src/network/room_member.h

@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <string>
+#include <vector>
 #include "common/common_types.h"
 #include "network/room.h"
 
@@ -31,6 +32,14 @@ public:
         CouldNotConnect ///< The room is not responding to a connection attempt
     };
 
+    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
+                                /// not playing anything.
+        MacAddress mac_address; ///< MAC address associated with this member.
+    };
+    using MemberList = std::vector<MemberInformation>;
+
     RoomMember();
     ~RoomMember();
 
@@ -39,6 +48,15 @@ public:
      */
     State GetState() const;
 
+    /**
+     * Returns information about the members in the room we're currently connected to.
+     */
+    const MemberList& GetMemberInformation() const;
+    /**
+     * Returns information about the room we're currently connected to.
+     */
+    RoomInformation GetRoomInformation() const;
+
     /**
      * Returns whether we're connected to a server or not.
      */