From 15a385a8251b2fa431e5bd9d5b7a9e286e247a8f Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Mon, 19 Aug 2024 11:05:47 +0200 Subject: [PATCH] better networking --- src/Lobby.cpp | 4 +-- src/Lobby.h | 4 +-- src/NetworkInterface.cpp | 55 +++++++++++++++------------------- src/NetworkInterface.h | 14 +++++---- src/Player.h | 5 ++-- src/Server.cpp | 11 +++---- src/Server.h | 7 +++-- src/World.cpp | 64 +++++++++++++++++++++++++++++----------- src/World.h | 21 ++++++++----- 9 files changed, 111 insertions(+), 74 deletions(-) diff --git a/src/Lobby.cpp b/src/Lobby.cpp index 105c6c9..db517dd 100644 --- a/src/Lobby.cpp +++ b/src/Lobby.cpp @@ -70,13 +70,13 @@ void Lobby::Shutdown() { } } -void Lobby::OnPlayerConnected(int64_t a_PeerId) { +void Lobby::OnPlayerConnected(PeerID a_PeerId) { if (get_multiplayer()->is_server()) { emit_signal("player_connected", a_PeerId); } } -void Lobby::OnPlayerDisconnected(int64_t a_PeerId) { +void Lobby::OnPlayerDisconnected(PeerID a_PeerId) { if (get_multiplayer()->is_server()) { emit_signal("player_disconnected", a_PeerId); } diff --git a/src/Lobby.h b/src/Lobby.h index ffa49cf..58d6a72 100644 --- a/src/Lobby.h +++ b/src/Lobby.h @@ -22,8 +22,8 @@ class Lobby : public godot::Node { void Shutdown(); private: - void OnPlayerConnected(int64_t a_PeerId); - void OnPlayerDisconnected(int64_t a_PeerId); + void OnPlayerConnected(PeerID a_PeerId); + void OnPlayerDisconnected(PeerID a_PeerId); void OnConnectOk(); void OnConnectFail(); void OnServerDisconnected(); diff --git a/src/NetworkInterface.cpp b/src/NetworkInterface.cpp index b71bc4b..f01efa2 100644 --- a/src/NetworkInterface.cpp +++ b/src/NetworkInterface.cpp @@ -1,5 +1,7 @@ #include "NetworkInterface.h" +#include +#include #include #include #include @@ -9,49 +11,40 @@ namespace blitz { using namespace godot; void NetworkInterface::_bind_methods() { - ClassDB::bind_method(D_METHOD("AddPlayer", "a_PlayerId", "a_PlayerName"), &NetworkInterface::AddPlayer); - ClassDB::bind_method(D_METHOD("RemovePlayer", "a_PlayerId"), &NetworkInterface::RemovePlayer); - ClassDB::bind_method(D_METHOD("SetPlayerPositionAndRotation", "a_PlayerId", "a_Position", "a_Rotation"), - &NetworkInterface::SetPlayerPositionAndRotation); - - ADD_SIGNAL(MethodInfo("AddPlayer", PropertyInfo(Variant::INT, "a_PlayerId"), PropertyInfo(Variant::STRING, "a_PlayerName"))); - ADD_SIGNAL(MethodInfo("RemovePlayer", PropertyInfo(Variant::INT, "a_PlayerId"))); - ADD_SIGNAL(MethodInfo("SetPlayerPositionAndRotation", PropertyInfo(Variant::INT, "a_PlayerId"), - PropertyInfo(Variant::VECTOR3, "a_Position"), PropertyInfo(Variant::VECTOR3, "a_Rotation"))); + ClassDB::bind_method(D_METHOD("RecievePacketDataReliable", "a_PacketData"), &NetworkInterface::RecievePacketDataReliable); + protocol::PacketFactory::Init(); } NetworkInterface::NetworkInterface() {} NetworkInterface::~NetworkInterface() {} -void NetworkInterface::AddPlayer(int64_t a_PlayerId, godot::String a_PlayerName) { - emit_signal("AddPlayer", a_PlayerId, a_PlayerName); -} - -void NetworkInterface::RemovePlayer(int64_t a_PlayerId) { - emit_signal("RemovePlayer", a_PlayerId); -} - -void NetworkInterface::SetPlayerPositionAndRotation(int64_t a_PlayerId, Vector3 a_Position, Vector3 a_Rotation) { - emit_signal("SetPlayerPositionAndRotation", a_PlayerId, a_Position, a_Rotation); -} - void NetworkInterface::_ready() { + // TODO: unreliable Dictionary config; - config["rpc_mode"] = MultiplayerAPI::RPC_MODE_AUTHORITY; + config["rpc_mode"] = MultiplayerAPI::RPC_MODE_ANY_PEER; config["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_RELIABLE; config["call_local"] = true; config["channel"] = 0; - rpc_config("AddPlayer", config); - rpc_config("RemovePlayer", config); - - Dictionary config2; - config["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_RELIABLE; - config["channel"] = 0; - config2["rpc_mode"] = MultiplayerAPI::RPC_MODE_ANY_PEER; - config2["call_local"] = false; - rpc_config("SetPlayerPositionAndRotation", config2); + rpc_config("RecievePacketDataReliable", config); } +void NetworkInterface::BroadcastPacket(const protocol::Packet& a_Packet) { + PackedByteArray byteArray = protocol::PacketSerializer::Serialize(a_Packet); + rpc("RecievePacketDataReliable", byteArray); +} + +void NetworkInterface::SendPacket(PeerID a_Peer, const protocol::Packet& a_Packet) { + PackedByteArray byteArray = protocol::PacketSerializer::Serialize(a_Packet); + rpc_id(a_Peer, "RecievePacketDataReliable", byteArray); +} + +void NetworkInterface::RecievePacketDataReliable(godot::PackedByteArray a_PacketData) { + auto packet = protocol::PacketSerializer::Deserialize(a_PacketData); + if (packet) { + packet->m_Sender = get_multiplayer()->get_remote_sender_id(); + Dispatch(*packet); + } +} } // namespace blitz \ No newline at end of file diff --git a/src/NetworkInterface.h b/src/NetworkInterface.h index 0b86a1a..6b6510e 100644 --- a/src/NetworkInterface.h +++ b/src/NetworkInterface.h @@ -1,9 +1,11 @@ #pragma once +#include #include +#include namespace blitz { -class NetworkInterface : public godot::Node { +class NetworkInterface : public godot::Node, public protocol::PacketDispatcher { GDCLASS(NetworkInterface, godot::Node) protected: static void _bind_methods(); @@ -12,11 +14,13 @@ class NetworkInterface : public godot::Node { NetworkInterface(); ~NetworkInterface(); - void AddPlayer(int64_t a_PlayerId, godot::String a_PlayerName); - void RemovePlayer(int64_t a_PlayerId); - void SetPlayerPositionAndRotation(int64_t a_PlayerId, godot::Vector3 a_Position, godot::Vector3 a_Rotation); + void BroadcastPacket(const protocol::Packet& a_Packet); + void SendPacket(PeerID a_Peer, const protocol::Packet& a_Packet); - void _ready() override; + void _ready() override; + + private: + void RecievePacketDataReliable(godot::PackedByteArray a_PacketData); }; } // namespace blitz \ No newline at end of file diff --git a/src/Player.h b/src/Player.h index d69f7f9..5f1cc9f 100644 --- a/src/Player.h +++ b/src/Player.h @@ -3,6 +3,7 @@ #include #include #include +#include namespace blitz { @@ -26,7 +27,7 @@ class Player : public godot::CharacterBody3D { godot::Vector3 GetCameraRotation() const; void SetCameraRotation(const godot::Vector3& a_Rotation); - uint64_t GetId() const { + PlayerID GetId() const { return m_PeerId; } @@ -36,7 +37,7 @@ class Player : public godot::CharacterBody3D { godot::Vector3 m_SnapVector; float m_Speed; - uint64_t m_PeerId; + PeerID m_PeerId; friend class World; }; diff --git a/src/Server.cpp b/src/Server.cpp index 883e9c2..b6ee784 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -28,17 +28,18 @@ void Server::_ready() { m_Lobby->connect("player_disconnected", callable_mp(this, &Server::OnPlayerDisconnect)); } -void Server::OnPlayerConnect(uint64_t a_PeerId) { +void Server::OnPlayerConnect(PeerID a_PeerId) { + protocol::PlayerInfo playerInfo{a_PeerId, "whoami"}; for (int i = 0; i < m_Peers.size(); i++) { - m_NetworkInterface->rpc_id(a_PeerId, "AddPlayer", m_Peers[i], "Aucuneidee"); + m_NetworkInterface->SendPacket(a_PeerId, protocol::packets::PlayerJoin({m_Peers[i], "whoami"})); } m_Peers.push_back(a_PeerId); - m_NetworkInterface->rpc("AddPlayer", a_PeerId, "Aucuneidee"); + m_NetworkInterface->BroadcastPacket(protocol::packets::PlayerJoin({playerInfo})); } -void Server::OnPlayerDisconnect(uint64_t a_PeerId) { +void Server::OnPlayerDisconnect(PeerID a_PeerId) { m_Peers.erase(a_PeerId); - m_NetworkInterface->rpc("RemovePlayer", a_PeerId); + m_NetworkInterface->BroadcastPacket(protocol::packets::PlayerLeave({a_PeerId})); } } // namespace blitz \ No newline at end of file diff --git a/src/Server.h b/src/Server.h index 2f98f08..c2debff 100644 --- a/src/Server.h +++ b/src/Server.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace blitz { @@ -18,14 +19,14 @@ class Server : public godot::Node { void _ready() override; - void OnPlayerConnect(uint64_t a_PeerId); - void OnPlayerDisconnect(uint64_t a_PeerId); + void OnPlayerConnect(PeerID a_PeerId); + void OnPlayerDisconnect(PeerID a_PeerId); private: Lobby* m_Lobby; NetworkInterface* m_NetworkInterface; - godot::TypedArray m_Peers; + godot::TypedArray m_Peers; }; } // namespace blitz \ No newline at end of file diff --git a/src/World.cpp b/src/World.cpp index 4b63e27..f9f4bc7 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -32,37 +32,53 @@ void World::_ready() { m_NetworkInterface = Object::cast_to(lobby->find_child("NetworkInterface")); DEV_ASSERT(m_NetworkInterface); - m_NetworkInterface->connect("AddPlayer", callable_mp(this, &World::AddPlayer)); - m_NetworkInterface->connect("RemovePlayer", callable_mp(this, &World::RemovePlayer)); - m_NetworkInterface->connect("SetPlayerPositionAndRotation", callable_mp(this, &World::SetPlayerPositionAndRotation)); + m_NetworkInterface->RegisterHandler(protocol::PacketType::PlayerJoin, *this); + m_NetworkInterface->RegisterHandler(protocol::PacketType::PlayerLeave, *this); + m_NetworkInterface->RegisterHandler(protocol::PacketType::PlayerPositionAndRotation, *this); } World::World() {} -World::~World() {} +World::~World() { + if (Engine::get_singleton()->is_editor_hint()) + return; + + m_NetworkInterface->UnregisterHandler(*this); +} void World::_process(float delta) { #if DEBUG_ENABLED if (Engine::get_singleton()->is_editor_hint()) return; #endif + m_PassedTime += delta; + if (m_PassedTime < 0.05f) + return; + + // UtilityFunctions::print(m_PassedTime); + + // m_PassedTime -= 0.05f; + // if (m_PassedTime > 0.5f) + // m_PassedTime = 0.0f; + if (get_multiplayer()->is_server()) { for (int i = 0; i < m_Players->get_child_count(); i++) { Player* player = Object::cast_to(m_Players->get_child(i)); DEV_ASSERT(player); - m_NetworkInterface->rpc( - "SetPlayerPositionAndRotation", player->m_PeerId, player->get_position(), player->GetCameraRotation()); + m_NetworkInterface->BroadcastPacket( + protocol::packets::PlayerPositionAndRotation({player->GetId(), player->get_position(), player->GetCameraRotation()})); } } else { Player* player = GetPlayerById(get_multiplayer()->get_unique_id()); - if (player) - m_NetworkInterface->rpc("SetPlayerPositionAndRotation", get_multiplayer()->get_unique_id(), player->get_position(), - player->GetCameraRotation()); + if (player) { + m_NetworkInterface->BroadcastPacket(protocol::packets::PlayerPositionAndRotation( + {get_multiplayer()->get_unique_id(), player->get_position(), player->GetCameraRotation()})); + } } } -Player* World::GetPlayerById(uint64_t a_PlayerId) { +Player* World::GetPlayerById(PlayerID a_PlayerId) { String stringId = UtilityFunctions::var_to_str(a_PlayerId); for (int i = 0; i < m_Players->get_child_count(); i++) { Node* player = m_Players->get_child(i); @@ -73,8 +89,25 @@ Player* World::GetPlayerById(uint64_t a_PlayerId) { return nullptr; } -void World::AddPlayer(int32_t a_PlayerId, String a_PlayerName) { - UtilityFunctions::print("New Player with id : ", a_PlayerId); +void World::HandlePacket(const protocol::packets::PlayerJoin& a_PlayerJoin) { + const protocol::PlayerInfo& playerInfo = a_PlayerJoin.m_Data.m_Player; + AddPlayer(playerInfo.m_PlayerId, playerInfo.m_PlayerName); +} + +void World::HandlePacket(const protocol::packets::PlayerLeave& a_PlayerLeave) { + RemovePlayer(a_PlayerLeave.m_Data.m_PlayerId); +} + +void World::HandlePacket(const protocol::packets::PlayerPositionAndRotation& a_PlayerPos) { + const auto& data = a_PlayerPos.m_Data; + if (data.m_Player == get_multiplayer()->get_unique_id() || data.m_Player != a_PlayerPos.m_Sender) + return; + + SetPlayerPositionAndRotation(data.m_Player, data.m_Position, data.m_Rotation); +} + +void World::AddPlayer(PlayerID a_PlayerId, String a_PlayerName) { + UtilityFunctions::print("New Player with id : ", a_PlayerId, " and name ", a_PlayerName); if (a_PlayerId == get_multiplayer()->get_unique_id()) { Ref serverScene = ResourceLoader::get_singleton()->load(FirstPersonPlayerScenePath); FirstPersonPlayer* player = Object::cast_to(serverScene->instantiate()); @@ -90,7 +123,7 @@ void World::AddPlayer(int32_t a_PlayerId, String a_PlayerName) { } } -void World::RemovePlayer(int32_t a_PlayerId) { +void World::RemovePlayer(PlayerID a_PlayerId) { UtilityFunctions::print("Removing Player with id : ", a_PlayerId); Player* player = GetPlayerById(a_PlayerId); if (player) { @@ -98,10 +131,7 @@ void World::RemovePlayer(int32_t a_PlayerId) { } } -void World::SetPlayerPositionAndRotation(int64_t a_PlayerId, Vector3 a_Position, Vector3 a_Rotation) { - if (a_PlayerId == get_multiplayer()->get_unique_id()) - return; - +void World::SetPlayerPositionAndRotation(PlayerID a_PlayerId, const Vector3& a_Position, const Vector3& a_Rotation) { Player* player = GetPlayerById(a_PlayerId); if (player) { player->set_position(a_Position); diff --git a/src/World.h b/src/World.h index 8618bfd..183221b 100644 --- a/src/World.h +++ b/src/World.h @@ -2,12 +2,14 @@ #include +#include + namespace blitz { class Player; class NetworkInterface; -class World : public godot::Node3D { +class World : public godot::Node3D, public protocol::PacketHandler { GDCLASS(World, godot::Node3D) protected: static void _bind_methods(); @@ -16,19 +18,24 @@ class World : public godot::Node3D { World(); ~World(); + // Godot overrides + void _ready() override; void _process(float delta); - void _ready() override; + Player* GetPlayerById(PlayerID a_PlayerId); - Player* GetPlayerById(uint64_t a_PlayerId); - - void AddPlayer(int32_t a_PlayerId, godot::String a_PlayerName); - void RemovePlayer(int32_t a_PlayerId); - void SetPlayerPositionAndRotation(int64_t a_PlayerId, godot::Vector3 a_Position, godot::Vector3 a_Rotation); + void HandlePacket(const protocol::packets::PlayerJoin&) override; + void HandlePacket(const protocol::packets::PlayerLeave&) override; + void HandlePacket(const protocol::packets::PlayerPositionAndRotation&) override; private: NetworkInterface* m_NetworkInterface; godot::Node* m_Players; float m_PassedTime; + + + void AddPlayer(PlayerID a_PlayerId, godot::String a_PlayerName); + void RemovePlayer(PlayerID a_PlayerId); + void SetPlayerPositionAndRotation(PlayerID a_PlayerId, const godot::Vector3& a_Position, const godot::Vector3& a_Rotation); }; } // namespace blitz \ No newline at end of file