Skip to content

Commit 1da71b8

Browse files
committed
Add high-level multiplayer packet management
Add PacketType tests
1 parent 50e90f4 commit 1da71b8

File tree

13 files changed

+1064
-0
lines changed

13 files changed

+1064
-0
lines changed

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>
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 = std::make_unique<ClientManager>(this);
134+
}
135+
136+
void GameManager::create_host(std::string session_name) {
137+
host_manager = std::make_unique<HostManager>(this);
138+
if (!session_name.empty()) {
139+
host_manager->get_host_session().set_game_name(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: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
11
#pragma once
22

3+
#include <memory>
34
#include <optional>
45
#include <span>
6+
#include <string>
57

68
#include "openvic-simulation/DefinitionManager.hpp"
79
#include "openvic-simulation/InstanceManager.hpp"
810
#include "openvic-simulation/dataloader/ModManager.hpp"
911
#include "openvic-simulation/dataloader/Dataloader.hpp"
1012
#include "openvic-simulation/misc/GameRulesManager.hpp"
1113
#include "openvic-simulation/gen/commit_info.gen.hpp"
14+
#include "openvic-simulation/multiplayer/ClientManager.hpp"
15+
#include "openvic-simulation/multiplayer/HostManager.hpp"
1216

1317
#include <function2/function2.hpp>
1418

1519
namespace OpenVic {
20+
struct HostManager;
21+
struct ClientManager;
22+
1623
struct GameManager {
1724
using elapsed_time_getter_func_t = fu2::function_base<true, true, fu2::capacity_none, false, false, uint64_t() const>;
1825

@@ -30,6 +37,9 @@ namespace OpenVic {
3037
bool PROPERTY_CUSTOM_PREFIX(definitions_loaded, are);
3138
bool PROPERTY_CUSTOM_PREFIX(mod_descriptors_loaded, are);
3239

40+
std::unique_ptr<HostManager> host_manager;
41+
std::unique_ptr<ClientManager> client_manager;
42+
3343
public:
3444
GameManager(
3545
InstanceManager::gamestate_updated_func_t new_gamestate_updated_callback,
@@ -45,6 +55,22 @@ namespace OpenVic {
4555
return instance_manager ? &*instance_manager : nullptr;
4656
}
4757

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

5076
bool load_mod_descriptors(std::span<const std::string> descriptors);
@@ -57,6 +83,9 @@ namespace OpenVic {
5783

5884
bool update_clock();
5985

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

0 commit comments

Comments
 (0)