Loading net/include/net/replication_system.hpp +13 −0 Original line number Diff line number Diff line #pragma once #include <com/runner.hpp> #include <net/types.hpp> #include <utils/serialization.hpp> namespace net { struct ReplicationSystem final : com::Runner Loading @@ -16,8 +17,20 @@ namespace net { com::ContextItem* owner, const std::string& getter_name, const std::string& setter_name); void handle_packet(ConnectionId from, utils::Deserializer& deserializer); private: utils::Buffer create_packet(const ReplicatedProperty& property, const com::Reflection::ValuePtr& value, int& written_bytes) const; void call_setter(const std::vector<std::string>& context_item_path, const std::string& setter_name, const com::Reflection::ValuePtr& value); void initialize() override; const size_t INITIAL_BUFFER_SIZE = 512; std::vector<ReplicatedProperty> replicated_properties; double replication_interval = 0.3; double time_since_last_replication = 0.0; }; } net/include/net/rpc_system.hpp +3 −1 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ namespace net * @brief Processes an incoming RPC packet, deserializes it, and calls the appropriate local function. * Should not be called directly, only by the NetDriver when receiving an RPC packet. */ void process_packet(ConnectionId from, utils::Deserializer& deserializer); void handle_packet(ConnectionId from, utils::Deserializer& deserializer); void call_remote( com::ContextItem* context_item, Loading Loading @@ -48,6 +48,8 @@ namespace net private: const size_t RPC_PACKET_INITIAL_BUFFER_SIZE = 1024; void register_functions() override; std::vector<uint8_t> create_packet( Loading net/include/net/types.hpp +2 −1 Original line number Diff line number Diff line Loading @@ -39,7 +39,8 @@ namespace net { enum class PacketType : uint8_t { RPC RPC, REPLICATION }; enum class SocketMode : uint8_t Loading net/src/driver.cpp +5 −1 Original line number Diff line number Diff line Loading @@ -143,7 +143,11 @@ void Driver::handle_packet(ConnectionId from, NetworkMessage* message) switch (packet_type) { case PacketType::RPC: rpc_system()->process_packet(from, deserializer); rpc_system()->handle_packet(from, deserializer); break; case PacketType::REPLICATION: replication()->handle_packet(from, deserializer); break; default: Loading net/src/replication_system.cpp +101 −2 Original line number Diff line number Diff line #include <net/index.hpp> #include <net/replication_system.hpp> #include <phx/timer.hpp> namespace net { void ReplicationSystem::next_round() { // TODO: put this code into some fixed_next_round function that is called at a fixed timestep time_since_last_replication += osi::timer()->dt(); if (time_since_last_replication > replication_interval) { for (const auto& prop : replicated_properties) { // TODO: Delta compression here com::Reflection::ValuePtr current_value = com::make_default_value(prop.last_value->typeID()); std::vector<com::Reflection::ValuePtr> params; params.push_back(current_value); prop.getter_func(params); int written_bytes = 0; auto buffer = create_packet(prop, current_value, written_bytes); std::span<const uint8_t> buffer_span(buffer.data(), written_bytes); driver()->broadcast(buffer_span, ReliabilityMode::UNRELIABLE); } time_since_last_replication -= replication_interval; } } Loading @@ -23,12 +42,14 @@ namespace net { } if (!owner->reflection()->functions().contains(getter_name)) { LOG(LSL_ERROR, "[ReplicationSystem] Getter function " << getter_name << " not found in owner " << owner->name()); LOG(LSL_ERROR, "[ReplicationSystem] Getter function " << getter_name << " not found in owner " << owner->name()); return; } if (!owner->reflection()->functions().contains(setter_name)) { LOG(LSL_ERROR, "[ReplicationSystem] Setter function " << setter_name << " not found in owner " << owner->name()); LOG(LSL_ERROR, "[ReplicationSystem] Setter function " << setter_name << " not found in owner " << owner->name()); return; } Loading @@ -48,6 +69,84 @@ namespace net { replicated_properties.push_back(property); } void ReplicationSystem::handle_packet(ConnectionId from, utils::Deserializer& deserializer) { std::vector<std::string> context_item_path; utils::deserialize_path(deserializer, context_item_path); if (context_item_path.empty()) { LOG(LSL_ERROR, "[ReplicationSystem] Received replication packet with empty context item path"); return; } std::string setter_name; deserializer.text1b(setter_name, MAX_STRING_LENGTH); auto value = utils::deserialize_reflection_value(deserializer); call_setter(context_item_path, setter_name, value); } void ReplicationSystem::call_setter(const std::vector<std::string>& context_item_path, const std::string& setter_name, const com::Reflection::ValuePtr& value) { const auto context_item = com::Folder::root()->locate<com::ContextItem>(context_item_path); if (!context_item) { LOG(LSL_ERROR, "[ReplicationSystem] Context item not found"); return; } auto& functions = context_item->reflection()->functions(); if (!functions.contains(setter_name)) { LOG(LSL_ERROR, "[ReplicationSystem] Setter Function not found"); return; } const auto& function = functions.at(setter_name); std::vector<com::Reflection::ValuePtr> params; params.push_back(value); if (function.param_types.size() != params.size()) { LOG(LSL_ERROR, "[ReplicationSystem] Setter function should have exactly one parameter, but found " << function.param_types.size()); return; } if (function.param_types[0] != params[0]->typeID()) { LOG(LSL_ERROR, "[ReplicationSystem] Parameter type mismatch when calling setter function " << setter_name << " in context item " << context_item->name()); return; } function.code(params); } utils::Buffer ReplicationSystem::create_packet(const ReplicatedProperty& property, const com::Reflection::ValuePtr& value, int& written_bytes) const { utils::Buffer buffer(INITIAL_BUFFER_SIZE); auto serializer = utils::create_serializer(buffer); serializer.value1b(PacketType::REPLICATION); utils::serialize_path(serializer, property.owner->path(com::Folder::root())); serializer.text1b(property.setter_name, MAX_STRING_LENGTH); utils::serialize_reflection_value(serializer, value); written_bytes = static_cast<int>(serializer.adapter().writtenBytesCount()); return buffer; } void ReplicationSystem::initialize() { osi::updaters()->find<com::Folder>("net")->push_back<com::Link>(self_name() + ".link", this); } ReplicationSystem::ReplicationSystem() : com::Runner(self_name()) { } Loading Loading
net/include/net/replication_system.hpp +13 −0 Original line number Diff line number Diff line #pragma once #include <com/runner.hpp> #include <net/types.hpp> #include <utils/serialization.hpp> namespace net { struct ReplicationSystem final : com::Runner Loading @@ -16,8 +17,20 @@ namespace net { com::ContextItem* owner, const std::string& getter_name, const std::string& setter_name); void handle_packet(ConnectionId from, utils::Deserializer& deserializer); private: utils::Buffer create_packet(const ReplicatedProperty& property, const com::Reflection::ValuePtr& value, int& written_bytes) const; void call_setter(const std::vector<std::string>& context_item_path, const std::string& setter_name, const com::Reflection::ValuePtr& value); void initialize() override; const size_t INITIAL_BUFFER_SIZE = 512; std::vector<ReplicatedProperty> replicated_properties; double replication_interval = 0.3; double time_since_last_replication = 0.0; }; }
net/include/net/rpc_system.hpp +3 −1 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ namespace net * @brief Processes an incoming RPC packet, deserializes it, and calls the appropriate local function. * Should not be called directly, only by the NetDriver when receiving an RPC packet. */ void process_packet(ConnectionId from, utils::Deserializer& deserializer); void handle_packet(ConnectionId from, utils::Deserializer& deserializer); void call_remote( com::ContextItem* context_item, Loading Loading @@ -48,6 +48,8 @@ namespace net private: const size_t RPC_PACKET_INITIAL_BUFFER_SIZE = 1024; void register_functions() override; std::vector<uint8_t> create_packet( Loading
net/include/net/types.hpp +2 −1 Original line number Diff line number Diff line Loading @@ -39,7 +39,8 @@ namespace net { enum class PacketType : uint8_t { RPC RPC, REPLICATION }; enum class SocketMode : uint8_t Loading
net/src/driver.cpp +5 −1 Original line number Diff line number Diff line Loading @@ -143,7 +143,11 @@ void Driver::handle_packet(ConnectionId from, NetworkMessage* message) switch (packet_type) { case PacketType::RPC: rpc_system()->process_packet(from, deserializer); rpc_system()->handle_packet(from, deserializer); break; case PacketType::REPLICATION: replication()->handle_packet(from, deserializer); break; default: Loading
net/src/replication_system.cpp +101 −2 Original line number Diff line number Diff line #include <net/index.hpp> #include <net/replication_system.hpp> #include <phx/timer.hpp> namespace net { void ReplicationSystem::next_round() { // TODO: put this code into some fixed_next_round function that is called at a fixed timestep time_since_last_replication += osi::timer()->dt(); if (time_since_last_replication > replication_interval) { for (const auto& prop : replicated_properties) { // TODO: Delta compression here com::Reflection::ValuePtr current_value = com::make_default_value(prop.last_value->typeID()); std::vector<com::Reflection::ValuePtr> params; params.push_back(current_value); prop.getter_func(params); int written_bytes = 0; auto buffer = create_packet(prop, current_value, written_bytes); std::span<const uint8_t> buffer_span(buffer.data(), written_bytes); driver()->broadcast(buffer_span, ReliabilityMode::UNRELIABLE); } time_since_last_replication -= replication_interval; } } Loading @@ -23,12 +42,14 @@ namespace net { } if (!owner->reflection()->functions().contains(getter_name)) { LOG(LSL_ERROR, "[ReplicationSystem] Getter function " << getter_name << " not found in owner " << owner->name()); LOG(LSL_ERROR, "[ReplicationSystem] Getter function " << getter_name << " not found in owner " << owner->name()); return; } if (!owner->reflection()->functions().contains(setter_name)) { LOG(LSL_ERROR, "[ReplicationSystem] Setter function " << setter_name << " not found in owner " << owner->name()); LOG(LSL_ERROR, "[ReplicationSystem] Setter function " << setter_name << " not found in owner " << owner->name()); return; } Loading @@ -48,6 +69,84 @@ namespace net { replicated_properties.push_back(property); } void ReplicationSystem::handle_packet(ConnectionId from, utils::Deserializer& deserializer) { std::vector<std::string> context_item_path; utils::deserialize_path(deserializer, context_item_path); if (context_item_path.empty()) { LOG(LSL_ERROR, "[ReplicationSystem] Received replication packet with empty context item path"); return; } std::string setter_name; deserializer.text1b(setter_name, MAX_STRING_LENGTH); auto value = utils::deserialize_reflection_value(deserializer); call_setter(context_item_path, setter_name, value); } void ReplicationSystem::call_setter(const std::vector<std::string>& context_item_path, const std::string& setter_name, const com::Reflection::ValuePtr& value) { const auto context_item = com::Folder::root()->locate<com::ContextItem>(context_item_path); if (!context_item) { LOG(LSL_ERROR, "[ReplicationSystem] Context item not found"); return; } auto& functions = context_item->reflection()->functions(); if (!functions.contains(setter_name)) { LOG(LSL_ERROR, "[ReplicationSystem] Setter Function not found"); return; } const auto& function = functions.at(setter_name); std::vector<com::Reflection::ValuePtr> params; params.push_back(value); if (function.param_types.size() != params.size()) { LOG(LSL_ERROR, "[ReplicationSystem] Setter function should have exactly one parameter, but found " << function.param_types.size()); return; } if (function.param_types[0] != params[0]->typeID()) { LOG(LSL_ERROR, "[ReplicationSystem] Parameter type mismatch when calling setter function " << setter_name << " in context item " << context_item->name()); return; } function.code(params); } utils::Buffer ReplicationSystem::create_packet(const ReplicatedProperty& property, const com::Reflection::ValuePtr& value, int& written_bytes) const { utils::Buffer buffer(INITIAL_BUFFER_SIZE); auto serializer = utils::create_serializer(buffer); serializer.value1b(PacketType::REPLICATION); utils::serialize_path(serializer, property.owner->path(com::Folder::root())); serializer.text1b(property.setter_name, MAX_STRING_LENGTH); utils::serialize_reflection_value(serializer, value); written_bytes = static_cast<int>(serializer.adapter().writtenBytesCount()); return buffer; } void ReplicationSystem::initialize() { osi::updaters()->find<com::Folder>("net")->push_back<com::Link>(self_name() + ".link", this); } ReplicationSystem::ReplicationSystem() : com::Runner(self_name()) { } Loading