Skip to content

Commit 429bb78

Browse files
committed
Add high-level multiplayer packet management
Add PacketType tests
1 parent 82e38a8 commit 429bb78

13 files changed

Lines changed: 1104 additions & 0 deletions

src/openvic-simulation/GameManager.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#include "GameManager.hpp"
22

33
#include <chrono>
4+
#include <string_view>
5+
6+
#include "openvic-simulation/multiplayer/ClientManager.hpp"
7+
#include "openvic-simulation/multiplayer/HostManager.hpp"
48

59
using namespace OpenVic;
610

@@ -125,6 +129,17 @@ bool GameManager::update_clock() {
125129
return instance_manager->update_clock();
126130
}
127131

132+
void GameManager::create_client() {
133+
client_manager = memory::make_unique<ClientManager>(this);
134+
}
135+
136+
void GameManager::create_host(std::string_view session_name) {
137+
host_manager = memory::make_unique<HostManager>(this);
138+
if (!session_name.empty()) {
139+
host_manager->get_host_session().set_game_name(memory::string { session_name });
140+
}
141+
}
142+
128143
uint64_t GameManager::get_elapsed_microseconds() {
129144
return get_elapsed_usec_time_callback();
130145
}

src/openvic-simulation/GameManager.hpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,23 @@
22

33
#include <optional>
44
#include <span>
5+
#include <string_view>
56

67
#include "openvic-simulation/DefinitionManager.hpp"
78
#include "openvic-simulation/InstanceManager.hpp"
89
#include "openvic-simulation/dataloader/ModManager.hpp"
910
#include "openvic-simulation/dataloader/Dataloader.hpp"
1011
#include "openvic-simulation/misc/GameRulesManager.hpp"
1112
#include "openvic-simulation/gen/commit_info.gen.hpp"
13+
#include "openvic-simulation/multiplayer/ClientManager.hpp"
14+
#include "openvic-simulation/multiplayer/HostManager.hpp"
1215

1316
#include <function2/function2.hpp>
1417

