Skip to content

Commit a9c405d

Browse files
committed
Add high-level multiplayer packet management
Add ChatManager Add PacketType tests Add ChatManager tests Add `snitch::game_manager` extern variable Add `snitch::get_mp_game_managers(size_t)` extern function Disable `SNITCH_DEFINE_MAIN` for tests/src/main.cpp Add cross-platform fopen in `OpenVic::utility`
1 parent b2f299c commit a9c405d

20 files changed

+2252
-1
lines changed

src/openvic-simulation/GameManager.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
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
#include <cstddef>
610
#include <string_view>
711

812
#include "openvic-simulation/dataloader/Dataloader.hpp"
13+
#include "openvic-simulation/utility/Containers.hpp"
914
#include "openvic-simulation/utility/Logger.hpp"
1015

1116
using namespace OpenVic;
@@ -230,6 +235,26 @@ bool GameManager::update_clock() {
230235
return instance_manager->update_clock();
231236
}
232237

238+
void GameManager::create_client() {
239+
client_manager = memory::make_unique<ClientManager>(this);
240+
chat_manager = memory::make_unique<ChatManager>(client_manager.get());
241+
}
242+
243+
void GameManager::create_host(std::string_view session_name) {
244+
host_manager = memory::make_unique<HostManager>(this);
245+
if (!session_name.empty()) {
246+
host_manager->get_host_session().set_game_name(memory::string { session_name });
247+
}
248+
}
249+
250+
void GameManager::delete_client() {
251+
client_manager.reset();
252+
}
253+
254+
void GameManager::delete_host(){
255+
host_manager.reset();
256+
}
257+
233258
uint64_t GameManager::get_elapsed_microseconds() {
234259
return get_elapsed_usec_time_callback();
235260
}

src/openvic-simulation/GameManager.hpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include <optional>
4+
#include <span>
45
#include <string_view>
56

67
#include "openvic-simulation/DefinitionManager.hpp"
@@ -9,11 +10,17 @@
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/ChatManager.hpp"
14+
#include "openvic-simulation/multiplayer/ClientManager.hpp"
15+
#include "openvic-simulation/multiplayer/HostManager.hpp"
1216
#include "openvic-simulation/utility/ForwardableSpan.hpp"
1317

1418
#include <function2/function2.hpp>
1519

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

