From dc143e94ecbd1a99fea1b4629ba7e91585bc512d Mon Sep 17 00:00:00 2001 From: ZeEndy Date: Fri, 13 Feb 2026 16:37:58 +0200 Subject: [PATCH 1/3] Port schemas from netfox --- src/diff_history_encoder.cpp | 91 ++-- src/diff_history_encoder.h | 16 +- src/network_schema.h | 38 ++ src/redundant_history_encoder.cpp | 118 ++--- src/redundant_history_encoder.h | 14 +- src/register_types.cpp | 74 ++- src/rollback_history_recorder.h | 14 +- src/rollback_history_transmitter.cpp | 206 +++------ src/rollback_history_transmitter.h | 35 +- src/schemas_static.hpp | 345 ++++++++++++++ src/serializers.h | 655 +++++++++++++++++++++++++++ src/snapshot_history_encoder.cpp | 87 ++-- src/snapshot_history_encoder.h | 14 +- 13 files changed, 1337 insertions(+), 370 deletions(-) create mode 100644 src/network_schema.h create mode 100644 src/schemas_static.hpp create mode 100644 src/serializers.h diff --git a/src/diff_history_encoder.cpp b/src/diff_history_encoder.cpp index a245de7..0262e23 100644 --- a/src/diff_history_encoder.cpp +++ b/src/diff_history_encoder.cpp @@ -2,37 +2,34 @@ #include "diff_history_encoder.h" #include "utils.h" -#include +#include #include +#include #include -#include -Ref<_DiffHistoryEncoder> _DiffHistoryEncoder::new_(Ref<_PropertyHistoryBuffer> p_history, Ref p_property_cache) -{ +Ref<_DiffHistoryEncoder> _DiffHistoryEncoder::new_(Ref<_PropertyHistoryBuffer> p_history, Ref p_property_cache, Ref<_NetworkSchema> p_schema) { Ref<_DiffHistoryEncoder> ref; ref.instantiate(); ref->_history = p_history; ref->_property_cache = p_property_cache; + ref->_schema = p_schema; return ref; } -void _DiffHistoryEncoder::add_properties(TypedArray properties) -{ +void _DiffHistoryEncoder::add_properties(TypedArray properties) { bool has_new_properties = false; - for(Ref property_entry : properties) - { + for (Ref property_entry : properties) { bool is_new = _ensure_property_idx(property_entry->_to_string()); has_new_properties = has_new_properties || is_new; } // If we added any new properties, increment version - if(has_new_properties) + if (has_new_properties) _version = (_version + 1) % 256; } -PackedByteArray _DiffHistoryEncoder::encode(int tick, int reference_tick, TypedArray properties) -{ +PackedByteArray _DiffHistoryEncoder::encode(int tick, int reference_tick, TypedArray properties) { ERR_FAIL_COND_V_MSG(properties.size() > 255, PackedByteArray(), "Property indices may not fit into bytes!"); Ref<_PropertySnapshot> snapshot = _history->get_snapshot(tick); @@ -42,30 +39,30 @@ PackedByteArray _DiffHistoryEncoder::encode(int tick, int reference_tick, TypedA _full_snapshot = snapshot->as_dictionary(); _encoded_snapshot = diff_snapshot->as_dictionary(); - if(diff_snapshot->is_empty()) + if (diff_snapshot->is_empty()) return PackedByteArray(); Ref buffer; buffer.instantiate(); buffer->put_u8(_version); - for(String property : diff_snapshot->properties()) - { + for (String property : diff_snapshot->properties()) { int property_idx = _property_indexes.get_by_value(property); Variant property_value = diff_snapshot->get_value(property); buffer->put_u8(property_idx); - buffer->put_var(property_value); + _schema->encode(property, property_value, buffer); + /* + buffer->put_var(property_value);*/ } return buffer->get_data_array(); } -Ref<_PropertySnapshot> _DiffHistoryEncoder::decode(PackedByteArray data, TypedArray properties) -{ +Ref<_PropertySnapshot> _DiffHistoryEncoder::decode(PackedByteArray data, TypedArray properties) { Ref<_PropertySnapshot> result = _PropertySnapshot::new_(); - if(data.is_empty()) + if (data.is_empty()) return result; Ref buffer; @@ -73,16 +70,12 @@ Ref<_PropertySnapshot> _DiffHistoryEncoder::decode(PackedByteArray data, TypedAr buffer->set_data_array(data); uint8_t packet_version = buffer->get_u8(); - if(packet_version != _version) - { - if(!_has_received) - { + if (packet_version != _version) { + if (!_has_received) { // This is the first time we receive data // Assume the version is OK _version = packet_version; - } - else - { + } else { // Since we don't remove entries, only add, we can still parse what we can _logger->warning(vformat("Property config version mismatch - own %d != received %d", _version, packet_version)); } @@ -90,47 +83,39 @@ Ref<_PropertySnapshot> _DiffHistoryEncoder::decode(PackedByteArray data, TypedAr _has_received = true; - while(buffer->get_available_bytes() > 0) - { + while (buffer->get_available_bytes() > 0) { int property_idx = buffer->get_u8(); - Variant property_value = buffer->get_var(); - if(!_property_indexes.has_key(property_idx)) - { + if (!_property_indexes.has_key(property_idx)) { _logger->warning(vformat("Received unknown property index %d, ignoring!", property_idx)); continue; } - String property_entry = _property_indexes.get_by_key(property_idx); + Variant property_value = _schema->decode(property_entry, buffer); result->set_value(property_entry, property_value); } return result; } -bool _DiffHistoryEncoder::apply(int tick, Ref<_PropertySnapshot> snapshot, int reference_tick, int sender) -{ - if(tick < (int) Utils::get_autoload("NetworkRollback")->get("history_start")) - { +bool _DiffHistoryEncoder::apply(int tick, Ref<_PropertySnapshot> snapshot, int reference_tick, int sender) { + if (tick < (int)Utils::get_autoload("NetworkRollback")->get("history_start")) { // State too old! _logger->error(vformat("Received diff snapshot for @%d, rejecting because older than %s frames", tick, Utils::get_autoload("NetworkRollback")->get("history_limit"))); return false; } - if(snapshot->is_empty()) + if (snapshot->is_empty()) return true; - if(sender > 0) - { + if (sender > 0) { snapshot->sanitize(sender, _property_cache); - if(snapshot->is_empty()) - { + if (snapshot->is_empty()) { _logger->warning(vformat("Received invalid diff from #%s for @%s", sender, tick)); return false; } } - if(!_history->has(reference_tick)) - { + if (!_history->has(reference_tick)) { // Reference tick missing, hope for the best _logger->warning(vformat("Reference tick %d missing for #%s applying %d", reference_tick, sender, tick)); } @@ -140,27 +125,22 @@ bool _DiffHistoryEncoder::apply(int tick, Ref<_PropertySnapshot> snapshot, int r return true; } -Dictionary _DiffHistoryEncoder::get_encoded_snapshot() -{ +Dictionary _DiffHistoryEncoder::get_encoded_snapshot() { return _encoded_snapshot; } -Dictionary _DiffHistoryEncoder::get_full_snapshot() -{ +Dictionary _DiffHistoryEncoder::get_full_snapshot() { return _full_snapshot; } -bool _DiffHistoryEncoder::_ensure_property_idx(String property) -{ - if(_property_indexes.has_value(property)) - { +bool _DiffHistoryEncoder::_ensure_property_idx(String property) { + if (_property_indexes.has_value(property)) { return false; } ERR_FAIL_COND_V_MSG(_property_indexes.size() >= 256, false, "Property index map is full, can't add new property!"); int idx = UtilityFunctions::hash(property) % 256; - while(_property_indexes.has_key(idx)) - { + while (_property_indexes.has_key(idx)) { idx = UtilityFunctions::hash(idx + 1) % 256; } _property_indexes.insert(idx, property); @@ -170,10 +150,9 @@ bool _DiffHistoryEncoder::_ensure_property_idx(String property) Ref<_NetfoxLogger> _DiffHistoryEncoder::_logger; -void _DiffHistoryEncoder::_bind_methods() -{ +void _DiffHistoryEncoder::_bind_methods() { _logger = _NetfoxLogger::for_netfox("DiffHistoryEncoder"); - + ClassDB::bind_static_method("_DiffHistoryEncoder", D_METHOD("new_", "p_history", "p_property_cache"), &_DiffHistoryEncoder::new_); ClassDB::bind_method(D_METHOD("add_properties", "properties"), &_DiffHistoryEncoder::add_properties); ClassDB::bind_method(D_METHOD("encode", "tick", "reference_tick", "properties"), &_DiffHistoryEncoder::encode); @@ -181,6 +160,4 @@ void _DiffHistoryEncoder::_bind_methods() ClassDB::bind_method(D_METHOD("apply", "tick", "snapshot", "reference_tick", "sender"), &_DiffHistoryEncoder::apply, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_encoded_snapshot"), &_DiffHistoryEncoder::get_encoded_snapshot); ClassDB::bind_method(D_METHOD("get_full_snapshot"), &_DiffHistoryEncoder::get_full_snapshot); - } - diff --git a/src/diff_history_encoder.h b/src/diff_history_encoder.h index de9e6e0..71a5546 100644 --- a/src/diff_history_encoder.h +++ b/src/diff_history_encoder.h @@ -1,26 +1,28 @@ #pragma once +#include "internal_bimap.h" +#include "logger.h" +#include "network_schema.h" #include "property_cache.h" #include "property_entry.h" -#include "logger.h" #include "property_history_buffer.h" #include "property_snapshot.h" -#include "internal_bimap.h" +#include #include #include #include -#include using namespace godot; class _DiffHistoryEncoder : public RefCounted { GDCLASS(_DiffHistoryEncoder, RefCounted); -public: +public: protected: Ref<_PropertyHistoryBuffer> _history; Ref _property_cache; + Ref<_NetworkSchema> _schema; Dictionary _full_snapshot; Dictionary _encoded_snapshot; @@ -37,15 +39,15 @@ class _DiffHistoryEncoder : public RefCounted { _DiffHistoryEncoder() = default; ~_DiffHistoryEncoder() override = default; - static Ref<_DiffHistoryEncoder> new_(Ref<_PropertyHistoryBuffer> p_history, Ref p_property_cache); + static Ref<_DiffHistoryEncoder> new_(Ref<_PropertyHistoryBuffer> p_history, Ref p_property_cache, Ref<_NetworkSchema> p_schema); void add_properties(TypedArray properties); PackedByteArray encode(int tick, int reference_tick, TypedArray properties); Ref<_PropertySnapshot> decode(PackedByteArray data, TypedArray properties); -// TODO: Rework metrics so these are not needed + // TODO: Rework metrics so these are not needed bool apply(int tick, Ref<_PropertySnapshot> snapshot, int reference_tick, int sender = -1); Dictionary get_encoded_snapshot(); Dictionary get_full_snapshot(); bool _ensure_property_idx(String property); -}; \ No newline at end of file +}; diff --git a/src/network_schema.h b/src/network_schema.h new file mode 100644 index 0000000..3f7d164 --- /dev/null +++ b/src/network_schema.h @@ -0,0 +1,38 @@ +#pragma once +#include "serializers.h" +#include +#include +#include + +using namespace godot; + +class _NetworkSchema : public RefCounted { + GDCLASS(_NetworkSchema, RefCounted); + +protected: + Dictionary _serializers; + Ref<_VariantSerializer> _fallback; + static void _bind_methods() { + ClassDB::bind_static_method("_NetworkSchema", D_METHOD("new_", "p_serializers"), &_NetworkSchema::new_); + }; + +public: + _NetworkSchema() { + _fallback.instantiate(); + }; + ~_NetworkSchema() {}; + void encode(String path, Variant value, Ref &buffer) { + Ref serializer = Object::cast_to(_serializers.get(path, _fallback)); + serializer->encode(value, buffer); + } + Variant decode(String path, Ref &buffer) { + Ref serializer = Object::cast_to(_serializers.get(path, _fallback)); + return serializer->decode(buffer); + } + static Ref<_NetworkSchema> new_(Dictionary p_serializers) { + Ref<_NetworkSchema> ref; + ref.instantiate(); + ref->_serializers = p_serializers; + return ref; + } +}; diff --git a/src/redundant_history_encoder.cpp b/src/redundant_history_encoder.cpp index 313de7a..7f0d4b5 100644 --- a/src/redundant_history_encoder.cpp +++ b/src/redundant_history_encoder.cpp @@ -1,77 +1,70 @@ #include "redundant_history_encoder.h" #include "utils.h" -#include +#include #include +#include #include -int _RedundantHistoryEncoder::get_redundancy() -{ +int _RedundantHistoryEncoder::get_redundancy() { return _redundancy; } -void _RedundantHistoryEncoder::set_redundancy(int p_redundancy) -{ - if(p_redundancy <= 0) - { +void _RedundantHistoryEncoder::set_redundancy(int p_redundancy) { + if (p_redundancy <= 0) { _logger->warning(vformat("Attempting to set redundancy to %d, which would send no data!", p_redundancy)); - return ; + return; } _redundancy = p_redundancy; } -void _RedundantHistoryEncoder::set_properties(TypedArray properties) -{ - if(_properties != properties) - { +void _RedundantHistoryEncoder::set_properties(TypedArray properties) { + if (_properties != properties) { _version = (_version + 1) % 256; _properties = properties.duplicate(); } } -Array _RedundantHistoryEncoder::encode(int tick, TypedArray properties) -{ - if(_history->is_empty()) - { +PackedByteArray _RedundantHistoryEncoder::encode(int tick, TypedArray properties) { + if (_history->is_empty()) { return Array(); } - Array data = Array(); + Ref buffer; + buffer.instantiate(); + buffer->put_u8(_version); - for(int i=0; isize()); i+=1) - { + for (int i = 0; i < Math::min(_redundancy, _history->size()); i += 1) { int offset_tick = tick - i; - if(offset_tick < _history->get_earliest_tick()) + if (offset_tick < _history->get_earliest_tick()) break; Ref<_PropertySnapshot> snapshot = _history->get_snapshot(offset_tick); - for(int i = 0; i < properties.size(); ++i) - { + for (int i = 0; i < properties.size(); ++i) { Ref property = properties[i]; - data.append(snapshot->get_value(property->_to_string())); + //data.append(snapshot->get_value(property->_to_string())); + String path = property->to_string(); + _schema->encode(path, snapshot->get_value(path), buffer); } } - - data.append(_version); - return data; + return buffer->get_data_array(); } -TypedArray<_PropertySnapshot> _RedundantHistoryEncoder::decode(Array data, TypedArray properties) -{ - if(data.is_empty() || properties.is_empty()) +TypedArray<_PropertySnapshot> _RedundantHistoryEncoder::decode(PackedByteArray data, TypedArray properties) { + if (data.is_empty() || properties.is_empty()) { return Array(); + } - int packet_version = data.pop_back(); + Ref buffer; + buffer.instantiate(); + buffer->set_data_array(data); + int packet_version = buffer->get_u8(); - if(packet_version != _version) - { - if(!_has_received) - { + if (packet_version != _version) { + if (!_has_received) { // First packet, assume version is OK _version = packet_version; - } - else - { + } else { // Version mismatch, can't parse _logger->warning(vformat("Version mismatch! own: %d, received: %s", _version, packet_version)); return Array(); @@ -79,45 +72,37 @@ TypedArray<_PropertySnapshot> _RedundantHistoryEncoder::decode(Array data, Typed } TypedArray<_PropertySnapshot> result = Array(); - int redundancy = data.size() / properties.size(); - for (int i = 0; i < redundancy; ++i) - result.append(_PropertySnapshot::new_()); - - for(int i=0; i snapshot = result[offset_idx]; - Ref property_entry = properties[prop_idx]; - snapshot->set_value(property_entry->_to_string(), data[i]); + while (buffer->get_available_bytes() > 0) { + Ref<_PropertySnapshot> snapshot; + snapshot.instantiate(); + for (int i = 0; i < properties.size(); i += 1) { + Ref property = properties[i]; + String path = property->to_string(); + Variant value = _schema->decode(path, buffer); + snapshot->set_value(path, value); + } + result.append(snapshot); } - _has_received = true; return result; } -int _RedundantHistoryEncoder::apply(int tick, TypedArray<_PropertySnapshot> snapshots, int sender) -{ +int _RedundantHistoryEncoder::apply(int tick, TypedArray<_PropertySnapshot> snapshots, int sender) { int earliest_new_tick = -1; - for(int i=0; i snapshot = snapshots[i]; - if(offset_tick < (int) Utils::get_autoload("NetworkRollback")->get("history_start")) - { + if (offset_tick < (int)Utils::get_autoload("NetworkRollback")->get("history_start")) { // Data too old _logger->warning(vformat("Received data for %s, rejecting because older than %s frames", offset_tick, Utils::get_autoload("NetworkRollback")->get("history_limit"))); continue; } - if(sender > 0) - { + if (sender > 0) { snapshot->sanitize(sender, _property_cache); - if(snapshot->is_empty()) - { + if (snapshot->is_empty()) { // No valid properties ( probably after sanitize ) _logger->warning(vformat("Received invalid data from %d for tick %d", sender, tick)); continue; @@ -125,8 +110,7 @@ int _RedundantHistoryEncoder::apply(int tick, TypedArray<_PropertySnapshot> snap } Ref<_PropertySnapshot> known_snapshot = _history->get_snapshot(offset_tick); - if(!known_snapshot->equals(snapshot)) - { + if (!known_snapshot->equals(snapshot)) { // Received a new snapshot, store and emit signal _history->set_snapshot(offset_tick, snapshot); earliest_new_tick = offset_tick; @@ -136,19 +120,18 @@ int _RedundantHistoryEncoder::apply(int tick, TypedArray<_PropertySnapshot> snap return earliest_new_tick; } -Ref<_RedundantHistoryEncoder> _RedundantHistoryEncoder::new_(Ref<_PropertyHistoryBuffer> p_history, Ref p_property_cache) -{ +Ref<_RedundantHistoryEncoder> _RedundantHistoryEncoder::new_(Ref<_PropertyHistoryBuffer> p_history, Ref p_property_cache, Ref<_NetworkSchema> p_schema) { Ref<_RedundantHistoryEncoder> ref; ref.instantiate(); ref->_history = p_history; ref->_property_cache = p_property_cache; + ref->_schema = p_schema; return ref; } Ref<_NetfoxLogger> _RedundantHistoryEncoder::_logger; -void _RedundantHistoryEncoder::_bind_methods() -{ +void _RedundantHistoryEncoder::_bind_methods() { _logger = _NetfoxLogger::for_netfox("_RedundantHistoryEncoder"); ClassDB::bind_static_method("_RedundantHistoryEncoder", D_METHOD("new_", "p_history", "p_property_cache"), &_RedundantHistoryEncoder::new_); @@ -158,7 +141,6 @@ void _RedundantHistoryEncoder::_bind_methods() ClassDB::bind_method(D_METHOD("encode", "tick", "properties"), &_RedundantHistoryEncoder::encode); ClassDB::bind_method(D_METHOD("decode", "data", "properties"), &_RedundantHistoryEncoder::decode); ClassDB::bind_method(D_METHOD("apply", "tick", "snapshots", "sender"), &_RedundantHistoryEncoder::apply, DEFVAL(0)); - + ADD_PROPERTY(PropertyInfo(Variant::INT, "redundancy"), "set_redundancy", "get_redundancy"); } - diff --git a/src/redundant_history_encoder.h b/src/redundant_history_encoder.h index 100f4dd..4ee7ef4 100644 --- a/src/redundant_history_encoder.h +++ b/src/redundant_history_encoder.h @@ -1,27 +1,29 @@ #pragma once #include "logger.h" +#include "network_schema.h" #include "property_cache.h" #include "property_entry.h" #include "property_history_buffer.h" #include "property_snapshot.h" +#include #include #include #include -#include using namespace godot; class _RedundantHistoryEncoder : public RefCounted { GDCLASS(_RedundantHistoryEncoder, RefCounted); -public: +public: protected: int _redundancy = 4; Ref<_PropertyHistoryBuffer> _history; Array _properties; Ref _property_cache; + Ref<_NetworkSchema> _schema; int _version = 0; bool _has_received = false; @@ -33,12 +35,12 @@ class _RedundantHistoryEncoder : public RefCounted { _RedundantHistoryEncoder() = default; ~_RedundantHistoryEncoder() override = default; - static Ref<_RedundantHistoryEncoder> new_(Ref<_PropertyHistoryBuffer> p_history, Ref p_property_cache); + static Ref<_RedundantHistoryEncoder> new_(Ref<_PropertyHistoryBuffer> p_history, Ref p_property_cache, Ref<_NetworkSchema> p_schema); int get_redundancy(); void set_redundancy(int p_redundancy); void set_properties(TypedArray properties); - Array encode(int tick, TypedArray properties); - TypedArray<_PropertySnapshot> decode(Array data, TypedArray properties); + PackedByteArray encode(int tick, TypedArray properties); + TypedArray<_PropertySnapshot> decode(PackedByteArray data, TypedArray properties); int apply(int tick, TypedArray<_PropertySnapshot> snapshots, int sender = -1); -}; \ No newline at end of file +}; diff --git a/src/register_types.cpp b/src/register_types.cpp index 6acb78c..0b19131 100644 --- a/src/register_types.cpp +++ b/src/register_types.cpp @@ -5,28 +5,30 @@ #include #include +#include "bimap.h" +#include "diff_history_encoder.h" #include "logger.h" +#include "network_schema.h" +#include "peer_visibility_filter.h" #include "property_cache.h" #include "property_config.h" #include "property_entry.h" #include "property_history_buffer.h" #include "property_snapshot.h" -#include "peer_visibility_filter.h" -#include "diff_history_encoder.h" #include "redundant_history_encoder.h" -#include "snapshot_history_encoder.h" +#include "ring_buffer.h" +#include "rollback_freshness_store.h" #include "rollback_history_recorder.h" #include "rollback_history_transmitter.h" -#include "rollback_freshness_store.h" +#include "schemas_static.hpp" +#include "serializers.h" #include "set.h" -#include "bimap.h" -#include "ring_buffer.h" +#include "snapshot_history_encoder.h" using namespace godot; -void initialize_gdextension_types(ModuleInitializationLevel p_level) -{ - if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) +void initialize_gdextension_types(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) return; GDREGISTER_CLASS(_NetfoxLogger); GDREGISTER_CLASS(_SetIterator); @@ -47,24 +49,50 @@ void initialize_gdextension_types(ModuleInitializationLevel p_level) GDREGISTER_CLASS(_RollbackHistoryRecorder); GDREGISTER_CLASS(_RollbackHistoryTransmitter); GDREGISTER_CLASS(RollbackFreshnessStore); + GDREGISTER_CLASS(_NetworkSchema); + GDREGISTER_CLASS(NetworkSchemaSerializer); + GDREGISTER_CLASS(_VariantSerializer); + GDREGISTER_CLASS(_StringSerializer); + GDREGISTER_CLASS(_BoolSerializer); + GDREGISTER_CLASS(_Uint8Serializer); + GDREGISTER_CLASS(_Uint16Serializer); + GDREGISTER_CLASS(_Uint32Serializer); + GDREGISTER_CLASS(_Uint64Serializer); + GDREGISTER_CLASS(_Int8Serializer); + GDREGISTER_CLASS(_Int16Serializer); + GDREGISTER_CLASS(_Int32Serializer); + GDREGISTER_CLASS(_Int64Serializer); + GDREGISTER_CLASS(_Float16Serializer); + GDREGISTER_CLASS(_Float32Serializer); + GDREGISTER_CLASS(_Float64Serializer); + GDREGISTER_CLASS(_GenericVec2Serializer); + GDREGISTER_CLASS(_GenericVec3Serializer); + GDREGISTER_CLASS(_Normal2Serializer); + GDREGISTER_CLASS(_Normal3Serializer); + GDREGISTER_CLASS(_GenericVec4Serializer); + GDREGISTER_CLASS(_GenericQuaternionSerializer); + GDREGISTER_CLASS(_GenericTransform2DSerializer); + GDREGISTER_CLASS(_GenericTransform3DSerializer); + GDREGISTER_CLASS(_QuantizingSerializer); + GDREGISTER_CLASS(_ModuloSerializer); + GDREGISTER_CLASS(_ArraySerializer); + GDREGISTER_CLASS(_DictionarySerializer); + GDREGISTER_CLASS(NetworkSchemas); } -void uninitialize_gdextension_types(ModuleInitializationLevel p_level) -{ +void uninitialize_gdextension_types(ModuleInitializationLevel p_level) { if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) return; } -extern "C" -{ - // Initialization - GDExtensionBool GDE_EXPORT netfox_boost_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) - { - GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization); - init_obj.register_initializer(initialize_gdextension_types); - init_obj.register_terminator(uninitialize_gdextension_types); - init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE); +extern "C" { +// Initialization +GDExtensionBool GDE_EXPORT netfox_boost_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) { + GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization); + init_obj.register_initializer(initialize_gdextension_types); + init_obj.register_terminator(uninitialize_gdextension_types); + init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE); - return init_obj.init(); - } -} \ No newline at end of file + return init_obj.init(); +} +} diff --git a/src/rollback_history_recorder.h b/src/rollback_history_recorder.h index 0322176..1360c11 100644 --- a/src/rollback_history_recorder.h +++ b/src/rollback_history_recorder.h @@ -1,25 +1,25 @@ #pragma once #include "property_cache.h" -#include "property_entry.h" #include "property_config.h" +#include "property_entry.h" #include "property_history_buffer.h" #include "property_snapshot.h" #include "set.h" +#include #include +#include #include #include -#include -#include using namespace godot; class _RollbackHistoryRecorder : public RefCounted { GDCLASS(_RollbackHistoryRecorder, RefCounted); -public: -// Provided externally by RBS +public: + // Provided externally by RBS protected: Ref<_PropertyHistoryBuffer> _state_history; @@ -52,10 +52,10 @@ class _RollbackHistoryRecorder : public RefCounted { bool _should_record_tick(int tick); TypedArray _get_state_props_to_record(int tick); -// Shared utils, extract later + // Shared utils, extract later bool _should_record_property(Ref property_entry, int tick); TypedArray _get_recorded_state_props(); TypedArray _get_owned_state_props(); TypedArray _get_recorded_input_props(); TypedArray _get_owned_input_props(); -}; \ No newline at end of file +}; diff --git a/src/rollback_history_transmitter.cpp b/src/rollback_history_transmitter.cpp index 2eba145..e6e1b0a 100644 --- a/src/rollback_history_transmitter.cpp +++ b/src/rollback_history_transmitter.cpp @@ -2,37 +2,32 @@ #include "rollback_history_transmitter.h" #include "utils.h" -#include -#include -#include #include #include +#include +#include +#include -int _RollbackHistoryTransmitter::get_earliest_input_tick() -{ +int _RollbackHistoryTransmitter::get_earliest_input_tick() { return _earliest_input_tick; } -int _RollbackHistoryTransmitter::get_latest_state_tick() -{ +int _RollbackHistoryTransmitter::get_latest_state_tick() { return _latest_state_tick; } -void _RollbackHistoryTransmitter::set_predicted_tick(Variant p_is_predicted_tick) -{ +void _RollbackHistoryTransmitter::set_predicted_tick(Variant p_is_predicted_tick) { _is_predicted_tick = p_is_predicted_tick; } -void _RollbackHistoryTransmitter::sync_settings(Node* p_root, bool p_enable_input_broadcast, int p_full_state_interval, int p_diff_ack_interval) -{ +void _RollbackHistoryTransmitter::sync_settings(Node *p_root, bool p_enable_input_broadcast, int p_full_state_interval, int p_diff_ack_interval) { root = p_root; enable_input_broadcast = p_enable_input_broadcast; full_state_interval = p_full_state_interval; diff_ack_interval = p_diff_ack_interval; } -void _RollbackHistoryTransmitter::configure(Ref<_PropertyHistoryBuffer> p_state_history, Ref<_PropertyHistoryBuffer> p_input_history, Ref<_PropertyConfig> p_state_property_config, Ref<_PropertyConfig> p_input_property_config, PeerVisibilityFilter* p_visibility_filter, Ref p_property_cache, Ref<_Set> p_skipset) -{ +void _RollbackHistoryTransmitter::configure(Ref<_PropertyHistoryBuffer> p_state_history, Ref<_PropertyHistoryBuffer> p_input_history, Ref<_PropertyConfig> p_state_property_config, Ref<_PropertyConfig> p_input_property_config, PeerVisibilityFilter *p_visibility_filter, Ref p_property_cache, Ref<_Set> p_skipset, Ref<_NetworkSchema> p_schema) { _state_history = p_state_history; _input_history = p_input_history; _state_property_config = p_state_property_config; @@ -41,17 +36,18 @@ void _RollbackHistoryTransmitter::configure(Ref<_PropertyHistoryBuffer> p_state_ _property_cache = p_property_cache; _skipset = p_skipset; - _input_encoder = _RedundantHistoryEncoder::new_(_input_history, _property_cache); - _full_state_encoder = _SnapshotHistoryEncoder::new_(_state_history, _property_cache); - _diff_state_encoder = _DiffHistoryEncoder::new_(_state_history, _property_cache); + _schema = p_schema; + + _input_encoder = _RedundantHistoryEncoder::new_(_input_history, _property_cache, _schema); + _full_state_encoder = _SnapshotHistoryEncoder::new_(_state_history, _property_cache, _schema); + _diff_state_encoder = _DiffHistoryEncoder::new_(_state_history, _property_cache, _schema); _is_initialized = true; reset(); } -void _RollbackHistoryTransmitter::reset() -{ +void _RollbackHistoryTransmitter::reset() { _ackd_state.clear(); int network_time_tick = Utils::get_autoload("NetworkTime")->get("tick"); _latest_state_tick = network_time_tick - 1; @@ -60,13 +56,10 @@ void _RollbackHistoryTransmitter::reset() _next_diff_ack_tick = network_time_tick; // Scatter full state sends, so not all nodes send at the same tick - if(is_inside_tree()) - { + if (is_inside_tree()) { _next_full_state_tick += UtilityFunctions::hash(root->get_path()) % Math::max(1, full_state_interval); _next_diff_ack_tick += UtilityFunctions::hash(root->get_path()) % Math::max(1, diff_ack_interval); - } - else - { + } else { _next_full_state_tick += UtilityFunctions::hash(root->get_name()) % Math::max(1, full_state_interval); _next_diff_ack_tick += UtilityFunctions::hash(root->get_name()) % Math::max(1, diff_ack_interval); } @@ -76,61 +69,49 @@ void _RollbackHistoryTransmitter::reset() _input_encoder->set_properties(_get_owned_input_props()); } -void _RollbackHistoryTransmitter::conclude_tick_loop() -{ +void _RollbackHistoryTransmitter::conclude_tick_loop() { int network_time_tick = Utils::get_autoload("NetworkTime")->get("tick"); _earliest_input_tick = network_time_tick; } -void _RollbackHistoryTransmitter::transmit_input(int tick) -{ - if(!_get_owned_input_props().is_empty()) - { +void _RollbackHistoryTransmitter::transmit_input(int tick) { + if (!_get_owned_input_props().is_empty()) { int network_rollback_input_delay = Utils::get_autoload("NetworkRollback")->get("input_delay"); int input_tick = tick + network_rollback_input_delay; Variant input_data = _input_encoder->encode(input_tick, _get_owned_input_props()); int state_owning_peer = root->get_multiplayer_authority(); - if(enable_input_broadcast) - { + if (enable_input_broadcast) { Array rpc_target_peers = _visibility_filter->get_rpc_target_peers(); - for(int i = 0; i < rpc_target_peers.size(); ++i) - { + for (int i = 0; i < rpc_target_peers.size(); ++i) { int peer = rpc_target_peers[i]; rpc_id(peer, "_submit_input", input_tick, input_data); } - } - else if(state_owning_peer != get_multiplayer()->get_unique_id()) - { + } else if (state_owning_peer != get_multiplayer()->get_unique_id()) { rpc_id(state_owning_peer, "_submit_input", input_tick, input_data); } } } -void _RollbackHistoryTransmitter::transmit_state(int tick) -{ - if(_get_owned_state_props().is_empty()) - { +void _RollbackHistoryTransmitter::transmit_state(int tick) { + if (_get_owned_state_props().is_empty()) { // We don't own state, don't transmit anything - return ; + return; } - if(_is_predicted_tick && !_input_property_config->get_properties().is_empty()) - { + if (_is_predicted_tick && !_input_property_config->get_properties().is_empty()) { // Don't transmit anything if we're predicting // EXCEPT when we're running inputless - return ; + return; } // Include properties we own Ref<_PropertySnapshot> full_state = _PropertySnapshot::new_(); Array props = _get_owned_state_props(); - for(int i = 0; i < props.size(); ++i) - { + for (int i = 0; i < props.size(); ++i) { Ref property = props[i]; - if(_should_broadcast(property, tick)) - { + if (_should_broadcast(property, tick)) { full_state->set_value(property->_to_string(), property->get_value()); } } @@ -138,9 +119,8 @@ void _RollbackHistoryTransmitter::transmit_state(int tick) emit_signal("_on_transmit_state", full_state, tick); // No properties to send? - if(full_state->is_empty()) - { - return ; + if (full_state->is_empty()) { + return; } _latest_state_tick = Math::max(_latest_state_tick, tick); @@ -149,34 +129,25 @@ void _RollbackHistoryTransmitter::transmit_state(int tick) bool is_sending_diffs = Utils::get_autoload("NetworkRollback")->get("enable_diff_states"); bool is_full_state_tick = !is_sending_diffs || (full_state_interval > 0 && tick > _next_full_state_tick); - if(is_full_state_tick) - { - + if (is_full_state_tick) { // Broadcast new full state TypedArray peers = _visibility_filter->get_rpc_target_peers(); - for(int i = 0; i < peers.size(); ++i) - { + for (int i = 0; i < peers.size(); ++i) { int peer = peers[i]; _send_full_state(tick, peer); } // Adjust next full state if sending diffs - if(is_sending_diffs) - { + if (is_sending_diffs) { _next_full_state_tick = tick + full_state_interval; } - } - else - { - + } else { // Send diffs to each peer TypedArray peers = _visibility_filter->get_visible_peers(); - for(int i = 0; i < peers.size(); ++i) - { + for (int i = 0; i < peers.size(); ++i) { int peer = peers[i]; int reference_tick = _ackd_state.get(peer, -1); - if(reference_tick < 0 || !_state_history->has(reference_tick)) - { + if (reference_tick < 0 || !_state_history->has(reference_tick)) { // Peer hasn't ack'd any tick, or we don't have the ack'd tick // Send full state _send_full_state(tick, peer); @@ -186,13 +157,10 @@ void _RollbackHistoryTransmitter::transmit_state(int tick) // Prepare diff Variant diff_state_data = _diff_state_encoder->encode(tick, reference_tick, _get_owned_state_props()); - if(_diff_state_encoder->get_full_snapshot().size() == _diff_state_encoder->get_encoded_snapshot().size()) - { + if (_diff_state_encoder->get_full_snapshot().size() == _diff_state_encoder->get_encoded_snapshot().size()) { // State is completely different, send full state _send_full_state(tick, peer); - } - else - { + } else { // Send only diff rpc_id(peer, "_submit_diff_state", diff_state_data, tick, reference_tick); @@ -205,25 +173,23 @@ void _RollbackHistoryTransmitter::transmit_state(int tick) } } -bool _RollbackHistoryTransmitter::_should_broadcast(Ref property, int tick) -{ +bool _RollbackHistoryTransmitter::_should_broadcast(Ref property, int tick) { auto network_rollback = Utils::get_autoload("NetworkRollback"); // Only broadcast if we've simulated the node // NOTE: _can_simulate checks mutations, but to override _skipset // we check first - if(network_rollback->call("is_mutated", property->node, tick - 1)) + if (network_rollback->call("is_mutated", property->node, tick - 1)) return true; - if(_skipset->has(property->node)) + if (_skipset->has(property->node)) return false; - if(network_rollback->call("is_rollback_aware", property->node)) + if (network_rollback->call("is_rollback_aware", property->node)) return network_rollback->call("is_simulated", property->node); // Node is not rollback-aware, broadcast updates only if we own it return property->node->is_multiplayer_authority(); } -void _RollbackHistoryTransmitter::_send_full_state(int tick, int peer) -{ +void _RollbackHistoryTransmitter::_send_full_state(int tick, int peer) { Dictionary full_state_snapshot = _state_history->get_snapshot(tick)->as_dictionary(); Variant full_state_data = _full_state_encoder->encode(tick, _get_owned_state_props()); @@ -231,22 +197,17 @@ void _RollbackHistoryTransmitter::_send_full_state(int tick, int peer) rpc_id(peer, "_submit_full_state", full_state_data, tick); - if(peer <= 0) - { + if (peer <= 0) { network_performance->call("push_full_state_broadcast", full_state_snapshot); network_performance->call("push_sent_state_broadcast", full_state_snapshot); - } - else - { + } else { network_performance->call("push_full_state", full_state_snapshot); network_performance->call("push_sent_state", full_state_snapshot); } } -void _RollbackHistoryTransmitter::_submit_input(int tick, Array data) -{ - if(!_is_initialized) - { +void _RollbackHistoryTransmitter::_submit_input(int tick, PackedByteArray data) { + if (!_is_initialized) { // Settings not processed yet return; } @@ -254,124 +215,109 @@ void _RollbackHistoryTransmitter::_submit_input(int tick, Array data) int sender = get_multiplayer()->get_remote_sender_id(); TypedArray<_PropertySnapshot> snapshots = _input_encoder->decode(data, _input_property_config->get_properties_owned_by(sender)); int earliest_received_input = _input_encoder->apply(tick, snapshots, sender); - if(earliest_received_input >= 0) + if (earliest_received_input >= 0) _earliest_input_tick = Math::min(_earliest_input_tick, earliest_received_input); } -void _RollbackHistoryTransmitter::_submit_full_state(Array data, int tick) -{ - if(!_is_initialized) - { +void _RollbackHistoryTransmitter::_submit_full_state(Array data, int tick) { + if (!_is_initialized) { // Settings not processed yet - return ; + return; } int sender = get_multiplayer()->get_remote_sender_id(); Variant snapshot = _full_state_encoder->decode(data, _state_property_config->get_properties_owned_by(sender)); - if(!_full_state_encoder->apply(tick, snapshot, sender)) - { + if (!_full_state_encoder->apply(tick, snapshot, sender)) { // Invalid data - return ; + return; } bool network_rollback_enable_diff_states = Utils::get_autoload("NetworkRollback")->get("enable_diff_states"); _latest_state_tick = tick; - if(network_rollback_enable_diff_states) + if (network_rollback_enable_diff_states) rpc_id(sender, "_ack_full_state", tick); } -void _RollbackHistoryTransmitter::_submit_diff_state(PackedByteArray data, int tick, int reference_tick) -{ - if(!_is_initialized) - { +void _RollbackHistoryTransmitter::_submit_diff_state(PackedByteArray data, int tick, int reference_tick) { + if (!_is_initialized) { // Settings not processed yet - return ; + return; } int sender = get_multiplayer()->get_remote_sender_id(); Variant diff_snapshot = _diff_state_encoder->decode(data, _state_property_config->get_properties_owned_by(sender)); - if(!_diff_state_encoder->apply(tick, diff_snapshot, reference_tick, sender)) - { + if (!_diff_state_encoder->apply(tick, diff_snapshot, reference_tick, sender)) { // Invalid data - return ; + return; } _latest_state_tick = tick; bool network_rollback_enable_diff_states = Utils::get_autoload("NetworkRollback")->get("enable_diff_states"); - if(network_rollback_enable_diff_states) - { - if(diff_ack_interval > 0 && tick > _next_diff_ack_tick) - { + if (network_rollback_enable_diff_states) { + if (diff_ack_interval > 0 && tick > _next_diff_ack_tick) { rpc_id(sender, "_ack_diff_state", tick); _next_diff_ack_tick = tick + diff_ack_interval; } } } -void _RollbackHistoryTransmitter::_ack_full_state(int tick) -{ +void _RollbackHistoryTransmitter::_ack_full_state(int tick) { int sender_id = get_multiplayer()->get_remote_sender_id(); _ackd_state[sender_id] = tick; _logger->trace(vformat("Peer %d ack'd full state for tick %d", sender_id, tick)); } -void _RollbackHistoryTransmitter::_ack_diff_state(int tick) -{ +void _RollbackHistoryTransmitter::_ack_diff_state(int tick) { int sender_id = get_multiplayer()->get_remote_sender_id(); _ackd_state[sender_id] = tick; _logger->trace(vformat("Peer %d ack'd diff state for tick %d", sender_id, tick)); } -TypedArray _RollbackHistoryTransmitter::_get_recorded_state_props() -{ +TypedArray _RollbackHistoryTransmitter::_get_recorded_state_props() { return _state_property_config->get_properties(); } -TypedArray _RollbackHistoryTransmitter::_get_owned_state_props() -{ +TypedArray _RollbackHistoryTransmitter::_get_owned_state_props() { return _state_property_config->get_owned_properties(); } -TypedArray _RollbackHistoryTransmitter::_get_recorded_input_props() -{ +TypedArray _RollbackHistoryTransmitter::_get_recorded_input_props() { return _input_property_config->get_owned_properties(); } -TypedArray _RollbackHistoryTransmitter::_get_owned_input_props() -{ +TypedArray _RollbackHistoryTransmitter::_get_owned_input_props() { return _input_property_config->get_owned_properties(); } -_RollbackHistoryTransmitter::_RollbackHistoryTransmitter() -{ +_RollbackHistoryTransmitter::_RollbackHistoryTransmitter() { Dictionary dict; dict["rpc_mode"] = MultiplayerAPI::RPC_MODE_ANY_PEER; dict["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_UNRELIABLE; dict["call_local"] = false; rpc_config("_submit_input", dict); - + dict.clear(); dict["rpc_mode"] = MultiplayerAPI::RPC_MODE_ANY_PEER; dict["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_UNRELIABLE_ORDERED; dict["call_local"] = false; rpc_config("_submit_full_state", dict); - + dict.clear(); dict["rpc_mode"] = MultiplayerAPI::RPC_MODE_ANY_PEER; dict["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_UNRELIABLE_ORDERED; dict["call_local"] = false; rpc_config("_submit_diff_state", dict); - + dict.clear(); dict["rpc_mode"] = MultiplayerAPI::RPC_MODE_ANY_PEER; dict["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_RELIABLE; dict["call_local"] = false; rpc_config("_ack_full_state", dict); - + dict.clear(); dict["rpc_mode"] = MultiplayerAPI::RPC_MODE_ANY_PEER; dict["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_UNRELIABLE_ORDERED; @@ -381,11 +327,10 @@ _RollbackHistoryTransmitter::_RollbackHistoryTransmitter() Ref<_NetfoxLogger> _RollbackHistoryTransmitter::_logger; -void _RollbackHistoryTransmitter::_bind_methods() -{ +void _RollbackHistoryTransmitter::_bind_methods() { _logger = _NetfoxLogger::for_netfox("_RollbackHistoryTransmitter"); - ClassDB::bind_method(D_METHOD("configure", "p_input_history", "p_state_property_config", "p_input_property_config", "p_visibility_filter", "p_property_cache", "p_skipset"), &_RollbackHistoryTransmitter::configure); + ClassDB::bind_method(D_METHOD("configure", "p_input_history", "p_state_property_config", "p_input_property_config", "p_visibility_filter", "p_property_cache", "p_skipset", "p_schema"), &_RollbackHistoryTransmitter::configure); ClassDB::bind_method(D_METHOD("get_earliest_input_tick"), &_RollbackHistoryTransmitter::get_earliest_input_tick); ClassDB::bind_method(D_METHOD("get_latest_state_tick"), &_RollbackHistoryTransmitter::get_latest_state_tick); ClassDB::bind_method(D_METHOD("set_predicted_tick", "p_is_predicted_tick"), &_RollbackHistoryTransmitter::set_predicted_tick); @@ -403,4 +348,3 @@ void _RollbackHistoryTransmitter::_bind_methods() ClassDB::bind_method(D_METHOD("_ack_full_state", "tick"), &_RollbackHistoryTransmitter::_ack_full_state); ClassDB::bind_method(D_METHOD("_ack_diff_state", "tick"), &_RollbackHistoryTransmitter::_ack_diff_state); } - diff --git a/src/rollback_history_transmitter.h b/src/rollback_history_transmitter.h index a4d1812..c37ec8a 100644 --- a/src/rollback_history_transmitter.h +++ b/src/rollback_history_transmitter.h @@ -1,21 +1,22 @@ #pragma once +#include "diff_history_encoder.h" +#include "logger.h" +#include "network_schema.h" #include "peer_visibility_filter.h" #include "property_cache.h" -#include "property_entry.h" -#include "logger.h" #include "property_config.h" +#include "property_entry.h" #include "property_history_buffer.h" #include "redundant_history_encoder.h" -#include "snapshot_history_encoder.h" -#include "diff_history_encoder.h" #include "set.h" +#include "snapshot_history_encoder.h" +#include #include +#include #include #include -#include -#include using namespace godot; @@ -23,28 +24,28 @@ class _RollbackHistoryTransmitter : public Node { GDCLASS(_RollbackHistoryTransmitter, Node); protected: - Node* root = nullptr; + Node *root = nullptr; bool enable_input_broadcast = true; int full_state_interval; int diff_ack_interval; -// Provided externally by RBS + // Provided externally by RBS Ref<_PropertyHistoryBuffer> _state_history; Ref<_PropertyHistoryBuffer> _input_history; - PeerVisibilityFilter* _visibility_filter = nullptr; + PeerVisibilityFilter *_visibility_filter = nullptr; Ref<_PropertyConfig> _state_property_config; Ref<_PropertyConfig> _input_property_config; Ref _property_cache; Ref<_Set> _skipset; - -// Collaborators + Ref<_NetworkSchema> _schema; + // Collaborators Ref<_RedundantHistoryEncoder> _input_encoder; Ref<_SnapshotHistoryEncoder> _full_state_encoder; Ref<_DiffHistoryEncoder> _diff_state_encoder; -// State + // State Dictionary _ackd_state; int _next_full_state_tick; int _next_diff_ack_tick; @@ -55,7 +56,7 @@ class _RollbackHistoryTransmitter : public Node { bool _is_predicted_tick; bool _is_initialized; -// Signals + // Signals /* signal _on_transmit_state(Dictionary state, int tick) */ static Ref<_NetfoxLogger> _logger; @@ -68,8 +69,8 @@ class _RollbackHistoryTransmitter : public Node { int get_earliest_input_tick(); int get_latest_state_tick(); void set_predicted_tick(Variant p_is_predicted_tick); - void sync_settings(Node* p_root, bool p_enable_input_broadcast, int p_full_state_interval, int p_diff_ack_interval); - void configure(Ref<_PropertyHistoryBuffer> p_state_history, Ref<_PropertyHistoryBuffer> p_input_history, Ref<_PropertyConfig> p_state_property_config, Ref<_PropertyConfig> p_input_property_config, PeerVisibilityFilter* p_visibility_filter, Ref p_property_cache, Ref<_Set> p_skipset); + void sync_settings(Node *p_root, bool p_enable_input_broadcast, int p_full_state_interval, int p_diff_ack_interval); + void configure(Ref<_PropertyHistoryBuffer> p_state_history, Ref<_PropertyHistoryBuffer> p_input_history, Ref<_PropertyConfig> p_state_property_config, Ref<_PropertyConfig> p_input_property_config, PeerVisibilityFilter *p_visibility_filter, Ref p_property_cache, Ref<_Set> p_skipset, Ref<_NetworkSchema> p_schema); void reset(); void conclude_tick_loop(); void transmit_input(int tick); @@ -78,7 +79,7 @@ class _RollbackHistoryTransmitter : public Node { void _send_full_state(int tick, int peer = 0); // `serialized_state` is a serialized _PropertySnapshot - void _submit_input(int tick, Array data); + void _submit_input(int tick, PackedByteArray data); // State is a serialized _PropertySnapshot (Dictionary[String, Variant]) void _submit_full_state(Array data, int tick); void _submit_diff_state(PackedByteArray data, int tick, int reference_tick); @@ -90,4 +91,4 @@ class _RollbackHistoryTransmitter : public Node { TypedArray _get_owned_state_props(); TypedArray _get_recorded_input_props(); TypedArray _get_owned_input_props(); -}; \ No newline at end of file +}; diff --git a/src/schemas_static.hpp b/src/schemas_static.hpp new file mode 100644 index 0000000..b58d2d9 --- /dev/null +++ b/src/schemas_static.hpp @@ -0,0 +1,345 @@ +#pragma once +//#include "serializers.h" +#include +#include + +using namespace godot; + +class NetworkSchemas : public RefCounted { + GDCLASS(NetworkSchemas, RefCounted); + +protected: + static void _bind_methods() { + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("variant"), &NetworkSchemas::variant); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("string"), &NetworkSchemas::string); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("bool8"), &NetworkSchemas::bool8); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("uint8"), &NetworkSchemas::uint8); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("uint16"), &NetworkSchemas::uint16); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("uint32"), &NetworkSchemas::uint32); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("uint64"), &NetworkSchemas::uint64); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("int8"), &NetworkSchemas::int8); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("int16"), &NetworkSchemas::int16); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("int32"), &NetworkSchemas::int32); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("int64"), &NetworkSchemas::int64); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("float16"), &NetworkSchemas::float16); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("float32"), &NetworkSchemas::float32); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("float64"), &NetworkSchemas::float64); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("sfrac8"), &NetworkSchemas::sfrac8); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("sfrac16"), &NetworkSchemas::sfrac16); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("sfrac32"), &NetworkSchemas::sfrac32); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("ufrac8"), &NetworkSchemas::ufrac8); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("ufrac16"), &NetworkSchemas::ufrac16); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("ufrac32"), &NetworkSchemas::ufrac32); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("degrees8"), &NetworkSchemas::degrees8); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("degrees16"), &NetworkSchemas::degrees16); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("degrees32"), &NetworkSchemas::degrees32); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("radians8"), &NetworkSchemas::radians8); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("radians16"), &NetworkSchemas::radians16); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("radians32"), &NetworkSchemas::radians32); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("vec2t", "component_serializer"), &NetworkSchemas::vec2t); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("vec2f16"), &NetworkSchemas::vec2f16); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("vec2f32"), &NetworkSchemas::vec2f32); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("vec2f64"), &NetworkSchemas::vec2f64); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("vec3t", "component_serializer"), &NetworkSchemas::vec3t); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("vec3f16"), &NetworkSchemas::vec3f16); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("vec3f32"), &NetworkSchemas::vec3f32); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("vec3f64"), &NetworkSchemas::vec3f64); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("vec4t", "component_serializer"), &NetworkSchemas::vec4t); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("vec4f16"), &NetworkSchemas::vec4f16); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("vec4f32"), &NetworkSchemas::vec4f32); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("vec4f64"), &NetworkSchemas::vec4f64); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("normal2t", "component_serializer"), &NetworkSchemas::normal2t); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("normal2f16"), &NetworkSchemas::normal2f16); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("normal2f32"), &NetworkSchemas::normal2f32); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("normal2f64"), &NetworkSchemas::normal2f64); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("normal3t", "component_serializer"), &NetworkSchemas::normal3t); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("normal3f16"), &NetworkSchemas::normal3f16); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("normal3f32"), &NetworkSchemas::normal3f32); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("normal3f64"), &NetworkSchemas::normal3f64); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("quatt", "component_serializer"), &NetworkSchemas::quatt); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("quatf16"), &NetworkSchemas::quatf16); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("quatf32"), &NetworkSchemas::quatf32); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("quatf64"), &NetworkSchemas::quatf64); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("transform2t", "component_serializer"), &NetworkSchemas::transform2t); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("transform2f16"), &NetworkSchemas::transform2f16); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("transform2f32"), &NetworkSchemas::transform2f32); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("transform2f64"), &NetworkSchemas::transform2f64); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("transform3t", "component_serializer"), &NetworkSchemas::transform3t); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("transform3f16"), &NetworkSchemas::transform3f16); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("transform3f32"), &NetworkSchemas::transform3f32); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("transform3f64"), &NetworkSchemas::transform3f64); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("array_of", "item_serializer", "size_serializer"), &NetworkSchemas::array_of); + ClassDB::bind_static_method("NetworkSchemas", D_METHOD("dictionary", "key_serializer", "value_serializer", "size_serializer"), &NetworkSchemas::dictionary); + }; + +public: + NetworkSchemas() {}; + ~NetworkSchemas() {}; + static Ref variant() { + Ref<_VariantSerializer> ref; + ref.instantiate(); + return ref; + } + + static Ref<_StringSerializer> string() { + Ref<_StringSerializer> ref; + ref.instantiate(); + return ref; + } + + static Ref<_BoolSerializer> bool8() { + Ref<_BoolSerializer> ref; + ref.instantiate(); + return ref; + } + + static Ref<_Uint8Serializer> uint8() { + Ref<_Uint8Serializer> ref; + ref.instantiate(); + return ref; + } + + static Ref<_Uint16Serializer> uint16() { + Ref<_Uint16Serializer> ref; + ref.instantiate(); + return ref; + } + + static Ref<_Uint32Serializer> uint32() { + Ref<_Uint32Serializer> ref; + ref.instantiate(); + return ref; + } + + static Ref<_Uint64Serializer> uint64() { + Ref<_Uint64Serializer> ref; + ref.instantiate(); + return ref; + } + + static Ref<_Int8Serializer> int8() { + Ref<_Int8Serializer> ref; + ref.instantiate(); + return ref; + } + + static Ref<_Int16Serializer> int16() { + Ref<_Int16Serializer> ref; + ref.instantiate(); + return ref; + } + + static Ref<_Int32Serializer> int32() { + Ref<_Int32Serializer> ref; + ref.instantiate(); + return ref; + } + + static Ref<_Int64Serializer> int64() { + Ref<_Int64Serializer> ref; + ref.instantiate(); + return ref; + } + + static Ref<_Float16Serializer> float16() { + Ref<_Float16Serializer> ref; + ref.instantiate(); + return ref; + } + + static Ref<_Float32Serializer> float32() { + Ref<_Float32Serializer> ref; + ref.instantiate(); + return ref; + } + + static Ref<_Float64Serializer> float64() { + Ref<_Float64Serializer> ref; + ref.instantiate(); + return ref; + } + + static Ref<_QuantizingSerializer> sfrac8() { + return _QuantizingSerializer::new_(uint8(), -1., 1., 0, 0xFF); + } + + static Ref<_QuantizingSerializer> sfrac16() { + return _QuantizingSerializer::new_(uint16(), -1., 1., 0, 0xFFFF); + } + + static Ref<_QuantizingSerializer> sfrac32() { + return _QuantizingSerializer::new_(uint32(), -1., 1., 0, 0xFFFFFFFF); + } + + static Ref<_QuantizingSerializer> ufrac8() { + return _QuantizingSerializer::new_(uint8(), 0., 1., 0, 0xFF); + } + + static Ref<_QuantizingSerializer> ufrac16() { + return _QuantizingSerializer::new_(uint16(), 0., 1., 0, 0xFFFF); + } + + static Ref<_QuantizingSerializer> ufrac32() { + return _QuantizingSerializer::new_(uint32(), 0., 1., 0, 0xFFFFFFFF); + } + + static Ref<_ModuloSerializer> degrees8() { + return _ModuloSerializer::new_(uint8(), 360., 0xFF); + } + + static Ref<_ModuloSerializer> degrees16() { + return _ModuloSerializer::new_(uint16(), 360., 0xFFFF); + } + + static Ref<_ModuloSerializer> degrees32() { + return _ModuloSerializer::new_(uint32(), 360., 0xFFFFFFFF); + } + + static Ref<_ModuloSerializer> radians8() { + return _ModuloSerializer::new_(uint8(), Math_TAU, 0xFF); + } + + static Ref<_ModuloSerializer> radians16() { + return _ModuloSerializer::new_(uint16(), Math_TAU, 0xFFFF); + } + + static Ref<_ModuloSerializer> radians32() { + return _ModuloSerializer::new_(uint32(), Math_TAU, 0xFFFFFFFF); + } + + static Ref<_GenericVec2Serializer> vec2t(Ref component_serializer) { + return _GenericVec2Serializer::new_(component_serializer); + } + + static Ref<_GenericVec2Serializer> vec2f16() { + return vec2t(float16()); + } + + static Ref<_GenericVec2Serializer> vec2f32() { + return vec2t(float32()); + } + + static Ref<_GenericVec2Serializer> vec2f64() { + return vec2t(float64()); + } + + static Ref<_GenericVec3Serializer> vec3t(Ref component_serializer) { + return _GenericVec3Serializer::new_(component_serializer); + } + + static Ref<_GenericVec3Serializer> vec3f16() { + return vec3t(float16()); + } + + static Ref<_GenericVec3Serializer> vec3f32() { + return vec3t(float32()); + } + + static Ref<_GenericVec3Serializer> vec3f64() { + return vec3t(float64()); + } + + static Ref<_GenericVec4Serializer> vec4t(Ref component_serializer) { + return _GenericVec4Serializer::new_(component_serializer); + } + + static Ref<_GenericVec4Serializer> vec4f16() { + return vec4t(float16()); + } + + static Ref<_GenericVec4Serializer> vec4f32() { + return vec4t(float32()); + } + + static Ref<_GenericVec4Serializer> vec4f64() { + return vec4t(float64()); + } + + static Ref<_Normal2Serializer> normal2t(Ref component_serializer) { + return _Normal2Serializer::new_(component_serializer); + } + + static Ref<_Normal2Serializer> normal2f16() { + return normal2t(float16()); + } + + static Ref<_Normal2Serializer> normal2f32() { + return normal2t(float32()); + } + + static Ref<_Normal2Serializer> normal2f64() { + return normal2t(float64()); + } + + static Ref<_Normal3Serializer> normal3t(Ref component_serializer) { + return _Normal3Serializer::new_(component_serializer); + } + + static Ref<_Normal3Serializer> normal3f16() { + return normal3t(float16()); + } + + static Ref<_Normal3Serializer> normal3f32() { + return normal3t(float32()); + } + + static Ref<_Normal3Serializer> normal3f64() { + return normal3t(float64()); + } + + static Ref<_GenericQuaternionSerializer> quatt(Ref component_serializer) { + return _GenericQuaternionSerializer::new_(component_serializer); + } + + static Ref<_GenericQuaternionSerializer> quatf16() { + return quatt(float16()); + } + + static Ref<_GenericQuaternionSerializer> quatf32() { + return quatt(float32()); + } + + static Ref<_GenericQuaternionSerializer> quatf64() { + return quatt(float64()); + } + + static Ref<_GenericTransform2DSerializer> transform2t(Ref component_serializer) { + return _GenericTransform2DSerializer::new_(component_serializer); + } + + static Ref<_GenericTransform2DSerializer> transform2f16() { + return transform2t(float16()); + } + + static Ref<_GenericTransform2DSerializer> transform2f32() { + return transform2t(float32()); + } + + static Ref<_GenericTransform2DSerializer> transform2f64() { + return transform2t(float64()); + } + + static Ref<_GenericTransform3DSerializer> transform3t(Ref component_serializer) { + return _GenericTransform3DSerializer::new_(component_serializer); + } + + static Ref<_GenericTransform3DSerializer> transform3f16() { + return transform3t(float16()); + } + + static Ref<_GenericTransform3DSerializer> transform3f32() { + return transform3t(float32()); + } + + static Ref<_GenericTransform3DSerializer> transform3f64() { + return transform3t(float64()); + } + static Ref<_ArraySerializer> array_of(Ref item_serializer = variant(), Ref size_serializer = uint16()) { + return _ArraySerializer::new_(item_serializer, size_serializer); + } + static Ref dictionary(Ref key_serializer = variant(), + Ref value_serializer = variant(), + Ref size_serializer = uint16()) { + return _DictionarySerializer::new_(key_serializer, value_serializer, size_serializer); + }; +}; diff --git a/src/serializers.h b/src/serializers.h new file mode 100644 index 0000000..849164b --- /dev/null +++ b/src/serializers.h @@ -0,0 +1,655 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace godot; + +class NetworkSchemaSerializer : public RefCounted { + GDCLASS(NetworkSchemaSerializer, RefCounted); + +protected: + static void _bind_methods() {}; + +public: + NetworkSchemaSerializer() {}; + ~NetworkSchemaSerializer() {}; + virtual void encode(Variant value, Ref &b) { + } + // Decode a value from [param buffer] and return it + virtual Variant decode(Ref &b) { + return NULL; + } +}; + +class _VariantSerializer : public NetworkSchemaSerializer { + GDCLASS(_VariantSerializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() {}; + +public: + _VariantSerializer() {}; + ~_VariantSerializer() {}; + void encode(Variant v, Ref &b) { + b->put_var(v, false); + } + Variant decode(Ref &b) { + return b->get_var(false); + } +}; + +class _StringSerializer : public NetworkSchemaSerializer { + GDCLASS(_StringSerializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() {}; + +public: + _StringSerializer() {}; + ~_StringSerializer() {}; + void encode(Variant v, Ref b) { + b->put_utf8_string(v.stringify()); + } + Variant decode(Ref b) { + return b->get_utf8_string(); + } +}; + +class _BoolSerializer : public NetworkSchemaSerializer { + GDCLASS(_BoolSerializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() {}; + +public: + _BoolSerializer() {}; + ~_BoolSerializer() {}; + void encode(Variant v, Ref b) { b->put_u8(v ? 1 : 0); } + Variant decode(Ref b) { return b->get_u8() > 0; } +}; + +class _Uint8Serializer : public NetworkSchemaSerializer { + GDCLASS(_Uint8Serializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() {}; + +public: + _Uint8Serializer() {}; + ~_Uint8Serializer() {}; + void encode(Variant v, Ref b) { b->put_u8(v); } + Variant decode(Ref b) { return b->get_u8(); } +}; + +class _Uint16Serializer : public NetworkSchemaSerializer { + GDCLASS(_Uint16Serializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() {}; + +public: + _Uint16Serializer() {}; + ~_Uint16Serializer() {}; + void encode(Variant v, Ref b) { b->put_u16(v); } + Variant decode(Ref b) { return b->get_u16(); } +}; + +class _Uint32Serializer : public NetworkSchemaSerializer { + GDCLASS(_Uint32Serializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() {}; + +public: + _Uint32Serializer() {}; + ~_Uint32Serializer() {}; + void encode(Variant v, Ref b) { b->put_u32(v); } + Variant decode(Ref b) { return b->get_u32(); } +}; + +class _Uint64Serializer : public NetworkSchemaSerializer { + GDCLASS(_Uint64Serializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() {}; + +public: + _Uint64Serializer() {}; + ~_Uint64Serializer() {}; + void encode(Variant v, Ref b) { b->put_u64(v); } + Variant decode(Ref b) { return b->get_u64(); } +}; + +class _Int8Serializer : public NetworkSchemaSerializer { + GDCLASS(_Int8Serializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() {}; + +public: + _Int8Serializer() {}; + ~_Int8Serializer() {}; + void encode(Variant v, Ref b) { b->put_8(v); } + Variant decode(Ref b) { return b->get_8(); } +}; + +class _Int16Serializer : public NetworkSchemaSerializer { + GDCLASS(_Int16Serializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() {}; + +public: + _Int16Serializer() {}; + ~_Int16Serializer() {}; + void encode(Variant v, Ref b) { b->put_16(v); } + Variant decode(Ref b) { return b->get_16(); } +}; + +class _Int32Serializer : public NetworkSchemaSerializer { + GDCLASS(_Int32Serializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() {}; + +public: + _Int32Serializer() {}; + ~_Int32Serializer() {}; + void encode(Variant v, Ref b) { b->put_32(v); } + Variant decode(Ref b) { return b->get_32(); } +}; + +class _Int64Serializer : public NetworkSchemaSerializer { + GDCLASS(_Int64Serializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() {}; + +public: + _Int64Serializer() {}; + ~_Int64Serializer() {}; + void encode(Variant v, Ref b) { b->put_64(v); } + Variant decode(Ref b) { return b->get_64(); } +}; + +class _Float16Serializer : public NetworkSchemaSerializer { + GDCLASS(_Float16Serializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() {}; + +public: + _Float16Serializer() {}; + ~_Float16Serializer() {}; + void encode(Variant v, Ref b) { + if (static_cast(Engine::get_singleton()->get_version_info()["hex"]) >= 0x040400) { + b->put_half(v); + } else { + b->put_float(v); + } + } + Variant decode(Ref b) { + if (static_cast(Engine::get_singleton()->get_version_info()["hex"]) >= 0x040400) { + return b->get_half(); + } else { + return b->get_float(); + } + } +}; + +class _Float32Serializer : public NetworkSchemaSerializer { + GDCLASS(_Float32Serializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() {}; + +public: + _Float32Serializer() {}; + ~_Float32Serializer() {}; + void encode(Variant v, Ref b) { b->put_float(v); } + Variant decode(Ref b) { return b->get_float(); } +}; + +class _Float64Serializer : public NetworkSchemaSerializer { + GDCLASS(_Float64Serializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() {}; + +public: + _Float64Serializer() {}; + ~_Float64Serializer() {}; + void encode(Variant v, Ref b) { b->put_double(v); } + Variant decode(Ref b) { return b->get_double(); } +}; + +class _GenericVec2Serializer : public NetworkSchemaSerializer { + GDCLASS(_GenericVec2Serializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() { + ClassDB::bind_static_method("_GenericVec2Serializer", D_METHOD("new_", "p_component"), &_GenericVec2Serializer::new_); + }; + +public: + Ref component; + static Ref<_GenericVec2Serializer> new_(Ref p_component) { + Ref<_GenericVec2Serializer> ref; + ref.instantiate(); + ref->component = p_component; + return ref; + } + _GenericVec2Serializer() {}; + ~_GenericVec2Serializer() {}; + + void encode(Variant v, Ref b) { + Vector2 v2 = static_cast(v); + component->encode(v2.x, b); + component->encode(v2.y, b); + } + Variant decode(Ref b) { + return Vector2(component->decode(b), component->decode(b)); + } +}; + +class _GenericVec3Serializer : public NetworkSchemaSerializer { + GDCLASS(_GenericVec3Serializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() { + ClassDB::bind_static_method("_GenericVec3Serializer", D_METHOD("new_", "p_component"), &_GenericVec3Serializer::new_); + }; + +public: + Ref component; + + static Ref<_GenericVec3Serializer> new_(Ref p_component) { + Ref<_GenericVec3Serializer> ref; + ref.instantiate(); + ref->component = p_component; + return ref; + } + _GenericVec3Serializer() {}; + ~_GenericVec3Serializer() {}; + void encode(Variant v, Ref b) { + Vector3 v3 = static_cast(v); + component->encode(v3.x, b); + component->encode(v3.y, b); + component->encode(v3.z, b); + } + Variant decode(Ref b) { + return Vector3( + component->decode(b), component->decode(b), component->decode(b)); + } +}; + +class _Normal2Serializer : public NetworkSchemaSerializer { + GDCLASS(_Normal2Serializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() { + ClassDB::bind_static_method("_Normal2Serializer", D_METHOD("new_", "p_component"), &_Normal2Serializer::new_); + }; + +public: + Ref component; + + static Ref<_Normal2Serializer> new_(Ref p_component) { + Ref<_Normal2Serializer> ref; + ref.instantiate(); + ref->component = p_component; + return ref; + } + _Normal2Serializer() {}; + ~_Normal2Serializer() {}; + void encode(Variant v, Ref b) { + component->encode(static_cast(v).angle(), b); + } + Variant decode(Ref b) { + return Vector2(1, 0).rotated(component->decode(b)); + } +}; + +class _Normal3Serializer : public NetworkSchemaSerializer { + GDCLASS(_Normal3Serializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() { + ClassDB::bind_static_method("_Normal3Serializer", D_METHOD("new_", "p_component"), &_Normal3Serializer::new_); + }; + +public: + Ref component; + + static Ref<_Normal3Serializer> new_(Ref p_component) { + Ref<_Normal3Serializer> ref; + ref.instantiate(); + ref->component = p_component; + return ref; + } + _Normal3Serializer() {}; + ~_Normal3Serializer() {}; + + void encode(Variant v, Ref b) { + Vector2 uv = static_cast(v).octahedron_encode(); + component->encode(uv.x, b); + component->encode(uv.y, b); + } + Variant decode(Ref b) { + return Vector3().octahedron_decode( + Vector2(component->decode(b), component->decode(b))); + } +}; + +class _GenericVec4Serializer : public NetworkSchemaSerializer { + GDCLASS(_GenericVec4Serializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() { + ClassDB::bind_static_method("_GenericVec4Serializer", D_METHOD("new_", "p_component"), &_GenericVec4Serializer::new_); + }; + +public: + Ref component; + static Ref<_GenericVec4Serializer> new_(Ref p_component) { + Ref<_GenericVec4Serializer> ref; + ref.instantiate(); + ref->component = p_component; + return ref; + } + _GenericVec4Serializer() {}; + ~_GenericVec4Serializer() {}; + void encode(Variant v, Ref b) { + Vector4 v4 = static_cast(v); + component->encode(v4.x, b); + component->encode(v4.y, b); + component->encode(v4.z, b); + component->encode(v4.w, b); + } + Variant decode(Ref b) { + return Vector4( + component->decode(b), component->decode(b), component->decode(b), component->decode(b)); + } +}; + +class _GenericQuaternionSerializer : public NetworkSchemaSerializer { + GDCLASS(_GenericQuaternionSerializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() { + ClassDB::bind_static_method("_GenericQuaternionSerializer", D_METHOD("new_", "p_component"), &_GenericQuaternionSerializer::new_); + }; + +public: + Ref component; + + static Ref<_GenericQuaternionSerializer> new_(Ref p_component) { + Ref<_GenericQuaternionSerializer> ref; + ref.instantiate(); + ref->component = p_component; + return ref; + } + _GenericQuaternionSerializer() {}; + ~_GenericQuaternionSerializer() {}; + void encode(Variant v, Ref b) { + Quaternion vq = static_cast(v); + component->encode(vq.x, b); + component->encode(vq.y, b); + component->encode(vq.z, b); + component->encode(vq.w, b); + } + Variant decode(Ref b) { + return Quaternion( + component->decode(b), component->decode(b), component->decode(b), component->decode(b)); + } +}; + +class _GenericTransform2DSerializer : public NetworkSchemaSerializer { + GDCLASS(_GenericTransform2DSerializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() { + ClassDB::bind_static_method("_GenericTransform2DSerializer", D_METHOD("new_", "p_component"), &_GenericTransform2DSerializer::new_); + }; + +public: + Ref component; + + static Ref<_GenericTransform2DSerializer> new_(Ref p_component) { + Ref<_GenericTransform2DSerializer> ref; + ref.instantiate(); + ref->component = p_component; + return ref; + } + _GenericTransform2DSerializer() {}; + ~_GenericTransform2DSerializer() {}; + void encode(Variant v, Ref b) { + Transform2D t = static_cast(v); + + component->encode(t.columns[0][0], b); + component->encode(t.columns[0][1], b); + component->encode(t.columns[1][0], b); + component->encode(t.columns[1][1], b); + component->encode(t.get_origin().x, b); + component->encode(t.get_origin().y, b); + } + Variant decode(Ref b) { + return Transform2D( + Vector2(component->decode(b), component->decode(b)), + Vector2(component->decode(b), component->decode(b)), + Vector2(component->decode(b), component->decode(b))); + } +}; + +class _GenericTransform3DSerializer : public NetworkSchemaSerializer { + GDCLASS(_GenericTransform3DSerializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() { + ClassDB::bind_static_method("_GenericTransform3DSerializer", D_METHOD("new_", "p_component"), &_GenericTransform3DSerializer::new_); + }; + +public: + Ref component; + + static Ref<_GenericTransform3DSerializer> new_(Ref p_component) { + Ref<_GenericTransform3DSerializer> ref; + ref.instantiate(); + ref->component = p_component; + return ref; + } + _GenericTransform3DSerializer() {}; + ~_GenericTransform3DSerializer() {}; + void encode(Variant v, Ref b) { + Transform3D t = static_cast(v); + component->encode(t.basis.get_column(0).x, b); + component->encode(t.basis.get_column(0).y, b); + component->encode(t.basis.get_column(0).z, b); + component->encode(t.basis.get_column(1).x, b); + component->encode(t.basis.get_column(1).y, b); + component->encode(t.basis.get_column(1).z, b); + component->encode(t.basis.get_column(2).x, b); + component->encode(t.basis.get_column(2).y, b); + component->encode(t.basis.get_column(2).z, b); + component->encode(t.origin.x, b); + component->encode(t.origin.y, b); + component->encode(t.origin.z, b); + } + Variant decode(Ref b) { + return Transform3D( + Basis( + Vector3(component->decode(b), component->decode(b), component->decode(b)), + Vector3(component->decode(b), component->decode(b), component->decode(b)), + Vector3(component->decode(b), component->decode(b), component->decode(b))), + Vector3(component->decode(b), component->decode(b), component->decode(b))); + } +}; + +class _QuantizingSerializer : public NetworkSchemaSerializer { + GDCLASS(_QuantizingSerializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() { + ClassDB::bind_static_method("_QuantizingSerializer", D_METHOD("new_", "p_component", "p_from_min", "p_from_max", "p_to_min", "p_to_max"), &_QuantizingSerializer::new_); + }; + +public: + Ref component; + Variant from_min; + Variant from_max; + Variant to_min; + Variant to_max; + + static Ref<_QuantizingSerializer> new_(Ref p_component, Variant p_from_min, Variant p_from_max, Variant p_to_min, Variant p_to_max) { + Ref<_QuantizingSerializer> ref; + ref.instantiate(); + ref->component = p_component; + ref->from_min = p_from_min; + ref->from_max = p_from_max; + ref->to_min = p_to_min; + ref->to_max = p_to_max; + return ref; + } + _QuantizingSerializer() {}; + ~_QuantizingSerializer() {}; + void encode(Variant v, Ref b) { + Variant f = UtilityFunctions::inverse_lerp(from_min, from_max, v); + Variant s = UtilityFunctions::lerp(to_min, to_max, f); + component->encode(s, b); + } + Variant decode(Ref b) { + Variant s = component->decode(b); + Variant f = UtilityFunctions::inverse_lerp(to_min, to_max, s); + return UtilityFunctions::lerp(from_min, from_max, f); + } +}; + +class _ModuloSerializer : public NetworkSchemaSerializer { + GDCLASS(_ModuloSerializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() { + ClassDB::bind_static_method("_ModuloSerializer", D_METHOD("new_", "p_component", "p_value_max", "p_component_max"), &_ModuloSerializer::new_); + }; + +public: + Ref component; + double value_max; + double component_max; + + static Ref<_ModuloSerializer> new_(Ref p_component, double p_value_max, double p_component_max) { + Ref<_ModuloSerializer> ref; + ref.instantiate(); + ref->component = p_component; + ref->value_max = p_value_max; + ref->component_max = p_component_max; + return ref; + } + _ModuloSerializer() {}; + ~_ModuloSerializer() {}; + void encode(Variant v, Ref b) { + double f = UtilityFunctions::fposmod(static_cast(v), value_max) / value_max; + double s = f * component_max; + component->encode(s, b); + } + Variant decode(Ref b) { + double s = static_cast(component->decode(b)); + return (s / component_max) * value_max; + } +}; + +class _ArraySerializer : public NetworkSchemaSerializer { + GDCLASS(_ArraySerializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() { + ClassDB::bind_static_method("_ArraySerializer", D_METHOD("new_", "p_component", "p_size"), &_ArraySerializer::new_); + }; + +public: + Ref component; + Ref size; + + static Ref<_ArraySerializer> new_(Ref p_component, Ref p_size) { + Ref<_ArraySerializer> ref; + ref.instantiate(); + ref->component = p_component; + ref->size = p_size; + return ref; + } + _ArraySerializer() {}; + ~_ArraySerializer() {}; + void encode(Variant v, Ref b) { + Array array = static_cast(v); + size->encode(array.size(), b); + for (int i = 0; i < array.size(); i++) { + component->encode(array[i], b); + } + } + Variant decode(Ref b) { + Array array = Array(); + int item_count = static_cast(size->decode(b)); + array.resize(item_count); + for (int i = 0; i < item_count; i++) { + array[i] = component->decode(b); + } + return array; + } +}; + +class _DictionarySerializer : public NetworkSchemaSerializer { + GDCLASS(_DictionarySerializer, NetworkSchemaSerializer); + +protected: + static void _bind_methods() { + ClassDB::bind_static_method("_ArraySerializer", D_METHOD("new_", "p_key_serializer", "p_value_serializer", "p_size_serializer"), &_ArraySerializer::new_); + }; + +public: + Ref key_serializer; + Ref value_serializer; + Ref size_serializer; + + static Ref<_DictionarySerializer> new_(Ref p_key_serializer, Ref p_value_serializer, Ref p_size_serializer) { + Ref<_DictionarySerializer> ref; + ref.instantiate(); + ref->key_serializer = p_key_serializer; + ref->value_serializer = p_value_serializer; + ref->size_serializer = p_size_serializer; + return ref; + } + _DictionarySerializer() {}; + ~_DictionarySerializer() {}; + void encode(Variant v, Ref b) { + Dictionary dictionary = static_cast(v); + + size_serializer->encode(dictionary.size(), b); + Array keys = dictionary.keys(); + for (int i = 0; i < keys.size(); i++) { + Variant value = dictionary[keys[i]]; + key_serializer->encode(keys[i], b); + value_serializer->encode(value, b); + } + } + Variant decode(Ref b) { + Dictionary dictionary = {}; + + int size = size_serializer->decode(b); + for (int i = 0; i < size; i++) { + Variant key = key_serializer->decode(b); + Variant value = value_serializer->decode(b); + dictionary[key] = value; + } + return dictionary; + } +}; diff --git a/src/snapshot_history_encoder.cpp b/src/snapshot_history_encoder.cpp index 3ec5939..bb33436 100644 --- a/src/snapshot_history_encoder.cpp +++ b/src/snapshot_history_encoder.cpp @@ -2,94 +2,87 @@ #include "snapshot_history_encoder.h" #include "utils.h" -#include #include +#include #include -Ref<_SnapshotHistoryEncoder> _SnapshotHistoryEncoder::new_(Ref<_PropertyHistoryBuffer> p_history, Ref p_property_cache) -{ +Ref<_SnapshotHistoryEncoder> _SnapshotHistoryEncoder::new_(Ref<_PropertyHistoryBuffer> p_history, Ref p_property_cache, Ref<_NetworkSchema> p_schema) { Ref<_SnapshotHistoryEncoder> ref; ref.instantiate(); ref->_history = p_history; ref->_property_cache = p_property_cache; + ref->_schema = p_schema; return ref; } -void _SnapshotHistoryEncoder::set_properties(Array properties) -{ - if(_properties != properties) - { +void _SnapshotHistoryEncoder::set_properties(Array properties) { + if (_properties != properties) { _version = (_version + 1) % 256; _properties = properties.duplicate(); } } -Array _SnapshotHistoryEncoder::encode(int tick, TypedArray properties) -{ +Array _SnapshotHistoryEncoder::encode(int tick, TypedArray properties) { Ref<_PropertySnapshot> snapshot = _history->get_snapshot(tick); - Array data = Array(); - data.resize(properties.size()); - for(int i=0; i buffer; + buffer.instantiate(); + buffer->put_u8(_version); + + for (int i = 0; i < properties.size(); i += 1) { Ref property_entry = properties[i]; - data[i] = snapshot->get_value(property_entry->_to_string()); + String path = property_entry->_to_string(); + _schema->encode(path, snapshot->get_value(path), buffer); } - data.append(_version); - - return data; + //UtilityFunctions::print(buffer->get_data_array()); + return buffer->get_data_array(); } -Ref<_PropertySnapshot> _SnapshotHistoryEncoder::decode(Array data, TypedArray properties) -{ +Ref<_PropertySnapshot> _SnapshotHistoryEncoder::decode(PackedByteArray data, TypedArray properties) { Ref<_PropertySnapshot> result = _PropertySnapshot::new_(); - uint8_t packet_version = data.pop_back(); - if(packet_version != _version) - { - if(!_has_received) - { + Ref buffer; + buffer.instantiate(); + buffer->set_data_array(data); + uint8_t packet_version = buffer->get_u8(); + + if (packet_version != _version) { + if (!_has_received) { // First packet, assume version is OK _version = packet_version; - } - else - { + } else { // Version mismatch, can't parse _logger->warning(vformat("Version mismatch! own: %d, received: %s", _version, packet_version)); return result; } } - if(properties.size() != data.size()) - { - _logger->warning(vformat("Received snapshot with %d entries, with %d known - parsing as much as possible", data.size(), properties.size())); - } - - for(int i=0; i< Math::min(data.size(), properties.size()); i+=1) - { - Ref entry = properties[i]; - result->set_value(entry->_to_string(), data[i]); + for (int i = 0; i < properties.size(); i += 1) { + if (buffer->get_available_bytes() == 0) { + _logger->warning(vformat("Received snapshot with %d entries, with %d known - parsing as much as possible", result->size(), properties.size())); + break; + } + Ref property = properties[i]; + String path = property->to_string(); + Variant value = _schema->decode(path, buffer); + result->set_value(path, value); } - _has_received = true; return result; } -bool _SnapshotHistoryEncoder::apply(int tick, Ref<_PropertySnapshot> snapshot, int sender) -{ +bool _SnapshotHistoryEncoder::apply(int tick, Ref<_PropertySnapshot> snapshot, int sender) { auto network_rollback = Utils::get_autoload("NetworkRollback"); - if(tick < (int) network_rollback->get("history_start")) - { + if (tick < (int)network_rollback->get("history_start")) { // State too old! _logger->error(vformat("Received full snapshot for %s, rejecting because older than %s frames", tick, network_rollback->get("history_limit"))); return false; } - if(sender > 0) - { + if (sender > 0) { snapshot->sanitize(sender, _property_cache); - if(snapshot->is_empty()) - {return false; + if (snapshot->is_empty()) { + return false; } } @@ -99,8 +92,7 @@ bool _SnapshotHistoryEncoder::apply(int tick, Ref<_PropertySnapshot> snapshot, i Ref<_NetfoxLogger> _SnapshotHistoryEncoder::_logger; -void _SnapshotHistoryEncoder::_bind_methods() -{ +void _SnapshotHistoryEncoder::_bind_methods() { _logger = _NetfoxLogger::for_netfox("_SnapshotHistoryEncoder"); ClassDB::bind_static_method("_SnapshotHistoryEncoder", D_METHOD("new_", "p_history", "p_property_cache"), &_SnapshotHistoryEncoder::new_); @@ -109,4 +101,3 @@ void _SnapshotHistoryEncoder::_bind_methods() ClassDB::bind_method(D_METHOD("decode", "data", "properties"), &_SnapshotHistoryEncoder::decode); ClassDB::bind_method(D_METHOD("apply", "tick", "snapshot", "sender"), &_SnapshotHistoryEncoder::apply, DEFVAL(-1)); } - diff --git a/src/snapshot_history_encoder.h b/src/snapshot_history_encoder.h index 0a4c59b..b59c757 100644 --- a/src/snapshot_history_encoder.h +++ b/src/snapshot_history_encoder.h @@ -1,24 +1,26 @@ #pragma once -#include "property_cache.h" #include "logger.h" +#include "network_schema.h" +#include "property_cache.h" #include "property_history_buffer.h" #include "property_snapshot.h" +#include #include #include #include -#include using namespace godot; class _SnapshotHistoryEncoder : public RefCounted { GDCLASS(_SnapshotHistoryEncoder, RefCounted); -public: +public: protected: Ref<_PropertyHistoryBuffer> _history; Ref _property_cache; + Ref<_NetworkSchema> _schema; Array _properties; uint8_t _version = -1; @@ -31,10 +33,10 @@ class _SnapshotHistoryEncoder : public RefCounted { _SnapshotHistoryEncoder() = default; ~_SnapshotHistoryEncoder() override = default; - static Ref<_SnapshotHistoryEncoder> new_(Ref<_PropertyHistoryBuffer> p_history, Ref p_property_cache); + static Ref<_SnapshotHistoryEncoder> new_(Ref<_PropertyHistoryBuffer> p_history, Ref p_property_cache, Ref<_NetworkSchema> p_schema); void set_properties(Array properties); Array encode(int tick, TypedArray properties); - Ref<_PropertySnapshot> decode(Array data, TypedArray properties); + Ref<_PropertySnapshot> decode(PackedByteArray data, TypedArray properties); bool apply(int tick, Ref<_PropertySnapshot> snapshot, int sender = -1); -}; \ No newline at end of file +}; From 6996760e9e35bf0793610b8459ca89b926b8da7a Mon Sep 17 00:00:00 2001 From: ZeEndy Date: Mon, 23 Feb 2026 00:09:08 +0200 Subject: [PATCH 2/3] ref passing serializers --- src/diff_history_encoder.cpp | 2 +- src/serializers.h | 107 +++++++++++++++---------------- src/snapshot_history_encoder.cpp | 6 +- src/snapshot_history_encoder.h | 2 +- 4 files changed, 58 insertions(+), 59 deletions(-) diff --git a/src/diff_history_encoder.cpp b/src/diff_history_encoder.cpp index 0262e23..b8d8e55 100644 --- a/src/diff_history_encoder.cpp +++ b/src/diff_history_encoder.cpp @@ -68,8 +68,8 @@ Ref<_PropertySnapshot> _DiffHistoryEncoder::decode(PackedByteArray data, TypedAr Ref buffer; buffer.instantiate(); buffer->set_data_array(data); - uint8_t packet_version = buffer->get_u8(); + if (packet_version != _version) { if (!_has_received) { // This is the first time we receive data diff --git a/src/serializers.h b/src/serializers.h index 849164b..cbfebe6 100644 --- a/src/serializers.h +++ b/src/serializers.h @@ -57,10 +57,10 @@ class _StringSerializer : public NetworkSchemaSerializer { public: _StringSerializer() {}; ~_StringSerializer() {}; - void encode(Variant v, Ref b) { + void encode(Variant v, Ref &b) { b->put_utf8_string(v.stringify()); } - Variant decode(Ref b) { + Variant decode(Ref &b) { return b->get_utf8_string(); } }; @@ -74,8 +74,8 @@ class _BoolSerializer : public NetworkSchemaSerializer { public: _BoolSerializer() {}; ~_BoolSerializer() {}; - void encode(Variant v, Ref b) { b->put_u8(v ? 1 : 0); } - Variant decode(Ref b) { return b->get_u8() > 0; } + void encode(Variant v, Ref &b) { b->put_u8(v ? 1 : 0); } + Variant decode(Ref &b) { return b->get_u8() > 0; } }; class _Uint8Serializer : public NetworkSchemaSerializer { @@ -87,8 +87,8 @@ class _Uint8Serializer : public NetworkSchemaSerializer { public: _Uint8Serializer() {}; ~_Uint8Serializer() {}; - void encode(Variant v, Ref b) { b->put_u8(v); } - Variant decode(Ref b) { return b->get_u8(); } + void encode(Variant v, Ref &b) { b->put_u8(v); } + Variant decode(Ref &b) { return b->get_u8(); } }; class _Uint16Serializer : public NetworkSchemaSerializer { @@ -100,8 +100,8 @@ class _Uint16Serializer : public NetworkSchemaSerializer { public: _Uint16Serializer() {}; ~_Uint16Serializer() {}; - void encode(Variant v, Ref b) { b->put_u16(v); } - Variant decode(Ref b) { return b->get_u16(); } + void encode(Variant v, Ref &b) { b->put_u16(v); } + Variant decode(Ref &b) { return b->get_u16(); } }; class _Uint32Serializer : public NetworkSchemaSerializer { @@ -113,8 +113,8 @@ class _Uint32Serializer : public NetworkSchemaSerializer { public: _Uint32Serializer() {}; ~_Uint32Serializer() {}; - void encode(Variant v, Ref b) { b->put_u32(v); } - Variant decode(Ref b) { return b->get_u32(); } + void encode(Variant v, Ref &b) { b->put_u32(v); } + Variant decode(Ref &b) { return b->get_u32(); } }; class _Uint64Serializer : public NetworkSchemaSerializer { @@ -126,8 +126,8 @@ class _Uint64Serializer : public NetworkSchemaSerializer { public: _Uint64Serializer() {}; ~_Uint64Serializer() {}; - void encode(Variant v, Ref b) { b->put_u64(v); } - Variant decode(Ref b) { return b->get_u64(); } + void encode(Variant v, Ref &b) { b->put_u64(v); } + Variant decode(Ref &b) { return b->get_u64(); } }; class _Int8Serializer : public NetworkSchemaSerializer { @@ -139,8 +139,8 @@ class _Int8Serializer : public NetworkSchemaSerializer { public: _Int8Serializer() {}; ~_Int8Serializer() {}; - void encode(Variant v, Ref b) { b->put_8(v); } - Variant decode(Ref b) { return b->get_8(); } + void encode(Variant v, Ref &b) { b->put_8(v); } + Variant decode(Ref &b) { return b->get_8(); } }; class _Int16Serializer : public NetworkSchemaSerializer { @@ -152,8 +152,8 @@ class _Int16Serializer : public NetworkSchemaSerializer { public: _Int16Serializer() {}; ~_Int16Serializer() {}; - void encode(Variant v, Ref b) { b->put_16(v); } - Variant decode(Ref b) { return b->get_16(); } + void encode(Variant v, Ref &b) { b->put_16(v); } + Variant decode(Ref &b) { return b->get_16(); } }; class _Int32Serializer : public NetworkSchemaSerializer { @@ -165,8 +165,8 @@ class _Int32Serializer : public NetworkSchemaSerializer { public: _Int32Serializer() {}; ~_Int32Serializer() {}; - void encode(Variant v, Ref b) { b->put_32(v); } - Variant decode(Ref b) { return b->get_32(); } + void encode(Variant v, Ref &b) { b->put_32(v); } + Variant decode(Ref &b) { return b->get_32(); } }; class _Int64Serializer : public NetworkSchemaSerializer { @@ -178,8 +178,8 @@ class _Int64Serializer : public NetworkSchemaSerializer { public: _Int64Serializer() {}; ~_Int64Serializer() {}; - void encode(Variant v, Ref b) { b->put_64(v); } - Variant decode(Ref b) { return b->get_64(); } + void encode(Variant v, Ref &b) { b->put_64(v); } + Variant decode(Ref &b) { return b->get_64(); } }; class _Float16Serializer : public NetworkSchemaSerializer { @@ -191,14 +191,14 @@ class _Float16Serializer : public NetworkSchemaSerializer { public: _Float16Serializer() {}; ~_Float16Serializer() {}; - void encode(Variant v, Ref b) { + void encode(Variant v, Ref &b) { if (static_cast(Engine::get_singleton()->get_version_info()["hex"]) >= 0x040400) { b->put_half(v); } else { b->put_float(v); } } - Variant decode(Ref b) { + Variant decode(Ref &b) { if (static_cast(Engine::get_singleton()->get_version_info()["hex"]) >= 0x040400) { return b->get_half(); } else { @@ -216,8 +216,8 @@ class _Float32Serializer : public NetworkSchemaSerializer { public: _Float32Serializer() {}; ~_Float32Serializer() {}; - void encode(Variant v, Ref b) { b->put_float(v); } - Variant decode(Ref b) { return b->get_float(); } + void encode(Variant v, Ref &b) { b->put_float(v); } + Variant decode(Ref &b) { return b->get_float(); } }; class _Float64Serializer : public NetworkSchemaSerializer { @@ -229,8 +229,8 @@ class _Float64Serializer : public NetworkSchemaSerializer { public: _Float64Serializer() {}; ~_Float64Serializer() {}; - void encode(Variant v, Ref b) { b->put_double(v); } - Variant decode(Ref b) { return b->get_double(); } + void encode(Variant v, Ref &b) { b->put_double(v); } + Variant decode(Ref &b) { return b->get_double(); } }; class _GenericVec2Serializer : public NetworkSchemaSerializer { @@ -252,12 +252,12 @@ class _GenericVec2Serializer : public NetworkSchemaSerializer { _GenericVec2Serializer() {}; ~_GenericVec2Serializer() {}; - void encode(Variant v, Ref b) { - Vector2 v2 = static_cast(v); + void encode(Variant v, Ref &b) { + Vector2 v2 = v; component->encode(v2.x, b); component->encode(v2.y, b); } - Variant decode(Ref b) { + Variant decode(Ref &b) { return Vector2(component->decode(b), component->decode(b)); } }; @@ -281,15 +281,14 @@ class _GenericVec3Serializer : public NetworkSchemaSerializer { } _GenericVec3Serializer() {}; ~_GenericVec3Serializer() {}; - void encode(Variant v, Ref b) { - Vector3 v3 = static_cast(v); + void encode(Variant v, Ref &b) { + Vector3 v3 = v; component->encode(v3.x, b); component->encode(v3.y, b); component->encode(v3.z, b); } - Variant decode(Ref b) { - return Vector3( - component->decode(b), component->decode(b), component->decode(b)); + Variant decode(Ref &b) { + return Vector3(component->decode(b), component->decode(b), component->decode(b)); } }; @@ -312,10 +311,10 @@ class _Normal2Serializer : public NetworkSchemaSerializer { } _Normal2Serializer() {}; ~_Normal2Serializer() {}; - void encode(Variant v, Ref b) { + void encode(Variant v, Ref &b) { component->encode(static_cast(v).angle(), b); } - Variant decode(Ref b) { + Variant decode(Ref &b) { return Vector2(1, 0).rotated(component->decode(b)); } }; @@ -340,12 +339,12 @@ class _Normal3Serializer : public NetworkSchemaSerializer { _Normal3Serializer() {}; ~_Normal3Serializer() {}; - void encode(Variant v, Ref b) { + void encode(Variant v, Ref &b) { Vector2 uv = static_cast(v).octahedron_encode(); component->encode(uv.x, b); component->encode(uv.y, b); } - Variant decode(Ref b) { + Variant decode(Ref &b) { return Vector3().octahedron_decode( Vector2(component->decode(b), component->decode(b))); } @@ -369,14 +368,14 @@ class _GenericVec4Serializer : public NetworkSchemaSerializer { } _GenericVec4Serializer() {}; ~_GenericVec4Serializer() {}; - void encode(Variant v, Ref b) { + void encode(Variant v, Ref &b) { Vector4 v4 = static_cast(v); component->encode(v4.x, b); component->encode(v4.y, b); component->encode(v4.z, b); component->encode(v4.w, b); } - Variant decode(Ref b) { + Variant decode(Ref &b) { return Vector4( component->decode(b), component->decode(b), component->decode(b), component->decode(b)); } @@ -401,14 +400,14 @@ class _GenericQuaternionSerializer : public NetworkSchemaSerializer { } _GenericQuaternionSerializer() {}; ~_GenericQuaternionSerializer() {}; - void encode(Variant v, Ref b) { + void encode(Variant v, Ref &b) { Quaternion vq = static_cast(v); component->encode(vq.x, b); component->encode(vq.y, b); component->encode(vq.z, b); component->encode(vq.w, b); } - Variant decode(Ref b) { + Variant decode(Ref &b) { return Quaternion( component->decode(b), component->decode(b), component->decode(b), component->decode(b)); } @@ -433,7 +432,7 @@ class _GenericTransform2DSerializer : public NetworkSchemaSerializer { } _GenericTransform2DSerializer() {}; ~_GenericTransform2DSerializer() {}; - void encode(Variant v, Ref b) { + void encode(Variant v, Ref &b) { Transform2D t = static_cast(v); component->encode(t.columns[0][0], b); @@ -443,7 +442,7 @@ class _GenericTransform2DSerializer : public NetworkSchemaSerializer { component->encode(t.get_origin().x, b); component->encode(t.get_origin().y, b); } - Variant decode(Ref b) { + Variant decode(Ref &b) { return Transform2D( Vector2(component->decode(b), component->decode(b)), Vector2(component->decode(b), component->decode(b)), @@ -470,7 +469,7 @@ class _GenericTransform3DSerializer : public NetworkSchemaSerializer { } _GenericTransform3DSerializer() {}; ~_GenericTransform3DSerializer() {}; - void encode(Variant v, Ref b) { + void encode(Variant v, Ref &b) { Transform3D t = static_cast(v); component->encode(t.basis.get_column(0).x, b); component->encode(t.basis.get_column(0).y, b); @@ -485,7 +484,7 @@ class _GenericTransform3DSerializer : public NetworkSchemaSerializer { component->encode(t.origin.y, b); component->encode(t.origin.z, b); } - Variant decode(Ref b) { + Variant decode(Ref &b) { return Transform3D( Basis( Vector3(component->decode(b), component->decode(b), component->decode(b)), @@ -522,12 +521,12 @@ class _QuantizingSerializer : public NetworkSchemaSerializer { } _QuantizingSerializer() {}; ~_QuantizingSerializer() {}; - void encode(Variant v, Ref b) { + void encode(Variant v, Ref &b) { Variant f = UtilityFunctions::inverse_lerp(from_min, from_max, v); Variant s = UtilityFunctions::lerp(to_min, to_max, f); component->encode(s, b); } - Variant decode(Ref b) { + Variant decode(Ref &b) { Variant s = component->decode(b); Variant f = UtilityFunctions::inverse_lerp(to_min, to_max, s); return UtilityFunctions::lerp(from_min, from_max, f); @@ -557,12 +556,12 @@ class _ModuloSerializer : public NetworkSchemaSerializer { } _ModuloSerializer() {}; ~_ModuloSerializer() {}; - void encode(Variant v, Ref b) { + void encode(Variant v, Ref &b) { double f = UtilityFunctions::fposmod(static_cast(v), value_max) / value_max; double s = f * component_max; component->encode(s, b); } - Variant decode(Ref b) { + Variant decode(Ref &b) { double s = static_cast(component->decode(b)); return (s / component_max) * value_max; } @@ -589,14 +588,14 @@ class _ArraySerializer : public NetworkSchemaSerializer { } _ArraySerializer() {}; ~_ArraySerializer() {}; - void encode(Variant v, Ref b) { + void encode(Variant v, Ref &b) { Array array = static_cast(v); size->encode(array.size(), b); for (int i = 0; i < array.size(); i++) { component->encode(array[i], b); } } - Variant decode(Ref b) { + Variant decode(Ref &b) { Array array = Array(); int item_count = static_cast(size->decode(b)); array.resize(item_count); @@ -630,7 +629,7 @@ class _DictionarySerializer : public NetworkSchemaSerializer { } _DictionarySerializer() {}; ~_DictionarySerializer() {}; - void encode(Variant v, Ref b) { + void encode(Variant v, Ref &b) { Dictionary dictionary = static_cast(v); size_serializer->encode(dictionary.size(), b); @@ -641,7 +640,7 @@ class _DictionarySerializer : public NetworkSchemaSerializer { value_serializer->encode(value, b); } } - Variant decode(Ref b) { + Variant decode(Ref &b) { Dictionary dictionary = {}; int size = size_serializer->decode(b); diff --git a/src/snapshot_history_encoder.cpp b/src/snapshot_history_encoder.cpp index bb33436..b6f0350 100644 --- a/src/snapshot_history_encoder.cpp +++ b/src/snapshot_history_encoder.cpp @@ -22,14 +22,14 @@ void _SnapshotHistoryEncoder::set_properties(Array properties) { } } -Array _SnapshotHistoryEncoder::encode(int tick, TypedArray properties) { +PackedByteArray _SnapshotHistoryEncoder::encode(int tick, TypedArray properties) { Ref<_PropertySnapshot> snapshot = _history->get_snapshot(tick); Ref buffer; buffer.instantiate(); buffer->put_u8(_version); - for (int i = 0; i < properties.size(); i += 1) { + for (int i = 0; i < properties.size(); i++) { Ref property_entry = properties[i]; String path = property_entry->_to_string(); _schema->encode(path, snapshot->get_value(path), buffer); @@ -57,7 +57,7 @@ Ref<_PropertySnapshot> _SnapshotHistoryEncoder::decode(PackedByteArray data, Typ } } - for (int i = 0; i < properties.size(); i += 1) { + for (int i = 0; i < properties.size(); i++) { if (buffer->get_available_bytes() == 0) { _logger->warning(vformat("Received snapshot with %d entries, with %d known - parsing as much as possible", result->size(), properties.size())); break; diff --git a/src/snapshot_history_encoder.h b/src/snapshot_history_encoder.h index b59c757..bf6315c 100644 --- a/src/snapshot_history_encoder.h +++ b/src/snapshot_history_encoder.h @@ -36,7 +36,7 @@ class _SnapshotHistoryEncoder : public RefCounted { static Ref<_SnapshotHistoryEncoder> new_(Ref<_PropertyHistoryBuffer> p_history, Ref p_property_cache, Ref<_NetworkSchema> p_schema); void set_properties(Array properties); - Array encode(int tick, TypedArray properties); + PackedByteArray encode(int tick, TypedArray properties); Ref<_PropertySnapshot> decode(PackedByteArray data, TypedArray properties); bool apply(int tick, Ref<_PropertySnapshot> snapshot, int sender = -1); }; From 6e967cd7ab4f841ad2c5ebd142944273f3b9b6ff Mon Sep 17 00:00:00 2001 From: ZeEndy Date: Tue, 24 Feb 2026 04:49:05 +0200 Subject: [PATCH 3/3] get rid of actidental double bind --- src/serializers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serializers.h b/src/serializers.h index cbfebe6..7279ec8 100644 --- a/src/serializers.h +++ b/src/serializers.h @@ -611,7 +611,7 @@ class _DictionarySerializer : public NetworkSchemaSerializer { protected: static void _bind_methods() { - ClassDB::bind_static_method("_ArraySerializer", D_METHOD("new_", "p_key_serializer", "p_value_serializer", "p_size_serializer"), &_ArraySerializer::new_); + ClassDB::bind_static_method("_DictionarySerializer", D_METHOD("new_", "p_key_serializer", "p_value_serializer", "p_size_serializer"), &_DictionarySerializer::new_); }; public: