17 enum class Directionality {
25 template<
typename ... A>
27 static constexpr size_t bufsize = (RPCMsgUnpacker::TotalSerializedSize<A>() + ...) + RPCMsgUnpacker::header_size;
29 std::array<char,bufsize> buffer {0};
32 auto& operator[](
size_t idx){
35 auto& operator[](
size_t idx)
const{
41 const std::string_view toView()
const{
42 return std::string_view(buffer.data(),bufsize);
61 typedef ConcurrentQueue<enqueued_rpc> queue_t;
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;
67 rpc_store ClientRPCs, ServerRPCs;
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);
75 reading = readingptr_s.load(), writing = writingptr_s.load();
76 std::swap(reading, writing);
77 readingptr_s.store(reading);
78 writingptr_s.store(writing);
82 std::shared_ptr<Data> data = std::make_shared<Data>();
93 inline void RegisterRPC_Impl(uint16_t
id,
const Fn& func, rpc_store& store, Directionality type) {
94 store[id] = rpc_entry{ func, type };
104 static inline void serializeType(
size_t& offset,
char* buffer,
const T& value){
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)>();
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;
122 msg[0] = NetworkBase::CommandCode::RPC;
123 std::memcpy(msg.data() + 1, uuid_bytes.raw(), uuid_bytes.size());
124 std::memcpy(msg.data() + 1 + uuid_bytes.size(), &
id,
sizeof(
id));
127 size_t offset = RPCMsgUnpacker::header_size;
128 (serializeType(offset, msg.data(), args), ...);
129 Debug::Assert(offset == msg.bufsize,
"Incorrect number of bytes written!");
138 inline void ProcessRPCs_impl(
const std::atomic<queue_t*>& ptr,
const rpc_store& table) {
139 auto reading = ptr.load();
141 while (reading->try_dequeue(cmd)) {
144 std::memcpy(&RPC, cmd.msg.data() + RPCMsgUnpacker::code_offset,
sizeof(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);
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);
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);
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);
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);
206 Debug::Warning(
"Cannot send Client RPC with ID {} to recipient {}",
id, target);
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);
217 Debug::Warning(
"Cannot send Client RPC with ID {} to all except {}",
id, doNotSend);
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);
242 data->writingptr_c.load()->enqueue({ std::string(cmd.data(),cmd.size()), isOwner, origin });
249 data->writingptr_s.load()->enqueue({ std::string(cmd.data(),cmd.size()), isOwner, origin });
256 ProcessRPCs_impl(data->readingptr_c, data->ClientRPCs);
263 ProcessRPCs_impl(data->readingptr_s, data->ServerRPCs);