@@ -31,6 +38,10 @@ namespace OpenVic {
3138
bool PROPERTY_CUSTOM_PREFIX(definitions_loaded, are);
3239
bool PROPERTY_CUSTOM_PREFIX(mod_descriptors_loaded, are);
3340

41+
memory::unique_ptr<HostManager> host_manager;
42+
memory::unique_ptr<ClientManager> client_manager;
43+
memory::unique_ptr<ChatManager> chat_manager;
44+
3445
bool _get_mod_dependencies(Mod const* mod, memory::vector<Mod const*>& load_list);
3546

3647
public:
@@ -48,6 +59,30 @@ namespace OpenVic {
4859
return instance_manager ? &*instance_manager : nullptr;
4960
}
5061

62+
inline HostManager* get_host_manager() {
63+
return host_manager.get();
64+
}
65+
66+
inline HostManager const* get_host_manager() const {
67+
return host_manager.get();
68+
}
69+
70+
inline ClientManager* get_client_manager() {
71+
return client_manager.get();
72+
}
73+
74+
inline ClientManager const* get_client_manager() const {
75+
return client_manager.get();
76+
}
77+
78+
inline ChatManager* get_chat_manager() {
79+
return chat_manager.get();
80+
}
81+
82+
inline ChatManager const* get_chat_manager() const {
83+
return chat_manager.get();
84+
}
85+
5186
inline bool set_base_path(Dataloader::path_span_t base_path) {
5287
OV_ERR_FAIL_COND_V_MSG(base_path.size() > 1, "more than one dataloader base path provided", false);
5388
OV_ERR_FAIL_COND_V_MSG(!dataloader.set_roots(base_path, {}), "failed to set dataloader base path", false);
@@ -70,6 +105,12 @@ namespace OpenVic {
70105

71106
bool update_clock();
72107

108+
void create_client();
109+
void create_host(std::string_view session_name = "");
110+
111+
void delete_client();
112+
void delete_host();
113+
73114
static constexpr std::string_view get_commit_hash() {
74115
return SIM_COMMIT_HASH;
75116
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
#include "BaseMultiplayerManager.hpp"
3+
4+
#include "openvic-simulation/multiplayer/PacketType.hpp"
5+
#include "openvic-simulation/utility/ErrorMacros.hpp"
6+
7+
using namespace OpenVic;
8+
9+
BaseMultiplayerManager::BaseMultiplayerManager(GameManager* game_manager) : game_manager(game_manager) {
10+
packet_cache.reserve_power(15);
11+
}
12+
13+
bool BaseMultiplayerManager::broadcast_packet(PacketType const& type, PacketType::argument_type argument) {
14+
OV_ERR_FAIL_COND_V(!PacketType::is_valid_type(type), false);
15+
return true;
16+
}
17+
18+
bool BaseMultiplayerManager::send_packet(client_id_type client_id, PacketType const& type, PacketType::argument_type argument) {
19+
OV_ERR_FAIL_COND_V(!PacketType::is_valid_type(type), false);
20+
return true;
21+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
5+
#include "openvic-simulation/multiplayer/HostSession.hpp"
6+
#include "openvic-simulation/multiplayer/PacketType.hpp"
7+
#include "openvic-simulation/multiplayer/lowlevel/ReliableUdpClient.hpp"
8+
#include "openvic-simulation/types/RingBuffer.hpp"
9+
#include "openvic-simulation/utility/Containers.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+
virtual ~BaseMultiplayerManager() = default;
18+
19+
using client_id_type = uint64_t;
20+
using sequence_type = ReliableUdpClient::sequence_type;
21+
22+
static constexpr client_id_type HOST_ID = static_cast<client_id_type>(~0);
23+
24+
virtual bool broadcast_packet(PacketType const& type, PacketType::argument_type argument);
25+
virtual bool send_packet(client_id_type client_id, PacketType const& type, PacketType::argument_type argument);
26+
virtual int64_t poll() = 0;
27+
virtual void close() = 0;
28+
29+
enum class ConnectionType : uint8_t { HOST, CLIENT };
30+
31+
virtual ConnectionType get_connection_type() const = 0;
32+
33+
template<typename T>
34+
T* cast_as() {
35+
if (get_connection_type() == T::type_tag) {
36+
return static_cast<T*>(this);
37+
}
38+
return nullptr;
39+
}
40+
41+
template<typename T>
42+
T const* cast_as() const {
43+
if (get_connection_type() == T::type_tag) {
44+
return static_cast<T const*>(this);
45+
}
46+
return nullptr;
47+
}
48+
49+
PacketSpan get_last_raw_packet() {
50+
return last_raw_packet;
51+
}
52+
53+
protected:
54+
bool PROPERTY_ACCESS(in_lobby, protected, false);
55+
GameManager* PROPERTY_PTR_ACCESS(game_manager, protected);
56+
HostSession PROPERTY_ACCESS(host_session, protected);
57+
58+
RingBuffer<uint8_t> packet_cache;
59+
60+
struct PacketCacheIndex {
61+
decltype(packet_cache)::const_iterator begin;
62+
decltype(packet_cache)::const_iterator end;
63+
constexpr bool is_valid() const {
64+
return begin != end;
65+
}
66+
};
67+
68+
memory::vector<uint8_t> last_raw_packet;
69+
70+
friend bool PacketTypes::send_raw_packet_process_callback( //
71+
BaseMultiplayerManager* multiplayer_manager, PacketSpan packet
72+
);
73+
};
74+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
2+
#include "ChatManager.hpp"
3+
4+
#include <chrono>
5+
#include <utility>
6+
7+
#include "openvic-simulation/GameManager.hpp"
8+
#include "openvic-simulation/multiplayer/ClientManager.hpp"
9+
#include "openvic-simulation/multiplayer/PacketType.hpp"
10+
#include "openvic-simulation/utility/ErrorMacros.hpp"
11+
12+
using namespace OpenVic;
13+
14+
ChatGroup::ChatGroup(index_t index, memory::vector<BaseMultiplayerManager::client_id_type>&& clients)
15+
: index { index }, clients { std::move(clients) } {}
16+
17+
ChatManager::ChatManager(ClientManager* client_manager) : client_manager { client_manager } {}
18+
19+
bool ChatManager::send_private_message(BaseMultiplayerManager::client_id_type to, memory::string&& message) {
20+
MessageData data { MessageType::PRIVATE, std::move(message), to };
21+
22+
ChatMessageLog const& log = log_message(client_manager->get_client_id(), std::move(data));
23+
bool was_sent = client_manager->broadcast_packet(PacketTypes::send_chat_message, &log);
24+
return was_sent;
25+
}
26+
27+
bool ChatManager::send_private_message(BaseMultiplayerManager::client_id_type to, std::string_view message) {
28+
return send_private_message(to, memory::string { message });
29+
}
30+
31+
bool ChatManager::send_public_message(memory::string&& message) {
32+
MessageData data { MessageType::PUBLIC, std::move(message) };
33+
34+
ChatMessageLog const& log = log_message(client_manager->get_client_id(), std::move(data));
35+
bool was_sent = client_manager->broadcast_packet(PacketTypes::send_chat_message, &log);
36+
return was_sent;
37+
}
38+
39+
bool ChatManager::send_public_message(std::string_view message) {
40+
return send_public_message(memory::string { message });
41+
}
42+
43+
bool ChatManager::send_group_message(ChatGroup const& group, memory::string&& message) {
44+
MessageData data { MessageType::GROUP, std::move(message), group.get_index() };
45+
46+
ChatMessageLog const& log = log_message(client_manager->get_client_id(), std::move(data));
47+
bool was_sent = client_manager->broadcast_packet(PacketTypes::send_chat_message, &log);
48+
return was_sent;
49+
}
50+
51+
bool ChatManager::send_group_message(ChatGroup::index_t group_id, memory::string&& message) {
52+
OV_ERR_FAIL_INDEX_V(group_id, groups.size(), false);
53+
return send_group_message(groups[group_id], std::move(message));
54+
}
55+
56+
bool ChatManager::send_group_message(ChatGroup const& group, std::string_view message) {
57+
return send_group_message(group, memory::string { message });
58+
}
59+
60+
bool ChatManager::send_group_message(ChatGroup::index_t group_id, std::string_view message) {
61+
return send_group_message(group_id, memory::string { message });
62+
}
63+
64+
ChatMessageLog const& ChatManager::log_message( //
65+
BaseMultiplayerManager::client_id_type from, MessageData&& message,
66+
std::chrono::time_point<std::chrono::system_clock> timestamp
67+
) {
68+
ChatMessageLog const& log = messages.emplace_back(
69+
from, std::move(message), std::chrono::time_point_cast<std::chrono::milliseconds>(timestamp).time_since_epoch().count()
70+
);
71+
message_logged(log);
72+
return log;
73+
}
74+
75+
ChatMessageLog const* ChatManager::_log_message(ChatMessageLog&& log) {
76+
std::chrono::time_point cur = std::chrono::system_clock::now();
77+
int64_t current_epoch = std::chrono::time_point_cast<std::chrono::milliseconds>(cur).time_since_epoch().count();
78+
OV_ERR_FAIL_COND_V_MSG(log.timestamp > current_epoch, nullptr, "Invalid chat message log, cannot log future timestamps.");
79+
80+
ChatMessageLog const& moved_log = messages.emplace_back(std::move(log));
81+
message_logged(moved_log);
82+
return &moved_log;
83+
}
84+
85+
memory::vector<ChatMessageLog> const& ChatManager::get_message_logs() const {
86+
return messages;
87+
}
88+
89+
void ChatManager::create_group(memory::vector<BaseMultiplayerManager::client_id_type>&& clients) {
90+
client_manager->broadcast_packet(PacketTypes::add_chat_group, clients);
91+
}
92+
93+
void ChatManager::_create_group(memory::vector<BaseMultiplayerManager::client_id_type>&& clients) {
94+
groups.push_back({ groups.size(), std::move(clients) });
95+
ChatGroup const& last = groups.back();
96+
group_created(last);
97+
}
98+
99+
void ChatManager::set_group(ChatGroup::index_t group_id, memory::vector<BaseMultiplayerManager::client_id_type>&& clients) {
100+
OV_ERR_FAIL_INDEX(group_id, groups.size());
101+
client_manager->broadcast_packet(PacketTypes::modify_chat_group, PacketChatGroupModifyData { group_id, clients });
102+
}
103+
104+
void ChatManager::_set_group(ChatGroup::index_t group_id, memory::vector<BaseMultiplayerManager::client_id_type>&& clients) {
105+
ChatGroup& group = groups[group_id];
106+
std::swap(group.clients, clients);
107+
group_modified(group, clients);
108+
}
109+
110+
ChatGroup const& ChatManager::get_group(ChatGroup::index_t group_index) const {
111+
return groups.at(group_index);
112+
}
113+
114+
void ChatManager::delete_group(ChatGroup::index_t group_id) {
115+
OV_ERR_FAIL_INDEX(group_id, groups.size());
116+
client_manager->broadcast_packet(
117+
PacketTypes::delete_chat_group,
118+
PacketType::argument_type { std::in_place_index<PacketTypes::delete_chat_group.packet_id>, group_id }
119+
);
120+
}
121+
122+
void ChatManager::_delete_group(ChatGroup::index_t group_id) {
123+
groups.erase(groups.begin() + group_id);
124+
group_deleted(group_id);
125+
}

0 commit comments

Comments
 (0)