1518
namespace OpenVic {
19+
struct HostManager;
20+
struct ClientManager;
21+
1622
struct GameManager {
1723
using elapsed_time_getter_func_t = fu2::function_base<true, true, fu2::capacity_none, false, false, uint64_t() const>;
1824

@@ -30,6 +36,9 @@ namespace OpenVic {
3036
bool PROPERTY_CUSTOM_PREFIX(definitions_loaded, are);
3137
bool PROPERTY_CUSTOM_PREFIX(mod_descriptors_loaded, are);
3238

39+
memory::unique_ptr<HostManager> host_manager;
40+
memory::unique_ptr<ClientManager> client_manager;
41+
3342
public:
3443
GameManager(
3544
InstanceManager::gamestate_updated_func_t new_gamestate_updated_callback,
@@ -45,6 +54,22 @@ namespace OpenVic {
4554
return instance_manager ? &*instance_manager : nullptr;
4655
}
4756

57+
inline HostManager* get_host_manager() {
58+
return host_manager.get();
59+
}
60+
61+
inline HostManager const* get_host_manager() const {
62+
return host_manager.get();
63+
}
64+
65+
inline ClientManager* get_client_manager() {
66+
return client_manager.get();
67+
}
68+
69+
inline ClientManager const* get_client_manager() const {
70+
return client_manager.get();
71+
}
72+
4873
bool set_roots(Dataloader::path_span_t roots, Dataloader::path_span_t replace_paths);
4974

5075
bool load_mod_descriptors(std::span<const memory::string> descriptors);
@@ -57,6 +82,9 @@ namespace OpenVic {
5782

5883
bool update_clock();
5984

85+
void create_client();
86+
void create_host(std::string_view session_name = "");
87+
6088
static constexpr std::string_view get_commit_hash() {
6189
return SIM_COMMIT_HASH;
6290
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
#include "BaseMultiplayerManager.hpp"
3+
4+
#include <any>
5+
6+
#include "openvic-simulation/multiplayer/PacketType.hpp"
7+
#include "openvic-simulation/utility/ErrorMacros.hpp"
8+
9+
using namespace OpenVic;
10+
11+
BaseMultiplayerManager::BaseMultiplayerManager(GameManager* game_manager) : game_manager(game_manager) {
12+
packet_cache.reserve_power(15);
13+
}
14+
15+
bool BaseMultiplayerManager::broadcast_packet(PacketType const& type, std::any const& argument) {
16+
OV_ERR_FAIL_COND_V(!PacketType::is_valid_type(type), false);
17+
return true;
18+
}
19+
20+
bool BaseMultiplayerManager::send_packet(client_id_type client_id, PacketType const& type, std::any const& argument) {
21+
OV_ERR_FAIL_COND_V(!PacketType::is_valid_type(type), false);
22+
return true;
23+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#pragma once
2+
3+
#include <any>
4+
#include <cstdint>
5+
6+
#include "openvic-simulation/multiplayer/HostSession.hpp"
7+
#include "openvic-simulation/multiplayer/PacketType.hpp"
8+
#include "openvic-simulation/multiplayer/lowlevel/ReliableUdpClient.hpp"
9+
#include "openvic-simulation/types/RingBuffer.hpp"
10+
#include "openvic-simulation/utility/Containers.hpp"
11+
#include "openvic-simulation/utility/Getters.hpp"
12+
13+
namespace OpenVic {
14+
struct GameManager;
15+
16+
struct BaseMultiplayerManager {
17+
BaseMultiplayerManager(GameManager* game_manager = nullptr);
18+
19+
using client_id_type = uint64_t;
20+
using sequence_type = ReliableUdpClient::sequence_type;
21+
22+
virtual bool broadcast_packet(PacketType const& type, std::any const& argument);
23+
virtual bool send_packet(client_id_type client_id, PacketType const& type, std::any const& argument);
24+
virtual int64_t poll() = 0;
25+
26+
enum class ConnectionType : uint8_t { HOST, CLIENT };
27+
28+
virtual ConnectionType get_connection_type() const = 0;
29+
30+
template<typename T>
31+
T* cast_as() {
32+
if (get_connection_type() == T::type_tag) {
33+
return static_cast<T*>(this);
34+
}
35+
return nullptr;
36+
}
37+
38+
PacketSpan get_last_raw_packet() {
39+
return last_raw_packet;
40+
}
41+
42+
protected:
43+
bool PROPERTY_ACCESS(in_lobby, protected, false);
44+
GameManager* PROPERTY_PTR_ACCESS(game_manager, protected);
45+
HostSession PROPERTY_ACCESS(host_session, protected);
46+
47+
RingBuffer<uint8_t> packet_cache;
48+
49+
struct PacketCacheIndex {
50+
decltype(packet_cache)::const_iterator begin;
51+
decltype(packet_cache)::const_iterator end;
52+
constexpr bool is_valid() const {
53+
return begin != end;
54+
}
55+
};
56+
57+
memory::vector<uint8_t> last_raw_packet;
58+
59+
friend bool PacketTypes::send_raw_packet_process_callback( //
60+
BaseMultiplayerManager* multiplayer_manager, PacketSpan packet
61+
);
62+
};
63+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
2+
#include "ClientManager.hpp"
3+
4+
#include "openvic-simulation/multiplayer/PacketType.hpp"
5+
#include "openvic-simulation/multiplayer/lowlevel/HostnameAddress.hpp"
6+
#include "openvic-simulation/multiplayer/lowlevel/NetworkError.hpp"
7+
#include "openvic-simulation/multiplayer/lowlevel/NetworkSocket.hpp"
8+
#include "openvic-simulation/multiplayer/lowlevel/PacketBuilder.hpp"
9+
#include "openvic-simulation/multiplayer/lowlevel/ReliableUdpClient.hpp"
10+
#include "openvic-simulation/utility/Containers.hpp"
11+
#include "openvic-simulation/utility/ErrorMacros.hpp"
12+
13+
using namespace OpenVic;
14+
15+
bool ClientManager::connect_to(HostnameAddress const& address, NetworkSocket::port_type port) {
16+
NetworkError err = client.connect_to(address.resolved_address(), port);
17+
OV_ERR_FAIL_COND_V(err != NetworkError::OK, false);
18+
PacketBuilder builder;
19+
builder.put_back<uint8_t>(1);
20+
return client.set_packet(builder) == NetworkError::OK;
21+
}
22+
23+
template<PacketType const& type>
24+
bool ClientManager::_send_packet_to_host(auto const& argument) {
25+
PacketBuilder builder;
26+
builder.put_back(type.packet_id);
27+
if (!type.create_packet(this, argument, builder)) {
28+
return false;
29+
}
30+
31+
if (!add_packet_to_cache(builder)) {
32+
return false;
33+
}
34+
35+
client.set_packet(builder);
36+
return true;
37+
}
38+
39+
bool ClientManager::broadcast_packet(PacketType const& type, std::any const& argument) {
40+
if (!BaseMultiplayerManager::broadcast_packet(type, argument)) {
41+
return false;
42+
}
43+
44+
OV_ERR_FAIL_COND_V(!type.can_client_send, false);
45+
return _send_packet_to_host<PacketTypes::broadcast_packet>(BroadcastData { type.packet_id, argument });
46+
}
47+
48+
bool ClientManager::send_packet(client_id_type client_id, PacketType const& type, std::any const& argument) {
49+
if (!BaseMultiplayerManager::send_packet(client_id, type, argument)) {
50+
return false;
51+
}
52+
53+
OV_ERR_FAIL_COND_V(!type.can_client_send, false);
54+
return _send_packet_to_host<PacketTypes::retransmit_packet>(RetransmitData { client_id, type.packet_id, argument });
55+
}
56+
57+
int64_t ClientManager::poll() {
58+
int64_t result = client.available_packets();
59+
if (result < 1) {
60+
return result;
61+
}
62+
63+
PacketSpan span = client.packet_span();
64+
if (client_id == INVALID_CLIENT_ID) {
65+
OV_ERR_FAIL_COND_V(client.get_current_sequence_value() != 0, -1);
66+
client_id = span.read<decltype(client_id)>();
67+
OV_ERR_FAIL_COND_V(client_id == INVALID_CLIENT_ID, -1);
68+
return poll();
69+
}
70+
71+
decltype(PacketType::packet_id) packet_id = span.read<decltype(packet_id)>();
72+
OV_ERR_FAIL_COND_V(!PacketType::is_valid_type(packet_id), -1);
73+
74+
PacketType const& packet_type = PacketType::get_type_by_id(packet_id);
75+
if (!packet_type.process_packet(this, span)) {
76+
// TODO: packet processing failed
77+
return -1;
78+
}
79+
// TODO: packet was processed
80+
81+
return result;
82+
}
83+
84+
bool ClientManager::add_packet_to_cache(std::span<uint8_t> bytes) {
85+
OV_ERR_FAIL_COND_V(bytes.size_bytes() > ReliableUdpClient::MAX_PACKET_SIZE, false);
86+
decltype(packet_cache)::iterator begin = packet_cache.append(bytes.data(), bytes.size_bytes());
87+
decltype(packet_cache)::iterator end = packet_cache.end();
88+
OV_ERR_FAIL_COND_V(begin == end, false);
89+
return sequence_to_index.try_emplace(client.get_next_sequence_value(), PacketCacheIndex { begin, end }).second;
90+
}
91+
92+
memory::vector<uint8_t> ClientManager::get_packet_cache(sequence_type sequence_value) {
93+
decltype(sequence_to_index)::iterator it = sequence_to_index.find(sequence_value);
94+
OV_ERR_FAIL_COND_V(it == sequence_to_index.end(), {});
95+
return { it.value().begin, it.value().end };
96+
}
97+
98+
void ClientManager::remove_from_cache(sequence_type sequence_value) {
99+
decltype(sequence_to_index)::iterator it = sequence_to_index.find(sequence_value);
100+
OV_ERR_FAIL_COND(it == sequence_to_index.end());
101+
sequence_to_index.unordered_erase(it);
102+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#pragma once
2+
3+
#include <limits>
4+
5+
#include "openvic-simulation/multiplayer/BaseMultiplayerManager.hpp"
6+
#include "openvic-simulation/multiplayer/lowlevel/HostnameAddress.hpp"
7+
#include "openvic-simulation/multiplayer/lowlevel/NetworkSocket.hpp"
8+
#include "openvic-simulation/multiplayer/lowlevel/ReliableUdpClient.hpp"
9+
#include "openvic-simulation/multiplayer/lowlevel/TcpPacketStream.hpp"
10+
#include "openvic-simulation/utility/Containers.hpp"
11+
12+
namespace OpenVic {
13+
struct GameManager;
14+
15+
struct ClientManager final : BaseMultiplayerManager {
16+
using BaseMultiplayerManager::BaseMultiplayerManager;
17+
18+
bool connect_to(HostnameAddress const& address, NetworkSocket::port_type port);
19+
20+
bool broadcast_packet(PacketType const& type, std::any const& argument) override;
21+
bool send_packet(client_id_type client_id, PacketType const& type, std::any const& argument) override;
22+
int64_t poll() override;
23+
24+
static constexpr ConnectionType type_tag = ConnectionType::CLIENT;
25+
inline constexpr ConnectionType get_connection_type() const override {
26+
return type_tag;
27+
}
28+
29+
static constexpr client_id_type INVALID_CLIENT_ID = std::numeric_limits<client_id_type>::max();
30+
31+
private:
32+
ReliableUdpClient PROPERTY_REF(client);
33+
TcpPacketStream file_client;
34+
client_id_type PROPERTY(client_id, INVALID_CLIENT_ID);
35+
36+
friend bool PacketTypes::update_host_session_process_callback(BaseMultiplayerManager* game_manager, PacketSpan packet);
37+
38+
ordered_map<sequence_type, PacketCacheIndex> sequence_to_index;
39+
40+
bool add_packet_to_cache(std::span<uint8_t> bytes);
41+
memory::vector<uint8_t> get_packet_cache(sequence_type sequence_value);
42+
void remove_from_cache(sequence_type sequence_value);
43+
44+
template<PacketType const& type>
45+
bool _send_packet_to_host(auto const& argument);
46+
};
47+
}

0 commit comments

Comments
 (0)