RavEngine
Loading...
Searching...
No Matches
RPCComponent.hpp
1#pragma once
2#include "Queryable.hpp"
3#include "RPCMsgUnpacker.hpp"
4#include "Ref.hpp"
5#include "DataStructures.hpp"
6#include "SpinLock.hpp"
7#include "NetworkBase.hpp"
8#include "Debug.hpp"
9#include "Entity.hpp"
10#include "App.hpp"
11#include "NetworkIdentity.hpp"
12#include <steam/isteamnetworkingsockets.h>
13
14namespace RavEngine {
15 class RPCComponent : public ComponentWithOwner, public Queryable<RPCComponent> {
16 public:
17 enum class Directionality {
18 OnlyOwnerInvokes, // the owner
19 Bidirectional
20 };
21 RPCComponent(Entity owner) : ComponentWithOwner(owner){}
22
23 MOVE_NO_COPY(RPCComponent);
24
25 template<typename ... A>
26 struct RPCMessage{
27 static constexpr size_t bufsize = (RPCMsgUnpacker::TotalSerializedSize<A>() + ...) + RPCMsgUnpacker::header_size;
28 private:
29 std::array<char,bufsize> buffer {0};
30 public:
31 static_assert(bufsize < std::numeric_limits<uint32_t>::max(), "Message is too long!");
32 auto& operator[](size_t idx){
33 return buffer[idx];
34 }
35 auto& operator[](size_t idx) const{
36 return buffer[idx];
37 }
38 auto data(){
39 return buffer.data();
40 }
41 const std::string_view toView() const{
42 return std::string_view(buffer.data(),bufsize);
43 }
44 };
45
46
47 private:
48 struct rpc_entry {
49 Function<void(RPCMsgUnpacker&, HSteamNetConnection)> func;
50 Directionality mode;
51 };
52
54
55 struct enqueued_rpc {
56 std::string msg;
57 bool isOwner;
59 };
60
61 typedef ConcurrentQueue<enqueued_rpc> queue_t;
62 struct Data{
63 queue_t C_buffer_A, C_buffer_B, S_buffer_A, S_buffer_B;
64 std::atomic<queue_t*> readingptr_c = &C_buffer_A, writingptr_c = &C_buffer_B,
65 readingptr_s = &S_buffer_A, writingptr_s = &S_buffer_B;
66
67 rpc_store ClientRPCs, ServerRPCs;
68
69 void Swap(){
70 queue_t* reading = readingptr_c.load(), * writing = writingptr_c.load();
71 std::swap(reading, writing);
72 readingptr_c.store(reading);
73 writingptr_c.store(writing);
74
75 reading = readingptr_s.load(), writing = writingptr_s.load();
76 std::swap(reading, writing);
77 readingptr_s.store(reading);
78 writingptr_s.store(writing);
79 }
80 };
81
82 std::shared_ptr<Data> data = std::make_shared<Data>();
83
84
92 template<typename Fn>
93 inline void RegisterRPC_Impl(uint16_t id, const Fn& func, rpc_store& store, Directionality type) {
94 store[id] = rpc_entry{ func, type };
95 }
96
103 template<typename T>
104 static inline void serializeType(size_t& offset, char* buffer, const T& value){
105 auto id = CTTI<T>();
106 std::memcpy(buffer + offset, &id, sizeof(ctti_t));
107 std::memcpy(buffer + offset + sizeof(ctti_t), &value, RPCMsgUnpacker::SerializedSize<T>());
108 offset += RPCMsgUnpacker::TotalSerializedSize<decltype(value)>();
109 }
110
116 template<typename ... A>
117 inline RPCMessage<A...> SerializeRPC(uint16_t id, A&& ... args) const{
118 auto& uuid_bytes = GetOwner().GetComponent<NetworkIdentity>().GetNetworkID();
119 RPCMessage<A...> msg; // default-init to zeros
120
121 //write message header
122 msg[0] = NetworkBase::CommandCode::RPC; //command code
123 std::memcpy(msg.data() + 1, uuid_bytes.raw(), uuid_bytes.size()); //entity uuid
124 std::memcpy(msg.data() + 1 + uuid_bytes.size(), &id, sizeof(id)); //RPC ID
125
126 //write mesage body
127 size_t offset = RPCMsgUnpacker::header_size;
128 (serializeType(offset, msg.data(), args), ...); //fold expression on all variadics
129 Debug::Assert(offset == msg.bufsize, "Incorrect number of bytes written!");
130 return msg;
131 }
132
138 inline void ProcessRPCs_impl(const std::atomic<queue_t*>& ptr, const rpc_store& table) {
139 auto reading = ptr.load();
140 enqueued_rpc cmd;
141 while (reading->try_dequeue(cmd)) {
142 //read out of the header which RPC to invoke
143 uint16_t RPC;
144 std::memcpy(&RPC, cmd.msg.data() + RPCMsgUnpacker::code_offset, sizeof(RPC));
145
146 //invoke that RPC
147 if (table.if_contains(RPC, [&](const rpc_entry& func) {
148 if (cmd.isOwner || func.mode == Directionality::Bidirectional) {
149 RPCMsgUnpacker packer{cmd.msg};
150 func.func(packer, cmd.origin);
151 }
152 })) {
153 }
154 else {
155 Debug::Warning("No cmd code with ID {}", RPC);
156 }
157 }
158 }
159
160 public:
161
167 template<typename Fn>
168 inline void RegisterServerRPC(uint16_t name, const Fn& func, Directionality type = Directionality::OnlyOwnerInvokes) {
169 RegisterRPC_Impl(name, func, data->ServerRPCs, type);
170 }
171
177 template<typename Fn>
178 inline void RegisterClientRPC(uint16_t name, const Fn& func, Directionality type = Directionality::OnlyOwnerInvokes) {
179 RegisterRPC_Impl(name, func, data->ClientRPCs, type);
180 }
181
188 template<typename ... A>
189 constexpr inline void InvokeServerRPC(uint16_t id, NetworkBase::Reliability mode, A&& ... args) const{
190 if (data->ServerRPCs.contains(id)) {
191 auto msg = SerializeRPC(id, args...);
192 GetApp()->networkManager.client->SendMessageToServer(msg.toView(), mode);
193 }
194 else {
195 Debug::Warning("Cannot send Server RPC with ID {}", id);
196 }
197 }
198
199 template<typename ... A>
200 constexpr inline void InvokeClientRPCDirected(uint16_t id, HSteamNetConnection target, NetworkBase::Reliability mode, A&& ... args) const{
201 if (data->ClientRPCs.contains(id)) {
202 auto msg = SerializeRPC(id, args...);
203 GetApp()->networkManager.server->SendMessageToClient(msg, target, mode);
204 }
205 else {
206 Debug::Warning("Cannot send Client RPC with ID {} to recipient {}", id, target);
207 }
208 }
209
210 template<typename ... A>
211 constexpr inline void InvokeClientRPCToAllExcept(uint16_t id, HSteamNetConnection doNotSend, NetworkBase::Reliability mode, A&& ... args) const{
212 if (data->ClientRPCs.contains(id)) {
213 auto msg = SerializeRPC(id, args...);
214 GetApp()->networkManager.server->SendMessageToAllClientsExcept(msg.toView(), doNotSend, mode);
215 }
216 else {
217 Debug::Warning("Cannot send Client RPC with ID {} to all except {}", id, doNotSend);
218 }
219 }
220
227 template<typename ... A>
228 constexpr inline void InvokeClientRPC(uint16_t id, NetworkBase::Reliability mode, A&& ... args) const{
229 if (data->ClientRPCs.contains(id)) {
230 auto msg = SerializeRPC(id, args...);
231 GetApp()->networkManager.server->SendMessageToAllClients(msg.toView(), mode);
232 }
233 else {
234 Debug::Warning("Cannot send Client RPC with ID {}", id);
235 }
236 }
237
241 inline void CacheClientRPC(const std::string_view& cmd, bool isOwner, HSteamNetConnection origin) {
242 data->writingptr_c.load()->enqueue({ std::string(cmd.data(),cmd.size()), isOwner, origin });
243 }
244
248 inline void CacheServerRPC(const std::string_view& cmd, bool isOwner, HSteamNetConnection origin) {
249 data->writingptr_s.load()->enqueue({ std::string(cmd.data(),cmd.size()), isOwner, origin });
250 }
251
255 inline void ProcessClientRPCs() {
256 ProcessRPCs_impl(data->readingptr_c, data->ClientRPCs);
257 }
258
262 inline void ProcessServerRPCs() {
263 ProcessRPCs_impl(data->readingptr_s, data->ServerRPCs);
264 }
265
266
270 inline void Swap() {
271 data->Swap();
272 }
273 };
274}
Definition ComponentWithOwner.hpp:6
static void Assert(bool condition, const char *formatstr, T &&... values)
Definition Debug.hpp:132
static void Warning(const char *message)
Definition Debug.hpp:64
Definition RPCComponent.hpp:15
void CacheServerRPC(const std::string_view &cmd, bool isOwner, HSteamNetConnection origin)
Definition RPCComponent.hpp:248
void RegisterServerRPC(uint16_t name, const Fn &func, Directionality type=Directionality::OnlyOwnerInvokes)
Definition RPCComponent.hpp:168
void RegisterClientRPC(uint16_t name, const Fn &func, Directionality type=Directionality::OnlyOwnerInvokes)
Definition RPCComponent.hpp:178
void Swap()
Definition RPCComponent.hpp:270
constexpr void InvokeServerRPC(uint16_t id, NetworkBase::Reliability mode, A &&... args) const
Definition RPCComponent.hpp:189
void CacheClientRPC(const std::string_view &cmd, bool isOwner, HSteamNetConnection origin)
Definition RPCComponent.hpp:241
void ProcessClientRPCs()
Definition RPCComponent.hpp:255
void ProcessServerRPCs()
Definition RPCComponent.hpp:262
constexpr void InvokeClientRPC(uint16_t id, NetworkBase::Reliability mode, A &&... args) const
Definition RPCComponent.hpp:228
Definition RPCMsgUnpacker.hpp:7
Definition concurrentqueue.h:747
uint16 uint16_t
Definition fwd.hpp:117
Definition Animation.hpp:6
Definition Entity.hpp:11
Definition Queryable.hpp:21
Definition RPCComponent.hpp:26