From efa9fd55ace59933b23e5af7ec0da7abb0de5d2b Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Wed, 25 Feb 2026 15:05:50 -0800 Subject: [PATCH 01/15] Update C++ module bindings to RawModuleDefV10 --- crates/bindings-cpp/ARCHITECTURE.md | 14 +- crates/bindings-cpp/CMakeLists.txt | 3 +- crates/bindings-cpp/README.md | 3 +- crates/bindings-cpp/include/spacetimedb.h | 5 +- .../include/spacetimedb/bsatn/sum_type.h | 7 +- .../include/spacetimedb/database.h | 3 +- .../include/spacetimedb/enum_macro.h | 3 +- .../include/spacetimedb/internal/Module.h | 207 ++---- .../spacetimedb/internal/Module_impl.h | 277 +------ .../internal/autogen/CaseConversionPolicy.g.h | 22 + .../internal/autogen/ExplicitNameEntry.g.h | 34 + .../internal/autogen/ExplicitNames.g.h | 27 + .../internal/autogen/FunctionVisibility.g.h | 22 + .../internal/autogen/IndexType.g.h | 22 + .../internal/autogen/MiscModuleExport.g.h | 20 + .../internal/autogen/NameMapping.g.h | 28 + .../internal/autogen/RawColumnDefV8.g.h | 29 + .../autogen/RawColumnDefaultValueV10.g.h | 28 + .../internal/autogen/RawConstraintDefV10.g.h | 29 + .../internal/autogen/RawConstraintDefV8.g.h | 30 + .../internal/autogen/RawIndexDefV10.g.h | 31 + .../internal/autogen/RawIndexDefV8.g.h | 33 + .../autogen/RawLifeCycleReducerDefV10.g.h | 29 + .../internal/autogen/RawModuleDef.g.h | 22 + .../internal/autogen/RawModuleDefV10.g.h | 27 + .../autogen/RawModuleDefV10Section.g.h | 30 + .../internal/autogen/RawModuleDefV8.g.h | 36 + .../internal/autogen/RawModuleDefV9.g.h | 8 +- .../internal/autogen/RawProcedureDefV10.g.h | 35 + .../internal/autogen/RawProcedureDefV9.g.h | 2 +- .../internal/autogen/RawReducerDefV10.g.h | 37 + .../internal/autogen/RawReducerDefV9.g.h | 2 +- .../internal/autogen/RawScheduleDefV10.g.h | 32 + .../internal/autogen/RawScopedTypeNameV10.g.h | 28 + .../internal/autogen/RawSequenceDefV10.g.h | 36 + .../internal/autogen/RawSequenceDefV8.g.h | 38 + .../internal/autogen/RawTableDefV10.g.h | 50 ++ .../internal/autogen/RawTableDefV8.g.h | 44 ++ .../internal/autogen/RawTableDefV9.g.h | 6 +- .../internal/autogen/RawTypeDefV10.g.h | 31 + .../internal/autogen/RawViewDefV10.g.h | 38 + .../internal/autogen/ReducerDef.g.h | 29 + .../internal/autogen/TableDesc.g.h | 29 + .../internal/autogen/TypeAlias.g.h | 28 + .../spacetimedb/internal/autogen_base.h | 11 +- ...istration.h => module_type_registration.h} | 39 +- .../internal/runtime_registration.h | 39 + .../spacetimedb/internal/template_utils.h | 56 ++ .../spacetimedb/internal/v10_builder.h | 675 ++++++++++++++++++ .../include/spacetimedb/internal/v9_builder.h | 107 +-- .../bindings-cpp/include/spacetimedb/macros.h | 30 +- .../include/spacetimedb/procedure_macros.h | 21 +- .../include/spacetimedb/reducer_macros.h | 24 +- .../spacetimedb/table_with_constraints.h | 127 +++- .../include/spacetimedb/view_macros.h | 22 +- crates/bindings-cpp/src/internal/Module.cpp | 191 +++-- ...ation.cpp => module_type_registration.cpp} | 229 ++---- .../bindings-cpp/src/internal/v10_builder.cpp | 269 +++++++ .../bindings-cpp/src/internal/v9_builder.cpp | 27 +- .../tests/type-isolation-test/README.md | 10 +- .../run_type_isolation_test.sh | 99 ++- .../error_default_missing_field.cpp | 21 + .../error_multicolumn_missing_field.cpp | 21 + .../test_multicolumn_index_valid.cpp | 21 + .../codegen/examples/regen-cpp-moduledef.rs | 8 +- crates/codegen/src/cpp.rs | 13 +- modules/sdk-test-cpp/src/lib.cpp | 6 +- .../src/module_bindings/mod.rs | 2 +- .../src/module_bindings/mod.rs | 2 +- .../src/module_bindings/mod.rs | 2 +- sdks/rust/tests/test.rs | 6 +- .../view-client/src/module_bindings/mod.rs | 2 +- .../Public/BSATN/Core/sum_type.h | 7 +- 73 files changed, 2728 insertions(+), 853 deletions(-) create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/CaseConversionPolicy.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/ExplicitNameEntry.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/ExplicitNames.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/FunctionVisibility.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/IndexType.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/MiscModuleExport.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/NameMapping.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawColumnDefV8.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawColumnDefaultValueV10.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawConstraintDefV10.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawConstraintDefV8.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawIndexDefV10.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawIndexDefV8.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawLifeCycleReducerDefV10.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDef.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDefV10.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDefV10Section.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDefV8.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawProcedureDefV10.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawReducerDefV10.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawScheduleDefV10.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawScopedTypeNameV10.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawSequenceDefV10.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawSequenceDefV8.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawTableDefV10.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawTableDefV8.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawTypeDefV10.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/RawViewDefV10.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/ReducerDef.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/TableDesc.g.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/autogen/TypeAlias.g.h rename crates/bindings-cpp/include/spacetimedb/internal/{v9_type_registration.h => module_type_registration.h} (93%) create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/runtime_registration.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/template_utils.h create mode 100644 crates/bindings-cpp/include/spacetimedb/internal/v10_builder.h rename crates/bindings-cpp/src/internal/{v9_type_registration.cpp => module_type_registration.cpp} (71%) create mode 100644 crates/bindings-cpp/src/internal/v10_builder.cpp create mode 100644 crates/bindings-cpp/tests/type-isolation-test/test_modules/error_default_missing_field.cpp create mode 100644 crates/bindings-cpp/tests/type-isolation-test/test_modules/error_multicolumn_missing_field.cpp create mode 100644 crates/bindings-cpp/tests/type-isolation-test/test_modules/test_multicolumn_index_valid.cpp diff --git a/crates/bindings-cpp/ARCHITECTURE.md b/crates/bindings-cpp/ARCHITECTURE.md index 70e5377d6a4..c5fc1f2151e 100644 --- a/crates/bindings-cpp/ARCHITECTURE.md +++ b/crates/bindings-cpp/ARCHITECTURE.md @@ -204,7 +204,7 @@ outcome.error() // const std::string& - get error message (UB if succ extern "C" __attribute__((export_name("__preinit__01_clear_global_state"))) void __preinit__01_clear_global_state() { ClearV9Module(); // Reset module definition and handler registries - getV9TypeRegistration().clear(); // Reset type registry and error state + getModuleTypeRegistration().clear(); // Reset type registry and error state } ``` @@ -308,15 +308,15 @@ if (constraint == FieldConstraint::PrimaryKey) { ### Phase 3: Type System Registration -**Component**: V9TypeRegistration system (`v9_type_registration.h`) +**Component**: ModuleTypeRegistration system (`module_type_registration.h`) **Core Principle**: Only user-defined structs and enums get registered in the typespace. Primitives, arrays, Options, and special types are always inlined. -**Architecture Note**: V9Builder serves as the registration coordinator but delegates all type processing to the V9TypeRegistration system. This separation ensures a single, unified type registration pathway. +**Architecture Note**: V9Builder serves as the registration coordinator but delegates all type processing to the ModuleTypeRegistration system. This separation ensures a single, unified type registration pathway. **Registration Flow**: ```cpp -class V9TypeRegistration { +class ModuleTypeRegistration { AlgebraicType registerType(const bsatn::AlgebraicType& bsatn_type, const std::string& explicit_name = "", const std::type_info* cpp_type = nullptr) { @@ -376,7 +376,7 @@ void __preinit__99_validate_types() { } // 3. Check for type registration errors - if (getV9TypeRegistration().hasError()) { + if (getModuleTypeRegistration().hasError()) { createErrorModule("ERROR_TYPE_REGISTRATION_" + sanitize(error_message)); return; } @@ -427,7 +427,7 @@ namespace SpacetimeDB::detail { ``` #### 2. LazyTypeRegistrar Integration -**Location**: `v9_type_registration.h` - Compile-time namespace detection +**Location**: `module_type_registration.h` - Compile-time namespace detection ```cpp template @@ -445,7 +445,7 @@ class LazyTypeRegistrar { } // Register with qualified name - type_index_ = getV9TypeRegistration().registerAndGetIndex( + type_index_ = getModuleTypeRegistration().registerAndGetIndex( algebraic_type, qualified_name, &typeid(T)); } }; diff --git a/crates/bindings-cpp/CMakeLists.txt b/crates/bindings-cpp/CMakeLists.txt index 9bcc7fefc08..48568994eae 100644 --- a/crates/bindings-cpp/CMakeLists.txt +++ b/crates/bindings-cpp/CMakeLists.txt @@ -19,7 +19,8 @@ set(LIBRARY_SOURCES src/internal/Module.cpp src/internal/AlgebraicType.cpp # Required for V9 autogen types src/internal/v9_builder.cpp # V9 incremental module builder - src/internal/v9_type_registration.cpp # Unified type registration system + src/internal/v10_builder.cpp # V10 facade over module definition assembly + src/internal/module_type_registration.cpp # Unified type registration system ) add_library(spacetimedb_cpp_library STATIC) diff --git a/crates/bindings-cpp/README.md b/crates/bindings-cpp/README.md index db6771f1644..c3d2ef2a2af 100644 --- a/crates/bindings-cpp/README.md +++ b/crates/bindings-cpp/README.md @@ -234,7 +234,7 @@ LOG_PANIC("Fatal error message"); The library uses a sophisticated hybrid compile-time/runtime architecture: - **Compile-Time Validation** (`table_with_constraints.h`): C++20 concepts and static assertions for constraint validation -- **V9 Type Registration System** (`internal/v9_type_registration.h`): Unified type registration with error detection and circular reference prevention +- **Module Type Registration System** (`internal/module_type_registration.h`): Unified type registration with error detection and circular reference prevention - **Priority-Ordered Initialization** (`internal/Module.cpp`): __preinit__ functions with numbered priorities ensure correct registration order - **Error Detection System** (`internal/Module.cpp`): Multi-layer validation with error module replacement for clear diagnostics - **BSATN Serialization** (`bsatn/`): Binary serialization system with algebraic type support for all data types @@ -274,3 +274,4 @@ See the `modules/*-cpp/src/` directory for example modules: ## Contributing This library is part of the SpacetimeDB project. Please see the main repository for contribution guidelines. + diff --git a/crates/bindings-cpp/include/spacetimedb.h b/crates/bindings-cpp/include/spacetimedb.h index aa398e83ce0..a36d96074a8 100644 --- a/crates/bindings-cpp/include/spacetimedb.h +++ b/crates/bindings-cpp/include/spacetimedb.h @@ -168,8 +168,7 @@ namespace spacetimedb { * @return Serialized module definition */ inline std::vector serialize_module_def() { - auto& module_def = SpacetimeDB::Internal::Module::GetModuleDef(); - return module_def.serialize(); + return SpacetimeDB::Internal::Module::SerializeModuleDef(); } } @@ -219,4 +218,4 @@ namespace spacetimedb { // Include BSATN implementation files after all headers are defined #include "spacetimedb/bsatn/types_impl.h" #include "spacetimedb/bsatn/schedule_at_impl.h" -#include "spacetimedb/enum_macro.h" \ No newline at end of file +#include "spacetimedb/enum_macro.h" diff --git a/crates/bindings-cpp/include/spacetimedb/bsatn/sum_type.h b/crates/bindings-cpp/include/spacetimedb/bsatn/sum_type.h index d426c5d440e..733cea12a55 100644 --- a/crates/bindings-cpp/include/spacetimedb/bsatn/sum_type.h +++ b/crates/bindings-cpp/include/spacetimedb/bsatn/sum_type.h @@ -125,9 +125,8 @@ struct bsatn_traits> { using sum_type = SumType; static AlgebraicType algebraic_type() { - // For now, return a string type as placeholder - // TODO: Implement proper sum type registration in V9TypeRegistration system - return AlgebraicType::String(); + // Reuse the canonical std::variant sum-shape implementation. + return bsatn_traits>::algebraic_type(); } }; @@ -162,4 +161,4 @@ SumType deserialize(Reader& reader, std::type_identity>) { } // namespace bsatn } // namespace SpacetimeDB -#endif // SPACETIMEDB_BSATN_SUM_TYPE_H \ No newline at end of file +#endif // SPACETIMEDB_BSATN_SUM_TYPE_H diff --git a/crates/bindings-cpp/include/spacetimedb/database.h b/crates/bindings-cpp/include/spacetimedb/database.h index 1c065374779..e6f80b93325 100644 --- a/crates/bindings-cpp/include/spacetimedb/database.h +++ b/crates/bindings-cpp/include/spacetimedb/database.h @@ -21,7 +21,6 @@ namespace SpacetimeDB { namespace Internal { class Module; - struct RawModuleDef; } // Field constraint flags - must match Rust's ColumnAttribute bits @@ -273,4 +272,4 @@ namespace spacetimedb { using TableAccessor = SpacetimeDB::TableAccessor; } -#endif // SPACETIMEDB_DATABASE_H \ No newline at end of file +#endif // SPACETIMEDB_DATABASE_H diff --git a/crates/bindings-cpp/include/spacetimedb/enum_macro.h b/crates/bindings-cpp/include/spacetimedb/enum_macro.h index a596533b563..0aff8aea5f9 100644 --- a/crates/bindings-cpp/include/spacetimedb/enum_macro.h +++ b/crates/bindings-cpp/include/spacetimedb/enum_macro.h @@ -3,7 +3,7 @@ #include "spacetimedb/bsatn/traits.h" #include "spacetimedb/bsatn/sum_type.h" #include "spacetimedb/macros.h" -#include "spacetimedb/internal/v9_type_registration.h" +#include "spacetimedb/internal/module_type_registration.h" /** * @file enum_macro.h @@ -488,3 +488,4 @@ namespace SpacetimeDB::detail { } + diff --git a/crates/bindings-cpp/include/spacetimedb/internal/Module.h b/crates/bindings-cpp/include/spacetimedb/internal/Module.h index 8d564589369..dd27c18dc3a 100644 --- a/crates/bindings-cpp/include/spacetimedb/internal/Module.h +++ b/crates/bindings-cpp/include/spacetimedb/internal/Module.h @@ -3,11 +3,7 @@ #include #include -#include -#include -#include #include -#include #include "../bsatn/types.h" #include "../reducer_macros.h" #include "../reducer_context.h" @@ -15,117 +11,20 @@ #include // For StatusCode #include "autogen/TableAccess.g.h" // For TableAccess enum #include "autogen/Lifecycle.g.h" // For Lifecycle enum -#include "autogen/RawTypeDefV9.g.h" // For RawTypeDefV9 -#include "autogen/RawModuleDefV9.g.h" // For RawModuleDefV9 +#include "autogen/CaseConversionPolicy.g.h" // For CaseConversionPolicy namespace SpacetimeDB { -struct FieldConstraintInfo; // Forward declaration for constraint info - namespace bsatn { class Writer; // Forward declaration } -namespace Internal { -struct RawScheduleDefV9; // Forward declaration -struct RawModuleDefV9; // Forward declaration -} - namespace Internal { // Forward declarations are handled by includes -// FieldInfo for table registration -struct FieldInfo { - const char* name; - uint8_t type_id; - size_t offset; - size_t size; - std::function&, const void*)> serialize; -}; - -// Raw module definition structure (similar to C# RawModuleDefV9) -struct RawModuleDef { - // Structure to store named index information - struct IndexInfo { - std::string name; // Index name (e.g., "foo" for test_a) - std::string accessor_name; // Accessor name for the index - std::vector columns; // Column indices - }; - - struct Table { - std::string name; - bool is_public; - const std::type_info* type; - std::vector fields; - std::function&)> write_schema; - std::function&, const void*)> serialize; - - // Constraint metadata - std::optional primary_key; - std::vector unique_columns; - std::vector indexed_columns; - std::vector autoinc_columns; - - // Named indexes (for NamedIndex macro support) - std::vector named_indexes; - - // Scheduled reducer metadata (pointer to avoid incomplete type issues) - SpacetimeDB::Internal::RawScheduleDefV9* schedule = nullptr; - - // Field type collection migrated to V9Builder system - }; - - struct Reducer { - std::string name; - std::function&)> write_params; - // Legacy write_params_with_registry removed - V9 system handles parameters - std::function handler; - std::optional lifecycle; - // Parameter type collection migrated to V9Builder system - - // V9 support: Store parameter metadata for RawReducerDefV9 - std::vector param_names; // Parameter names from macro - }; - - std::vector tables; - std::vector reducers; - std::vector types; - std::map table_indices; - - // V9 ModuleDef built incrementally during registration - mutable RawModuleDefV9 v9_module; - - // Direct V9 type registration - replaces TypeRegistry - // Returns the typespace index for the type - uint32_t registerOrLookupType(const bsatn::AlgebraicType& type, - const std::string& type_name = "", - bool is_table_type = false) const; - - // Helper to convert bsatn types to Internal types with proper references - SpacetimeDB::Internal::AlgebraicType convertWithReferences(const bsatn::AlgebraicType& type) const; - - void AddTable(Table table) { - table_indices[table.type] = tables.size(); - tables.push_back(std::move(table)); - } - - void AddReducer(Reducer reducer) { - reducers.push_back(std::move(reducer)); - } - - // Serialize the entire module definition to binary format - std::vector serialize() const; - - // Legacy serialization method (manual BSATN writing) - std::vector serialize_legacy() const; - -}; - // Module class - singleton pattern similar to C# static class class Module { private: - RawModuleDef module_def_; - Module() = default; Module(const Module&) = delete; Module& operator=(const Module&) = delete; @@ -136,15 +35,11 @@ class Module { return instance; } - // Get module definition (for internal use) - static RawModuleDef& GetModuleDef() { - return Instance().module_def_; - } - // Initialize module (called once) // Module description for FFI (matching existing signature) static void __describe_module__(BytesSink sink); + static std::vector SerializeModuleDef(); // Reducer invocation for FFI (matching existing signature) static Status __call_reducer__( @@ -183,90 +78,92 @@ class Module { // Internal registration methods (inline to avoid linking issues) template - static void RegisterTableInternal(const char* name, bool is_public) { + static void RegisterTableInternal(const char* name, bool is_public, bool is_event = false) { // Forward declaration - implementation will be included at end of file - RegisterTableInternalImpl(name, is_public); + RegisterTableInternalImpl(name, is_public, is_event); } - template - static void RegisterReducerInternal(const std::string& name, void (*func)(ReducerContext, Args...)) { + template + static void RegisterReducerInternal(const std::string& name, Func func) { // Forward declaration - implementation will be included at end of file - RegisterReducerInternalImpl(name, func); + RegisterReducerInternalImpl(name, func); } // Implementation methods (will be defined after including Module_impl.h) template - static void RegisterTableInternalImpl(const char* name, bool is_public); - -public: - // New overload that accepts constraints - must be public for table_with_constraints.h - template - static void RegisterTableInternalImpl(const char* name, bool is_public, - const std::vector& constraints); - -private: - + static void RegisterTableInternalImpl(const char* name, bool is_public, bool is_event = false); + public: // These need to be public for macro access - template - static void RegisterReducerInternalImpl(const std::string& name, void (*func)(ReducerContext, Args...)); + template + static void RegisterReducerInternalImpl(const std::string& name, Func func); - template - static void RegisterReducerInternalWithNames(const std::string& name, void (*func)(ReducerContext, Args...), const std::vector& param_names); + template + static void RegisterReducerInternalWithNames(const std::string& name, Func func, const std::vector& param_names); private: public: - // Direct table registration (for rust_style_table.h) - static void RegisterTableDirect(const std::string& name, - TableAccess access, - std::function()> typeGen); - - // Special registration for lifecycle reducers - static void RegisterInitReducer(void (*func)(ReducerContext)); - static void RegisterClientConnectedReducer(void (*func)(ReducerContext, Identity)); - static void RegisterClientDisconnectedReducer(void (*func)(ReducerContext, Identity)); - -public: - // Registration support migrated to V9Builder system + // Registration support routed through the V10 module-definition builder. + static void RegisterClientVisibilityFilter(const char* sql); + static void SetCaseConversionPolicy(CaseConversionPolicy policy); + static void RegisterExplicitTableName(const std::string& source_name, const std::string& canonical_name); + static void RegisterExplicitFunctionName(const std::string& source_name, const std::string& canonical_name); + static void RegisterExplicitIndexName(const std::string& source_name, const std::string& canonical_name); }; // Helper functions for module description std::vector ConsumeBytes(BytesSource source); void WriteBytes(BytesSink sink, const std::vector& bytes); -// Schedule registration function -void register_table_schedule(const char* table_name, uint16_t scheduled_at_column, const char* reducer_name); - -// Get the global V9 module for direct population -RawModuleDefV9& GetV9Module(); +void SetTableIsEventFlag(const std::string& table_name, bool is_event); +bool GetTableIsEventFlag(const std::string& table_name); } // namespace Internal +// Public alias to mirror C# API shape (`SpacetimeDB.CaseConversionPolicy`). +using CaseConversionPolicy = Internal::CaseConversionPolicy; + // Public API similar to C# Module class class Module { public: // Table registration template - static void RegisterTable(const char* name, bool is_public = true) { - Internal::Module::RegisterTableInternal(name, is_public); + static void RegisterTable(const char* name, bool is_public = true, bool is_event = false) { + Internal::Module::RegisterTableInternal(name, is_public, is_event); } // Reducer registration - template - static void RegisterReducer(const char* name, void (*func)(ReducerContext&, Args...)) { + template + static void RegisterReducer(const char* name, Func func) { Internal::Module::RegisterReducerInternal(name, func); } - // Client visibility filter (similar to C#) - static void RegisterClientVisibilityFilter([[maybe_unused]] const char* sql) { - // TODO: Implement when row-level security is added + // Client visibility filter (similar to C# / Rust) + static void RegisterClientVisibilityFilter(const char* sql) { + Internal::Module::RegisterClientVisibilityFilter(sql); } // Module metadata (future extension) static void SetMetadata([[maybe_unused]] const char* name, [[maybe_unused]] const char* version) { // TODO: Implement module metadata } + + static void SetCaseConversionPolicy(CaseConversionPolicy policy) { + Internal::Module::SetCaseConversionPolicy(policy); + } + + static void RegisterExplicitTableName(const char* source_name, const char* canonical_name) { + Internal::Module::RegisterExplicitTableName(source_name, canonical_name); + } + + static void RegisterExplicitFunctionName(const char* source_name, const char* canonical_name) { + Internal::Module::RegisterExplicitFunctionName(source_name, canonical_name); + } + + static void RegisterExplicitIndexName(const char* source_name, const char* canonical_name) { + Internal::Module::RegisterExplicitIndexName(source_name, canonical_name); + } }; // Global registration functions for X-Macro support @@ -275,14 +172,14 @@ void register_table_impl(const char* name, bool is_public) { Internal::Module::RegisterTableInternal(name, is_public); } -template -void register_reducer_impl(const std::string& name, void (*func)(ReducerContext, Args...)) { +template +void register_reducer_impl(const std::string& name, Func func) { Internal::Module::RegisterReducerInternal(name, func); } -// Initialize module - no longer needed in V9 as preinit functions handle everything +// Initialize module - no-op; preinit functions handle registration. inline void initialize_module() { - // No-op in V9 + // No-op. } // Write module definition (for FFI) @@ -312,4 +209,4 @@ inline int16_t spacetimedb_call_reducer(uint32_t id, uint32_t args, // Include the template implementations #include "Module_impl.h" -#endif // SPACETIMEDB_MODULE_H \ No newline at end of file +#endif // SPACETIMEDB_MODULE_H diff --git a/crates/bindings-cpp/include/spacetimedb/internal/Module_impl.h b/crates/bindings-cpp/include/spacetimedb/internal/Module_impl.h index fbe82e59a1e..d2a74d4b1c0 100644 --- a/crates/bindings-cpp/include/spacetimedb/internal/Module_impl.h +++ b/crates/bindings-cpp/include/spacetimedb/internal/Module_impl.h @@ -17,25 +17,20 @@ #include "Module.h" #include "field_registration.h" #include "../table_with_constraints.h" +#include "../outcome.h" #include #include "bsatn_adapters.h" #include #include #include #include "autogen/Lifecycle.g.h" -#include "autogen/RawConstraintDefV9.g.h" -#include "autogen/RawUniqueConstraintDataV9.g.h" -#include "autogen/RawIndexDefV9.g.h" -#include "autogen/RawIndexAlgorithm.g.h" -#include "v9_builder.h" +#include "v10_builder.h" #include #include #include #include #include #include -#include -#include #include namespace SpacetimeDB { @@ -157,161 +152,12 @@ inline uint32_t read_u32(uint32_t source) { // TABLE REGISTRATION // ============================================================================= -// Apply constraints to table with optimized field lookup -inline void apply_table_constraints(RawModuleDef::Table& table, - const std::vector& constraints) { - if (constraints.empty() || table.fields.empty()) return; - - // Build field name lookup map - std::unordered_map field_indices; - field_indices.reserve(table.fields.size()); - for (size_t i = 0; i < table.fields.size(); ++i) { - field_indices.emplace(table.fields[i].name, static_cast(i)); - } - - // Pre-allocate constraint vectors - std::vector unique_fields, indexed_fields, autoinc_fields; - unique_fields.reserve(constraints.size()); - indexed_fields.reserve(constraints.size()); - autoinc_fields.reserve(constraints.size()); - - // Process constraints in single pass - for (const auto& constraint : constraints) { - if (constraint.field_name == nullptr) continue; - - auto field_it = field_indices.find(constraint.field_name); - if (field_it == field_indices.end()) continue; - - const uint16_t field_idx = field_it->second; - const auto constraint_flags = constraint.constraints; - - if (constraint_flags == FieldConstraint::PrimaryKey || constraint_flags == FieldConstraint::PrimaryKeyAuto) { - table.primary_key = field_idx; - unique_fields.push_back(field_idx); - indexed_fields.push_back(field_idx); - } - else if (constraint_flags == FieldConstraint::Unique || constraint_flags == FieldConstraint::Identity) { - unique_fields.push_back(field_idx); - indexed_fields.push_back(field_idx); - } - else if (has_constraint(constraint_flags, FieldConstraint::Indexed)) { - indexed_fields.push_back(field_idx); - } - - if (has_constraint(constraint_flags, FieldConstraint::AutoInc)) { - autoinc_fields.push_back(field_idx); - } - } - - // Sort and deduplicate - auto sort_and_dedupe = [](std::vector& vec) { - if (!vec.empty()) { - std::sort(vec.begin(), vec.end()); - vec.erase(std::unique(vec.begin(), vec.end()), vec.end()); - } - }; - - sort_and_dedupe(unique_fields); - sort_and_dedupe(indexed_fields); - sort_and_dedupe(autoinc_fields); - - // Move into table - table.unique_columns = std::move(unique_fields); - table.indexed_columns = std::move(indexed_fields); - table.autoinc_columns = std::move(autoinc_fields); -} - -// Extract fields from type and populate table structure -template -void add_fields_for_type(RawModuleDef::Table& table) { - auto algebraic_type = bsatn::bsatn_traits::algebraic_type(); - - if (algebraic_type.tag() != bsatn::AlgebraicTypeTag::Product) { - return; - } - - const auto& product = algebraic_type.as_product(); - const size_t field_count = product.elements.size(); - - table.fields.reserve(field_count); - - // Type-specific storage for field names - static std::map> type_field_storage; - auto& field_names = type_field_storage[&typeid(T)]; - field_names.clear(); - field_names.reserve(field_count); - - // Update global descriptors - auto& global_descriptors = get_table_descriptors(); - auto& descriptor = global_descriptors[&typeid(T)]; - descriptor.fields.clear(); - descriptor.fields.reserve(field_count); - - // Process fields - for (size_t i = 0; i < field_count; ++i) { - const auto& element = product.elements[i]; - - std::string field_name = element.name.has_value() ? - element.name.value() : - "field_" + std::to_string(i); - field_names.push_back(std::move(field_name)); - - FieldInfo field; - field.name = field_names[i].c_str(); - field.offset = i * sizeof(void*); - field.size = sizeof(void*); - field.type_id = 0; - field.serialize = [](std::vector&, const void*) {}; - table.fields.push_back(field); - - FieldDescriptor global_field; - global_field.name = field_names[i]; - global_field.offset = field.offset; - global_field.size = field.size; - global_field.write_type = [](std::vector&) {}; - global_field.get_algebraic_type = []() { return bsatn::AlgebraicType::U32(); }; - global_field.serialize = [](std::vector&, const void*) {}; - global_field.get_type_name = []() { return std::string(); }; - descriptor.fields.push_back(std::move(global_field)); - } -} - // Unified table registration - single implementation template -void Module::RegisterTableInternalImpl(const char* name, bool is_public, - const std::vector& constraints) { - RawModuleDef::Table table; - table.name = name; - table.is_public = is_public; - table.type = &typeid(T); - - add_fields_for_type(table); - - if (!constraints.empty()) { - apply_table_constraints(table, constraints); - } - - // V9 registration - always register tables with V9Builder - getV9Builder().RegisterTable(name, is_public); - - table.serialize = [](std::vector& buf, const void* obj) { - auto& module_def = GetModuleDef(); - auto it = module_def.table_indices.find(&typeid(T)); - if (it == module_def.table_indices.end()) return; - - const auto& table = module_def.tables[it->second]; - for (const auto& field : table.fields) { - field.serialize(buf, obj); - } - }; - - GetModuleDef().AddTable(std::move(table)); -} - -// Overload for tables without constraints -template -void Module::RegisterTableInternalImpl(const char* name, bool is_public) { - RegisterTableInternalImpl(name, is_public, {}); +void Module::RegisterTableInternalImpl(const char* name, bool is_public, bool is_event) { + // V10 registration entrypoint. + SetTableIsEventFlag(name, is_event); + getV10Builder().RegisterTable(name, is_public, is_event); } // ============================================================================= @@ -567,105 +413,24 @@ inline std::optional get_lifecycle_for_name(const std::string& name) return std::nullopt; } -// Unified reducer registration -template -void RegisterReducerUnified(const std::string& name, - void (*func)(ReducerContext, Args...), - std::optional lifecycle = std::nullopt, - const std::vector& param_names = {}) { - RawModuleDef::Reducer reducer; - reducer.name = name; - reducer.lifecycle = lifecycle; - - reducer.handler = [func](ReducerContext& ctx, uint32_t args) { - spacetimedb_reducer_wrapper(func, ctx, args); - }; - - if constexpr (sizeof...(Args) == 0) { - reducer.write_params = [](std::vector& buf) { - write_u32(buf, 0); - }; - reducer.param_names = {}; +template +void Module::RegisterReducerInternalImpl(const std::string& name, Func func) { + auto lifecycle = get_lifecycle_for_name(name); + if (lifecycle.has_value()) { + getV10Builder().RegisterLifecycleReducer(name, func, lifecycle.value()); } else { - reducer.param_names = param_names; + getV10Builder().RegisterReducer(name, func, std::vector{}); } - - // V9 registration - { - auto& v9_builder = getV9Builder(); - - std::vector param_types; - std::vector param_cpp_types; - std::vector param_type_names; - - if constexpr (sizeof...(Args) > 0) { - (param_types.push_back(bsatn::bsatn_traits::algebraic_type()), ...); - (param_cpp_types.push_back(&typeid(Args)), ...); - param_type_names.resize(sizeof...(Args)); - } - - v9_builder.AddV9Reducer( - name, - param_types, - param_names, - param_cpp_types, - param_type_names, - lifecycle - ); - } - - Module::GetModuleDef().AddReducer(std::move(reducer)); } -// Lifecycle reducer registration -inline void RegisterLifecycleReducer(const std::string& name, - std::optional lifecycle, - std::function handler) { - auto& v9_builder = getV9Builder(); - - v9_builder.AddV9Reducer( - name, - {}, - {}, - {}, - {}, - lifecycle - ); - - RawModuleDef::Reducer reducer; - reducer.name = name; - reducer.lifecycle = lifecycle; - reducer.handler = handler; - reducer.write_params = [](std::vector& buf) { - write_u32(buf, 0); - }; - - Module::GetModuleDef().AddReducer(std::move(reducer)); -} - -template -void Module::RegisterReducerInternalImpl(const std::string& name, void (*func)(ReducerContext, Args...)) { - RegisterReducerUnified(name, func, get_lifecycle_for_name(name)); -} - -template -void Module::RegisterReducerInternalWithNames(const std::string& name, void (*func)(ReducerContext, Args...), const std::vector& param_names) { - RegisterReducerUnified(name, func, get_lifecycle_for_name(name), param_names); -} - -inline void Module::RegisterInitReducer(void (*func)(ReducerContext)) { - RegisterLifecycleReducer("init", Lifecycle::Init, - [func](ReducerContext& ctx, uint32_t) { func(ctx); }); -} - -inline void Module::RegisterClientConnectedReducer(void (*func)(ReducerContext, Identity)) { - RegisterLifecycleReducer("client_connected", Lifecycle::OnConnect, - [func](ReducerContext& ctx, uint32_t) { func(ctx, ctx.sender); }); -} - -inline void Module::RegisterClientDisconnectedReducer(void (*func)(ReducerContext, Identity)) { - RegisterLifecycleReducer("client_disconnected", Lifecycle::OnDisconnect, - [func](ReducerContext& ctx, uint32_t) { func(ctx, ctx.sender); }); +template +void Module::RegisterReducerInternalWithNames(const std::string& name, Func func, const std::vector& param_names) { + auto lifecycle = get_lifecycle_for_name(name); + if (lifecycle.has_value()) { + getV10Builder().RegisterLifecycleReducer(name, func, lifecycle.value()); + } else { + getV10Builder().RegisterReducer(name, func, param_names); + } } // ============================================================================= @@ -727,4 +492,4 @@ inline std::vector parse_parameter_names(const std::string& params_ } // namespace Internal } // namespace SpacetimeDB -#endif // SPACETIMEDB_MODULE_IMPL_H \ No newline at end of file +#endif // SPACETIMEDB_MODULE_IMPL_H diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/CaseConversionPolicy.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/CaseConversionPolicy.g.h new file mode 100644 index 00000000000..3e3bef32761 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/CaseConversionPolicy.g.h @@ -0,0 +1,22 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" + +namespace SpacetimeDB::Internal { + +enum class CaseConversionPolicy : uint8_t { + None = 0, + SnakeCase = 1, +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/ExplicitNameEntry.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/ExplicitNameEntry.g.h new file mode 100644 index 00000000000..9b2c93e49d3 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/ExplicitNameEntry.g.h @@ -0,0 +1,34 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "NameMapping.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(ExplicitNameEntry_Function_Wrapper) { + SpacetimeDB::Internal::NameMapping value; + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, value); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(value) +}; +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(ExplicitNameEntry_Index_Wrapper) { + SpacetimeDB::Internal::NameMapping value; + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, value); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(value) +}; +SPACETIMEDB_INTERNAL_TAGGED_ENUM(ExplicitNameEntry, SpacetimeDB::Internal::NameMapping, ExplicitNameEntry_Function_Wrapper, ExplicitNameEntry_Index_Wrapper) +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/ExplicitNames.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/ExplicitNames.g.h new file mode 100644 index 00000000000..9e3cdc6721a --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/ExplicitNames.g.h @@ -0,0 +1,27 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "ExplicitNameEntry.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(ExplicitNames) { + std::vector entries; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, entries); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(entries) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/FunctionVisibility.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/FunctionVisibility.g.h new file mode 100644 index 00000000000..423276de9b4 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/FunctionVisibility.g.h @@ -0,0 +1,22 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" + +namespace SpacetimeDB::Internal { + +enum class FunctionVisibility : uint8_t { + Private = 0, + ClientCallable = 1, +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/IndexType.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/IndexType.g.h new file mode 100644 index 00000000000..bed3188b981 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/IndexType.g.h @@ -0,0 +1,22 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" + +namespace SpacetimeDB::Internal { + +enum class IndexType : uint8_t { + BTree = 0, + Hash = 1, +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/MiscModuleExport.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/MiscModuleExport.g.h new file mode 100644 index 00000000000..5a2494e51f1 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/MiscModuleExport.g.h @@ -0,0 +1,20 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "TypeAlias.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_TAGGED_ENUM(MiscModuleExport, SpacetimeDB::Internal::TypeAlias) +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/NameMapping.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/NameMapping.g.h new file mode 100644 index 00000000000..2991b37076b --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/NameMapping.g.h @@ -0,0 +1,28 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(NameMapping) { + std::string source_name; + std::string canonical_name; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, source_name); + ::SpacetimeDB::bsatn::serialize(writer, canonical_name); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(source_name, canonical_name) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawColumnDefV8.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawColumnDefV8.g.h new file mode 100644 index 00000000000..c3ac64c1e49 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawColumnDefV8.g.h @@ -0,0 +1,29 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "AlgebraicType.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawColumnDefV8) { + std::string col_name; + SpacetimeDB::Internal::AlgebraicType col_type; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, col_name); + ::SpacetimeDB::bsatn::serialize(writer, col_type); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(col_name, col_type) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawColumnDefaultValueV10.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawColumnDefaultValueV10.g.h new file mode 100644 index 00000000000..10e2aaf269e --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawColumnDefaultValueV10.g.h @@ -0,0 +1,28 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawColumnDefaultValueV10) { + uint16_t col_id; + std::vector value; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, col_id); + ::SpacetimeDB::bsatn::serialize(writer, value); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(col_id, value) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawConstraintDefV10.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawConstraintDefV10.g.h new file mode 100644 index 00000000000..7dcbc2588c8 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawConstraintDefV10.g.h @@ -0,0 +1,29 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "RawConstraintDataV9.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawConstraintDefV10) { + std::optional source_name; + SpacetimeDB::Internal::RawConstraintDataV9 data; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, source_name); + ::SpacetimeDB::bsatn::serialize(writer, data); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(source_name, data) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawConstraintDefV8.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawConstraintDefV8.g.h new file mode 100644 index 00000000000..8ebe5776fbb --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawConstraintDefV8.g.h @@ -0,0 +1,30 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawConstraintDefV8) { + std::string constraint_name; + uint8_t constraints; + std::vector columns; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, constraint_name); + ::SpacetimeDB::bsatn::serialize(writer, constraints); + ::SpacetimeDB::bsatn::serialize(writer, columns); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(constraint_name, constraints, columns) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawIndexDefV10.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawIndexDefV10.g.h new file mode 100644 index 00000000000..3bcc1f61252 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawIndexDefV10.g.h @@ -0,0 +1,31 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "RawIndexAlgorithm.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawIndexDefV10) { + std::optional source_name; + std::optional accessor_name; + SpacetimeDB::Internal::RawIndexAlgorithm algorithm; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, source_name); + ::SpacetimeDB::bsatn::serialize(writer, accessor_name); + ::SpacetimeDB::bsatn::serialize(writer, algorithm); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(source_name, accessor_name, algorithm) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawIndexDefV8.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawIndexDefV8.g.h new file mode 100644 index 00000000000..0f1bf1aa1cc --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawIndexDefV8.g.h @@ -0,0 +1,33 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "IndexType.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawIndexDefV8) { + std::string index_name; + bool is_unique; + SpacetimeDB::Internal::IndexType index_type; + std::vector columns; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, index_name); + ::SpacetimeDB::bsatn::serialize(writer, is_unique); + ::SpacetimeDB::bsatn::serialize(writer, index_type); + ::SpacetimeDB::bsatn::serialize(writer, columns); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(index_name, is_unique, index_type, columns) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawLifeCycleReducerDefV10.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawLifeCycleReducerDefV10.g.h new file mode 100644 index 00000000000..6c6e6c25e21 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawLifeCycleReducerDefV10.g.h @@ -0,0 +1,29 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "Lifecycle.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawLifeCycleReducerDefV10) { + SpacetimeDB::Internal::Lifecycle lifecycle_spec; + std::string function_name; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, lifecycle_spec); + ::SpacetimeDB::bsatn::serialize(writer, function_name); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(lifecycle_spec, function_name) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDef.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDef.g.h new file mode 100644 index 00000000000..c7f144eb07d --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDef.g.h @@ -0,0 +1,22 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "RawModuleDefV8.g.h" +#include "RawModuleDefV9.g.h" +#include "RawModuleDefV10.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_TAGGED_ENUM(RawModuleDef, SpacetimeDB::Internal::RawModuleDefV8, SpacetimeDB::Internal::RawModuleDefV9, SpacetimeDB::Internal::RawModuleDefV10) +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDefV10.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDefV10.g.h new file mode 100644 index 00000000000..42f95e7b80b --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDefV10.g.h @@ -0,0 +1,27 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "RawModuleDefV10Section.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawModuleDefV10) { + std::vector sections; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, sections); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(sections) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDefV10Section.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDefV10Section.g.h new file mode 100644 index 00000000000..241466f467c --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDefV10Section.g.h @@ -0,0 +1,30 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "RawViewDefV10.g.h" +#include "CaseConversionPolicy.g.h" +#include "RawScheduleDefV10.g.h" +#include "RawTableDefV10.g.h" +#include "Typespace.g.h" +#include "RawReducerDefV10.g.h" +#include "RawProcedureDefV10.g.h" +#include "RawTypeDefV10.g.h" +#include "RawLifeCycleReducerDefV10.g.h" +#include "RawRowLevelSecurityDefV9.g.h" +#include "ExplicitNames.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_TAGGED_ENUM(RawModuleDefV10Section, SpacetimeDB::Internal::Typespace, std::vector, std::vector, std::vector, std::vector, std::vector, std::vector, std::vector, std::vector, SpacetimeDB::Internal::CaseConversionPolicy, SpacetimeDB::Internal::ExplicitNames) +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDefV8.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDefV8.g.h new file mode 100644 index 00000000000..e856af0fec5 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDefV8.g.h @@ -0,0 +1,36 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "ReducerDef.g.h" +#include "MiscModuleExport.g.h" +#include "Typespace.g.h" +#include "TableDesc.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawModuleDefV8) { + SpacetimeDB::Internal::Typespace typespace; + std::vector tables; + std::vector reducers; + std::vector misc_exports; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, typespace); + ::SpacetimeDB::bsatn::serialize(writer, tables); + ::SpacetimeDB::bsatn::serialize(writer, reducers); + ::SpacetimeDB::bsatn::serialize(writer, misc_exports); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(typespace, tables, reducers, misc_exports) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDefV9.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDefV9.g.h index f2fdde5a32d..9ab21147e08 100644 --- a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDefV9.g.h +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawModuleDefV9.g.h @@ -12,12 +12,12 @@ #include #include "../autogen_base.h" #include "spacetimedb/bsatn/bsatn.h" -#include "RawMiscModuleExportV9.g.h" -#include "RawTypeDefV9.g.h" #include "RawTableDefV9.g.h" -#include "RawRowLevelSecurityDefV9.g.h" -#include "RawReducerDefV9.g.h" +#include "RawTypeDefV9.g.h" +#include "RawMiscModuleExportV9.g.h" #include "Typespace.g.h" +#include "RawReducerDefV9.g.h" +#include "RawRowLevelSecurityDefV9.g.h" namespace SpacetimeDB::Internal { diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawProcedureDefV10.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawProcedureDefV10.g.h new file mode 100644 index 00000000000..f316264fc5c --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawProcedureDefV10.g.h @@ -0,0 +1,35 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "FunctionVisibility.g.h" +#include "ProductType.g.h" +#include "AlgebraicType.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawProcedureDefV10) { + std::string source_name; + SpacetimeDB::Internal::ProductType params; + SpacetimeDB::Internal::AlgebraicType return_type; + SpacetimeDB::Internal::FunctionVisibility visibility; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, source_name); + ::SpacetimeDB::bsatn::serialize(writer, params); + ::SpacetimeDB::bsatn::serialize(writer, return_type); + ::SpacetimeDB::bsatn::serialize(writer, visibility); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(source_name, params, return_type, visibility) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawProcedureDefV9.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawProcedureDefV9.g.h index a49d9d78970..667d9864a2a 100644 --- a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawProcedureDefV9.g.h +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawProcedureDefV9.g.h @@ -12,8 +12,8 @@ #include #include "../autogen_base.h" #include "spacetimedb/bsatn/bsatn.h" -#include "AlgebraicType.g.h" #include "ProductType.g.h" +#include "AlgebraicType.g.h" namespace SpacetimeDB::Internal { diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawReducerDefV10.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawReducerDefV10.g.h new file mode 100644 index 00000000000..89934c2d4d7 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawReducerDefV10.g.h @@ -0,0 +1,37 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "AlgebraicType.g.h" +#include "FunctionVisibility.g.h" +#include "ProductType.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawReducerDefV10) { + std::string source_name; + SpacetimeDB::Internal::ProductType params; + SpacetimeDB::Internal::FunctionVisibility visibility; + SpacetimeDB::Internal::AlgebraicType ok_return_type; + SpacetimeDB::Internal::AlgebraicType err_return_type; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, source_name); + ::SpacetimeDB::bsatn::serialize(writer, params); + ::SpacetimeDB::bsatn::serialize(writer, visibility); + ::SpacetimeDB::bsatn::serialize(writer, ok_return_type); + ::SpacetimeDB::bsatn::serialize(writer, err_return_type); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(source_name, params, visibility, ok_return_type, err_return_type) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawReducerDefV9.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawReducerDefV9.g.h index 964ed98df12..8121773a40d 100644 --- a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawReducerDefV9.g.h +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawReducerDefV9.g.h @@ -12,8 +12,8 @@ #include #include "../autogen_base.h" #include "spacetimedb/bsatn/bsatn.h" -#include "ProductType.g.h" #include "Lifecycle.g.h" +#include "ProductType.g.h" namespace SpacetimeDB::Internal { diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawScheduleDefV10.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawScheduleDefV10.g.h new file mode 100644 index 00000000000..c1dba45adcb --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawScheduleDefV10.g.h @@ -0,0 +1,32 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawScheduleDefV10) { + std::optional source_name; + std::string table_name; + uint16_t schedule_at_col; + std::string function_name; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, source_name); + ::SpacetimeDB::bsatn::serialize(writer, table_name); + ::SpacetimeDB::bsatn::serialize(writer, schedule_at_col); + ::SpacetimeDB::bsatn::serialize(writer, function_name); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(source_name, table_name, schedule_at_col, function_name) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawScopedTypeNameV10.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawScopedTypeNameV10.g.h new file mode 100644 index 00000000000..328e861f23d --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawScopedTypeNameV10.g.h @@ -0,0 +1,28 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawScopedTypeNameV10) { + std::vector scope; + std::string source_name; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, scope); + ::SpacetimeDB::bsatn::serialize(writer, source_name); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(scope, source_name) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawSequenceDefV10.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawSequenceDefV10.g.h new file mode 100644 index 00000000000..d4bd7f933ce --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawSequenceDefV10.g.h @@ -0,0 +1,36 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawSequenceDefV10) { + std::optional source_name; + uint16_t column; + std::optional start; + std::optional min_value; + std::optional max_value; + SpacetimeDB::I128 increment; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, source_name); + ::SpacetimeDB::bsatn::serialize(writer, column); + ::SpacetimeDB::bsatn::serialize(writer, start); + ::SpacetimeDB::bsatn::serialize(writer, min_value); + ::SpacetimeDB::bsatn::serialize(writer, max_value); + ::SpacetimeDB::bsatn::serialize(writer, increment); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(source_name, column, start, min_value, max_value, increment) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawSequenceDefV8.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawSequenceDefV8.g.h new file mode 100644 index 00000000000..086a679e155 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawSequenceDefV8.g.h @@ -0,0 +1,38 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawSequenceDefV8) { + std::string sequence_name; + uint16_t col_pos; + SpacetimeDB::I128 increment; + std::optional start; + std::optional min_value; + std::optional max_value; + SpacetimeDB::I128 allocated; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, sequence_name); + ::SpacetimeDB::bsatn::serialize(writer, col_pos); + ::SpacetimeDB::bsatn::serialize(writer, increment); + ::SpacetimeDB::bsatn::serialize(writer, start); + ::SpacetimeDB::bsatn::serialize(writer, min_value); + ::SpacetimeDB::bsatn::serialize(writer, max_value); + ::SpacetimeDB::bsatn::serialize(writer, allocated); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(sequence_name, col_pos, increment, start, min_value, max_value, allocated) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawTableDefV10.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawTableDefV10.g.h new file mode 100644 index 00000000000..715364b13cf --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawTableDefV10.g.h @@ -0,0 +1,50 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "RawIndexDefV10.g.h" +#include "TableType.g.h" +#include "TableAccess.g.h" +#include "RawColumnDefaultValueV10.g.h" +#include "RawConstraintDefV10.g.h" +#include "RawSequenceDefV10.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawTableDefV10) { + std::string source_name; + uint32_t product_type_ref; + std::vector primary_key; + std::vector indexes; + std::vector constraints; + std::vector sequences; + SpacetimeDB::Internal::TableType table_type; + SpacetimeDB::Internal::TableAccess table_access; + std::vector default_values; + bool is_event; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, source_name); + ::SpacetimeDB::bsatn::serialize(writer, product_type_ref); + ::SpacetimeDB::bsatn::serialize(writer, primary_key); + ::SpacetimeDB::bsatn::serialize(writer, indexes); + ::SpacetimeDB::bsatn::serialize(writer, constraints); + ::SpacetimeDB::bsatn::serialize(writer, sequences); + ::SpacetimeDB::bsatn::serialize(writer, table_type); + ::SpacetimeDB::bsatn::serialize(writer, table_access); + ::SpacetimeDB::bsatn::serialize(writer, default_values); + ::SpacetimeDB::bsatn::serialize(writer, is_event); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(source_name, product_type_ref, primary_key, indexes, constraints, sequences, table_type, table_access, default_values, is_event) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawTableDefV8.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawTableDefV8.g.h new file mode 100644 index 00000000000..a985ad2f6e7 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawTableDefV8.g.h @@ -0,0 +1,44 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "RawSequenceDefV8.g.h" +#include "RawColumnDefV8.g.h" +#include "RawConstraintDefV8.g.h" +#include "RawIndexDefV8.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawTableDefV8) { + std::string table_name; + std::vector columns; + std::vector indexes; + std::vector constraints; + std::vector sequences; + std::string table_type; + std::string table_access; + std::optional scheduled; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, table_name); + ::SpacetimeDB::bsatn::serialize(writer, columns); + ::SpacetimeDB::bsatn::serialize(writer, indexes); + ::SpacetimeDB::bsatn::serialize(writer, constraints); + ::SpacetimeDB::bsatn::serialize(writer, sequences); + ::SpacetimeDB::bsatn::serialize(writer, table_type); + ::SpacetimeDB::bsatn::serialize(writer, table_access); + ::SpacetimeDB::bsatn::serialize(writer, scheduled); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(table_name, columns, indexes, constraints, sequences, table_type, table_access, scheduled) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawTableDefV9.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawTableDefV9.g.h index 8daa1883319..a69a502fb0e 100644 --- a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawTableDefV9.g.h +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawTableDefV9.g.h @@ -12,12 +12,12 @@ #include #include "../autogen_base.h" #include "spacetimedb/bsatn/bsatn.h" +#include "RawScheduleDefV9.g.h" +#include "RawSequenceDefV9.g.h" +#include "TableType.g.h" #include "TableAccess.g.h" #include "RawConstraintDefV9.g.h" #include "RawIndexDefV9.g.h" -#include "TableType.g.h" -#include "RawSequenceDefV9.g.h" -#include "RawScheduleDefV9.g.h" namespace SpacetimeDB::Internal { diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawTypeDefV10.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawTypeDefV10.g.h new file mode 100644 index 00000000000..de12ed9bcc5 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawTypeDefV10.g.h @@ -0,0 +1,31 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "RawScopedTypeNameV10.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawTypeDefV10) { + SpacetimeDB::Internal::RawScopedTypeNameV10 source_name; + uint32_t ty; + bool custom_ordering; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, source_name); + ::SpacetimeDB::bsatn::serialize(writer, ty); + ::SpacetimeDB::bsatn::serialize(writer, custom_ordering); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(source_name, ty, custom_ordering) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawViewDefV10.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawViewDefV10.g.h new file mode 100644 index 00000000000..7f38fa8e5b7 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/RawViewDefV10.g.h @@ -0,0 +1,38 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "AlgebraicType.g.h" +#include "ProductType.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(RawViewDefV10) { + std::string source_name; + uint32_t index; + bool is_public; + bool is_anonymous; + SpacetimeDB::Internal::ProductType params; + SpacetimeDB::Internal::AlgebraicType return_type; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, source_name); + ::SpacetimeDB::bsatn::serialize(writer, index); + ::SpacetimeDB::bsatn::serialize(writer, is_public); + ::SpacetimeDB::bsatn::serialize(writer, is_anonymous); + ::SpacetimeDB::bsatn::serialize(writer, params); + ::SpacetimeDB::bsatn::serialize(writer, return_type); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(source_name, index, is_public, is_anonymous, params, return_type) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/ReducerDef.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/ReducerDef.g.h new file mode 100644 index 00000000000..945b0f32ddb --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/ReducerDef.g.h @@ -0,0 +1,29 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "ProductTypeElement.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(ReducerDef) { + std::string name; + std::vector args; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, name); + ::SpacetimeDB::bsatn::serialize(writer, args); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(name, args) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/TableDesc.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/TableDesc.g.h new file mode 100644 index 00000000000..b9712b21d90 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/TableDesc.g.h @@ -0,0 +1,29 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" +#include "RawTableDefV8.g.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(TableDesc) { + SpacetimeDB::Internal::RawTableDefV8 schema; + uint32_t data; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, schema); + ::SpacetimeDB::bsatn::serialize(writer, data); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(schema, data) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen/TypeAlias.g.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen/TypeAlias.g.h new file mode 100644 index 00000000000..fde57b6eb83 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen/TypeAlias.g.h @@ -0,0 +1,28 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb codegen. + +#pragma once + +#include +#include +#include +#include +#include +#include "../autogen_base.h" +#include "spacetimedb/bsatn/bsatn.h" + +namespace SpacetimeDB::Internal { + +SPACETIMEDB_INTERNAL_PRODUCT_TYPE(TypeAlias) { + std::string name; + uint32_t ty; + + void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const { + ::SpacetimeDB::bsatn::serialize(writer, name); + ::SpacetimeDB::bsatn::serialize(writer, ty); + } + SPACETIMEDB_PRODUCT_TYPE_EQUALITY(name, ty) +}; +} // namespace SpacetimeDB::Internal diff --git a/crates/bindings-cpp/include/spacetimedb/internal/autogen_base.h b/crates/bindings-cpp/include/spacetimedb/internal/autogen_base.h index 9cc52c5ffa6..e6fb5f5b85b 100644 --- a/crates/bindings-cpp/include/spacetimedb/internal/autogen_base.h +++ b/crates/bindings-cpp/include/spacetimedb/internal/autogen_base.h @@ -113,6 +113,15 @@ class TaggedEnumBase { #define SPACETIMEDB_INTERNAL_PRODUCT_TYPE(TypeName) \ struct TypeName +// Public aliases used by generated non-internal code paths. +#ifndef SPACETIMEDB_PRODUCT_TYPE +#define SPACETIMEDB_PRODUCT_TYPE(TypeName) SPACETIMEDB_INTERNAL_PRODUCT_TYPE(TypeName) +#endif + +#ifndef SPACETIMEDB_TAGGED_ENUM +#define SPACETIMEDB_TAGGED_ENUM(TypeName, ...) SPACETIMEDB_INTERNAL_TAGGED_ENUM(TypeName, __VA_ARGS__) +#endif + // Macro for product type equality - generates == and != operators // This generates a simple equality comparison using std::tie #define SPACETIMEDB_PRODUCT_TYPE_EQUALITY(...) \ @@ -121,4 +130,4 @@ class TaggedEnumBase { } \ bool operator!=(const auto& other) const noexcept { \ return !(*this == other); \ - } \ No newline at end of file + } diff --git a/crates/bindings-cpp/include/spacetimedb/internal/v9_type_registration.h b/crates/bindings-cpp/include/spacetimedb/internal/module_type_registration.h similarity index 93% rename from crates/bindings-cpp/include/spacetimedb/internal/v9_type_registration.h rename to crates/bindings-cpp/include/spacetimedb/internal/module_type_registration.h index 3f08f594926..4249c6b4c98 100644 --- a/crates/bindings-cpp/include/spacetimedb/internal/v9_type_registration.h +++ b/crates/bindings-cpp/include/spacetimedb/internal/module_type_registration.h @@ -1,14 +1,25 @@ -#ifndef SPACETIMEDB_V9_TYPE_REGISTRATION_H -#define SPACETIMEDB_V9_TYPE_REGISTRATION_H +#ifndef SPACETIMEDB_MODULE_TYPE_REGISTRATION_H +#define SPACETIMEDB_MODULE_TYPE_REGISTRATION_H #include #include #include #include #include -#include +#include #include "../bsatn/bsatn.h" +#if defined(__has_include) +#if __has_include() && !defined(_MSC_VER) +#include +#define SPACETIMEDB_HAS_CXA_DEMANGLE 1 +#else +#define SPACETIMEDB_HAS_CXA_DEMANGLE 0 +#endif +#else +#define SPACETIMEDB_HAS_CXA_DEMANGLE 0 +#endif + // Forward declarations namespace SpacetimeDB { namespace Internal { @@ -23,24 +34,28 @@ namespace detail { // Helper function to demangle C++ type names - inline implementation for template usage inline std::string demangle_cpp_type_name(const char* name) { +#if SPACETIMEDB_HAS_CXA_DEMANGLE int status = 0; std::unique_ptr demangled( abi::__cxa_demangle(name, nullptr, nullptr, &status), std::free ); return (status == 0 && demangled) ? std::string(demangled.get()) : std::string(name); +#else + return std::string(name); +#endif } namespace SpacetimeDB { namespace Internal { /** - * V9TypeRegistration - Single unified type registration system for V9 modules + * ModuleTypeRegistration - Single unified type registration system for module definitions * * Core principles: * - Only user-defined structs and enums get registered in the types array * - Primitives, arrays, Options, and special types are always inlined - * - Every registered type gets a name and RawTypeDefV9 export + * - Every registered type gets a name and RawTypeDefV10 export * - Single entry point: registerType() * * Type handling: @@ -50,9 +65,9 @@ namespace Internal { * - Special types (Identity, etc.) → Return inline Product structure * - User structs/enums → Register in typespace, return Ref */ -class V9TypeRegistration { +class ModuleTypeRegistration { private: - // Cache of type name -> typespace index (built from GetV9Module().types) + // Cache of type name -> typespace index (built from V10Builder type defs) std::unordered_map type_name_cache_; // Track types currently being registered to detect cycles @@ -249,13 +264,13 @@ class V9TypeRegistration { }; // Global V9 type registration instance -extern std::unique_ptr g_v9_type_registration; +extern std::unique_ptr g_module_type_registration; // Initialize the V9 type registration (called once at module startup) -void initializeV9TypeRegistration(); +void initializeModuleTypeRegistration(); // Get the global V9 type registration -V9TypeRegistration& getV9TypeRegistration(); +ModuleTypeRegistration& getModuleTypeRegistration(); } // namespace Internal @@ -369,7 +384,7 @@ class LazyTypeRegistrar { } // Register with V9 system and cache the index using the qualified name - type_index_ = getV9TypeRegistration().registerAndGetIndex( + type_index_ = getModuleTypeRegistration().registerAndGetIndex( algebraic_type, qualified_name, &typeid(T)); return bsatn::AlgebraicType::make_ref(type_index_); @@ -405,4 +420,4 @@ class LazyTypeRegistrar { } // namespace Internal } // namespace SpacetimeDB -#endif // SPACETIMEDB_V9_TYPE_REGISTRATION_H \ No newline at end of file +#endif // SPACETIMEDB_MODULE_TYPE_REGISTRATION_H diff --git a/crates/bindings-cpp/include/spacetimedb/internal/runtime_registration.h b/crates/bindings-cpp/include/spacetimedb/internal/runtime_registration.h new file mode 100644 index 00000000000..4d84cb975d4 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/runtime_registration.h @@ -0,0 +1,39 @@ +#ifndef SPACETIMEDB_RUNTIME_REGISTRATION_H +#define SPACETIMEDB_RUNTIME_REGISTRATION_H + +#include +#include +#include +#include +#include "../abi/opaque_types.h" +#include "autogen/Lifecycle.g.h" + +namespace SpacetimeDB { + +struct ReducerContext; +struct ViewContext; +struct AnonymousViewContext; +struct ProcedureContext; + +namespace Internal { + +void RegisterReducerHandler(const std::string& name, + std::function handler, + std::optional lifecycle = std::nullopt); +void RegisterViewHandler(const std::string& name, + std::function(ViewContext&, BytesSource)> handler); +void RegisterAnonymousViewHandler(const std::string& name, + std::function(AnonymousViewContext&, BytesSource)> handler); +void RegisterProcedureHandler(const std::string& name, + std::function(ProcedureContext&, BytesSource)> handler); +size_t GetViewHandlerCount(); +size_t GetAnonymousViewHandlerCount(); +size_t GetProcedureHandlerCount(); +std::vector ConsumeBytes(BytesSource source); +void SetMultiplePrimaryKeyError(const std::string& table_name); +void SetConstraintRegistrationError(const std::string& code, const std::string& details); + +} // namespace Internal +} // namespace SpacetimeDB + +#endif // SPACETIMEDB_RUNTIME_REGISTRATION_H diff --git a/crates/bindings-cpp/include/spacetimedb/internal/template_utils.h b/crates/bindings-cpp/include/spacetimedb/internal/template_utils.h new file mode 100644 index 00000000000..57ab5ecbc84 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/template_utils.h @@ -0,0 +1,56 @@ +#ifndef SPACETIMEDB_TEMPLATE_UTILS_H +#define SPACETIMEDB_TEMPLATE_UTILS_H + +#include +#include +#include +#include +#include + +namespace SpacetimeDB { +namespace Internal { + +template +struct function_traits; + +template +struct function_traits { + static constexpr size_t arity = sizeof...(Args); + using result_type = R; + + template + using arg_t = typename std::tuple_element>::type; +}; + +template +std::vector view_result_to_vec(std::vector&& vec) { + return std::move(vec); +} + +template +std::vector view_result_to_vec(const std::vector& vec) { + return vec; +} + +template +std::vector view_result_to_vec(std::optional&& opt) { + std::vector result; + if (opt.has_value()) { + result.push_back(std::move(*opt)); + } + return result; +} + +template +std::vector view_result_to_vec(const std::optional& opt) { + std::vector result; + if (opt.has_value()) { + result.push_back(*opt); + } + return result; +} + +} // namespace Internal +} // namespace SpacetimeDB + +#endif // SPACETIMEDB_TEMPLATE_UTILS_H diff --git a/crates/bindings-cpp/include/spacetimedb/internal/v10_builder.h b/crates/bindings-cpp/include/spacetimedb/internal/v10_builder.h new file mode 100644 index 00000000000..9de0f0a2312 --- /dev/null +++ b/crates/bindings-cpp/include/spacetimedb/internal/v10_builder.h @@ -0,0 +1,675 @@ +#ifndef SPACETIMEDB_V10_BUILDER_H +#define SPACETIMEDB_V10_BUILDER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../bsatn/bsatn.h" +#include "../database.h" +#include "autogen/CaseConversionPolicy.g.h" +#include "autogen/ExplicitNameEntry.g.h" +#include "autogen/NameMapping.g.h" +#include "autogen/AlgebraicType.g.h" +#include "autogen/SumType.g.h" +#include "autogen/ProductType.g.h" +#include "autogen/ProductTypeElement.g.h" +#include "autogen/RawModuleDefV10.g.h" +#include "autogen/Typespace.g.h" +#include "autogen/RawTableDefV10.g.h" +#include "autogen/RawReducerDefV10.g.h" +#include "autogen/RawProcedureDefV10.g.h" +#include "autogen/RawViewDefV10.g.h" +#include "autogen/RawScheduleDefV10.g.h" +#include "autogen/RawLifeCycleReducerDefV10.g.h" +#include "autogen/RawColumnDefaultValueV10.g.h" +#include "autogen/RawRowLevelSecurityDefV9.g.h" +#include "autogen/RawTypeDefV10.g.h" +#include "field_registration.h" +#include "buffer_pool.h" +#include "runtime_registration.h" +#include "template_utils.h" +#include "module_type_registration.h" + +namespace SpacetimeDB { + +void fail_reducer(std::string message); + +namespace Internal { + +class V10Builder { +public: + V10Builder() = default; + + void Clear(); + + template + void RegisterTable(const std::string& table_name, bool is_public, bool is_event = false) { + if (g_circular_ref_error) { + std::fprintf(stderr, "ERROR: Skipping table registration '%s' because circular reference error is set\n", table_name.c_str()); + return; + } + SpacetimeDB::field_registrar::register_fields(); + auto& descriptor_map = SpacetimeDB::get_table_descriptors(); + auto it = descriptor_map.find(&typeid(T)); + if (it == descriptor_map.end()) { + SetConstraintRegistrationError( + "TABLE_NO_FIELD_DESCRIPTORS", + "table='" + table_name + "' has no registered field descriptors"); + return; + } + + std::vector elements; + const auto& field_descs = it->second.fields; + for (const auto& field_desc : field_descs) { + bsatn::AlgebraicType field_type = field_desc.get_algebraic_type(); + std::string field_type_name = field_desc.get_type_name ? field_desc.get_type_name() : ""; + if (!field_type_name.empty() && field_type.tag() == bsatn::AlgebraicTypeTag::Sum) { + const auto& sum = field_type.as_sum(); + bool is_option = (sum.variants.size() == 2 && sum.variants[0].name == "some" && sum.variants[1].name == "none"); + bool is_schedule_at = (sum.variants.size() == 2 && sum.variants[0].name == "Interval" && sum.variants[1].name == "Time"); + bool is_result = (sum.variants.size() == 2 && sum.variants[0].name == "ok" && sum.variants[1].name == "err"); + if (!is_option && !is_schedule_at && !is_result) { + size_t last_colon = field_type_name.rfind("::"); + if (last_colon != std::string::npos) { + field_type_name = field_type_name.substr(last_colon + 2); + } + getModuleTypeRegistration().registerTypeByName(field_type_name, field_type, nullptr); + } + } + elements.emplace_back(std::make_optional(field_desc.name), std::move(field_type)); + } + + bsatn::ProductType bsatn_product(std::move(elements)); + bsatn::AlgebraicType table_type = bsatn::AlgebraicType::make_product( + std::make_unique(std::move(bsatn_product))); + AlgebraicType registered_type = getModuleTypeRegistration().registerType(table_type, "", &typeid(T)); + if (registered_type.get_tag() != AlgebraicType::Tag::Ref) { + SetConstraintRegistrationError( + "TABLE_TYPE_NOT_REF", + "table='" + table_name + "' did not register as a named Ref type"); + return; + } + + RawTableDefV10 table_def{ + table_name, + registered_type.get<0>(), + {}, + {}, + {}, + {}, + TableType::User, + is_public ? TableAccess::Public : TableAccess::Private, + column_defaults_by_table_[table_name], + is_event, + }; + UpsertTable(table_def); + SetTableIsEventFlag(table_name, is_event); + } + + template + void AddFieldConstraint(const std::string& table_name, + const std::string& field_name, + FieldConstraint constraint) { + if (g_circular_ref_error) { + std::fprintf(stderr, "ERROR: Skipping field constraint registration '%s.%s' because circular reference error is set\n", + table_name.c_str(), field_name.c_str()); + return; + } + SpacetimeDB::field_registrar::register_fields(); + auto& descriptor_map = SpacetimeDB::get_table_descriptors(); + auto it = descriptor_map.find(&typeid(T)); + if (it == descriptor_map.end()) { + SetConstraintRegistrationError( + "NO_FIELD_DESCRIPTORS", + "table='" + table_name + "' field='" + field_name + "' has no registered field descriptors"); + return; + } + + uint16_t field_idx = 0; + bool field_found = false; + for (const auto& field_desc : it->second.fields) { + if (field_desc.name == field_name) { + field_found = true; + break; + } + field_idx++; + } + if (!field_found) { + SetConstraintRegistrationError( + "FIELD_NOT_FOUND", + "table='" + table_name + "' field='" + field_name + "' was not found"); + return; + } + + auto table_it = FindTable(table_name); + if (table_it == tables_.end()) { + SetConstraintRegistrationError( + "TABLE_NOT_FOUND", + "table='" + table_name + "' was not registered before applying field constraints"); + return; + } + + int constraint_bits = static_cast(constraint); + if (constraint_bits & 0b1000) { + if (!table_it->primary_key.empty()) { + SetMultiplePrimaryKeyError(table_name); + return; + } + table_it->primary_key.push_back(field_idx); + table_it->constraints.push_back(CreateUniqueConstraint(table_name, field_name, field_idx)); + table_it->indexes.push_back(CreateBTreeIndex(table_name, table_name + "_" + field_name + "_idx_btree", {field_idx}, field_name)); + } else if ((constraint_bits & 0b0100) && !(constraint_bits & 0b1000)) { + table_it->constraints.push_back(CreateUniqueConstraint(table_name, field_name, field_idx)); + table_it->indexes.push_back(CreateBTreeIndex(table_name, table_name + "_" + field_name + "_idx_btree", {field_idx}, field_name)); + } else if ((constraint_bits & 0b0001) && !(constraint_bits & 0b1100)) { + table_it->indexes.push_back(CreateBTreeIndex(table_name, table_name + "_" + field_name + "_idx_btree", {field_idx}, field_name)); + } + + if (constraint_bits & static_cast(FieldConstraint::AutoInc)) { + RawSequenceDefV10 seq_def; + // Defer sequence naming to host-side canonical generation for Rust/C# parity. + seq_def.source_name = std::nullopt; + seq_def.column = field_idx; + seq_def.start = std::nullopt; + seq_def.increment = SpacetimeDB::I128(1); + seq_def.min_value = std::nullopt; + seq_def.max_value = std::nullopt; + table_it->sequences.push_back(std::move(seq_def)); + } + } + + template + void AddMultiColumnIndex(const std::string& table_name, + const std::string& index_name, + const std::vector& field_names) { + if (g_circular_ref_error) { + std::fprintf(stderr, "ERROR: Skipping multi-column index registration '%s.%s' because circular reference error is set\n", + table_name.c_str(), index_name.c_str()); + return; + } + if (field_names.empty()) { + SetConstraintRegistrationError( + "MULTI_INDEX_EMPTY", + "table='" + table_name + "' index='" + index_name + "' has no fields"); + return; + } + SpacetimeDB::field_registrar::register_fields(); + auto& descriptor_map = SpacetimeDB::get_table_descriptors(); + auto it = descriptor_map.find(&typeid(T)); + if (it == descriptor_map.end()) { + SetConstraintRegistrationError( + "NO_FIELD_DESCRIPTORS", + "table='" + table_name + "' index='" + index_name + "' has no registered field descriptors"); + return; + } + + auto table_it = FindTable(table_name); + if (table_it == tables_.end()) { + SetConstraintRegistrationError( + "TABLE_NOT_FOUND", + "table='" + table_name + "' index='" + index_name + "' references an unknown table"); + return; + } + + std::vector field_indexes; + for (const std::string& field_name : field_names) { + uint16_t field_idx = 0; + bool found = false; + for (const auto& field_desc : it->second.fields) { + if (field_desc.name == field_name) { + field_indexes.push_back(field_idx); + found = true; + break; + } + field_idx++; + } + if (!found) { + SetConstraintRegistrationError( + "FIELD_NOT_FOUND", + "table='" + table_name + "' index='" + index_name + "' field='" + field_name + "' was not found"); + return; + } + } + + std::string generated_name = table_name + "_" + field_names[0]; + for (size_t i = 1; i < field_names.size(); ++i) { + generated_name += "_" + field_names[i]; + } + generated_name += "_idx_btree"; + table_it->indexes.push_back(CreateBTreeIndex(table_name, generated_name, field_indexes, index_name)); + } + + template + void AddColumnDefault(const std::string& table_name, + const std::string& field_name, + const std::vector& serialized_value) { + if (g_circular_ref_error) { + std::fprintf(stderr, "ERROR: Skipping default-value registration '%s.%s' because circular reference error is set\n", + table_name.c_str(), field_name.c_str()); + return; + } + auto table_it = FindTable(table_name); + if (table_it == tables_.end()) { + SetConstraintRegistrationError( + "TABLE_NOT_FOUND", + "table='" + table_name + "' default field='" + field_name + "' references an unknown table"); + return; + } + + SpacetimeDB::field_registrar::register_fields(); + auto& descriptor_map = SpacetimeDB::get_table_descriptors(); + auto it = descriptor_map.find(&typeid(T)); + if (it == descriptor_map.end()) { + SetConstraintRegistrationError( + "NO_FIELD_DESCRIPTORS", + "table='" + table_name + "' default field='" + field_name + "' has no registered field descriptors"); + return; + } + + bool field_found = false; + const auto& fields = it->second.fields; + for (uint16_t i = 0; i < fields.size(); ++i) { + if (fields[i].name == field_name) { + field_found = true; + for (uint16_t pk_col : table_it->primary_key) { + if (pk_col == i) { + SetConstraintRegistrationError( + "DEFAULT_ON_PRIMARY_KEY", + "table='" + table_name + "' field='" + field_name + "' cannot have default on primary key"); + return; + } + } + for (const auto& constraint : table_it->constraints) { + if (constraint.data.get_tag() == 0) { + const auto& unique_data = constraint.data.get<0>(); + if (unique_data.columns.size() == 1 && unique_data.columns[0] == i) { + SetConstraintRegistrationError( + "DEFAULT_ON_UNIQUE", + "table='" + table_name + "' field='" + field_name + "' cannot have default on unique field"); + return; + } + } + } + for (const auto& sequence : table_it->sequences) { + if (sequence.column == i) { + SetConstraintRegistrationError( + "DEFAULT_ON_AUTOINC", + "table='" + table_name + "' field='" + field_name + "' cannot have default on autoincrement field"); + return; + } + } + column_defaults_by_table_[table_name].push_back(RawColumnDefaultValueV10{i, serialized_value}); + table_it->default_values = column_defaults_by_table_[table_name]; + break; + } + } + if (!field_found) { + SetConstraintRegistrationError( + "FIELD_NOT_FOUND", + "table='" + table_name + "' default field='" + field_name + "' was not found"); + } + } + + template + void RegisterReducer(const std::string& reducer_name, + Func func, + const std::vector& param_names) { + if (g_circular_ref_error) { + std::fprintf(stderr, "ERROR: Skipping reducer registration '%s' because circular reference error is set\n", + reducer_name.c_str()); + return; + } + using traits = function_traits; + static_assert(traits::arity > 0, "Reducer must have at least one parameter (ReducerContext)"); + if constexpr (traits::arity > 0) { + using FirstParamType = std::remove_cv_t>>; + static_assert(std::is_same_v, + "First parameter of reducer must be ReducerContext"); + } + + std::function handler; + if constexpr (traits::arity == 1) { + handler = [func](ReducerContext& ctx, BytesSource) { + auto result = func(ctx); + if (result.is_err()) { + ::SpacetimeDB::fail_reducer(result.error()); + } + }; + } else { + handler = [func](ReducerContext& ctx, BytesSource args_source) { + std::vector args_bytes = ConsumeBytes(args_source); + [](std::index_sequence, Func fn, ReducerContext& ctx_inner, const std::vector& bytes) { + bsatn::Reader reader(bytes.data(), bytes.size()); + auto args = std::make_tuple(bsatn::deserialize>(reader)...); + std::apply([&ctx_inner, fn](auto&&... unpacked) { + auto result = fn(ctx_inner, std::forward(unpacked)...); + if (result.is_err()) { + ::SpacetimeDB::fail_reducer(result.error()); + } + }, args); + }(std::make_index_sequence{}, func, ctx, args_bytes); + }; + } + RegisterReducerHandler(reducer_name, handler, std::nullopt); + + ProductType params; + if constexpr (traits::arity > 1) { + auto& type_reg = getModuleTypeRegistration(); + [](std::index_sequence, + ProductType& out_params, + const std::vector& names, + ModuleTypeRegistration& reg) { + (([](ProductType& p, + const std::vector& n, + ModuleTypeRegistration& r) { + using param_type = std::remove_cv_t>>; + auto bsatn_type = bsatn::bsatn_traits::algebraic_type(); + AlgebraicType internal_type = r.registerType(bsatn_type, "", &typeid(param_type)); + std::string param_name = (I < n.size()) ? n[I] : ("arg" + std::to_string(I)); + p.elements.emplace_back(std::make_optional(param_name), std::move(internal_type)); + }.template operator()(out_params, names, reg)), ...); + }(std::make_index_sequence{}, params, param_names, type_reg); + } + + RawReducerDefV10 reducer_def{ + reducer_name, + std::move(params), + FunctionVisibility::ClientCallable, + MakeUnitAlgebraicType(), + MakeStringAlgebraicType(), + }; + UpsertReducer(reducer_def); + } + + template + void RegisterLifecycleReducer(const std::string& reducer_name, Func func, Lifecycle lifecycle) { + if (g_circular_ref_error) { + std::fprintf(stderr, "ERROR: Skipping lifecycle reducer registration '%s' because circular reference error is set\n", + reducer_name.c_str()); + return; + } + using traits = function_traits; + static_assert(traits::arity > 0, "Reducer must have at least one parameter (ReducerContext)"); + if constexpr (traits::arity > 0) { + using FirstParamType = std::remove_cv_t>>; + static_assert(std::is_same_v, + "First parameter of reducer must be ReducerContext"); + } + + std::function handler; + if constexpr (traits::arity == 1) { + handler = [func](ReducerContext& ctx, BytesSource) { + auto result = func(ctx); + if (result.is_err()) { + ::SpacetimeDB::fail_reducer(result.error()); + } + }; + } else { + handler = [func](ReducerContext& ctx, BytesSource args_source) { + std::vector args_bytes = ConsumeBytes(args_source); + [](std::index_sequence, Func fn, ReducerContext& ctx_inner, const std::vector& bytes) { + bsatn::Reader reader(bytes.data(), bytes.size()); + auto args = std::make_tuple(bsatn::deserialize>(reader)...); + std::apply([&ctx_inner, fn](auto&&... unpacked) { + auto result = fn(ctx_inner, std::forward(unpacked)...); + if (result.is_err()) { + ::SpacetimeDB::fail_reducer(result.error()); + } + }, args); + }(std::make_index_sequence{}, func, ctx, args_bytes); + }; + } + RegisterReducerHandler(reducer_name, handler, lifecycle); + + RawReducerDefV10 reducer_def{ + reducer_name, + ProductType{}, + FunctionVisibility::Private, + MakeUnitAlgebraicType(), + MakeStringAlgebraicType(), + }; + UpsertReducer(reducer_def); + UpsertLifecycleReducer(RawLifeCycleReducerDefV10{lifecycle, reducer_name}); + } + + template + void RegisterView(const std::string& view_name, + Func func, + bool is_public, + const std::vector& param_names = {}) { + if (g_circular_ref_error) { + std::fprintf(stderr, "ERROR: Skipping view registration '%s' because circular reference error is set\n", + view_name.c_str()); + return; + } + (void)param_names; + using traits = function_traits; + using ContextType = std::remove_cv_t>>; + using ReturnType = typename traits::result_type; + static_assert(traits::arity > 0, "View must have at least one parameter (ViewContext or AnonymousViewContext)"); + static_assert(std::is_same_v || std::is_same_v, + "First parameter of view must be ViewContext or AnonymousViewContext"); + + if constexpr (std::is_same_v) { + std::function(ViewContext&, BytesSource)> handler = + [func](ViewContext& ctx, BytesSource args_source) -> std::vector { + (void)args_source; + auto result = func(ctx); + auto result_vec = view_result_to_vec(std::move(result)); + IterBuf buf = IterBuf::take(); + { + bsatn::Writer writer(buf.get()); + bsatn::serialize(writer, result_vec); + } + return buf.release(); + }; + RegisterViewHandler(view_name, handler); + } else { + std::function(AnonymousViewContext&, BytesSource)> handler = + [func](AnonymousViewContext& ctx, BytesSource args_source) -> std::vector { + (void)args_source; + auto result = func(ctx); + auto result_vec = view_result_to_vec(std::move(result)); + IterBuf buf = IterBuf::take(); + { + bsatn::Writer writer(buf.get()); + bsatn::serialize(writer, result_vec); + } + return buf.release(); + }; + RegisterAnonymousViewHandler(view_name, handler); + } + + auto& type_reg = getModuleTypeRegistration(); + auto bsatn_return = bsatn::bsatn_traits::algebraic_type(); + AlgebraicType return_type = type_reg.registerType(bsatn_return, "", &typeid(ReturnType)); + bool is_anonymous = std::is_same_v; + uint32_t index = static_cast(is_anonymous ? (GetAnonymousViewHandlerCount() - 1) : (GetViewHandlerCount() - 1)); + + RawViewDefV10 view_def{ + view_name, + index, + is_public, + is_anonymous, + ProductType{}, + return_type, + }; + UpsertView(view_def); + } + + template + void RegisterProcedure(const std::string& procedure_name, + Func func, + const std::vector& param_names = {}) { + if (g_circular_ref_error) { + std::fprintf(stderr, "ERROR: Skipping procedure registration '%s' because circular reference error is set\n", + procedure_name.c_str()); + return; + } + using traits = function_traits; + using ReturnType = typename traits::result_type; + static_assert(traits::arity > 0, "Procedure must have at least one parameter (ProcedureContext)"); + if constexpr (traits::arity > 0) { + using FirstParamType = std::remove_cv_t>>; + static_assert(std::is_same_v, + "First parameter of procedure must be ProcedureContext"); + } + + std::function(ProcedureContext&, BytesSource)> handler; + if constexpr (traits::arity == 1) { + handler = [func](ProcedureContext& ctx, BytesSource) -> std::vector { + auto result = func(ctx); + IterBuf buf = IterBuf::take(); + { + bsatn::Writer writer(buf.get()); + bsatn::serialize(writer, result); + } + return buf.release(); + }; + } else { + handler = [func](ProcedureContext& ctx, BytesSource args_source) -> std::vector { + std::vector args_bytes = ConsumeBytes(args_source); + return [](std::index_sequence, Func fn, ProcedureContext& ctx_inner, const std::vector& bytes) -> std::vector { + bsatn::Reader reader(bytes.data(), bytes.size()); + auto args = std::make_tuple(bsatn::deserialize>(reader)...); + auto result = std::apply([&ctx_inner, fn](auto&&... unpacked) { + return fn(ctx_inner, std::forward(unpacked)...); + }, args); + IterBuf buf = IterBuf::take(); + { + bsatn::Writer writer(buf.get()); + bsatn::serialize(writer, result); + } + return buf.release(); + }(std::make_index_sequence{}, func, ctx, args_bytes); + }; + } + RegisterProcedureHandler(procedure_name, handler); + + auto& type_reg = getModuleTypeRegistration(); + auto bsatn_return = bsatn::bsatn_traits::algebraic_type(); + AlgebraicType return_type = type_reg.registerType(bsatn_return, "", &typeid(ReturnType)); + + ProductType params; + if constexpr (traits::arity > 1) { + [](std::index_sequence, + ProductType& out_params, + const std::vector& names, + ModuleTypeRegistration& reg) { + (([](ProductType& p, + const std::vector& n, + ModuleTypeRegistration& r) { + using param_type = std::remove_cv_t>>; + auto bsatn_type = bsatn::bsatn_traits::algebraic_type(); + AlgebraicType internal_type = r.registerType(bsatn_type, "", &typeid(param_type)); + std::string param_name = (I < n.size()) ? n[I] : ("arg" + std::to_string(I)); + p.elements.emplace_back(std::make_optional(param_name), std::move(internal_type)); + }.template operator()(out_params, names, reg)), ...); + }(std::make_index_sequence{}, params, param_names, type_reg); + } + + RawProcedureDefV10 procedure_def{ + procedure_name, + std::move(params), + return_type, + FunctionVisibility::ClientCallable, + }; + UpsertProcedure(procedure_def); + } + + void RegisterSchedule(const std::string& table_name, uint16_t scheduled_at_column, const std::string& reducer_name) { + if (g_circular_ref_error) { + std::fprintf(stderr, "ERROR: Skipping schedule registration for table '%s' because circular reference error is set\n", + table_name.c_str()); + return; + } + std::optional schedule_name = table_name + "_sched"; + auto it = std::find_if(schedules_.begin(), schedules_.end(), [&](const auto& schedule) { + return schedule.table_name == table_name; + }); + RawScheduleDefV10 schedule{schedule_name, table_name, scheduled_at_column, reducer_name}; + if (it == schedules_.end()) { + schedules_.push_back(std::move(schedule)); + } else { + *it = std::move(schedule); + } + } + + void RegisterRowLevelSecurity(const std::string& sql_query) { + row_level_security_.push_back(RawRowLevelSecurityDefV9{sql_query}); + } + + void SetTableIsEventFlag(const std::string& table_name, bool is_event); + bool GetTableIsEventFlag(const std::string& table_name) const; + + void SetCaseConversionPolicy(CaseConversionPolicy policy) { + case_conversion_policy_ = policy; + } + + void RegisterExplicitTableName(const std::string& source_name, const std::string& canonical_name); + void RegisterExplicitFunctionName(const std::string& source_name, const std::string& canonical_name); + void RegisterExplicitIndexName(const std::string& source_name, const std::string& canonical_name); + + RawModuleDefV10 BuildModuleDef() const; + Typespace& GetTypespace() { return typespace_; } + const Typespace& GetTypespace() const { return typespace_; } + std::vector& GetTypeDefs() { return types_; } + const std::vector& GetTypeDefs() const { return types_; } + std::vector& GetTables() { return tables_; } + const std::vector& GetTables() const { return tables_; } + std::vector& GetReducers() { return reducers_; } + const std::vector& GetReducers() const { return reducers_; } + const std::optional& GetCaseConversionPolicy() const { return case_conversion_policy_; } + const std::vector& GetExplicitNames() const { return explicit_names_; } + +private: + std::vector::iterator FindTable(const std::string& table_name) { + return std::find_if(tables_.begin(), tables_.end(), [&](const auto& table) { return table.source_name == table_name; }); + } + void UpsertTable(const RawTableDefV10& table); + void UpsertLifecycleReducer(const RawLifeCycleReducerDefV10& lifecycle); + void UpsertReducer(const RawReducerDefV10& reducer); + void UpsertProcedure(const RawProcedureDefV10& procedure); + void UpsertView(const RawViewDefV10& view); + RawIndexDefV10 CreateBTreeIndex(const std::string& table_name, + const std::string& source_name, + const std::vector& columns, + const std::string& accessor_name) const; + RawConstraintDefV10 CreateUniqueConstraint(const std::string& table_name, + const std::string& field_name, + uint16_t field_idx) const; + static AlgebraicType MakeUnitAlgebraicType(); + static AlgebraicType MakeStringAlgebraicType(); + + std::vector> table_is_event_; + std::optional case_conversion_policy_; + std::vector explicit_names_; + std::unordered_map> column_defaults_by_table_; + std::vector tables_; + std::vector reducers_; + std::vector procedures_; + std::vector views_; + std::vector schedules_; + std::vector lifecycle_reducers_; + std::vector row_level_security_; + Typespace typespace_{}; + std::vector types_; +}; + +extern std::unique_ptr g_v10_builder; + +void initializeV10Builder(); +V10Builder& getV10Builder(); + +} // namespace Internal +} // namespace SpacetimeDB + +#endif // SPACETIMEDB_V10_BUILDER_H + diff --git a/crates/bindings-cpp/include/spacetimedb/internal/v9_builder.h b/crates/bindings-cpp/include/spacetimedb/internal/v9_builder.h index 72c74b87de0..5c96d7ec9be 100644 --- a/crates/bindings-cpp/include/spacetimedb/internal/v9_builder.h +++ b/crates/bindings-cpp/include/spacetimedb/internal/v9_builder.h @@ -27,69 +27,37 @@ #include "../bsatn/bsatn.h" #include "../database.h" // For FieldConstraintInfo #include "field_registration.h" // For get_table_descriptors -#include "v9_type_registration.h" // For getV9TypeRegistration +#include "module_type_registration.h" // For getModuleTypeRegistration #include "../reducer_error.h" // For Outcome #include "buffer_pool.h" // For IterBuf +#include "runtime_registration.h" +#include "template_utils.h" namespace SpacetimeDB { -// Forward declarations for view context types (defined in view_context.h) -struct ViewContext; -struct AnonymousViewContext; - -// Forward declaration for procedure context type (defined in procedure_context.h) -struct ProcedureContext; - // Forward declare fail_reducer from reducer_error.h for use in templates void fail_reducer(std::string message); namespace Internal { -// Forward declare the handler registration function from Module.cpp -void RegisterReducerHandler(const std::string& name, - std::function handler, - std::optional lifecycle = std::nullopt); - -// Forward declare view handler registration functions from Module.cpp -void RegisterViewHandler(const std::string& name, - std::function(ViewContext&, BytesSource)> handler); -void RegisterAnonymousViewHandler(const std::string& name, - std::function(AnonymousViewContext&, BytesSource)> handler); - -// Get the number of registered view handlers -size_t GetViewHandlerCount(); -size_t GetAnonymousViewHandlerCount(); - -// Forward declare procedure handler registration function from Module.cpp -void RegisterProcedureHandler(const std::string& name, - std::function(ProcedureContext&, BytesSource)> handler); - -// Get the number of registered procedure handlers -size_t GetProcedureHandlerCount(); - -// Helper to consume bytes from BytesSource (declared in Module.cpp) -std::vector ConsumeBytes(BytesSource source); - -// Forward declare the multiple primary key error function from Module.cpp -void SetMultiplePrimaryKeyError(const std::string& table_name); - // Forward declare the global V9 module accessor (defined in v9_builder.cpp) RawModuleDefV9& GetV9Module(); +void ClearV9CompatModuleState(); -// External global flags for circular reference detection (defined in v9_type_registration.cpp) +// External global flags for circular reference detection (defined in module_type_registration.cpp) extern bool g_circular_ref_error; extern std::string g_circular_ref_type_name; /** * V9Builder - Builds a RawModuleDefV9 structure during module registration * - * This builder now uses the unified V9TypeRegistration system for all type handling. + * This builder now uses the unified ModuleTypeRegistration system for all type handling. * It focuses solely on building tables, reducers, and module structure. * * Type registration principles: * - Only user-defined structs/enums get registered (have entries in types array) * - Primitives, arrays, Options, special types are always inlined - * - Single entry point for types: registerType() -> V9TypeRegistration + * - Single entry point for types: registerType() -> ModuleTypeRegistration */ class V9Builder { public: @@ -97,7 +65,7 @@ class V9Builder { /** * Register a type using the unified type registration system - * Delegates to V9TypeRegistration::registerType() + * Delegates to ModuleTypeRegistration::registerType() * * @param bsatn_type The type to register * @param explicit_name Optional explicit name for the type @@ -412,7 +380,7 @@ void V9Builder::RegisterTable(const std::string& table_name, } //fprintf(stdout, "DEBUG: Registering enum type '%s' for field '%s'\n", // field_type_name.c_str(), field_desc.name.c_str()); - getV9TypeRegistration().registerTypeByName(field_type_name, field_type, nullptr); + getModuleTypeRegistration().registerTypeByName(field_type_name, field_type, nullptr); } } @@ -716,19 +684,6 @@ void V9Builder::AddColumnDefault(const std::string& table_name, GetV9Module().misc_exports.push_back(export_entry); } -// Helper trait to extract function parameter types -template -struct function_traits; - -template -struct function_traits { - static constexpr size_t arity = sizeof...(Args); - using result_type = R; - - template - using arg_t = typename std::tuple_element>::type; -}; - // Helper to extract T from Outcome template struct outcome_inner_type; @@ -871,38 +826,6 @@ void V9Builder::RegisterLifecycleReducer(const std::string& reducer_name, Func f RegisterReducerCommon(reducer_name, func, empty_names, lifecycle); } -// Helper: Convert view return types to vector format (matching Rust's ViewReturn trait) -// Vec stays as Vec, Option becomes Vec with 0 or 1 elements -template -std::vector view_result_to_vec(std::vector&& vec) { - return std::move(vec); // Already a vector -} - -template -std::vector view_result_to_vec(const std::vector& vec) { - return vec; // Already a vector -} - -template -std::vector view_result_to_vec(std::optional&& opt) { - // Convert Option to Vec: Some(x) -> [x], None -> [] - std::vector result; - if (opt.has_value()) { - result.push_back(std::move(*opt)); - } - return result; -} - -template -std::vector view_result_to_vec(const std::optional& opt) { - // Convert Option to Vec: Some(x) -> [x], None -> [] - std::vector result; - if (opt.has_value()) { - result.push_back(*opt); - } - return result; -} - // Template implementation for RegisterView template void V9Builder::RegisterView(const std::string& view_name, Func func, @@ -934,7 +857,7 @@ void V9Builder::RegisterView(const std::string& view_name, Func func, using ReturnType = typename traits::result_type; // Build the AlgebraicType for the return type - auto& type_reg = getV9TypeRegistration(); + auto& type_reg = getModuleTypeRegistration(); bsatn::AlgebraicType bsatn_return_type = bsatn::algebraic_type_of::get(); AlgebraicType return_algebraic_type = type_reg.registerType(bsatn_return_type, "", &typeid(ReturnType)); @@ -945,10 +868,10 @@ void V9Builder::RegisterView(const std::string& view_name, Func func, // [](std::index_sequence, // std::vector& elements, // const std::vector& names, - // V9TypeRegistration& type_reg_inner) { + // ModuleTypeRegistration& type_reg_inner) { // (([](std::vector& elems, // const std::vector& n, - // V9TypeRegistration& tr) { + // ModuleTypeRegistration& tr) { // if constexpr (I > 0) { // Skip the first parameter (ViewContext/AnonymousViewContext) // using param_type = typename traits::template arg_t; // bsatn::AlgebraicType param_bsatn = bsatn::algebraic_type_of::get(); @@ -1089,7 +1012,7 @@ void V9Builder::RegisterProcedure(const std::string& procedure_name, using ReturnType = typename traits::result_type; // Build the AlgebraicType for the return type - auto& type_reg = getV9TypeRegistration(); + auto& type_reg = getModuleTypeRegistration(); bsatn::AlgebraicType bsatn_return_type = bsatn::algebraic_type_of::get(); AlgebraicType return_algebraic_type = type_reg.registerType(bsatn_return_type, "", &typeid(ReturnType)); @@ -1099,10 +1022,10 @@ void V9Builder::RegisterProcedure(const std::string& procedure_name, [](std::index_sequence, std::vector& elements, const std::vector& names, - V9TypeRegistration& type_reg_inner) { + ModuleTypeRegistration& type_reg_inner) { (([](std::vector& elems, const std::vector& n, - V9TypeRegistration& tr) { + ModuleTypeRegistration& tr) { if constexpr (I > 0) { // Skip the first parameter (ProcedureContext) using param_type = typename traits::template arg_t; bsatn::AlgebraicType param_bsatn = bsatn::algebraic_type_of::get(); diff --git a/crates/bindings-cpp/include/spacetimedb/macros.h b/crates/bindings-cpp/include/spacetimedb/macros.h index 90baf9e5271..b0ca63b5336 100644 --- a/crates/bindings-cpp/include/spacetimedb/macros.h +++ b/crates/bindings-cpp/include/spacetimedb/macros.h @@ -155,7 +155,7 @@ inline std::vector parseParameterNames(const std::string& param_lis #define SPACETIMEDB_PASTE(a, b) SPACETIMEDB_CONCAT(a, b) #endif -// TypeRegistry system removed - use V9TypeRegistration instead +// TypeRegistry system removed - use ModuleTypeRegistration instead /* // Register a C++ type name in the global TypeRegistry for reducer parameter lookup // This replaces the old TypeNameRegistry approach with a unified one. @@ -179,15 +179,15 @@ inline std::vector parseParameterNames(const std::string& param_lis if (!Type##_v9_registered) { \ Type##_v9_registered = true; \ std::string type_name = #Type; \ - ::SpacetimeDB::Internal::getV9TypeRegistration().registerTypeByName(type_name, algebraic_type, &typeid(Type)); \ + ::SpacetimeDB::Internal::getModuleTypeRegistration().registerTypeByName(type_name, algebraic_type, &typeid(Type)); \ } \ } while(0) */ /** - * @brief Updated registration using V9TypeRegistration system + * @brief Updated registration using ModuleTypeRegistration system * - * This is the new registration point using the V9TypeRegistration system. + * This is the new registration point using the ModuleTypeRegistration system. */ #define SPACETIMEDB_REGISTER_TYPE_IN_V9(Type, algebraic_type) \ do { \ @@ -196,7 +196,7 @@ inline std::vector parseParameterNames(const std::string& param_lis Type##_v9_registered = true; \ std::string type_name = #Type; \ /* Register immediately with name and structure */ \ - ::SpacetimeDB::Internal::getV9TypeRegistration().registerTypeByName(type_name, algebraic_type, &typeid(Type)); \ + ::SpacetimeDB::Internal::getModuleTypeRegistration().registerTypeByName(type_name, algebraic_type, &typeid(Type)); \ } \ } while(0) @@ -248,7 +248,7 @@ inline std::vector parseParameterNames(const std::string& param_lis * - Empty field_registrar specialization * * Use this for simple types that don't need custom field registration. - * Note: Type name registration is now handled automatically by V9TypeRegistration. + * Note: Type name registration is now handled automatically by ModuleTypeRegistration. */ #define SPACETIMEDB_GENERATE_TYPE_REGISTRATION_BUNDLE(Type) \ template<> \ @@ -263,7 +263,7 @@ inline std::vector parseParameterNames(const std::string& param_lis * @brief Generate the complete registration bundle with field registration * * This version includes actual field registration for table types. - * Note: Type name registration is now handled automatically by V9TypeRegistration. + * Note: Type name registration is now handled automatically by ModuleTypeRegistration. */ #define SPACETIMEDB_GENERATE_TYPE_REGISTRATION_BUNDLE_WITH_FIELDS(Type, ...) \ template<> \ @@ -542,6 +542,17 @@ inline std::vector parseParameterNames(const std::string& param_lis // VISIBILITY FILTER MACRO // ============================================================================= +/** + * @brief Set module case conversion policy using a fixed preinit registration symbol. + * + * Defining this macro more than once in a module intentionally causes a duplicate symbol error. + */ +#define SPACETIMEDB_SETTING_CASE_CONVERSION(policy_enum_value) \ + extern "C" __attribute__((export_name("__preinit__18_module_settings_case_conversion_policy"))) \ + void __spacetimedb_preinit_case_conversion_policy() { \ + SpacetimeDB::Module::SetCaseConversionPolicy(policy_enum_value); \ + } + /** * @brief Register a client visibility filter with the SpacetimeDB module system * @@ -556,7 +567,7 @@ inline std::vector parseParameterNames(const std::string& param_lis #define SPACETIMEDB_CLIENT_VISIBILITY_FILTER(filter_name, sql_query) \ __attribute__((export_name("__preinit__25_register_row_level_security_" #filter_name))) \ extern "C" void __register_client_visibility_filter_##filter_name() { \ - SpacetimeDB::Internal::getV9Builder().RegisterRowLevelSecurity(sql_query); \ + SpacetimeDB::Module::RegisterClientVisibilityFilter(sql_query); \ } // ============================================================================= @@ -770,4 +781,5 @@ inline std::vector parseParameterNames(const std::string& param_lis } -#endif // SPACETIMEDB_MACROS_H \ No newline at end of file +#endif // SPACETIMEDB_MACROS_H + diff --git a/crates/bindings-cpp/include/spacetimedb/procedure_macros.h b/crates/bindings-cpp/include/spacetimedb/procedure_macros.h index 66ff0d7a0e2..5c6728a9f5f 100644 --- a/crates/bindings-cpp/include/spacetimedb/procedure_macros.h +++ b/crates/bindings-cpp/include/spacetimedb/procedure_macros.h @@ -2,7 +2,7 @@ #include "spacetimedb/procedure_context.h" #include "spacetimedb/internal/Module.h" -#include "spacetimedb/internal/v9_builder.h" +#include "spacetimedb/internal/v10_builder.h" #include "spacetimedb/macros.h" // For CONCAT #include "spacetimedb/error_handling.h" #include @@ -98,11 +98,26 @@ struct is_valid_procedure_return_type : std::integral_constant param_names = \ SpacetimeDB::Internal::parseParameterNames(param_list); \ \ - /* Register the procedure with the V9Builder system */ \ + /* Register the procedure with the V10Builder system */ \ /* Note: Procedures are always public (no is_public parameter) */ \ - ::SpacetimeDB::Internal::getV9Builder().RegisterProcedure( \ + ::SpacetimeDB::Internal::getV10Builder().RegisterProcedure( \ #procedure_name, procedure_name, param_names); \ } \ \ /* The actual procedure function definition */ \ return_type procedure_name(ctx_param __VA_OPT__(,) __VA_ARGS__) + +#define SPACETIMEDB_PROCEDURE_NAMED(return_type, procedure_name, canonical_name, ctx_param, ...) \ + static_assert(::SpacetimeDB::Internal::is_valid_procedure_return_type::value, \ + "Procedure return type must be a SpacetimeType (implement Serializable trait)"); \ + return_type procedure_name(ctx_param __VA_OPT__(,) __VA_ARGS__); \ + __attribute__((export_name("__preinit__50_proc_" #procedure_name))) \ + extern "C" void CONCAT(_spacetimedb_preinit_register_proc_, procedure_name)() { \ + std::string param_list = #__VA_ARGS__; \ + std::vector param_names = \ + SpacetimeDB::Internal::parseParameterNames(param_list); \ + ::SpacetimeDB::Internal::getV10Builder().RegisterProcedure( \ + #procedure_name, procedure_name, param_names); \ + SpacetimeDB::Module::RegisterExplicitFunctionName(#procedure_name, canonical_name); \ + } \ + return_type procedure_name(ctx_param __VA_OPT__(,) __VA_ARGS__) diff --git a/crates/bindings-cpp/include/spacetimedb/reducer_macros.h b/crates/bindings-cpp/include/spacetimedb/reducer_macros.h index 503f08e4e8f..d11380ead52 100644 --- a/crates/bindings-cpp/include/spacetimedb/reducer_macros.h +++ b/crates/bindings-cpp/include/spacetimedb/reducer_macros.h @@ -3,7 +3,7 @@ #include "spacetimedb/bsatn/types.h" #include "spacetimedb/reducer_context.h" #include "spacetimedb/internal/Module.h" -#include "spacetimedb/internal/v9_builder.h" +#include "spacetimedb/internal/v10_builder.h" #include "spacetimedb/macros.h" #include @@ -68,12 +68,24 @@ std::vector param_names = \ SpacetimeDB::Internal::parseParameterNames(param_list); \ /* Register the reducer with the unified V9Builder system */ \ - SpacetimeDB::Internal::getV9Builder().RegisterReducer(#name, name, param_names); \ + SpacetimeDB::Internal::getV10Builder().RegisterReducer(#name, name, param_names); \ } \ \ /* The actual reducer function definition - returns ReducerResult */ \ SpacetimeDB::ReducerResult name(ctx_param __VA_OPT__(,) __VA_ARGS__) +#define SPACETIMEDB_REDUCER_NAMED(name, canonical_name, ctx_param, ...) \ + SpacetimeDB::ReducerResult name(ctx_param __VA_OPT__(,) __VA_ARGS__); \ + __attribute__((export_name("__preinit__30_reducer_" #name))) \ + extern "C" void CONCAT(_spacetimedb_preinit_register_, name)() { \ + std::string param_list = #__VA_ARGS__; \ + std::vector param_names = \ + SpacetimeDB::Internal::parseParameterNames(param_list); \ + SpacetimeDB::Internal::getV10Builder().RegisterReducer(#name, name, param_names); \ + SpacetimeDB::Module::RegisterExplicitFunctionName(#name, canonical_name); \ + } \ + SpacetimeDB::ReducerResult name(ctx_param __VA_OPT__(,) __VA_ARGS__) + // ----------------------------------------------------------------------------- // Lifecycle Reducer Macros // ----------------------------------------------------------------------------- @@ -101,7 +113,7 @@ SpacetimeDB::ReducerResult function_name(ctx_param); \ __attribute__((export_name("__preinit__20_reducer_init"))) \ extern "C" void CONCAT(_preinit_register_init_reducer_, function_name)() { \ - ::SpacetimeDB::Internal::getV9Builder().RegisterLifecycleReducer(#function_name, function_name, ::SpacetimeDB::Internal::Lifecycle::Init); \ + ::SpacetimeDB::Internal::getV10Builder().RegisterLifecycleReducer(#function_name, function_name, ::SpacetimeDB::Internal::Lifecycle::Init); \ } \ SpacetimeDB::ReducerResult function_name(ctx_param) @@ -125,7 +137,7 @@ SpacetimeDB::ReducerResult function_name(ctx_param); \ __attribute__((export_name("__preinit__20_reducer_client_connected"))) \ extern "C" void CONCAT(_preinit_register_client_connected_, function_name)() { \ - ::SpacetimeDB::Internal::getV9Builder().RegisterLifecycleReducer(#function_name, function_name, ::SpacetimeDB::Internal::Lifecycle::OnConnect); \ + ::SpacetimeDB::Internal::getV10Builder().RegisterLifecycleReducer(#function_name, function_name, ::SpacetimeDB::Internal::Lifecycle::OnConnect); \ } \ SpacetimeDB::ReducerResult function_name(ctx_param) @@ -149,6 +161,6 @@ SpacetimeDB::ReducerResult function_name(ctx_param); \ __attribute__((export_name("__preinit__20_reducer_client_disconnected"))) \ extern "C" void CONCAT(_preinit_register_client_disconnected_, function_name)() { \ - ::SpacetimeDB::Internal::getV9Builder().RegisterLifecycleReducer(#function_name, function_name, ::SpacetimeDB::Internal::Lifecycle::OnDisconnect); \ + ::SpacetimeDB::Internal::getV10Builder().RegisterLifecycleReducer(#function_name, function_name, ::SpacetimeDB::Internal::Lifecycle::OnDisconnect); \ } \ - SpacetimeDB::ReducerResult function_name(ctx_param) \ No newline at end of file + SpacetimeDB::ReducerResult function_name(ctx_param) diff --git a/crates/bindings-cpp/include/spacetimedb/table_with_constraints.h b/crates/bindings-cpp/include/spacetimedb/table_with_constraints.h index b0a7678e148..ba3321f5e41 100644 --- a/crates/bindings-cpp/include/spacetimedb/table_with_constraints.h +++ b/crates/bindings-cpp/include/spacetimedb/table_with_constraints.h @@ -3,6 +3,7 @@ #include "internal/Module.h" #include "internal/field_registration.h" #include "internal/autogen/RawScheduleDefV9.g.h" +#include "internal/v10_builder.h" #include "macros.h" #include "error_handling.h" // For DatabaseResult, DatabaseError, UpsertResult #include "index_iterator.h" // For IndexIterator @@ -52,6 +53,34 @@ namespace detail { } return {}; } + + struct TableMacroOptions { + bool is_event = false; + const char* canonical_name = nullptr; + }; + + inline TableMacroOptions MakeTableMacroOptions() { + return TableMacroOptions{}; + } + + inline TableMacroOptions MakeTableMacroOptions(bool is_event) { + TableMacroOptions options; + options.is_event = is_event; + return options; + } + + inline TableMacroOptions MakeTableMacroOptions(const char* canonical_name) { + TableMacroOptions options; + options.canonical_name = canonical_name; + return options; + } + + inline TableMacroOptions MakeTableMacroOptions(bool is_event, const char* canonical_name) { + TableMacroOptions options; + options.is_event = is_event; + options.canonical_name = canonical_name; + return options; + } } // ============================================================================= @@ -80,12 +109,6 @@ struct TableTag { // Table Registration // ============================================================================= -template -void register_table_type_with_constraints(const char* name, bool is_public, - const std::vector& constraints) { - SpacetimeDB::Internal::Module::RegisterTableInternalImpl(name, is_public, constraints); -} - // ============================================================================= // Main Table Registration Macro // ============================================================================= @@ -101,24 +124,41 @@ void register_table_type_with_constraints(const char* name, bool is_public, * FIELD_PrimaryKeyAutoInc(users, id) * FIELD_Unique(users, email) */ -#define SPACETIMEDB_TABLE(type, table_name, access_enum) \ +#define SPACETIMEDB_TABLE_IMPL(type, table_name, access_enum, options_expr) \ extern "C" __attribute__((export_name("__preinit__20_register_table_" #type "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ void SPACETIMEDB_PASTE(__preinit__20_register_table_, SPACETIMEDB_PASTE(type, SPACETIMEDB_PASTE(_line_, __LINE__)))() { \ + auto _spacetimedb_table_options = (options_expr); \ bool is_public = (access_enum == SpacetimeDB::Internal::TableAccess::Public); \ - SpacetimeDB::Module::RegisterTable(#table_name, is_public); \ + SpacetimeDB::Module::RegisterTable(#table_name, is_public, _spacetimedb_table_options.is_event); \ + if (_spacetimedb_table_options.canonical_name != nullptr) { \ + SpacetimeDB::Module::RegisterExplicitTableName(#table_name, _spacetimedb_table_options.canonical_name); \ + } \ } \ struct SPACETIMEDB_PASTE(table_name, _tag_type) : SpacetimeDB::TableTag { \ static constexpr const char* __table_name_internal = #table_name; \ }; \ constexpr SPACETIMEDB_PASTE(table_name, _tag_type) table_name{}; +#define SPACETIMEDB_TABLE_3(type, table_name, access_enum) \ + SPACETIMEDB_TABLE_IMPL(type, table_name, access_enum, SpacetimeDB::detail::MakeTableMacroOptions()) + +#define SPACETIMEDB_TABLE_4(type, table_name, access_enum, arg4) \ + SPACETIMEDB_TABLE_IMPL(type, table_name, access_enum, SpacetimeDB::detail::MakeTableMacroOptions(arg4)) + +#define SPACETIMEDB_TABLE_5(type, table_name, access_enum, arg4, arg5) \ + SPACETIMEDB_TABLE_IMPL(type, table_name, access_enum, SpacetimeDB::detail::MakeTableMacroOptions(arg4, arg5)) + +#define SPACETIMEDB_TABLE_SELECT(_1, _2, _3, _4, _5, NAME, ...) NAME +#define SPACETIMEDB_TABLE(...) \ + SPACETIMEDB_TABLE_SELECT(__VA_ARGS__, SPACETIMEDB_TABLE_5, SPACETIMEDB_TABLE_4, SPACETIMEDB_TABLE_3)(__VA_ARGS__) + /** * @brief Schedule a table for automatic reducer execution */ #define SPACETIMEDB_SCHEDULE(table_name, scheduled_at_column_index, reducer_name) \ extern "C" __attribute__((export_name("__preinit__19_schedule_" #table_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ void SPACETIMEDB_PASTE(__preinit__19_schedule_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_line_, __LINE__)))() { \ - SpacetimeDB::Internal::getV9Builder().RegisterSchedule(#table_name, scheduled_at_column_index, #reducer_name); \ + SpacetimeDB::Internal::getV10Builder().RegisterSchedule(#table_name, scheduled_at_column_index, #reducer_name); \ } // ============================================================================= @@ -680,7 +720,7 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { table_name##_##field_name { #table_name, #field_name, &std::remove_cv_t::type::field_name }; \ extern "C" __attribute__((export_name("__preinit__21_field_constraint_" #table_name "_" #field_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ void SPACETIMEDB_PASTE(__preinit__21_field_constraint_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, SPACETIMEDB_PASTE(field_name, SPACETIMEDB_PASTE(_line_, __LINE__)))))() { \ - SpacetimeDB::Internal::getV9Builder().AddFieldConstraint::type>( \ + SpacetimeDB::Internal::getV10Builder().AddFieldConstraint::type>( \ #table_name, #field_name, ::SpacetimeDB::FieldConstraint::PrimaryKey); \ } @@ -697,7 +737,7 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { table_name##_##field_name { #table_name, #field_name, &std::remove_cv_t::type::field_name }; \ extern "C" __attribute__((export_name("__preinit__21_field_constraint_" #table_name "_" #field_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ void SPACETIMEDB_PASTE(__preinit__21_field_constraint_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, SPACETIMEDB_PASTE(field_name, SPACETIMEDB_PASTE(_line_, __LINE__)))))() { \ - SpacetimeDB::Internal::getV9Builder().AddFieldConstraint::type>( \ + SpacetimeDB::Internal::getV10Builder().AddFieldConstraint::type>( \ #table_name, #field_name, ::SpacetimeDB::FieldConstraint::Unique); \ } @@ -714,7 +754,7 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { table_name##_##field_name { #table_name, #field_name, &std::remove_cv_t::type::field_name }; \ extern "C" __attribute__((export_name("__preinit__21_field_constraint_" #table_name "_" #field_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ void SPACETIMEDB_PASTE(__preinit__21_field_constraint_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, SPACETIMEDB_PASTE(field_name, SPACETIMEDB_PASTE(_line_, __LINE__)))))() { \ - SpacetimeDB::Internal::getV9Builder().AddFieldConstraint::type>( \ + SpacetimeDB::Internal::getV10Builder().AddFieldConstraint::type>( \ #table_name, #field_name, ::SpacetimeDB::FieldConstraint::Indexed); \ } @@ -731,7 +771,7 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { table_name##_##field_name { #table_name, #field_name, &std::remove_cv_t::type::field_name }; \ extern "C" __attribute__((export_name("__preinit__21_field_constraint_" #table_name "_" #field_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ void SPACETIMEDB_PASTE(__preinit__21_field_constraint_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, SPACETIMEDB_PASTE(field_name, SPACETIMEDB_PASTE(_line_, __LINE__)))))() { \ - SpacetimeDB::Internal::getV9Builder().AddFieldConstraint::type>( \ + SpacetimeDB::Internal::getV10Builder().AddFieldConstraint::type>( \ #table_name, #field_name, static_cast<::SpacetimeDB::FieldConstraint>( \ static_cast(::SpacetimeDB::FieldConstraint::PrimaryKey) | static_cast(::SpacetimeDB::FieldConstraint::AutoInc))); \ } \ @@ -752,7 +792,7 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { table_name##_##field_name { #table_name, #field_name, &std::remove_cv_t::type::field_name }; \ extern "C" __attribute__((export_name("__preinit__21_field_constraint_" #table_name "_" #field_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ void SPACETIMEDB_PASTE(__preinit__21_field_constraint_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, SPACETIMEDB_PASTE(field_name, SPACETIMEDB_PASTE(_line_, __LINE__)))))() { \ - SpacetimeDB::Internal::getV9Builder().AddFieldConstraint::type>( \ + SpacetimeDB::Internal::getV10Builder().AddFieldConstraint::type>( \ #table_name, #field_name, static_cast<::SpacetimeDB::FieldConstraint>( \ static_cast(::SpacetimeDB::FieldConstraint::Unique) | static_cast(::SpacetimeDB::FieldConstraint::AutoInc))); \ } \ @@ -773,7 +813,7 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { table_name##_##field_name { #table_name, #field_name, &std::remove_cv_t::type::field_name }; \ extern "C" __attribute__((export_name("__preinit__21_field_constraint_" #table_name "_" #field_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ void SPACETIMEDB_PASTE(__preinit__21_field_constraint_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, SPACETIMEDB_PASTE(field_name, SPACETIMEDB_PASTE(_line_, __LINE__)))))() { \ - SpacetimeDB::Internal::getV9Builder().AddFieldConstraint::type>( \ + SpacetimeDB::Internal::getV10Builder().AddFieldConstraint::type>( \ #table_name, #field_name, static_cast<::SpacetimeDB::FieldConstraint>( \ static_cast(::SpacetimeDB::FieldConstraint::Indexed) | static_cast(::SpacetimeDB::FieldConstraint::AutoInc))); \ } @@ -788,11 +828,41 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { }(), "AutoIncrement validation for " #table_name "." #field_name); \ extern "C" __attribute__((export_name("__preinit__21_field_constraint_" #table_name "_" #field_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ void SPACETIMEDB_PASTE(__preinit__21_field_constraint_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, SPACETIMEDB_PASTE(field_name, SPACETIMEDB_PASTE(_line_, __LINE__)))))() { \ - SpacetimeDB::Internal::getV9Builder().AddFieldConstraint::type>( \ + SpacetimeDB::Internal::getV10Builder().AddFieldConstraint::type>( \ #table_name, #field_name, ::SpacetimeDB::FieldConstraint::AutoInc); \ } \ SPACETIMEDB_AUTOINC_INTEGRATION_IMPL(typename std::remove_cv_t::type, field_name) +#define SPACETIMEDB_REGISTER_EXPLICIT_SINGLE_COLUMN_INDEX_NAME(table_name, field_name, canonical_name) \ + extern "C" __attribute__((export_name("__preinit__18_explicit_index_name_" #table_name "_" #field_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ + void SPACETIMEDB_PASTE(__preinit__18_explicit_index_name_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, SPACETIMEDB_PASTE(field_name, SPACETIMEDB_PASTE(_line_, __LINE__)))))() { \ + SpacetimeDB::Module::RegisterExplicitIndexName(#table_name "_" #field_name "_idx_btree", canonical_name); \ + } + +#define FIELD_PrimaryKey_NAMED(table_name, field_name, canonical_name) \ + FIELD_PrimaryKey(table_name, field_name) \ + SPACETIMEDB_REGISTER_EXPLICIT_SINGLE_COLUMN_INDEX_NAME(table_name, field_name, canonical_name) + +#define FIELD_Unique_NAMED(table_name, field_name, canonical_name) \ + FIELD_Unique(table_name, field_name) \ + SPACETIMEDB_REGISTER_EXPLICIT_SINGLE_COLUMN_INDEX_NAME(table_name, field_name, canonical_name) + +#define FIELD_Index_NAMED(table_name, field_name, canonical_name) \ + FIELD_Index(table_name, field_name) \ + SPACETIMEDB_REGISTER_EXPLICIT_SINGLE_COLUMN_INDEX_NAME(table_name, field_name, canonical_name) + +#define FIELD_PrimaryKeyAutoInc_NAMED(table_name, field_name, canonical_name) \ + FIELD_PrimaryKeyAutoInc(table_name, field_name) \ + SPACETIMEDB_REGISTER_EXPLICIT_SINGLE_COLUMN_INDEX_NAME(table_name, field_name, canonical_name) + +#define FIELD_UniqueAutoInc_NAMED(table_name, field_name, canonical_name) \ + FIELD_UniqueAutoInc(table_name, field_name) \ + SPACETIMEDB_REGISTER_EXPLICIT_SINGLE_COLUMN_INDEX_NAME(table_name, field_name, canonical_name) + +#define FIELD_IndexAutoInc_NAMED(table_name, field_name, canonical_name) \ + FIELD_IndexAutoInc(table_name, field_name) \ + SPACETIMEDB_REGISTER_EXPLICIT_SINGLE_COLUMN_INDEX_NAME(table_name, field_name, canonical_name) + // Helper to join field names with underscores at compile time #define SPACETIMEDB_JOIN_FIELDS(...) SPACETIMEDB_JOIN_FIELDS_IMPL(__VA_ARGS__) #define SPACETIMEDB_JOIN_FIELDS_IMPL(...) SPACETIMEDB_GET_JOIN_MACRO(__VA_ARGS__, \ @@ -806,17 +876,34 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { #define SPACETIMEDB_JOIN_5(a,b,c,d,e) #a "_" #b "_" #c "_" #d "_" #e #define SPACETIMEDB_JOIN_6(a,b,c,d,e,f) #a "_" #b "_" #c "_" #d "_" #e "_" #f -// Multi-column index registration macro -#define FIELD_NamedMultiColumnIndex(table_name, index_name, ...) \ +// Multi-column index registration macro (unnamed canonical mapping) +#define FIELD_MultiColumnIndex(table_name, index_name, ...) \ + static constexpr auto table_name##_##index_name = SpacetimeDB::MultiColumnIndexTag< \ + typename std::remove_cv_t::type \ + >{#table_name, #index_name, SPACETIMEDB_JOIN_FIELDS(__VA_ARGS__)}; \ + extern "C" __attribute__((export_name("__preinit__21_field_multi_index_" #table_name "_" #index_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ + void SPACETIMEDB_PASTE(__preinit__21_field_multi_index_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, SPACETIMEDB_PASTE(index_name, SPACETIMEDB_PASTE(_line_, __LINE__)))))() { \ + SpacetimeDB::Internal::getV10Builder().AddMultiColumnIndex::type>( \ + #table_name, #index_name, {SPACETIMEDB_STRINGIFY_EACH(__VA_ARGS__)}); \ + } + +#define FIELD_MultiColumnIndex_NAMED(table_name, index_name, canonical_name, ...) \ static constexpr auto table_name##_##index_name = SpacetimeDB::MultiColumnIndexTag< \ typename std::remove_cv_t::type \ >{#table_name, #index_name, SPACETIMEDB_JOIN_FIELDS(__VA_ARGS__)}; \ extern "C" __attribute__((export_name("__preinit__21_field_multi_index_" #table_name "_" #index_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ void SPACETIMEDB_PASTE(__preinit__21_field_multi_index_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, SPACETIMEDB_PASTE(index_name, SPACETIMEDB_PASTE(_line_, __LINE__)))))() { \ - SpacetimeDB::Internal::getV9Builder().AddMultiColumnIndex::type>( \ + SpacetimeDB::Internal::getV10Builder().AddMultiColumnIndex::type>( \ #table_name, #index_name, {SPACETIMEDB_STRINGIFY_EACH(__VA_ARGS__)}); \ + SpacetimeDB::Module::RegisterExplicitIndexName( \ + #table_name "_" SPACETIMEDB_JOIN_FIELDS(__VA_ARGS__) "_idx_btree", \ + canonical_name); \ } +// Compatibility alias retained for migration. +#define FIELD_NamedMultiColumnIndex(table_name, index_name, ...) \ + FIELD_MultiColumnIndex(table_name, index_name, __VA_ARGS__) + #define FIELD_Default(table_name, field_name, default_value) \ extern "C" __attribute__((export_name("__preinit__21_field_default_" #table_name "_" #field_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ void SPACETIMEDB_PASTE(__preinit__21_field_default_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, SPACETIMEDB_PASTE(field_name, SPACETIMEDB_PASTE(_line_, __LINE__)))))() { \ @@ -825,7 +912,7 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { /* Serialize the default value to BSATN bytes */ \ auto serialized = SpacetimeDB::bsatn::to_bytes(default_value); \ \ - SpacetimeDB::Internal::getV9Builder().AddColumnDefault( \ + SpacetimeDB::Internal::getV10Builder().AddColumnDefault( \ #table_name, \ #field_name, \ serialized \ diff --git a/crates/bindings-cpp/include/spacetimedb/view_macros.h b/crates/bindings-cpp/include/spacetimedb/view_macros.h index 713b0f92fe2..9780534b2d6 100644 --- a/crates/bindings-cpp/include/spacetimedb/view_macros.h +++ b/crates/bindings-cpp/include/spacetimedb/view_macros.h @@ -2,7 +2,7 @@ #include "spacetimedb/view_context.h" #include "spacetimedb/internal/Module.h" -#include "spacetimedb/internal/v9_builder.h" +#include "spacetimedb/internal/v10_builder.h" #include "spacetimedb/macros.h" // For parseParameterNames #include "spacetimedb/error_handling.h" #include @@ -106,12 +106,28 @@ struct is_valid_view_return_type> /* std::vector param_names = parseParameterNames(#__VA_ARGS__); */ \ std::vector param_names; \ \ - /* Register the view with the V9Builder system */ \ + /* Register the view with the V10Builder system */ \ /* RegisterView validates ctx_param is ViewContext or AnonymousViewContext */ \ - ::SpacetimeDB::Internal::getV9Builder().RegisterView( \ + ::SpacetimeDB::Internal::getV10Builder().RegisterView( \ #view_name, view_name, is_public, param_names); \ } \ \ /* TODO: When parameters are supported, function definition becomes: */ \ /* return_type view_name(ctx_param, __VA_ARGS__) */ \ return_type view_name(ctx_param) + +#define SPACETIMEDB_VIEW_NAMED(return_type, view_name, canonical_name, access_enum, ctx_param) \ + static_assert(access_enum == SpacetimeDB::Internal::TableAccess::Public, \ + "Views must be Public - Private views are not yet supported"); \ + static_assert(::SpacetimeDB::Internal::is_valid_view_return_type::value, \ + "View return type must be std::vector or std::optional where T is a SpacetimeType"); \ + return_type view_name(ctx_param); \ + __attribute__((export_name("__preinit__40_view_" #view_name))) \ + extern "C" void CONCAT(_spacetimedb_preinit_register_view_, view_name)() { \ + bool is_public = (access_enum == SpacetimeDB::Internal::TableAccess::Public); \ + std::vector param_names; \ + ::SpacetimeDB::Internal::getV10Builder().RegisterView( \ + #view_name, view_name, is_public, param_names); \ + SpacetimeDB::Module::RegisterExplicitFunctionName(#view_name, canonical_name); \ + } \ + return_type view_name(ctx_param) diff --git a/crates/bindings-cpp/src/internal/Module.cpp b/crates/bindings-cpp/src/internal/Module.cpp index 23aba2dcc6e..b0dcb1ceae3 100644 --- a/crates/bindings-cpp/src/internal/Module.cpp +++ b/crates/bindings-cpp/src/internal/Module.cpp @@ -4,9 +4,12 @@ #include "spacetimedb.h" #include "spacetimedb/internal/Module.h" #include "spacetimedb/internal/buffer_pool.h" -#include "spacetimedb/internal/autogen/RawModuleDefV9.g.h" -#include "spacetimedb/internal/bsatn_adapters.h" -#include "spacetimedb/internal/v9_type_registration.h" +#include "spacetimedb/internal/autogen/RawModuleDef.g.h" +#include "spacetimedb/internal/autogen/RawModuleDefV10.g.h" +#include "spacetimedb/internal/autogen/RawTypeDefV10.g.h" +#include "spacetimedb/internal/v9_builder.h" +#include "spacetimedb/internal/v10_builder.h" +#include "spacetimedb/internal/module_type_registration.h" #include "spacetimedb/abi/FFI.h" #include "spacetimedb/bsatn/bsatn.h" #include "spacetimedb/bsatn/writer.h" @@ -14,7 +17,6 @@ #include "spacetimedb/view_context.h" #include "spacetimedb/procedure_context.h" #include -#include #include #include #include @@ -26,9 +28,6 @@ namespace Internal { // Thread-local reducer error message storage thread_local std::optional g_reducer_error_message = std::nullopt; - // The global V9 module that preinit functions will populate directly - static RawModuleDefV9 g_v9_module; - // Global reducer handler storage for runtime dispatch struct ReducerHandler { std::string name; @@ -71,8 +70,11 @@ namespace Internal { // Global error flag for multiple primary key detection static bool g_multiple_primary_key_error = false; static std::string g_multiple_primary_key_table_name = ""; + static bool g_constraint_registration_error = false; + static std::string g_constraint_registration_error_code = ""; + static std::string g_constraint_registration_error_details = ""; - // External global flags for circular reference detection (defined in v9_type_registration.cpp) + // External global flags for circular reference detection (defined in module_type_registration.cpp) extern bool g_circular_ref_error; extern std::string g_circular_ref_type_name; @@ -82,6 +84,13 @@ namespace Internal { g_multiple_primary_key_table_name = table_name; fprintf(stderr, "ERROR: Multiple primary keys detected in table '%s'\n", table_name.c_str()); } + + void SetConstraintRegistrationError(const std::string& code, const std::string& details) { + g_constraint_registration_error = true; + g_constraint_registration_error_code = code; + g_constraint_registration_error_details = details; + fprintf(stderr, "ERROR: Constraint registration failed [%s] %s\n", code.c_str(), details.c_str()); + } // Register a reducer handler (called by V9Builder during registration) void RegisterReducerHandler(const std::string& name, @@ -122,20 +131,27 @@ namespace Internal { return g_procedure_handlers.size(); } - // Get the global V9 module - RawModuleDefV9& GetV9Module() { - return g_v9_module; + void SetTableIsEventFlag(const std::string& table_name, bool is_event) { + getV10Builder().SetTableIsEventFlag(table_name, is_event); + } + + bool GetTableIsEventFlag(const std::string& table_name) { + return getV10Builder().GetTableIsEventFlag(table_name); } - // Clear the global V9 module state - called at module initialization - void ClearV9Module() { - g_v9_module = RawModuleDefV9{}; // Reset to default state + // Clear registration state - called at module initialization. + void ClearModuleRegistrationState() { + ClearV9CompatModuleState(); g_reducer_handlers.clear(); // Also clear reducer handlers g_view_handlers.clear(); // Clear view handlers g_view_anon_handlers.clear(); // Clear anonymous view handlers g_procedure_handlers.clear(); // Clear procedure handlers g_multiple_primary_key_error = false; // Reset error flag g_multiple_primary_key_table_name = ""; // Reset error table name + g_constraint_registration_error = false; + g_constraint_registration_error_code = ""; + g_constraint_registration_error_details = ""; + getV10Builder().Clear(); } @@ -145,9 +161,9 @@ namespace Internal { // The number 01 ensures this runs first to clear any leftover state extern "C" __attribute__((export_name("__preinit__01_clear_global_state"))) void __preinit__01_clear_global_state() { - ClearV9Module(); - // Also clear the V9 type registration state - auto& type_reg = getV9TypeRegistration(); + ClearModuleRegistrationState(); + // Also clear module type registration state + auto& type_reg = getModuleTypeRegistration(); type_reg.clear(); } @@ -166,16 +182,11 @@ void __preinit__99_validate_types() { if (g_circular_ref_error) { // Circular reference error detected - create a special error module - // Clear the entire V9 module to start fresh - RawModuleDefV9& v9_module = GetV9Module(); - v9_module.typespace.types.clear(); - v9_module.types.clear(); - v9_module.tables.clear(); - v9_module.reducers.clear(); - v9_module.misc_exports.clear(); + // Clear the module state to start fresh. + getV10Builder().Clear(); // Also clear the V9 type registration to remove any partial registrations - auto& type_reg = getV9TypeRegistration(); + auto& type_reg = getModuleTypeRegistration(); type_reg.clear(); // Create the error type name that indicates the circular reference @@ -183,13 +194,13 @@ void __preinit__99_validate_types() { // Add a single named type export that points to a non-existent typespace index // This will cause SpacetimeDB to error when it tries to resolve the type - RawTypeDefV9 error_type; - error_type.name.scope = {}; - error_type.name.name = error_type_name; + RawTypeDefV10 error_type; + error_type.source_name.scope = {}; + error_type.source_name.source_name = error_type_name; error_type.ty = 999999; // Invalid typespace index - will cause an error error_type.custom_ordering = false; - v9_module.types.push_back(error_type); + getV10Builder().GetTypeDefs().push_back(error_type); // Don't add anything to the typespace - this ensures the reference is invalid // The server will fail with an error message that includes our error type name @@ -205,26 +216,21 @@ void __preinit__99_validate_types() { if (g_multiple_primary_key_error) { // Multiple primary key error detected - create a special error module - // Clear the entire V9 module to start fresh - RawModuleDefV9& v9_module = GetV9Module(); - v9_module.typespace.types.clear(); - v9_module.types.clear(); - v9_module.tables.clear(); - v9_module.reducers.clear(); - v9_module.misc_exports.clear(); + // Clear the module state to start fresh. + getV10Builder().Clear(); // Create the error type name std::string error_type_name = "ERROR_MULTIPLE_PRIMARY_KEYS_" + g_multiple_primary_key_table_name; // Add a single named type export that points to a non-existent typespace index // This will cause SpacetimeDB to error when it tries to resolve the type - RawTypeDefV9 error_type; - error_type.name.scope = {}; - error_type.name.name = error_type_name; + RawTypeDefV10 error_type; + error_type.source_name.scope = {}; + error_type.source_name.source_name = error_type_name; error_type.ty = 999999; // Invalid typespace index - will cause an error error_type.custom_ordering = false; - v9_module.types.push_back(error_type); + getV10Builder().GetTypeDefs().push_back(error_type); // Don't add anything to the typespace - this ensures the reference is invalid // The server will fail with an error message that includes our error type name @@ -236,20 +242,38 @@ void __preinit__99_validate_types() { return; // Exit early, don't check type registration errors } + + if (g_constraint_registration_error) { + getV10Builder().Clear(); + + std::string error_type_name = "ERROR_CONSTRAINT_REGISTRATION_" + g_constraint_registration_error_code; + for (char& c : error_type_name) { + if (!std::isalnum(c) && c != '_') { + c = '_'; + } + } + + RawTypeDefV10 error_type; + error_type.source_name.scope = {}; + error_type.source_name.source_name = error_type_name; + error_type.ty = 999999; + error_type.custom_ordering = false; + getV10Builder().GetTypeDefs().push_back(error_type); + + fprintf(stderr, "\n[CONSTRAINT REGISTRATION ERROR] Module cleared and replaced with error type: %s\n", error_type_name.c_str()); + fprintf(stderr, "Original error: %s\n\n", g_constraint_registration_error_details.c_str()); + fflush(stderr); + return; + } // Check if any errors occurred during type registration - auto& type_reg = getV9TypeRegistration(); + auto& type_reg = getModuleTypeRegistration(); if (type_reg.hasError()) { // Type registration detected an error - create a special error module const std::string& error = type_reg.getErrorMessage(); - // Clear the entire V9 module to start fresh - RawModuleDefV9& v9_module = GetV9Module(); - v9_module.typespace.types.clear(); - v9_module.types.clear(); - v9_module.tables.clear(); - v9_module.reducers.clear(); - v9_module.misc_exports.clear(); + // Clear the module state to start fresh. + getV10Builder().Clear(); // Create an error type name that embeds the error message and type structure std::string error_type_name; @@ -285,13 +309,13 @@ void __preinit__99_validate_types() { // Add a single named type export that points to a non-existent typespace index // This will cause SpacetimeDB to error when it tries to resolve the type - RawTypeDefV9 error_type; - error_type.name.scope = {}; - error_type.name.name = error_type_name; + RawTypeDefV10 error_type; + error_type.source_name.scope = {}; + error_type.source_name.source_name = error_type_name; error_type.ty = 999999; // Invalid typespace index - will cause an error error_type.custom_ordering = false; - v9_module.types.push_back(error_type); + getV10Builder().GetTypeDefs().push_back(error_type); // Don't add anything to the typespace - this ensures the reference is invalid // The server will fail with an error message that includes our error type name @@ -305,35 +329,32 @@ void __preinit__99_validate_types() { // Type validation passed - log statistics only in debug mode #ifdef DEBUG_TYPE_REGISTRATION else { - RawModuleDefV9& v9_module = GetV9Module(); - fprintf(stderr, "[Type Validation] OK - %zu types, %zu tables, %zu reducers %zu misc_exports\n", - v9_module.typespace.types.size(), - v9_module.tables.size(), - v9_module.reducers.size(), - v9_module.misc_exports.size()); + fprintf(stderr, "[Type Validation] OK - %zu types, %zu tables, %zu reducers\n", + getV10Builder().GetTypespace().types.size(), + getV10Builder().GetTables().size(), + getV10Builder().GetReducers().size()); } #endif } -// FFI export - V9 serialization +std::vector Internal::Module::SerializeModuleDef() { + RawModuleDefV10 v10_module = getV10Builder().BuildModuleDef(); + RawModuleDef versioned_module; + versioned_module.set<2>(std::move(v10_module)); + + std::vector buffer; + bsatn::Writer writer(buffer); + versioned_module.bsatn_serialize(writer); + return buffer; +} + +// FFI export - V10 serialization void Internal::Module::__describe_module__(BytesSink sink) { // The preinit functions should have already been called by SpacetimeDB // Including our validation preinit which checks for recursive types + std::vector buffer = SerializeModuleDef(); - // Get the global V9 module - RawModuleDefV9& v9_module = GetV9Module(); - - - // Create a buffer and writer - std::vector buffer; - bsatn::Writer writer(buffer); - // Write version byte - writer.write_u8(1); - - // Serialize the V9 module with our manually added table - v9_module.bsatn_serialize(writer); - // Now try to write using FFI directly if (!buffer.empty()) { size_t bytes_to_write = buffer.size(); @@ -608,8 +629,32 @@ int16_t Module::__call_procedure__( return 0; // Success (StatusCode::OK) } + +void Module::SetCaseConversionPolicy(CaseConversionPolicy policy) { + getV10Builder().SetCaseConversionPolicy(policy); +} + +void Module::RegisterClientVisibilityFilter(const char* sql) { + if (sql == nullptr || sql[0] == '\0') { + return; + } + getV10Builder().RegisterRowLevelSecurity(sql); +} + +void Module::RegisterExplicitTableName(const std::string& source_name, const std::string& canonical_name) { + getV10Builder().RegisterExplicitTableName(source_name, canonical_name); } + +void Module::RegisterExplicitFunctionName(const std::string& source_name, const std::string& canonical_name) { + getV10Builder().RegisterExplicitFunctionName(source_name, canonical_name); } +void Module::RegisterExplicitIndexName(const std::string& source_name, const std::string& canonical_name) { + getV10Builder().RegisterExplicitIndexName(source_name, canonical_name); +} +} +} + + + - \ No newline at end of file diff --git a/crates/bindings-cpp/src/internal/v9_type_registration.cpp b/crates/bindings-cpp/src/internal/module_type_registration.cpp similarity index 71% rename from crates/bindings-cpp/src/internal/v9_type_registration.cpp rename to crates/bindings-cpp/src/internal/module_type_registration.cpp index 97907f83a6a..9d8c5a34de5 100644 --- a/crates/bindings-cpp/src/internal/v9_type_registration.cpp +++ b/crates/bindings-cpp/src/internal/module_type_registration.cpp @@ -1,12 +1,10 @@ -#include "spacetimedb/internal/v9_type_registration.h" -#include "spacetimedb/internal/v9_builder.h" +#include "spacetimedb/internal/module_type_registration.h" +#include "spacetimedb/internal/v10_builder.h" #include "spacetimedb/internal/autogen/AlgebraicType.g.h" -#include "spacetimedb/internal/autogen/RawModuleDefV9.g.h" -#include "spacetimedb/internal/autogen/RawTypeDefV9.g.h" +#include "spacetimedb/internal/autogen/RawTypeDefV10.g.h" #include "spacetimedb/internal/autogen/ProductType.g.h" #include "spacetimedb/internal/autogen/SumType.g.h" #include "spacetimedb/logger.h" // For LOG_ERROR, LOG_PANIC -#include #include #include #include @@ -17,11 +15,8 @@ namespace Internal { // Use the correct namespaces - these types are already in the correct namespace -// Forward declaration of the global V9 module accessor -RawModuleDefV9& GetV9Module(); - -// Global V9 type registration instance -std::unique_ptr g_v9_type_registration; +// Global module type registration instance +std::unique_ptr g_module_type_registration; // Thread-local storage for tracking the chain of types being registered thread_local std::vector g_type_registration_chain; @@ -30,24 +25,24 @@ thread_local std::vector g_type_registration_chain; bool g_circular_ref_error = false; std::string g_circular_ref_type_name; -void initializeV9TypeRegistration() { - g_v9_type_registration = std::make_unique(); +void initializeModuleTypeRegistration() { + g_module_type_registration = std::make_unique(); // Clear any previous error state g_circular_ref_error = false; g_circular_ref_type_name.clear(); g_type_registration_chain.clear(); } -V9TypeRegistration& getV9TypeRegistration() { - if (!g_v9_type_registration) { - initializeV9TypeRegistration(); +ModuleTypeRegistration& getModuleTypeRegistration() { + if (!g_module_type_registration) { + initializeModuleTypeRegistration(); } - return *g_v9_type_registration; + return *g_module_type_registration; } // Function moved outside Internal namespace - see end of file -AlgebraicType V9TypeRegistration::registerType(const bsatn::AlgebraicType& bsatn_type, +AlgebraicType ModuleTypeRegistration::registerType(const bsatn::AlgebraicType& bsatn_type, const std::string& explicit_name, const std::type_info* cpp_type) { @@ -91,10 +86,7 @@ AlgebraicType V9TypeRegistration::registerType(const bsatn::AlgebraicType& bsatn if (sum.variants.size() == 2 && sum.variants[0].name == "Interval" && sum.variants[1].name == "Time") { - // This is ScheduleAt - should have been caught above! - fprintf(stdout, "WARNING: ScheduleAt type detected but not inlined! explicit_name='%s'\n", - explicit_name.c_str()); - // Force inline it + // This is ScheduleAt - inline it. return convertInlineSum(bsatn_type); } } @@ -134,7 +126,14 @@ AlgebraicType V9TypeRegistration::registerType(const bsatn::AlgebraicType& bsatn if (type_name.empty()) { // Complex types MUST have proper names - this is a validation error error_type_description_ = describeType(bsatn_type); +#if !SPACETIMEDB_HAS_CXA_DEMANGLE + error_message_ = + "Missing type name for complex type on toolchain without demangling support. " + "Provide an explicit type name: " + + error_type_description_; +#else error_message_ = "Missing type name for complex type: " + error_type_description_; +#endif has_error_ = true; // Return a dummy type to avoid crashing @@ -162,8 +161,8 @@ AlgebraicType V9TypeRegistration::registerType(const bsatn::AlgebraicType& bsatn } // Check module's types array - for (const auto& type_def : GetV9Module().types) { - if (type_def.name.name == type_name) { + for (const auto& type_def : getV10Builder().GetTypeDefs()) { + if (type_def.source_name.source_name == type_name) { uint32_t typespace_index = type_def.ty; type_name_cache_[type_name] = typespace_index; AlgebraicType result(AlgebraicType::Tag::Ref); @@ -176,7 +175,7 @@ AlgebraicType V9TypeRegistration::registerType(const bsatn::AlgebraicType& bsatn return registerComplexType(bsatn_type, type_name); } -uint32_t V9TypeRegistration::registerAndGetIndex(const bsatn::AlgebraicType& bsatn_type, +uint32_t ModuleTypeRegistration::registerAndGetIndex(const bsatn::AlgebraicType& bsatn_type, const std::string& type_name, const std::type_info* cpp_type) { // Check if already registered in cache @@ -200,135 +199,40 @@ uint32_t V9TypeRegistration::registerAndGetIndex(const bsatn::AlgebraicType& bsa return 0; } -void V9TypeRegistration::registerTypeByName(const std::string& type_name, +void ModuleTypeRegistration::registerTypeByName(const std::string& type_name, const bsatn::AlgebraicType& algebraic_type, [[maybe_unused]] const std::type_info* cpp_type) { // Check if already registered in cache auto cache_it = type_name_cache_.find(type_name); if (cache_it != type_name_cache_.end()) { - fprintf(stdout, "ENUM DEBUG: Type '%s' already registered at index %u\n", - type_name.c_str(), cache_it->second); return; } // Check if already registered in module's types array - for (const auto& type_def : GetV9Module().types) { - if (type_def.name.name == type_name) { + for (const auto& type_def : getV10Builder().GetTypeDefs()) { + if (type_def.source_name.source_name == type_name) { uint32_t typespace_index = type_def.ty; type_name_cache_[type_name] = typespace_index; - fprintf(stdout, "ENUM DEBUG: Type '%s' found in module at index %u\n", - type_name.c_str(), typespace_index); return; } } - - // Register new type immediately - fprintf(stdout, "ENUM DEBUG: Registering new type '%s' immediately\n", type_name.c_str()); - - // Mark this type as being registered (for cycle detection) - types_being_registered_.insert(type_name); - - // Reserve space in typespace - uint32_t typespace_index = GetV9Module().typespace.types.size(); - - // For immediate registration, we process the type directly without recursive calls - // This avoids infinite loops when the enum's algebraic_type() calls registerTypeByName - AlgebraicType processed_type; - - if (algebraic_type.tag() == bsatn::AlgebraicTypeTag::Sum) { - // For enums, directly process the Sum type structure without recursive registerType calls - auto sum = std::make_unique(); - - for (const auto& variant : algebraic_type.as_sum().variants) { - SumTypeVariant v; - v.name = variant.name; - - // For simple enum variants, they should be Unit types (no payload) - // Check if it's a Unit type and convert appropriately - if (isUnitType(*variant.algebraic_type)) { - v.algebraic_type = convertUnitType(); - } else if (isPrimitive(*variant.algebraic_type)) { - // For primitive variant types - v.algebraic_type = convertPrimitive(*variant.algebraic_type); - } else { - // For complex variant types, we need to recursively process them - // But we can't call registerType here as it would cause infinite recursion - // So we do a simple inline conversion - if (variant.algebraic_type->tag() == bsatn::AlgebraicTypeTag::Array) { - v.algebraic_type = convertArray(*variant.algebraic_type); - } else if (variant.algebraic_type->tag() == bsatn::AlgebraicTypeTag::Product) { - v.algebraic_type = convertSpecialType(*variant.algebraic_type); - } else { - // Fallback to primitive conversion - v.algebraic_type = convertPrimitive(*variant.algebraic_type); - } - } - sum->variants.push_back(std::move(v)); - } - - processed_type = AlgebraicType(AlgebraicType::Tag::Sum); - processed_type.set<1>(std::move(sum)); - } else if (algebraic_type.tag() == bsatn::AlgebraicTypeTag::Product) { - // For structs, process directly - auto product = std::make_unique(); - - for (const auto& field : algebraic_type.as_product().elements) { - ProductTypeElement elem; - elem.name = field.name; - // Convert field type appropriately - handle different types - if (isPrimitive(*field.algebraic_type)) { - elem.algebraic_type = convertPrimitive(*field.algebraic_type); - } else if (isUnitType(*field.algebraic_type)) { - elem.algebraic_type = convertUnitType(); - } else { - // For complex field types, just convert as primitive for now - elem.algebraic_type = convertPrimitive(*field.algebraic_type); - } - product->elements.push_back(std::move(elem)); - } - - processed_type = AlgebraicType(AlgebraicType::Tag::Product); - processed_type.set<2>(std::move(product)); - } else { - fprintf(stderr, "[Warning] Unexpected type tag %d for '%s'\n", - static_cast(algebraic_type.tag()), type_name.c_str()); - processed_type = convertPrimitive(algebraic_type); + + // Register by name using the same full-fidelity path as other complex type registration. + // This avoids lossy conversion of nested fields/variants. + auto result = registerType(algebraic_type, type_name, cpp_type); + if (result.get_tag() != AlgebraicType::Tag::Ref) { + fprintf(stderr, "ERROR: Failed to register named complex type '%s'\n", type_name.c_str()); } - - // Add to typespace - GetV9Module().typespace.types.push_back(processed_type); - - // Create RawTypeDefV9 export with namespace support - RawTypeDefV9 type_def; - - // Parse namespace from type name - auto [scope, simple_name] = parseNamespaceAndName(type_name); - type_def.name.scope = scope; - type_def.name.name = simple_name; - type_def.ty = typespace_index; - type_def.custom_ordering = true; // Complex types need custom ordering - - // Add to module's types array - GetV9Module().types.push_back(type_def); - - // Update cache - type_name_cache_[type_name] = typespace_index; - - // Remove from types being registered (cycle detection cleanup) - types_being_registered_.erase(type_name); - - fprintf(stdout, "ENUM DEBUG: Successfully registered type '%s' at index %u\n", - type_name.c_str(), typespace_index); } -bool V9TypeRegistration::isPrimitive(const bsatn::AlgebraicType& type) const { +bool ModuleTypeRegistration::isPrimitive(const bsatn::AlgebraicType& type) const { auto tag = static_cast(type.tag()); // Use range check: String (4) to F64 (19) covers all primitive types return tag >= static_cast(bsatn::AlgebraicTypeTag::String) && tag <= static_cast(bsatn::AlgebraicTypeTag::F64); } -bool V9TypeRegistration::isSpecialType(const bsatn::AlgebraicType& type) const { +bool ModuleTypeRegistration::isSpecialType(const bsatn::AlgebraicType& type) const { if (type.tag() != bsatn::AlgebraicTypeTag::Product) { return false; } @@ -346,7 +250,7 @@ bool V9TypeRegistration::isSpecialType(const bsatn::AlgebraicType& type) const { field_name == "__uuid__"; } -bool V9TypeRegistration::isOptionType(const bsatn::AlgebraicType& type) const { +bool ModuleTypeRegistration::isOptionType(const bsatn::AlgebraicType& type) const { if (type.tag() != bsatn::AlgebraicTypeTag::Sum) { return false; } @@ -357,7 +261,7 @@ bool V9TypeRegistration::isOptionType(const bsatn::AlgebraicType& type) const { sum.variants[1].name == "none"; } -bool V9TypeRegistration::isResultType(const bsatn::AlgebraicType& type) const { +bool ModuleTypeRegistration::isResultType(const bsatn::AlgebraicType& type) const { if (type.tag() != bsatn::AlgebraicTypeTag::Sum) { return false; } @@ -368,7 +272,7 @@ bool V9TypeRegistration::isResultType(const bsatn::AlgebraicType& type) const { sum.variants[1].name == "err"; } -bool V9TypeRegistration::isScheduleAtType(const bsatn::AlgebraicType& type) const { +bool ModuleTypeRegistration::isScheduleAtType(const bsatn::AlgebraicType& type) const { if (type.tag() != bsatn::AlgebraicTypeTag::Sum) { return false; } @@ -379,7 +283,7 @@ bool V9TypeRegistration::isScheduleAtType(const bsatn::AlgebraicType& type) cons sum.variants[1].name == "Time"; } -bool V9TypeRegistration::isUnitType(const bsatn::AlgebraicType& type) const { +bool ModuleTypeRegistration::isUnitType(const bsatn::AlgebraicType& type) const { if (type.tag() != bsatn::AlgebraicTypeTag::Product) { return false; } @@ -389,7 +293,7 @@ bool V9TypeRegistration::isUnitType(const bsatn::AlgebraicType& type) const { return product.elements.empty(); } -AlgebraicType V9TypeRegistration::convertUnitType() const { +AlgebraicType ModuleTypeRegistration::convertUnitType() const { // Create an empty Product type (Unit) auto product = std::make_unique(); // No elements - empty Product @@ -399,7 +303,11 @@ AlgebraicType V9TypeRegistration::convertUnitType() const { return result; } -std::string V9TypeRegistration::extractTypeName(const std::type_info* cpp_type) const { +std::string ModuleTypeRegistration::extractTypeName(const std::type_info* cpp_type) const { +#if !SPACETIMEDB_HAS_CXA_DEMANGLE + (void)cpp_type; + return ""; +#else std::string demangled = demangle_cpp_type_name(cpp_type->name()); // Extract simple name (last component after ::) @@ -415,9 +323,10 @@ std::string V9TypeRegistration::extractTypeName(const std::type_info* cpp_type) } return demangled; +#endif } -std::pair, std::string> V9TypeRegistration::parseNamespaceAndName(const std::string& qualified_name) const { +std::pair, std::string> ModuleTypeRegistration::parseNamespaceAndName(const std::string& qualified_name) const { std::vector scope; std::string name; @@ -459,7 +368,7 @@ std::pair, std::string> V9TypeRegistration::parseNamesp return std::make_pair(scope, name); } -AlgebraicType V9TypeRegistration::convertPrimitive(const bsatn::AlgebraicType& type) const { +AlgebraicType ModuleTypeRegistration::convertPrimitive(const bsatn::AlgebraicType& type) const { switch (type.tag()) { case bsatn::AlgebraicTypeTag::Bool: return AlgebraicType(AlgebraicType::Tag::Bool); @@ -499,7 +408,7 @@ AlgebraicType V9TypeRegistration::convertPrimitive(const bsatn::AlgebraicType& t } } -AlgebraicType V9TypeRegistration::convertArray(const bsatn::AlgebraicType& type) { +AlgebraicType ModuleTypeRegistration::convertArray(const bsatn::AlgebraicType& type) { const auto& array = type.as_array(); // Recursively process element type @@ -511,7 +420,7 @@ AlgebraicType V9TypeRegistration::convertArray(const bsatn::AlgebraicType& type) return result; } -AlgebraicType V9TypeRegistration::convertSpecialType(const bsatn::AlgebraicType& type) { +AlgebraicType ModuleTypeRegistration::convertSpecialType(const bsatn::AlgebraicType& type) { // Special types are inlined as Product structures auto product = std::make_unique(); @@ -529,7 +438,7 @@ AlgebraicType V9TypeRegistration::convertSpecialType(const bsatn::AlgebraicType& return result; } -AlgebraicType V9TypeRegistration::convertInlineSum(const bsatn::AlgebraicType& type) { +AlgebraicType ModuleTypeRegistration::convertInlineSum(const bsatn::AlgebraicType& type) { // Options and ScheduleAt are inlined as Sum structures auto sum = std::make_unique(); @@ -547,13 +456,13 @@ AlgebraicType V9TypeRegistration::convertInlineSum(const bsatn::AlgebraicType& t return result; } -AlgebraicType V9TypeRegistration::registerComplexType(const bsatn::AlgebraicType& type, +AlgebraicType ModuleTypeRegistration::registerComplexType(const bsatn::AlgebraicType& type, const std::string& type_name) { // Mark this type as being registered (for cycle detection) types_being_registered_.insert(type_name); // Reserve space in typespace - uint32_t typespace_index = GetV9Module().typespace.types.size(); + uint32_t typespace_index = getV10Builder().GetTypespace().types.size(); // Debug logging (disabled in production) #ifdef DEBUG_TYPE_REGISTRATION @@ -576,20 +485,20 @@ AlgebraicType V9TypeRegistration::registerComplexType(const bsatn::AlgebraicType } // Add to typespace - GetV9Module().typespace.types.push_back(processed_type); + getV10Builder().GetTypespace().types.push_back(processed_type); // Create RawTypeDefV9 export with namespace support - RawTypeDefV9 type_def; + RawTypeDefV10 type_def; // Parse namespace from type name auto [scope, simple_name] = parseNamespaceAndName(type_name); - type_def.name.scope = scope; - type_def.name.name = simple_name; + type_def.source_name.scope = scope; + type_def.source_name.source_name = simple_name; type_def.ty = typespace_index; type_def.custom_ordering = true; // Complex types need custom ordering // Add to module's types array - GetV9Module().types.push_back(type_def); + getV10Builder().GetTypeDefs().push_back(type_def); // Update cache type_name_cache_[type_name] = typespace_index; @@ -603,7 +512,7 @@ AlgebraicType V9TypeRegistration::registerComplexType(const bsatn::AlgebraicType return result; } -AlgebraicType V9TypeRegistration::processProduct(const bsatn::AlgebraicType& type) { +AlgebraicType ModuleTypeRegistration::processProduct(const bsatn::AlgebraicType& type) { auto product = std::make_unique(); for (const auto& field : type.as_product().elements) { @@ -622,7 +531,7 @@ AlgebraicType V9TypeRegistration::processProduct(const bsatn::AlgebraicType& typ return result; } -AlgebraicType V9TypeRegistration::processSum(const bsatn::AlgebraicType& type) { +AlgebraicType ModuleTypeRegistration::processSum(const bsatn::AlgebraicType& type) { auto sum = std::make_unique(); for (const auto& variant : type.as_sum().variants) { @@ -639,7 +548,7 @@ AlgebraicType V9TypeRegistration::processSum(const bsatn::AlgebraicType& type) { return result; } -std::string V9TypeRegistration::describeType(const bsatn::AlgebraicType& type) const { +std::string ModuleTypeRegistration::describeType(const bsatn::AlgebraicType& type) const { switch (type.tag()) { case bsatn::AlgebraicTypeTag::Bool: return "Bool"; case bsatn::AlgebraicTypeTag::U8: return "U8"; @@ -715,14 +624,13 @@ std::string V9TypeRegistration::describeType(const bsatn::AlgebraicType& type) c } } -void V9TypeRegistration::updateTypeNameInModule(uint32_t type_index, const std::string& new_name) { - // Get access to the global V9 module - RawModuleDefV9& v9_module = GetV9Module(); +void ModuleTypeRegistration::updateTypeNameInModule(uint32_t type_index, const std::string& new_name) { + auto& type_defs = getV10Builder().GetTypeDefs(); // Check if the type index is valid - if (type_index >= v9_module.types.size()) { + if (type_index >= type_defs.size()) { fprintf(stderr, "ERROR: Invalid type index %u for namespace update (max: %zu)\n", - type_index, v9_module.types.size()); + type_index, type_defs.size()); return; } @@ -730,11 +638,9 @@ void V9TypeRegistration::updateTypeNameInModule(uint32_t type_index, const std:: auto [scope, name] = parseNamespaceAndName(new_name); // Update the type definition's scoped name - v9_module.types[type_index].name.scope = scope; - v9_module.types[type_index].name.name = name; + type_defs[type_index].source_name.scope = scope; + type_defs[type_index].source_name.source_name = name; - fprintf(stdout, "DEBUG: Updated type index %u name to '%s' with %zu scope parts\n", - type_index, name.c_str(), scope.size()); } // processOptionInnerType function removed - no longer needed @@ -742,4 +648,5 @@ void V9TypeRegistration::updateTypeNameInModule(uint32_t type_index, const std:: } // namespace Internal -} // namespace SpacetimeDB \ No newline at end of file +} // namespace SpacetimeDB + diff --git a/crates/bindings-cpp/src/internal/v10_builder.cpp b/crates/bindings-cpp/src/internal/v10_builder.cpp new file mode 100644 index 00000000000..65f1895b035 --- /dev/null +++ b/crates/bindings-cpp/src/internal/v10_builder.cpp @@ -0,0 +1,269 @@ +#include "spacetimedb/internal/v10_builder.h" +#include "spacetimedb/internal/autogen/AlgebraicType.g.h" +#include "spacetimedb/internal/autogen/ProductType.g.h" +#include "spacetimedb/internal/autogen/ProductTypeElement.g.h" +#include "spacetimedb/internal/autogen/RawModuleDefV10Section.g.h" +#include "spacetimedb/internal/autogen/RawTypeDefV10.g.h" +#include "spacetimedb/internal/autogen/RawScopedTypeNameV10.g.h" +#include "spacetimedb/internal/autogen/FunctionVisibility.g.h" +#include "spacetimedb/internal/autogen/ExplicitNames.g.h" +#include +#include + +namespace SpacetimeDB { +namespace Internal { + +std::unique_ptr g_v10_builder; + +void initializeV10Builder() { + g_v10_builder = std::make_unique(); +} + +V10Builder& getV10Builder() { + if (!g_v10_builder) { + initializeV10Builder(); + } + return *g_v10_builder; +} + +void V10Builder::Clear() { + typespace_ = Typespace{}; + types_.clear(); + table_is_event_.clear(); + case_conversion_policy_.reset(); + explicit_names_.clear(); + column_defaults_by_table_.clear(); + tables_.clear(); + reducers_.clear(); + procedures_.clear(); + views_.clear(); + schedules_.clear(); + lifecycle_reducers_.clear(); + row_level_security_.clear(); +} + +void V10Builder::SetTableIsEventFlag(const std::string& table_name, bool is_event) { + for (auto& entry : table_is_event_) { + if (entry.first == table_name) { + entry.second = is_event; + for (auto& table : tables_) { + if (table.source_name == table_name) { + table.is_event = is_event; + break; + } + } + return; + } + } + table_is_event_.emplace_back(table_name, is_event); +} + +bool V10Builder::GetTableIsEventFlag(const std::string& table_name) const { + for (const auto& entry : table_is_event_) { + if (entry.first == table_name) { + return entry.second; + } + } + return false; +} + +void V10Builder::RegisterExplicitTableName(const std::string& source_name, const std::string& canonical_name) { + ExplicitNameEntry entry; + entry.set<0>(NameMapping{source_name, canonical_name}); + explicit_names_.push_back(std::move(entry)); +} + +void V10Builder::RegisterExplicitFunctionName(const std::string& source_name, const std::string& canonical_name) { + ExplicitNameEntry entry; + entry.set<1>(NameMapping{source_name, canonical_name}); + explicit_names_.push_back(std::move(entry)); +} + +void V10Builder::RegisterExplicitIndexName(const std::string& source_name, const std::string& canonical_name) { + ExplicitNameEntry entry; + entry.set<2>(NameMapping{source_name, canonical_name}); + explicit_names_.push_back(std::move(entry)); +} + +AlgebraicType V10Builder::MakeUnitAlgebraicType() { + AlgebraicType unit(AlgebraicType::Tag::Product); + unit.set<2>(std::make_unique()); + return unit; +} + +AlgebraicType V10Builder::MakeStringAlgebraicType() { + return AlgebraicType(AlgebraicType::Tag::String); +} + +void V10Builder::UpsertTable(const RawTableDefV10& table) { + auto it = std::find_if(tables_.begin(), tables_.end(), [&](const auto& existing) { + return existing.source_name == table.source_name; + }); + if (it == tables_.end()) { + tables_.push_back(table); + } else { + *it = table; + } +} + +void V10Builder::UpsertLifecycleReducer(const RawLifeCycleReducerDefV10& lifecycle) { + auto it = std::find_if(lifecycle_reducers_.begin(), lifecycle_reducers_.end(), [&](const auto& existing) { + return existing.function_name == lifecycle.function_name; + }); + if (it == lifecycle_reducers_.end()) { + lifecycle_reducers_.push_back(lifecycle); + } else { + *it = lifecycle; + } +} + +void V10Builder::UpsertReducer(const RawReducerDefV10& reducer) { + auto it = std::find_if(reducers_.begin(), reducers_.end(), [&](const auto& existing) { + return existing.source_name == reducer.source_name; + }); + if (it == reducers_.end()) { + reducers_.push_back(reducer); + } else { + *it = reducer; + } +} + +void V10Builder::UpsertProcedure(const RawProcedureDefV10& procedure) { + auto it = std::find_if(procedures_.begin(), procedures_.end(), [&](const auto& existing) { + return existing.source_name == procedure.source_name; + }); + if (it == procedures_.end()) { + procedures_.push_back(procedure); + } else { + *it = procedure; + } +} + +void V10Builder::UpsertView(const RawViewDefV10& view) { + auto it = std::find_if(views_.begin(), views_.end(), [&](const auto& existing) { + return existing.source_name == view.source_name; + }); + if (it == views_.end()) { + views_.push_back(view); + } else { + *it = view; + } +} + +RawIndexDefV10 V10Builder::CreateBTreeIndex(const std::string& table_name, + const std::string& source_name, + const std::vector& columns, + const std::string& accessor_name) const { + RawIndexAlgorithmBTreeData btree_data; + btree_data.columns = columns; + RawIndexAlgorithm algorithm; + algorithm.set<0>(btree_data); + (void)table_name; + return RawIndexDefV10{ + source_name, + accessor_name, + std::move(algorithm), + }; +} + +RawConstraintDefV10 V10Builder::CreateUniqueConstraint(const std::string& table_name, + const std::string& field_name, + uint16_t field_idx) const { + RawUniqueConstraintDataV9 unique_data; + unique_data.columns = {field_idx}; + RawConstraintDataV9 constraint_data; + constraint_data.set<0>(unique_data); + (void)table_name; + (void)field_name; + return RawConstraintDefV10{ + std::nullopt, + std::move(constraint_data), + }; +} + +RawModuleDefV10 V10Builder::BuildModuleDef() const { + RawModuleDefV10 v10_module; + + std::vector types = types_; + + std::vector reducers = reducers_; + std::vector procedures = procedures_; + + std::unordered_set internal_functions; + for (const auto& lifecycle : lifecycle_reducers_) { + internal_functions.insert(lifecycle.function_name); + } + for (const auto& schedule : schedules_) { + internal_functions.insert(schedule.function_name); + } + for (auto& reducer : reducers) { + if (internal_functions.find(reducer.source_name) != internal_functions.end()) { + reducer.visibility = FunctionVisibility::Private; + } + } + for (auto& procedure : procedures) { + if (internal_functions.find(procedure.source_name) != internal_functions.end()) { + procedure.visibility = FunctionVisibility::Private; + } + } + + RawModuleDefV10Section section_typespace; + section_typespace.set<0>(typespace_); + v10_module.sections.push_back(section_typespace); + + if (!types.empty()) { + RawModuleDefV10Section section_types; + section_types.set<1>(std::move(types)); + v10_module.sections.push_back(std::move(section_types)); + } + if (!tables_.empty()) { + RawModuleDefV10Section section_tables; + section_tables.set<2>(tables_); + v10_module.sections.push_back(std::move(section_tables)); + } + if (!reducers.empty()) { + RawModuleDefV10Section section_reducers; + section_reducers.set<3>(std::move(reducers)); + v10_module.sections.push_back(std::move(section_reducers)); + } + if (!procedures.empty()) { + RawModuleDefV10Section section_procedures; + section_procedures.set<4>(std::move(procedures)); + v10_module.sections.push_back(std::move(section_procedures)); + } + if (!views_.empty()) { + RawModuleDefV10Section section_views; + section_views.set<5>(views_); + v10_module.sections.push_back(std::move(section_views)); + } + if (!schedules_.empty()) { + RawModuleDefV10Section section_schedules; + section_schedules.set<6>(schedules_); + v10_module.sections.push_back(std::move(section_schedules)); + } + if (!lifecycle_reducers_.empty()) { + RawModuleDefV10Section section_lifecycle; + section_lifecycle.set<7>(lifecycle_reducers_); + v10_module.sections.push_back(std::move(section_lifecycle)); + } + if (case_conversion_policy_.has_value()) { + RawModuleDefV10Section section_case_policy; + section_case_policy.set<9>(case_conversion_policy_.value()); + v10_module.sections.push_back(std::move(section_case_policy)); + } + if (!explicit_names_.empty()) { + RawModuleDefV10Section section_explicit_names; + section_explicit_names.set<10>(ExplicitNames{explicit_names_}); + v10_module.sections.push_back(std::move(section_explicit_names)); + } + if (!row_level_security_.empty()) { + RawModuleDefV10Section section_rls; + section_rls.set<8>(row_level_security_); + v10_module.sections.push_back(std::move(section_rls)); + } + + return v10_module; +} + +} // namespace Internal +} // namespace SpacetimeDB diff --git a/crates/bindings-cpp/src/internal/v9_builder.cpp b/crates/bindings-cpp/src/internal/v9_builder.cpp index 643d58fdbe1..c2a477ae428 100644 --- a/crates/bindings-cpp/src/internal/v9_builder.cpp +++ b/crates/bindings-cpp/src/internal/v9_builder.cpp @@ -21,13 +21,12 @@ // Then include the main headers #include "spacetimedb/internal/v9_builder.h" -#include "spacetimedb/internal/v9_type_registration.h" +#include "spacetimedb/internal/module_type_registration.h" #include "spacetimedb/internal/debug.h" #include "spacetimedb/bsatn/bsatn.h" #include "spacetimedb/internal/Module_impl.h" #include #include -#include #include #include #include @@ -35,10 +34,17 @@ namespace SpacetimeDB { namespace Internal { -// Forward declaration of the global V9 module accessor -RawModuleDefV9& GetV9Module(); +static RawModuleDefV9 g_v9_compat_module; -// demangle_cpp_type_name function removed - using global version from v9_type_registration.cpp +RawModuleDefV9& GetV9Module() { + return g_v9_compat_module; +} + +void ClearV9CompatModuleState() { + g_v9_compat_module = RawModuleDefV9{}; +} + +// demangle_cpp_type_name function removed - using global version from module_type_registration.cpp // Global V9Builder instance std::unique_ptr g_v9_builder; @@ -46,7 +52,7 @@ std::unique_ptr g_v9_builder; void initializeV9Builder() { g_v9_builder = std::make_unique(); // Also initialize the type registration system - initializeV9TypeRegistration(); + initializeModuleTypeRegistration(); } V9Builder& getV9Builder() { @@ -59,17 +65,17 @@ V9Builder& getV9Builder() { // Constructor V9Builder::V9Builder() { - // No TypeRegistry anymore - everything goes through V9TypeRegistration + // No TypeRegistry anymore - everything goes through ModuleTypeRegistration } /** * Register a type using the unified type registration system - * This is now just a thin wrapper around the V9TypeRegistration system + * This is now just a thin wrapper around the ModuleTypeRegistration system */ AlgebraicType V9Builder::registerType(const bsatn::AlgebraicType& bsatn_type, const std::string& explicit_name, const std::type_info* cpp_type) { - return getV9TypeRegistration().registerType(bsatn_type, explicit_name, cpp_type); + return getModuleTypeRegistration().registerType(bsatn_type, explicit_name, cpp_type); } void V9Builder::AddV9Table(const std::string& table_name, @@ -353,4 +359,5 @@ RawConstraintDefV9 V9Builder::createUniqueConstraint(const std::string& table_na } // namespace Internal -} // namespace SpacetimeDB \ No newline at end of file +} // namespace SpacetimeDB + diff --git a/crates/bindings-cpp/tests/type-isolation-test/README.md b/crates/bindings-cpp/tests/type-isolation-test/README.md index 69e160d755c..1d6da3ad15e 100644 --- a/crates/bindings-cpp/tests/type-isolation-test/README.md +++ b/crates/bindings-cpp/tests/type-isolation-test/README.md @@ -5,12 +5,18 @@ Comprehensive test framework for systematically testing individual C++ types wit ## Quick Start ```bash -# Run all tests with default parallelism (16 builds) +# Run default V10 regression checks (16-way parallel build) ./run_type_isolation_test.sh # Run with custom parallelism ./run_type_isolation_test.sh 8 +# Explicit V10 regression mode (same as default) +./run_type_isolation_test.sh --v10-regression + +# Run broader legacy/full suite (V9 check path) +./run_type_isolation_test.sh --v9 + # Monitor progress in real-time (separate terminal) watch -n 1 cat test_summary_live.txt ``` @@ -146,4 +152,4 @@ SUCCESS_RATE=$(grep "Success rate:" test_summary_live.txt | grep -o '[0-9]*%') [[ "${SUCCESS_RATE}" == "89%" ]] || exit 1 # Expected rate with intentional failures ``` -The test suite validates the C++ bindings type system by testing individual types in isolation, ensuring reliable constraint validation and error detection. \ No newline at end of file +The test suite validates the C++ bindings type system by testing individual types in isolation, ensuring reliable constraint validation and error detection. diff --git a/crates/bindings-cpp/tests/type-isolation-test/run_type_isolation_test.sh b/crates/bindings-cpp/tests/type-isolation-test/run_type_isolation_test.sh index 942b63783bd..8fabddb4c4c 100644 --- a/crates/bindings-cpp/tests/type-isolation-test/run_type_isolation_test.sh +++ b/crates/bindings-cpp/tests/type-isolation-test/run_type_isolation_test.sh @@ -23,6 +23,25 @@ detect_emcmake_command() { EMCMAKE_CMD=$(detect_emcmake_command) echo "Using emcmake command: $EMCMAKE_CMD" +# Parse arguments +MAX_PARALLEL=16 +TEST_MODE="v10-regression" +for arg in "$@"; do + case "$arg" in + --v10-regression) + TEST_MODE="v10-regression" + ;; + --v9) + TEST_MODE="v9" + ;; + ''|*[!0-9]*) + ;; + *) + MAX_PARALLEL="$arg" + ;; + esac +done + # Clear previous state echo "Starting fresh test run..." rm -f test_log.txt test_summary_live.txt @@ -62,13 +81,28 @@ for cpp_file in test_modules/*.cpp; do fi done +# Optional focused regression selection for V10 behavior checks +if [ "$TEST_MODE" = "v10-regression" ]; then + declare -a FILTERED_MODULES=() + for module in "${MODULES[@]}"; do + case "$module" in + test_multicolumn_index_valid|error_multicolumn_missing_field|error_default_missing_field|error_circular_ref) + FILTERED_MODULES+=("$module") + ;; + esac + done + MODULES=("${FILTERED_MODULES[@]}") +fi + # Sort modules IFS=$'\n' MODULES=($(sort <<<"${MODULES[*]}")) unset IFS echo "=========================================" echo "Testing ${#MODULES[@]} modules" -echo "Parallelism: ${1:-16} (use ./run_type_isolation_test.sh to change)" +echo "Mode: ${TEST_MODE}" +echo "Parallelism: ${MAX_PARALLEL} (use ./run_type_isolation_test.sh to change)" +echo "Use --v9 to run the broader legacy/full module suite." echo "=========================================" echo "Monitor table with: watch -n 1 cat test_summary_live.txt" echo "Monitor log with: tail -f test_log.txt" @@ -180,6 +214,24 @@ echo "=========================================" export SPACETIMEDB_LIBRARY_DIR="$(pwd)/$LIBRARY_BUILD_DIR/spacetimedb_lib" export SPACETIMEDB_INCLUDE_DIR="$(pwd)/../../include" +get_expected_failure_marker() { + local module=$1 + case "$module" in + error_multicolumn_missing_field) + echo "ERROR_CONSTRAINT_REGISTRATION_FIELD_NOT_FOUND" + ;; + error_default_missing_field) + echo "ERROR_CONSTRAINT_REGISTRATION_FIELD_NOT_FOUND" + ;; + error_circular_ref) + echo "ERROR_CIRCULAR_REFERENCE_" + ;; + *) + echo "" + ;; + esac +} + # Function to publish module in background publish_module() { local module=$1 @@ -201,7 +253,47 @@ publish_module() { local db_name=$(echo "testmod-${module}" | sed 's/_/-/g') echo " 📤 Publishing $module as $db_name..." local PUBLISH_ERROR_FILE="$TMP_DIR/publish_error_${module}.txt" - if timeout 60 spacetime publish --bin-path "$wasm" -c "$db_name" -y > /dev/null 2>"$PUBLISH_ERROR_FILE"; then + timeout 60 spacetime publish --bin-path "$wasm" -c "$db_name" -y >"$PUBLISH_ERROR_FILE" 2>&1 + local publish_exit=$? + + local expected_marker + expected_marker=$(get_expected_failure_marker "$module") + + local has_publish_error=0 + if grep -q "Error: Errors occurred:" "$PUBLISH_ERROR_FILE" 2>/dev/null || \ + grep -q "HTTP status server error" "$PUBLISH_ERROR_FILE" 2>/dev/null || \ + grep -q "invalid ref:" "$PUBLISH_ERROR_FILE" 2>/dev/null; then + has_publish_error=1 + fi + + local publish_success=0 + if [ $publish_exit -eq 0 ] && [ $has_publish_error -eq 0 ]; then + publish_success=1 + fi + + if [ -n "$expected_marker" ]; then + if [ $publish_success -eq 0 ] && grep -q "$expected_marker" "$PUBLISH_ERROR_FILE" 2>/dev/null; then + write_log "$module" "publish" "pass" + write_log "$module" "error" "Expected publish failure validated: $expected_marker" + echo " ✅ Expected publish failure validated: $module ($expected_marker)" + rm -f "$PUBLISH_ERROR_FILE" + return + fi + + write_log "$module" "publish" "fail" + local EXPECTED_MSG="Expected publish failure with marker '$expected_marker'" + ERROR_MSG=$(sed -n '/Error:/,+10p' "$PUBLISH_ERROR_FILE" 2>/dev/null | tr '\n' ' ') + if [ -z "$ERROR_MSG" ]; then + ERROR_MSG=$(tail -n 15 "$PUBLISH_ERROR_FILE" 2>/dev/null | tr '\n' ' ') + fi + ERROR_MSG="$EXPECTED_MSG | Actual: ${ERROR_MSG:0:400}" + write_log "$module" "error" "$ERROR_MSG" + echo " ❌ Expected failure marker missing for $module" + rm -f "$PUBLISH_ERROR_FILE" + return + fi + + if [ $publish_success -eq 1 ]; then write_log "$module" "publish" "pass" echo " ✅ Published $module" rm -f "$PUBLISH_ERROR_FILE" @@ -284,7 +376,6 @@ build_module() { } # Parallel build management with configurable parallelism -MAX_PARALLEL=16 # Default to 16, or use first argument echo "Building modules with parallelism of $MAX_PARALLEL..." # Build modules maintaining constant parallelism @@ -340,4 +431,4 @@ echo "=========================================" echo "Test Complete!" echo "=========================================" echo "Final table in: test_summary_live.txt" -echo "Log file: test_log.txt" \ No newline at end of file +echo "Log file: test_log.txt" diff --git a/crates/bindings-cpp/tests/type-isolation-test/test_modules/error_default_missing_field.cpp b/crates/bindings-cpp/tests/type-isolation-test/test_modules/error_default_missing_field.cpp new file mode 100644 index 00000000000..6a3e5fd5bad --- /dev/null +++ b/crates/bindings-cpp/tests/type-isolation-test/test_modules/error_default_missing_field.cpp @@ -0,0 +1,21 @@ +#include + +using namespace SpacetimeDB; + +struct BadDefaultRow { + uint32_t id; + uint32_t player; +}; +SPACETIMEDB_STRUCT(BadDefaultRow, id, player) +SPACETIMEDB_TABLE(BadDefaultRow, bad_default_row, Public) +FIELD_PrimaryKey(bad_default_row, id) + +// Negative test: "missing_col" does not exist in BadDefaultRow. +FIELD_Default(bad_default_row, missing_col, uint32_t(7)) + +SPACETIMEDB_REDUCER(insert_bad_default_row, ReducerContext ctx, uint32_t id, uint32_t player) +{ + ctx.db[bad_default_row].insert(BadDefaultRow{id, player}); + return Ok(); +} + diff --git a/crates/bindings-cpp/tests/type-isolation-test/test_modules/error_multicolumn_missing_field.cpp b/crates/bindings-cpp/tests/type-isolation-test/test_modules/error_multicolumn_missing_field.cpp new file mode 100644 index 00000000000..1fd946dd671 --- /dev/null +++ b/crates/bindings-cpp/tests/type-isolation-test/test_modules/error_multicolumn_missing_field.cpp @@ -0,0 +1,21 @@ +#include + +using namespace SpacetimeDB; + +struct BadIndexRow { + uint32_t id; + uint32_t player; +}; +SPACETIMEDB_STRUCT(BadIndexRow, id, player) +SPACETIMEDB_TABLE(BadIndexRow, bad_index_row, Public) +FIELD_PrimaryKey(bad_index_row, id) + +// Negative test: "round" does not exist in BadIndexRow. +FIELD_MultiColumnIndex(bad_index_row, by_player_round, player, round) + +SPACETIMEDB_REDUCER(insert_bad_index_row, ReducerContext ctx, uint32_t id, uint32_t player) +{ + ctx.db[bad_index_row].insert(BadIndexRow{id, player}); + return Ok(); +} + diff --git a/crates/bindings-cpp/tests/type-isolation-test/test_modules/test_multicolumn_index_valid.cpp b/crates/bindings-cpp/tests/type-isolation-test/test_modules/test_multicolumn_index_valid.cpp new file mode 100644 index 00000000000..e13faeba8a7 --- /dev/null +++ b/crates/bindings-cpp/tests/type-isolation-test/test_modules/test_multicolumn_index_valid.cpp @@ -0,0 +1,21 @@ +#include + +using namespace SpacetimeDB; + +struct ScoreRow { + uint32_t id; + uint32_t player; + uint32_t round; + int32_t score; +}; +SPACETIMEDB_STRUCT(ScoreRow, id, player, round, score) +SPACETIMEDB_TABLE(ScoreRow, score_row, Public) +FIELD_PrimaryKey(score_row, id) +FIELD_MultiColumnIndex(score_row, by_player_round, player, round) + +SPACETIMEDB_REDUCER(insert_score, ReducerContext ctx, uint32_t id, uint32_t player, uint32_t round, int32_t score) +{ + ctx.db[score_row].insert(ScoreRow{id, player, round, score}); + return Ok(); +} + diff --git a/crates/codegen/examples/regen-cpp-moduledef.rs b/crates/codegen/examples/regen-cpp-moduledef.rs index d508d572c8b..62c06f72629 100644 --- a/crates/codegen/examples/regen-cpp-moduledef.rs +++ b/crates/codegen/examples/regen-cpp-moduledef.rs @@ -4,13 +4,15 @@ use fs_err as fs; use spacetimedb_codegen::{cpp, generate, CodegenOptions, OutputFile}; -use spacetimedb_lib::db::raw_def::v9::{RawModuleDefV9, RawModuleDefV9Builder}; +use spacetimedb_lib::db::raw_def::v10::{RawModuleDefV10, RawModuleDefV10Builder}; +use spacetimedb_lib::RawModuleDef; use spacetimedb_schema::def::ModuleDef; use std::path::Path; fn main() -> anyhow::Result<()> { - let mut builder = RawModuleDefV9Builder::new(); - builder.add_type::(); + let mut builder = RawModuleDefV10Builder::new(); + builder.add_type::(); + builder.add_type::(); let module = builder.finish(); // Build relative path from the codegen crate to the C++ Module Library autogen directory diff --git a/crates/codegen/src/cpp.rs b/crates/codegen/src/cpp.rs index f8ffe3b8931..45c4cd5b25f 100644 --- a/crates/codegen/src/cpp.rs +++ b/crates/codegen/src/cpp.rs @@ -277,7 +277,18 @@ impl<'opts> Cpp<'opts> { if let Some(_idx) = duplicate_index { // Found duplicate - create a wrapper struct to make it unique let wrapper_name = format!("{}_{}_Wrapper", type_name, variant_name); - writeln!(output, "struct {} {{ {} value; }};", wrapper_name, type_str).unwrap(); + let wrapper_macro = if self.namespace == "SpacetimeDB::Internal" { + "SPACETIMEDB_INTERNAL_PRODUCT_TYPE" + } else { + "SPACETIMEDB_PRODUCT_TYPE" + }; + writeln!(output, "{}({}) {{", wrapper_macro, wrapper_name).unwrap(); + writeln!(output, " {} value;", type_str).unwrap(); + writeln!(output, " void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const {{").unwrap(); + writeln!(output, " ::SpacetimeDB::bsatn::serialize(writer, value);").unwrap(); + writeln!(output, " }}").unwrap(); + writeln!(output, " SPACETIMEDB_PRODUCT_TYPE_EQUALITY(value)").unwrap(); + writeln!(output, "}};").unwrap(); variant_types.push(wrapper_name); } else { // No duplicate, use the type directly diff --git a/modules/sdk-test-cpp/src/lib.cpp b/modules/sdk-test-cpp/src/lib.cpp index 350a759e34c..18a093ec6f7 100644 --- a/modules/sdk-test-cpp/src/lib.cpp +++ b/modules/sdk-test-cpp/src/lib.cpp @@ -654,7 +654,7 @@ struct IndexedTable2 { }; SPACETIMEDB_STRUCT(IndexedTable2, player_id, player_snazz) SPACETIMEDB_TABLE(IndexedTable2, indexed_table_2, Private) // Remove constraint from table macro -// FIELD_NamedMultiColumnIndex(indexed_table_2, player_id_snazz_index, player_id, player_snazz); +FIELD_MultiColumnIndex(indexed_table_2, player_id_snazz_index, player_id, player_snazz); struct BTreeU32 { uint32_t n; @@ -2072,7 +2072,7 @@ SPACETIMEDB_REDUCER(send_scheduled_message, ReducerContext ctx, ScheduledTable a SPACETIMEDB_CLIENT_VISIBILITY_FILTER( one_u8_visible, - "SELECT * FROM one_u8" + "SELECT * FROM one_u_8" ) SPACETIMEDB_CLIENT_VISIBILITY_FILTER( @@ -2088,4 +2088,4 @@ SPACETIMEDB_REDUCER(no_op_succeeds, ReducerContext ctx) { LOG_INFO("No-op reducer executed successfully"); return Ok(); -} \ No newline at end of file +} diff --git a/sdks/rust/tests/connect_disconnect_client/src/module_bindings/mod.rs b/sdks/rust/tests/connect_disconnect_client/src/module_bindings/mod.rs index 90d0f869806..fcd85e7f5d0 100644 --- a/sdks/rust/tests/connect_disconnect_client/src/module_bindings/mod.rs +++ b/sdks/rust/tests/connect_disconnect_client/src/module_bindings/mod.rs @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 2.0.0 (commit 9e0e81a6aaec6bf3619cfb9f7916743d86ab7ffc). +// This was generated using spacetimedb cli version 2.0.0 (commit 85095cfa85e3addc29ce58bfe670b6003271b288). #![allow(unused, clippy::all)] use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; diff --git a/sdks/rust/tests/event-table-client/src/module_bindings/mod.rs b/sdks/rust/tests/event-table-client/src/module_bindings/mod.rs index 270a63fc8c2..76f5f7db170 100644 --- a/sdks/rust/tests/event-table-client/src/module_bindings/mod.rs +++ b/sdks/rust/tests/event-table-client/src/module_bindings/mod.rs @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 2.0.0 (commit f9ecae027971fa57c15a8a38f49d2df66ee48026). +// This was generated using spacetimedb cli version 2.0.0 (commit 85095cfa85e3addc29ce58bfe670b6003271b288). #![allow(unused, clippy::all)] use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; diff --git a/sdks/rust/tests/procedure-client/src/module_bindings/mod.rs b/sdks/rust/tests/procedure-client/src/module_bindings/mod.rs index 5a108fec382..e4e34268510 100644 --- a/sdks/rust/tests/procedure-client/src/module_bindings/mod.rs +++ b/sdks/rust/tests/procedure-client/src/module_bindings/mod.rs @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 2.0.0 (commit e528393902d8cc982769e3b1a0f250d7d53edfa1). +// This was generated using spacetimedb cli version 2.0.0 (commit 85095cfa85e3addc29ce58bfe670b6003271b288). #![allow(unused, clippy::all)] use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; diff --git a/sdks/rust/tests/test.rs b/sdks/rust/tests/test.rs index a430382c841..d6c5cac38ae 100644 --- a/sdks/rust/tests/test.rs +++ b/sdks/rust/tests/test.rs @@ -314,7 +314,7 @@ declare_tests_with_suffix!(rust, ""); declare_tests_with_suffix!(typescript, "-ts"); // TODO: migrate csharp to snake_case table names declare_tests_with_suffix!(csharp, "-cs"); -//declare_tests_with_suffix!(cpp, "-cpp"); +declare_tests_with_suffix!(cpp, "-cpp"); /// Tests of event table functionality, using <./event-table-client> and <../../../modules/sdk-test>. /// @@ -425,7 +425,7 @@ macro_rules! procedure_tests { procedure_tests!(rust_procedures, ""); procedure_tests!(typescript_procedures, "-ts"); -//procedure_tests!(cpp_procedures, "-cpp"); +procedure_tests!(cpp_procedures, "-cpp"); macro_rules! view_tests { ($mod_name:ident, $suffix:literal) => { @@ -487,4 +487,4 @@ macro_rules! view_tests { } view_tests!(rust_view, ""); -//view_tests!(cpp_view, "-cpp"); +view_tests!(cpp_view, "-cpp"); diff --git a/sdks/rust/tests/view-client/src/module_bindings/mod.rs b/sdks/rust/tests/view-client/src/module_bindings/mod.rs index 48c5151eee9..525e09f98b9 100644 --- a/sdks/rust/tests/view-client/src/module_bindings/mod.rs +++ b/sdks/rust/tests/view-client/src/module_bindings/mod.rs @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 2.0.0 (commit e528393902d8cc982769e3b1a0f250d7d53edfa1). +// This was generated using spacetimedb cli version 2.0.0 (commit 85095cfa85e3addc29ce58bfe670b6003271b288). #![allow(unused, clippy::all)] use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/BSATN/Core/sum_type.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/BSATN/Core/sum_type.h index 9f6bec90524..492901b8780 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/BSATN/Core/sum_type.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/BSATN/Core/sum_type.h @@ -125,9 +125,8 @@ struct bsatn_traits> { using sum_type = SumType; static AlgebraicType algebraic_type() { - // For now, return a string type as placeholder - // TODO: Implement proper sum type registration in V9TypeRegistration system - return AlgebraicType::String(); + // Reuse the canonical std::variant sum-shape implementation. + return bsatn_traits>::algebraic_type(); } }; @@ -178,4 +177,4 @@ Result Err(E&& error) { } // namespace SpacetimeDb -#endif // SPACETIMEDB_BSATN_SUM_TYPE_H \ No newline at end of file +#endif // SPACETIMEDB_BSATN_SUM_TYPE_H From bab6691d2b6a0924be6e28bce5d449c91d615795 Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Thu, 26 Feb 2026 14:33:37 -0800 Subject: [PATCH 02/15] Fix for linting --- crates/codegen/src/cpp.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/codegen/src/cpp.rs b/crates/codegen/src/cpp.rs index 45c4cd5b25f..3f20b4d271a 100644 --- a/crates/codegen/src/cpp.rs +++ b/crates/codegen/src/cpp.rs @@ -284,7 +284,11 @@ impl<'opts> Cpp<'opts> { }; writeln!(output, "{}({}) {{", wrapper_macro, wrapper_name).unwrap(); writeln!(output, " {} value;", type_str).unwrap(); - writeln!(output, " void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const {{").unwrap(); + writeln!( + output, + " void bsatn_serialize(::SpacetimeDB::bsatn::Writer& writer) const {{" + ) + .unwrap(); writeln!(output, " ::SpacetimeDB::bsatn::serialize(writer, value);").unwrap(); writeln!(output, " }}").unwrap(); writeln!(output, " SPACETIMEDB_PRODUCT_TYPE_EQUALITY(value)").unwrap(); From aa566a82bafb834321d1ea7bd164e760a42865ea Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Fri, 27 Feb 2026 10:27:11 -0800 Subject: [PATCH 03/15] Make event tables inaccessible from views --- .../include/spacetimedb/database.h | 18 ++--- .../spacetimedb/readonly_database_context.h | 26 ++++--- .../spacetimedb/table_with_constraints.h | 71 +++++++++---------- 3 files changed, 61 insertions(+), 54 deletions(-) diff --git a/crates/bindings-cpp/include/spacetimedb/database.h b/crates/bindings-cpp/include/spacetimedb/database.h index e6f80b93325..859a070c745 100644 --- a/crates/bindings-cpp/include/spacetimedb/database.h +++ b/crates/bindings-cpp/include/spacetimedb/database.h @@ -51,7 +51,7 @@ struct TableTag; // Forward declaration for field tags -template +template struct FieldTag; // Forward declarations for typed field accessors @@ -236,23 +236,23 @@ class DatabaseContext { // Field tag accessor - NEW: ctx.db[simple_table.id] syntax // Overloaded for each field constraint type - template - TypedPrimaryKeyAccessor operator[](const FieldTag& field_tag) const { + template + TypedPrimaryKeyAccessor operator[](const FieldTag& field_tag) const { return TypedPrimaryKeyAccessor(field_tag.table_name, field_tag.field_name, field_tag.member_ptr); } - template - TypedUniqueAccessor operator[](const FieldTag& field_tag) const { + template + TypedUniqueAccessor operator[](const FieldTag& field_tag) const { return TypedUniqueAccessor(field_tag.table_name, field_tag.field_name, field_tag.member_ptr); } - template - TypedIndexedAccessor operator[](const FieldTag& field_tag) const { + template + TypedIndexedAccessor operator[](const FieldTag& field_tag) const { return TypedIndexedAccessor(field_tag.table_name, field_tag.field_name, field_tag.member_ptr); } - template - TypedRegularAccessor operator[](const FieldTag& field_tag) const { + template + TypedRegularAccessor operator[](const FieldTag& field_tag) const { return TypedRegularAccessor(field_tag.table_name, field_tag.field_name, field_tag.member_ptr); } diff --git a/crates/bindings-cpp/include/spacetimedb/readonly_database_context.h b/crates/bindings-cpp/include/spacetimedb/readonly_database_context.h index bfda299b385..3e17c4cac68 100644 --- a/crates/bindings-cpp/include/spacetimedb/readonly_database_context.h +++ b/crates/bindings-cpp/include/spacetimedb/readonly_database_context.h @@ -58,36 +58,46 @@ class ReadOnlyDatabaseContext { // Tag-based accessor using operator[] (SpacetimeDB standard) template ReadOnlyTableAccessor operator[](const Tag&) const { + static_assert(!Tag::__is_event_internal, + "Event tables are not accessible from views."); return ReadOnlyTableAccessor(std::string(Tag::__table_name_internal)); } // Field tag accessors - read-only versions // These return read-only field accessors that only support querying, not mutation - template + template ReadOnlyPrimaryKeyAccessor operator[]( - const FieldTag& field_tag) const { + const FieldTag& field_tag) const { + static_assert(!IsEventTable, + "Event tables are not accessible from views."); return ReadOnlyPrimaryKeyAccessor( field_tag.table_name, field_tag.field_name, field_tag.member_ptr); } - template + template ReadOnlyUniqueAccessor operator[]( - const FieldTag& field_tag) const { + const FieldTag& field_tag) const { + static_assert(!IsEventTable, + "Event tables are not accessible from views."); return ReadOnlyUniqueAccessor( field_tag.table_name, field_tag.field_name, field_tag.member_ptr); } - template + template ReadOnlyIndexedAccessor operator[]( - const FieldTag& field_tag) const { + const FieldTag& field_tag) const { + static_assert(!IsEventTable, + "Event tables are not accessible from views."); return ReadOnlyIndexedAccessor( field_tag.table_name, field_tag.field_name, field_tag.member_ptr); } - template + template ReadOnlyRegularAccessor operator[]( - const FieldTag& field_tag) const { + const FieldTag& field_tag) const { + static_assert(!IsEventTable, + "Event tables are not accessible from views."); return ReadOnlyRegularAccessor( field_tag.table_name, field_tag.field_name, field_tag.member_ptr); } diff --git a/crates/bindings-cpp/include/spacetimedb/table_with_constraints.h b/crates/bindings-cpp/include/spacetimedb/table_with_constraints.h index ba3321f5e41..060667aa82b 100644 --- a/crates/bindings-cpp/include/spacetimedb/table_with_constraints.h +++ b/crates/bindings-cpp/include/spacetimedb/table_with_constraints.h @@ -59,23 +59,23 @@ namespace detail { const char* canonical_name = nullptr; }; - inline TableMacroOptions MakeTableMacroOptions() { + constexpr TableMacroOptions MakeTableMacroOptions() { return TableMacroOptions{}; } - inline TableMacroOptions MakeTableMacroOptions(bool is_event) { + constexpr TableMacroOptions MakeTableMacroOptions(bool is_event) { TableMacroOptions options; options.is_event = is_event; return options; } - inline TableMacroOptions MakeTableMacroOptions(const char* canonical_name) { + constexpr TableMacroOptions MakeTableMacroOptions(const char* canonical_name) { TableMacroOptions options; options.canonical_name = canonical_name; return options; } - inline TableMacroOptions MakeTableMacroOptions(bool is_event, const char* canonical_name) { + constexpr TableMacroOptions MakeTableMacroOptions(bool is_event, const char* canonical_name) { TableMacroOptions options; options.is_event = is_event; options.canonical_name = canonical_name; @@ -97,6 +97,7 @@ template struct TableTag { using type = T; static constexpr const char* name = nullptr; + static constexpr bool __is_event_internal = false; static std::vector get_constraints() { return {}; @@ -136,6 +137,7 @@ struct TableTag { } \ struct SPACETIMEDB_PASTE(table_name, _tag_type) : SpacetimeDB::TableTag { \ static constexpr const char* __table_name_internal = #table_name; \ + static constexpr bool __is_event_internal = (options_expr).is_event; \ }; \ constexpr SPACETIMEDB_PASTE(table_name, _tag_type) table_name{}; @@ -165,7 +167,7 @@ struct TableTag { // Field Tag System // ============================================================================= -template +template struct FieldTag { const char* field_name; const char* table_name; @@ -179,14 +181,14 @@ struct FieldTag { : field_name(field), table_name(table), member_ptr(ptr) {} }; -template -using PrimaryKeyFieldTag = FieldTag; +template +using PrimaryKeyFieldTag = FieldTag; -template -using UniqueFieldTag = FieldTag; +template +using UniqueFieldTag = FieldTag; -template -using IndexedFieldTag = FieldTag; +template +using IndexedFieldTag = FieldTag; // ============================================================================= // Multi-Column Index Tag System @@ -613,28 +615,17 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { if (cached_index_id_) { return *cached_index_id_; } - - // Try to resolve index with multiple name patterns - auto try_pattern = [this](const std::string& pattern) -> IndexId { - IndexId id; - if (is_ok(::index_id_from_name( - reinterpret_cast(pattern.data()), - pattern.length(), + + // Resolve by the deterministic generated source name + const std::string canonical_source_name = table_name_ + "_" + column_list_ + "_idx_btree"; + IndexId id{0}; + if (!is_ok(::index_id_from_name( + reinterpret_cast(canonical_source_name.data()), + canonical_source_name.length(), &id))) { - return id; - } - return IndexId{0}; - }; - - // Try patterns in order of likelihood - IndexId id = try_pattern(index_name_); // User accessor name - if (id.inner == 0) { - id = try_pattern(table_name_ + "_" + column_list_ + "_idx_btree"); // Database-generated + id = IndexId{0}; } - if (id.inner == 0) { - id = try_pattern(table_name_ + "_" + index_name_ + "_idx_btree"); // Accessor-based - } - + cached_index_id_ = id; return id; } @@ -716,7 +707,8 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { #define FIELD_PrimaryKey(table_name, field_name) \ static constexpr SpacetimeDB::PrimaryKeyFieldTag::type, \ - decltype(std::declval::type>().field_name)> \ + decltype(std::declval::type>().field_name), \ + SPACETIMEDB_PASTE(table_name, _tag_type)::__is_event_internal> \ table_name##_##field_name { #table_name, #field_name, &std::remove_cv_t::type::field_name }; \ extern "C" __attribute__((export_name("__preinit__21_field_constraint_" #table_name "_" #field_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ void SPACETIMEDB_PASTE(__preinit__21_field_constraint_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, SPACETIMEDB_PASTE(field_name, SPACETIMEDB_PASTE(_line_, __LINE__)))))() { \ @@ -733,7 +725,8 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { return true; \ }(), "Constraint validation for " #table_name "." #field_name); \ static constexpr SpacetimeDB::UniqueFieldTag::type, \ - decltype(std::declval::type>().field_name)> \ + decltype(std::declval::type>().field_name), \ + SPACETIMEDB_PASTE(table_name, _tag_type)::__is_event_internal> \ table_name##_##field_name { #table_name, #field_name, &std::remove_cv_t::type::field_name }; \ extern "C" __attribute__((export_name("__preinit__21_field_constraint_" #table_name "_" #field_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ void SPACETIMEDB_PASTE(__preinit__21_field_constraint_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, SPACETIMEDB_PASTE(field_name, SPACETIMEDB_PASTE(_line_, __LINE__)))))() { \ @@ -750,7 +743,8 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { return true; \ }(), "Constraint validation for " #table_name "." #field_name); \ static constexpr SpacetimeDB::IndexedFieldTag::type, \ - decltype(std::declval::type>().field_name)> \ + decltype(std::declval::type>().field_name), \ + SPACETIMEDB_PASTE(table_name, _tag_type)::__is_event_internal> \ table_name##_##field_name { #table_name, #field_name, &std::remove_cv_t::type::field_name }; \ extern "C" __attribute__((export_name("__preinit__21_field_constraint_" #table_name "_" #field_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ void SPACETIMEDB_PASTE(__preinit__21_field_constraint_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, SPACETIMEDB_PASTE(field_name, SPACETIMEDB_PASTE(_line_, __LINE__)))))() { \ @@ -767,7 +761,8 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { return true; \ }(), "AutoIncrement validation for " #table_name "." #field_name); \ static constexpr SpacetimeDB::PrimaryKeyFieldTag::type, \ - decltype(std::declval::type>().field_name)> \ + decltype(std::declval::type>().field_name), \ + SPACETIMEDB_PASTE(table_name, _tag_type)::__is_event_internal> \ table_name##_##field_name { #table_name, #field_name, &std::remove_cv_t::type::field_name }; \ extern "C" __attribute__((export_name("__preinit__21_field_constraint_" #table_name "_" #field_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ void SPACETIMEDB_PASTE(__preinit__21_field_constraint_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, SPACETIMEDB_PASTE(field_name, SPACETIMEDB_PASTE(_line_, __LINE__)))))() { \ @@ -788,7 +783,8 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { return true; \ }(), "Constraint validation for " #table_name "." #field_name); \ static constexpr SpacetimeDB::UniqueFieldTag::type, \ - decltype(std::declval::type>().field_name)> \ + decltype(std::declval::type>().field_name), \ + SPACETIMEDB_PASTE(table_name, _tag_type)::__is_event_internal> \ table_name##_##field_name { #table_name, #field_name, &std::remove_cv_t::type::field_name }; \ extern "C" __attribute__((export_name("__preinit__21_field_constraint_" #table_name "_" #field_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ void SPACETIMEDB_PASTE(__preinit__21_field_constraint_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, SPACETIMEDB_PASTE(field_name, SPACETIMEDB_PASTE(_line_, __LINE__)))))() { \ @@ -809,7 +805,8 @@ class TypedMultiColumnIndexAccessor : public TableAccessor { return true; \ }(), "Constraint validation for " #table_name "." #field_name); \ static constexpr SpacetimeDB::IndexedFieldTag::type, \ - decltype(std::declval::type>().field_name)> \ + decltype(std::declval::type>().field_name), \ + SPACETIMEDB_PASTE(table_name, _tag_type)::__is_event_internal> \ table_name##_##field_name { #table_name, #field_name, &std::remove_cv_t::type::field_name }; \ extern "C" __attribute__((export_name("__preinit__21_field_constraint_" #table_name "_" #field_name "_line_" SPACETIMEDB_STRINGIFY(__LINE__)))) \ void SPACETIMEDB_PASTE(__preinit__21_field_constraint_, SPACETIMEDB_PASTE(table_name, SPACETIMEDB_PASTE(_, SPACETIMEDB_PASTE(field_name, SPACETIMEDB_PASTE(_line_, __LINE__)))))() { \ From f71513b7946113d7904d2dfe380807db827a2dcd Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Thu, 26 Feb 2026 14:30:23 -0800 Subject: [PATCH 04/15] Unreal SDK update to websocket 2.0 for core sdk and tests --- crates/codegen/src/unrealcpp.rs | 374 +- sdks/unreal/DEVELOP.md | 56 +- .../Private/ChatClientActor.cpp | 4 +- .../ModuleBindings/SpacetimeDBClient.g.cpp | 241 +- .../QuickstartChatOptionalString.g.h | 2 +- .../Reducers/ClientConnected.g.h | 43 - .../Reducers/ClientDisconnected.g.h | 43 - .../ModuleBindings/SpacetimeDBClient.g.h | 271 +- .../ModuleBindings/Tables/UserTable.g.h | 2 +- .../Public/ModuleBindings/Types/UserType.g.h | 2 +- .../Private/Connection/DbConnectionBase.cpp | 938 ++-- .../Private/Connection/Websocket.cpp | 32 +- .../Private/Tests/SpacetimeDBBSATNTestOrg.cpp | 380 +- .../Public/BSATN/UEBSATNHelpers.h | 68 +- .../Public/Connection/Callback.h | 127 +- .../Public/Connection/DbConnectionBase.h | 235 +- .../Public/Connection/DbConnectionBuilder.h | 1 - .../Public/Connection/README.md | 13 +- .../Public/Connection/SetReducerFlags.h | 31 - .../Public/Connection/Subscription.h | 2 +- .../Public/Connection/Websocket.h | 18 +- ....h => SpacetimeDbSdkOptionalQueryRows.g.h} | 25 +- .../SpacetimeDbSdkResultQueryRowsString.g.h | 101 + .../Types/CallProcedureType.g.h | 22 +- .../ModuleBindings/Types/CallReducerType.g.h | 22 +- .../Types/ClientMessageType.g.h | 211 +- .../Types/CompressableQueryUpdateType.g.h | 187 - .../Types/DatabaseUpdateType.g.h | 46 - .../ModuleBindings/Types/EnergyQuantaType.g.h | 46 - .../Types/EventTableRowsType.g.h | 46 + .../Types/IdentityTokenType.g.h | 54 - .../Types/InitialConnectionType.g.h | 54 + .../Types/InitialSubscriptionType.g.h | 55 - .../Types/OneOffQueryResponseType.g.h | 60 - .../Types/OneOffQueryResultType.g.h | 51 + .../ModuleBindings/Types/OneOffQueryType.g.h | 10 +- .../ModuleBindings/Types/OneOffTableType.g.h | 50 - .../Types/PersistentTableRowsType.g.h | 50 + .../Types/ProcedureStatusType.g.h | 63 +- .../ModuleBindings/Types/QueryRowsType.g.h | 46 + .../{QueryIdType.g.h => QuerySetIdType.g.h} | 20 +- .../Types/QuerySetUpdateType.g.h | 51 + .../ModuleBindings/Types/QueryUpdateType.g.h | 50 - .../Types/ReducerCallInfoType.g.h | 57 - .../ModuleBindings/Types/ReducerOkType.g.h | 50 + .../Types/ReducerOutcomeType.g.h | 224 + .../Types/ReducerResultType.g.h | 55 + .../ModuleBindings/Types/RowSizeHintType.g.h | 4 +- .../Types/ServerMessageType.g.h | 301 +- .../Types/SingleTableRowsType.g.h | 50 + .../Types/SubscribeAppliedType.g.h | 18 +- .../Types/SubscribeMultiAppliedType.g.h | 59 - .../Types/SubscribeMultiType.g.h | 54 - .../Types/SubscribeRowsType.g.h | 54 - .../Types/SubscribeSingleType.g.h | 54 - .../ModuleBindings/Types/SubscribeType.g.h | 19 +- .../Types/SubscriptionErrorType.g.h | 21 +- .../Types/TableUpdateRowsType.g.h | 152 + .../ModuleBindings/Types/TableUpdateType.g.h | 20 +- .../Types/TransactionUpdateLightType.g.h | 50 - .../Types/TransactionUpdateType.g.h | 37 +- .../Types/UnsubscribeAppliedType.g.h | 19 +- .../Types/UnsubscribeFlagsType.g.h | 19 + .../Types/UnsubscribeMultiAppliedType.g.h | 59 - .../Types/UnsubscribeMultiType.g.h | 50 - .../ModuleBindings/Types/UnsubscribeType.g.h | 15 +- .../ModuleBindings/Types/UpdateStatusType.g.h | 188 - .../tests/TestClient/Config/DefaultEngine.ini | 2 +- .../ModuleBindings/SpacetimeDBClient.g.cpp | 3760 +++++------------ .../Private/Tests/CommonTestFunctions.cpp | 2 + ...TestClientOptionalEveryPrimitiveStruct.g.h | 2 +- .../Optionals/TestClientOptionalIdentity.g.h | 2 +- .../Optionals/TestClientOptionalInt32.g.h | 2 +- .../TestClientOptionalSimpleEnum.g.h | 2 +- .../Optionals/TestClientOptionalString.g.h | 2 +- .../Optionals/TestClientOptionalUuid.g.h | 2 +- .../TestClientOptionalVecOptionalInt32.g.h | 2 +- ...ClientResultEveryPrimitiveStructString.g.h | 4 +- .../TestClientResultIdentityString.g.h | 4 +- .../Results/TestClientResultInt32String.g.h | 4 +- .../TestClientResultSimpleEnumInt32.g.h | 4 +- .../Results/TestClientResultStringInt32.g.h | 4 +- .../TestClientResultVecInt32String.g.h | 4 +- .../ModuleBindings/SpacetimeDBClient.g.h | 693 +-- .../ModuleBindings/Tables/BtreeU32Table.g.h | 4 +- .../ModuleBindings/Tables/OneF32Table.g.h | 4 +- .../ModuleBindings/Tables/OneF64Table.g.h | 4 +- .../ModuleBindings/Tables/OneI128Table.g.h | 4 +- .../ModuleBindings/Tables/OneI16Table.g.h | 4 +- .../ModuleBindings/Tables/OneI256Table.g.h | 4 +- .../ModuleBindings/Tables/OneI32Table.g.h | 4 +- .../ModuleBindings/Tables/OneI64Table.g.h | 4 +- .../ModuleBindings/Tables/OneI8Table.g.h | 4 +- .../ModuleBindings/Tables/OneU128Table.g.h | 4 +- .../ModuleBindings/Tables/OneU16Table.g.h | 4 +- .../ModuleBindings/Tables/OneU256Table.g.h | 4 +- .../ModuleBindings/Tables/OneU32Table.g.h | 4 +- .../ModuleBindings/Tables/OneU64Table.g.h | 4 +- .../ModuleBindings/Tables/OneU8Table.g.h | 4 +- .../ModuleBindings/Tables/OptionI32Table.g.h | 4 +- .../Tables/OptionVecOptionI32Table.g.h | 4 +- .../ModuleBindings/Tables/PkI128Table.g.h | 4 +- .../ModuleBindings/Tables/PkI16Table.g.h | 4 +- .../ModuleBindings/Tables/PkI256Table.g.h | 4 +- .../ModuleBindings/Tables/PkI32Table.g.h | 4 +- .../ModuleBindings/Tables/PkI64Table.g.h | 4 +- .../ModuleBindings/Tables/PkI8Table.g.h | 4 +- .../ModuleBindings/Tables/PkU128Table.g.h | 4 +- .../ModuleBindings/Tables/PkU16Table.g.h | 4 +- .../ModuleBindings/Tables/PkU256Table.g.h | 4 +- .../ModuleBindings/Tables/PkU32Table.g.h | 4 +- .../ModuleBindings/Tables/PkU32TwoTable.g.h | 4 +- .../ModuleBindings/Tables/PkU64Table.g.h | 4 +- .../ModuleBindings/Tables/PkU8Table.g.h | 4 +- .../Tables/ResultI32StringTable.g.h | 4 +- .../Tables/ResultSimpleEnumI32Table.g.h | 4 +- .../Tables/ResultStringI32Table.g.h | 4 +- .../Tables/ResultVecI32StringTable.g.h | 4 +- .../ModuleBindings/Tables/UniqueI128Table.g.h | 4 +- .../ModuleBindings/Tables/UniqueI16Table.g.h | 4 +- .../ModuleBindings/Tables/UniqueI256Table.g.h | 4 +- .../ModuleBindings/Tables/UniqueI32Table.g.h | 4 +- .../ModuleBindings/Tables/UniqueI64Table.g.h | 4 +- .../ModuleBindings/Tables/UniqueI8Table.g.h | 4 +- .../ModuleBindings/Tables/UniqueU128Table.g.h | 4 +- .../ModuleBindings/Tables/UniqueU16Table.g.h | 4 +- .../ModuleBindings/Tables/UniqueU256Table.g.h | 4 +- .../ModuleBindings/Tables/UniqueU32Table.g.h | 4 +- .../ModuleBindings/Tables/UniqueU64Table.g.h | 4 +- .../ModuleBindings/Tables/UniqueU8Table.g.h | 4 +- .../ModuleBindings/Tables/VecF32Table.g.h | 4 +- .../ModuleBindings/Tables/VecF64Table.g.h | 4 +- .../ModuleBindings/Tables/VecI128Table.g.h | 4 +- .../ModuleBindings/Tables/VecI16Table.g.h | 4 +- .../ModuleBindings/Tables/VecI256Table.g.h | 4 +- .../ModuleBindings/Tables/VecI32Table.g.h | 4 +- .../ModuleBindings/Tables/VecI64Table.g.h | 4 +- .../ModuleBindings/Tables/VecI8Table.g.h | 4 +- .../ModuleBindings/Tables/VecU128Table.g.h | 4 +- .../ModuleBindings/Tables/VecU16Table.g.h | 4 +- .../ModuleBindings/Tables/VecU256Table.g.h | 4 +- .../ModuleBindings/Tables/VecU32Table.g.h | 4 +- .../ModuleBindings/Tables/VecU64Table.g.h | 4 +- .../ModuleBindings/Tables/VecU8Table.g.h | 4 +- .../Types/EnumWithPayloadType.g.h | 4 +- .../ModuleBindings/SpacetimeDBClient.g.cpp | 78 +- .../ModuleBindings/SpacetimeDBClient.g.h | 69 +- .../ModuleBindings/Types/ReturnEnumType.g.h | 2 +- 148 files changed, 4221 insertions(+), 6499 deletions(-) delete mode 100644 sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Reducers/ClientConnected.g.h delete mode 100644 sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Reducers/ClientDisconnected.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/SetReducerFlags.h rename sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Optionals/{SpacetimeDbSdkOptionalString.g.h => SpacetimeDbSdkOptionalQueryRows.g.h} (56%) create mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Results/SpacetimeDbSdkResultQueryRowsString.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/CompressableQueryUpdateType.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/DatabaseUpdateType.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/EnergyQuantaType.g.h create mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/EventTableRowsType.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/IdentityTokenType.g.h create mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/InitialConnectionType.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/InitialSubscriptionType.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/OneOffQueryResponseType.g.h create mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/OneOffQueryResultType.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/OneOffTableType.g.h create mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/PersistentTableRowsType.g.h create mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QueryRowsType.g.h rename sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/{QueryIdType.g.h => QuerySetIdType.g.h} (53%) create mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QuerySetUpdateType.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QueryUpdateType.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ReducerCallInfoType.g.h create mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ReducerOkType.g.h create mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ReducerOutcomeType.g.h create mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ReducerResultType.g.h create mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SingleTableRowsType.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeMultiAppliedType.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeMultiType.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeRowsType.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeSingleType.g.h create mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/TableUpdateRowsType.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/TransactionUpdateLightType.g.h create mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeFlagsType.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeMultiAppliedType.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeMultiType.g.h delete mode 100644 sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UpdateStatusType.g.h diff --git a/crates/codegen/src/unrealcpp.rs b/crates/codegen/src/unrealcpp.rs index c4b9fd81efb..ce233d995e7 100644 --- a/crates/codegen/src/unrealcpp.rs +++ b/crates/codegen/src/unrealcpp.rs @@ -330,18 +330,20 @@ impl Lang for UnrealCpp<'_> { writeln!(output, " const {row_struct}&, NewRow);"); writeln!(output); - writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams( "); - writeln!(output, " FOn{table_pascal}Update,"); - writeln!(output, " const FEventContext&, Context,"); - writeln!(output, " const {row_struct}&, OldRow,"); - writeln!(output, " const {row_struct}&, NewRow);"); - writeln!(output); + if !table.is_event { + writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams( "); + writeln!(output, " FOn{table_pascal}Update,"); + writeln!(output, " const FEventContext&, Context,"); + writeln!(output, " const {row_struct}&, OldRow,"); + writeln!(output, " const {row_struct}&, NewRow);"); + writeln!(output); - writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams( "); - writeln!(output, " FOn{table_pascal}Delete,"); - writeln!(output, " const FEventContext&, Context,"); - writeln!(output, " const {row_struct}&, DeletedRow);"); - writeln!(output); + writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams( "); + writeln!(output, " FOn{table_pascal}Delete,"); + writeln!(output, " const FEventContext&, Context,"); + writeln!(output, " const {row_struct}&, DeletedRow);"); + writeln!(output); + } writeln!( output, @@ -350,19 +352,21 @@ impl Lang for UnrealCpp<'_> { writeln!(output, " FOn{table_pascal}Insert OnInsert;"); writeln!(output); - writeln!( - output, - " UPROPERTY(BlueprintAssignable, Category = \"SpacetimeDB Events\")" - ); - writeln!(output, " FOn{table_pascal}Update OnUpdate;"); - writeln!(output); + if !table.is_event { + writeln!( + output, + " UPROPERTY(BlueprintAssignable, Category = \"SpacetimeDB Events\")" + ); + writeln!(output, " FOn{table_pascal}Update OnUpdate;"); + writeln!(output); - writeln!( - output, - " UPROPERTY(BlueprintAssignable, Category = \"SpacetimeDB Events\")" - ); - writeln!(output, " FOn{table_pascal}Delete OnDelete;"); - writeln!(output); + writeln!( + output, + " UPROPERTY(BlueprintAssignable, Category = \"SpacetimeDB Events\")" + ); + writeln!(output, " FOn{table_pascal}Delete OnDelete;"); + writeln!(output); + } writeln!(output, "private:"); writeln!(output, " const FString TableName = TEXT(\"{table_name}\");"); @@ -804,7 +808,6 @@ impl Lang for UnrealCpp<'_> { includes.insert("Connection/DbConnectionBase.h".to_string()); includes.insert("Connection/DbConnectionBuilder.h".to_string()); includes.insert("Connection/Subscription.h".to_string()); - includes.insert("Connection/SetReducerFlags.h".to_string()); includes.insert("Connection/Callback.h".to_string()); includes.insert("ModuleBindings/ReducerBase.g.h".to_string()); includes.insert("Kismet/BlueprintFunctionLibrary.h".to_string()); @@ -883,28 +886,6 @@ impl Lang for UnrealCpp<'_> { &self.module_name.to_case(Case::Pascal), ); - // SetReducerFlags class - inherits from USetReducerFlagsBase - writeln!(client_h, "UCLASS(BlueprintType)"); - writeln!( - client_h, - "class {} USetReducerFlags : public USetReducerFlagsBase", - self.get_api_macro() - ); - writeln!(client_h, "{{"); - writeln!(client_h, "\tGENERATED_BODY()"); - writeln!(client_h); - writeln!(client_h, "public:"); - - for reducer in iter_reducers(module, options.visibility) { - let reducer_pascal = reducer.name.deref().to_case(Case::Pascal); - writeln!(client_h, "\tUFUNCTION(BlueprintCallable, Category = \"SpacetimeDB\")"); - writeln!(client_h, "\tvoid {reducer_pascal}(ECallReducerFlags Flag);"); - } - - writeln!(client_h); - writeln!(client_h, "}};"); - writeln!(client_h); - // RemoteTables class generate_remote_tables_class(&mut client_h, module, options.visibility, &self.get_api_macro()); @@ -1172,24 +1153,38 @@ fn generate_table_cpp(module: &ModuleDef, table: &TableDef, module_name: &str, s "FTableAppliedDiff<{row_struct}> U{table_pascal}Table::Update(TArray> InsertsRef, TArray> DeletesRef)" ); writeln!(output, "{{"); - writeln!( - output, - " FTableAppliedDiff<{row_struct}> Diff = BaseUpdate<{row_struct}>(InsertsRef, DeletesRef, Data, TableName);" - ); + if table.is_event { + writeln!( + output, + " // Event tables are callback-only: do not persist rows in the local cache." + ); + writeln!(output, " FTableAppliedDiff<{row_struct}> Diff;"); + writeln!(output, " for (const FWithBsatn<{row_struct}>& Insert : InsertsRef)"); + writeln!(output, " {{"); + writeln!(output, " Diff.Inserts.Add(Insert.Bsatn, Insert.Row);"); + writeln!(output, " }}"); + } else { + writeln!( + output, + " FTableAppliedDiff<{row_struct}> Diff = BaseUpdate<{row_struct}>(InsertsRef, DeletesRef, Data, TableName);" + ); + } writeln!(output); - // Add DeriveUpdatesByPrimaryKey if table has a primary key - if let Some(pk) = schema.pk() { - let pk_field_name = pk.col_name.deref().to_case(Case::Pascal); - let pk_type = &product_type.unwrap().elements[pk.col_pos.idx()].1; - let pk_type_str = cpp_ty_fmt_with_module(module, pk_type, module_name).to_string(); - writeln!(output, " Diff.DeriveUpdatesByPrimaryKey<{pk_type_str}>("); - writeln!(output, " [](const {row_struct}& Row) "); - writeln!(output, " {{"); - writeln!(output, " return Row.{pk_field_name}; "); - writeln!(output, " }}"); - writeln!(output, " );"); - writeln!(output); + // Add DeriveUpdatesByPrimaryKey for persistent tables with a primary key. + if !table.is_event { + if let Some(pk) = schema.pk() { + let pk_field_name = pk.col_name.deref().to_case(Case::Pascal); + let pk_type = &product_type.unwrap().elements[pk.col_pos.idx()].1; + let pk_type_str = cpp_ty_fmt_with_module(module, pk_type, module_name).to_string(); + writeln!(output, " Diff.DeriveUpdatesByPrimaryKey<{pk_type_str}>("); + writeln!(output, " [](const {row_struct}& Row) "); + writeln!(output, " {{"); + writeln!(output, " return Row.{pk_field_name}; "); + writeln!(output, " }}"); + writeln!(output, " );"); + writeln!(output); + } } // Reset cache for indexes @@ -1266,7 +1261,7 @@ fn generate_context_structs( writeln!(output); writeln!( output, - "\tFContextBase() : Db(nullptr), Reducers(nullptr), SetReducerFlags(nullptr), Procedures(nullptr), Conn(nullptr) {{}};" + "\tFContextBase() : Db(nullptr), Reducers(nullptr), Procedures(nullptr), Conn(nullptr) {{}};" ); writeln!(output, "\tFContextBase(UDbConnection* InConn);"); writeln!(output); @@ -1277,9 +1272,6 @@ fn generate_context_structs( writeln!(output, "\tURemoteReducers* Reducers;"); writeln!(output); writeln!(output, "\tUPROPERTY(BlueprintReadOnly, Category = \"SpacetimeDB\")"); - writeln!(output, "\tUSetReducerFlags* SetReducerFlags;"); - writeln!(output); - writeln!(output, "\tUPROPERTY(BlueprintReadOnly, Category = \"SpacetimeDB\")"); writeln!(output, "\tURemoteProcedures* Procedures;"); writeln!(output); writeln!(output, "\tbool IsActive() const;"); @@ -1321,12 +1313,6 @@ fn generate_context_structs( "\tstatic URemoteReducers* GetReducers(const FContextBase& Ctx) {{ return Ctx.Reducers; }}" ); writeln!(output); - writeln!(output, "\tUFUNCTION(BlueprintPure, Category=\"SpacetimeDB\")"); - writeln!( - output, - "\tstatic USetReducerFlags* GetSetReducerFlags(const FContextBase& Ctx) {{ return Ctx.SetReducerFlags; }}" - ); - writeln!(output); writeln!( output, "\tstatic URemoteProcedures* GetProcedures(const FContextBase& Ctx) {{ return Ctx.Procedures; }}" @@ -1413,6 +1399,18 @@ fn generate_context_structs( writeln!(output, "\t}}"); writeln!(output); + writeln!( + output, + "\tstatic F{module_name}Event Transaction(const FSpacetimeDBUnit& Value)" + ); + writeln!(output, "\t{{"); + writeln!(output, "\t\tF{module_name}Event Obj;"); + writeln!(output, "\t\tObj.Tag = ESpacetimeDBEventTag::Transaction;"); + writeln!(output, "\t\tObj.MessageData.Set(Value);"); + writeln!(output, "\t\treturn Obj;"); + writeln!(output, "\t}}"); + writeln!(output); + writeln!( output, "\tstatic F{module_name}Event SubscribeError(const FString& Value)" @@ -1490,6 +1488,19 @@ fn generate_context_structs( writeln!(output, "\t\treturn MessageData.Get();"); writeln!(output, "\t}}"); writeln!(output); + writeln!( + output, + "\tFORCEINLINE bool IsTransaction() const {{ return Tag == ESpacetimeDBEventTag::Transaction; }}" + ); + writeln!(output, "\tFORCEINLINE FSpacetimeDBUnit GetAsTransaction() const"); + writeln!(output, "\t{{"); + writeln!( + output, + "\t\tensureMsgf(IsTransaction(), TEXT(\"MessageData does not hold Transaction!\"));" + ); + writeln!(output, "\t\treturn MessageData.Get();"); + writeln!(output, "\t}}"); + writeln!(output); writeln!( output, "\tFORCEINLINE bool IsSubscribeError() const {{ return Tag == ESpacetimeDBEventTag::SubscribeError; }}" @@ -1536,6 +1547,10 @@ fn generate_context_structs( output, "\t\tcase ESpacetimeDBEventTag::Disconnected: return GetAsDisconnected() == Other.GetAsDisconnected();" ); + writeln!( + output, + "\t\tcase ESpacetimeDBEventTag::Transaction: return GetAsTransaction() == Other.GetAsTransaction();" + ); writeln!( output, "\t\tcase ESpacetimeDBEventTag::SubscribeError: return GetAsSubscribeError() == Other.GetAsSubscribeError();" @@ -1626,6 +1641,20 @@ fn generate_context_structs( writeln!(output, " }}"); writeln!(output); + // Transaction + writeln!( + output, + " UFUNCTION(BlueprintCallable, Category = \"SpacetimeDB|{module_name}Event\")" + ); + writeln!( + output, + " static F{module_name}Event Transaction(const FSpacetimeDBUnit& InValue)" + ); + writeln!(output, " {{"); + writeln!(output, " return F{module_name}Event::Transaction(InValue);"); + writeln!(output, " }}"); + writeln!(output); + // SubscribeError writeln!( output, @@ -1663,6 +1692,7 @@ fn generate_context_structs( "SubscribeApplied", "UnsubscribeApplied", "Disconnected", + "Transaction", "SubscribeError", "UnknownTransaction", ] { @@ -1730,6 +1760,19 @@ fn generate_context_structs( writeln!(output, " }}"); writeln!(output); + writeln!( + output, + " UFUNCTION(BlueprintPure, Category = \"SpacetimeDB|{module_name}Event\")" + ); + writeln!( + output, + " static FSpacetimeDBUnit GetAsTransaction(const F{module_name}Event& Event)" + ); + writeln!(output, " {{"); + writeln!(output, " return Event.GetAsTransaction();"); + writeln!(output, " }}"); + writeln!(output); + writeln!( output, " UFUNCTION(BlueprintPure, Category = \"SpacetimeDB|{module_name}Event\")" @@ -2591,9 +2634,6 @@ fn generate_remote_reducers_class( writeln!(output); writeln!(output, " UPROPERTY()"); writeln!(output, " class UDbConnection* Conn;"); - writeln!(output); - writeln!(output, " UPROPERTY()"); - writeln!(output, " USetReducerFlags* SetCallReducerFlags;"); writeln!(output, "}};"); writeln!(output); } @@ -2914,9 +2954,6 @@ fn generate_db_connection_class(output: &mut UnrealCppAutogen, _module: &ModuleD writeln!(output, " URemoteReducers* Reducers;"); writeln!(output); writeln!(output, " UPROPERTY(BlueprintReadOnly, Category=\"SpacetimeDB\")"); - writeln!(output, " USetReducerFlags* SetReducerFlags;"); - writeln!(output); - writeln!(output, " UPROPERTY(BlueprintReadOnly, Category=\"SpacetimeDB\")"); writeln!(output, " URemoteProcedures* Procedures;"); writeln!(output); writeln!( @@ -3000,6 +3037,28 @@ fn generate_db_connection_class(output: &mut UnrealCppAutogen, _module: &ModuleD output, " virtual void ProcedureEventFailed(const FProcedureEvent& Event, const FString ErrorMessage) override;" ); + writeln!(output); + writeln!(output, " friend class URemoteReducers;"); + writeln!(output); + writeln!( + output, + " // Internal reducer correlation helpers (request_id -> typed reducer)" + ); + writeln!( + output, + " void RegisterPendingTypedReducer(uint32 RequestId, FReducer Reducer);" + ); + writeln!( + output, + " bool TryGetPendingTypedReducer(uint32 RequestId, FReducer& OutReducer) const;" + ); + writeln!( + output, + " bool TryTakePendingTypedReducer(uint32 RequestId, FReducer& OutReducer);" + ); + writeln!(output); + writeln!(output, "private:"); + writeln!(output, " TMap PendingTypedReducers;"); writeln!(output, "}};"); writeln!(output); } @@ -3010,42 +3069,12 @@ fn generate_client_implementation( visibility: CodegenVisibility, module_name: &str, ) { - // Helper: Decode reducer args into FReducer from either event types - writeln!(output, "static FReducer DecodeReducer(const FReducerEvent& Event)"); - writeln!(output, "{{"); - writeln!( - output, - " const FString& ReducerName = Event.ReducerCall.ReducerName;" - ); - writeln!(output); - - for reducer in iter_reducers(module, visibility) { - let reducer_name = reducer.name.deref(); - let reducer_pascal = reducer_name.to_case(Case::Pascal); - - writeln!(output, " if (ReducerName == TEXT(\"{reducer_name}\"))"); - writeln!(output, " {{"); - writeln!( - output, - " F{reducer_pascal}Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args);" - ); - writeln!(output, " return FReducer::{reducer_pascal}(Args);"); - writeln!(output, " }}"); - writeln!(output); - } - - writeln!(output, " return FReducer();"); - writeln!(output, "}}"); - writeln!(output); - // UDbConnection constructor writeln!( output, "UDbConnection::UDbConnection(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)" ); writeln!(output, "{{"); - writeln!(output, "\tSetReducerFlags = ObjectInitializer.CreateDefaultSubobject(this, TEXT(\"SetReducerFlags\"));"); - writeln!(output); writeln!( output, "\tDb = ObjectInitializer.CreateDefaultSubobject(this, TEXT(\"RemoteTables\"));" @@ -3056,7 +3085,6 @@ fn generate_client_implementation( output, "\tReducers = ObjectInitializer.CreateDefaultSubobject(this, TEXT(\"RemoteReducers\"));" ); - writeln!(output, "\tReducers->SetCallReducerFlags = SetReducerFlags;"); writeln!(output, "\tReducers->Conn = this;"); writeln!(output); writeln!( @@ -3086,7 +3114,6 @@ fn generate_client_implementation( writeln!(output, "{{"); writeln!(output, "\tDb = InConn->Db;"); writeln!(output, "\tReducers = InConn->Reducers;"); - writeln!(output, "\tSetReducerFlags = InConn->SetReducerFlags;"); writeln!(output, "\tProcedures = InConn->Procedures;"); writeln!(output, "\tConn = InConn;"); writeln!(output, "}}"); @@ -3144,19 +3171,6 @@ fn generate_client_implementation( writeln!(output, "}}"); writeln!(output); - // USetReducerFlags methods - for reducer in iter_reducers(module, visibility) { - let reducer_pascal = reducer.name.deref().to_case(Case::Pascal); - writeln!( - output, - "void USetReducerFlags::{reducer_pascal}(ECallReducerFlags Flag)" - ); - writeln!(output, "{{"); - writeln!(output, "\tFlagMap.Add(\"{reducer_pascal}\", Flag);"); - writeln!(output, "}}"); - } - writeln!(output); - generate_remote_reducer_calls(output, module, visibility, module_name); generate_remote_procedure_calls(output, module, visibility, module_name); @@ -3213,14 +3227,69 @@ fn generate_client_implementation( writeln!(output, "}}"); writeln!(output); + writeln!( + output, + "void UDbConnection::RegisterPendingTypedReducer(uint32 RequestId, FReducer Reducer)" + ); + writeln!(output, "{{"); + writeln!(output, " Reducer.RequestId = RequestId;"); + writeln!(output, " PendingTypedReducers.Add(RequestId, MoveTemp(Reducer));"); + writeln!(output, "}}"); + writeln!(output); + writeln!( + output, + "bool UDbConnection::TryGetPendingTypedReducer(uint32 RequestId, FReducer& OutReducer) const" + ); + writeln!(output, "{{"); + writeln!( + output, + " if (const FReducer* Found = PendingTypedReducers.Find(RequestId))" + ); + writeln!(output, " {{"); + writeln!(output, " OutReducer = *Found;"); + writeln!(output, " return true;"); + writeln!(output, " }}"); + writeln!(output, " return false;"); + writeln!(output, "}}"); + writeln!(output); + writeln!( + output, + "bool UDbConnection::TryTakePendingTypedReducer(uint32 RequestId, FReducer& OutReducer)" + ); + writeln!(output, "{{"); + writeln!( + output, + " if (FReducer* Found = PendingTypedReducers.Find(RequestId))" + ); + writeln!(output, " {{"); + writeln!(output, " OutReducer = *Found;"); + writeln!(output, " PendingTypedReducers.Remove(RequestId);"); + writeln!(output, " return true;"); + writeln!(output, " }}"); + writeln!(output, " return false;"); + writeln!(output, "}}"); + writeln!(output); + // ReducerEvent method implementation writeln!(output, "void UDbConnection::ReducerEvent(const FReducerEvent& Event)"); writeln!(output, "{{"); writeln!(output, " if (!Reducers) {{ return; }}"); writeln!(output); - // Decode reducer call args - writeln!(output, " FReducer DecodedReducer = DecodeReducer(Event);"); + writeln!(output, " FReducer DecodedReducer;"); + writeln!( + output, + " if (!TryTakePendingTypedReducer(Event.RequestId, DecodedReducer))" + ); + writeln!(output, " {{"); + writeln!( + output, + " const FString ErrorMessage = FString::Printf(TEXT(\"Reducer result for unknown request_id %u\"), Event.RequestId);" + ); + writeln!(output, " UE_LOG(LogTemp, Error, TEXT(\"%s\"), *ErrorMessage);"); + writeln!(output, " ReducerEventFailed(Event, ErrorMessage);"); + writeln!(output, " return;"); + writeln!(output, " }}"); writeln!(output); let module_name_pascal = module_name.to_case(Case::Pascal); @@ -3239,10 +3308,10 @@ fn generate_client_implementation( writeln!(output, " FReducerEventContext Context(this, ReducerEvent);"); writeln!(output); - writeln!(output, " // Use hardcoded string matching for reducer dispatching"); + writeln!(output, " // Dispatch by typed reducer metadata"); writeln!( output, - " const FString& ReducerName = Event.ReducerCall.ReducerName;" + " const FString& ReducerName = ReducerEvent.Reducer.ReducerName;" ); writeln!(output); @@ -3575,7 +3644,22 @@ fn generate_client_implementation( writeln!(output, " case ESpacetimeDBEventTag::Reducer:"); writeln!(output, " {{"); writeln!(output, " FReducerEvent ReducerEvent = Event.GetAsReducer();"); - writeln!(output, " FReducer Reducer = DecodeReducer(ReducerEvent);"); + writeln!(output, " FReducer Reducer;"); + writeln!( + output, + " if (!TryGetPendingTypedReducer(ReducerEvent.RequestId, Reducer))" + ); + writeln!(output, " {{"); + writeln!( + output, + " UE_LOG(LogTemp, Warning, TEXT(\"Missing typed reducer for request_id %u while building table-update event context; using UnknownTransaction event\"), ReducerEvent.RequestId);" + ); + writeln!( + output, + " BaseEvent = F{module_name_pascal}Event::UnknownTransaction(FSpacetimeDBUnit());" + ); + writeln!(output, " break;"); + writeln!(output, " }}"); writeln!( output, " BaseEvent = F{module_name_pascal}Event::Reducer(Reducer);" @@ -3609,6 +3693,14 @@ fn generate_client_implementation( writeln!(output, " break;"); writeln!(output); + writeln!(output, " case ESpacetimeDBEventTag::Transaction:"); + writeln!( + output, + " BaseEvent = F{module_name_pascal}Event::Transaction(Event.GetAsTransaction());" + ); + writeln!(output, " break;"); + writeln!(output); + writeln!(output, " case ESpacetimeDBEventTag::SubscribeError:"); writeln!( output, @@ -3696,15 +3788,17 @@ fn generate_remote_reducer_calls( writeln!(output); // Call reducer using typed helper to hide serialization if reducer.params_for_generate.elements.is_empty() { + writeln!(output, "\tF{reducer_pascal}Args ReducerArgs;"); writeln!( output, - "\tConn->CallReducerTyped(TEXT(\"{reducer_snake}\"), F{reducer_pascal}Args(), SetCallReducerFlags);" + "\tconst uint32 RequestId = Conn->CallReducerTyped(TEXT(\"{reducer_snake}\"), ReducerArgs);" ); - } else { - write!( + writeln!( output, - "\tConn->CallReducerTyped(TEXT(\"{reducer_snake}\"), F{reducer_pascal}Args(" + "\tif (RequestId != 0) {{ Conn->RegisterPendingTypedReducer(RequestId, FReducer::{reducer_pascal}(ReducerArgs)); }}" ); + } else { + write!(output, "\tF{reducer_pascal}Args ReducerArgs("); let mut first = true; for (param_name, _) in &reducer.params_for_generate.elements { if !first { @@ -3714,7 +3808,15 @@ fn generate_remote_reducer_calls( let param_pascal = param_name.deref().to_case(Case::Pascal); write!(output, "{param_pascal}"); } - writeln!(output, "), SetCallReducerFlags);"); + writeln!(output, ");"); + writeln!( + output, + "\tconst uint32 RequestId = Conn->CallReducerTyped(TEXT(\"{reducer_snake}\"), ReducerArgs);" + ); + writeln!( + output, + "\tif (RequestId != 0) {{ Conn->RegisterPendingTypedReducer(RequestId, FReducer::{reducer_pascal}(ReducerArgs)); }}" + ); } writeln!(output, "}}"); writeln!(output); @@ -4417,7 +4519,7 @@ fn generate_optional_type(optional_name: &str, module: &ModuleDef, api_macro: &s "// NOTE: {cpp_inner_type} field not exposed to Blueprint due to non-blueprintable elements" ); } - writeln!(output, "{cpp_inner_type} Value;"); + writeln!(output, "{cpp_inner_type} Value = {{}};"); writeln!(output); // Constructors @@ -4594,7 +4696,7 @@ fn generate_result_type( "// NOTE: {cpp_ok_type} field not exposed to Blueprint due to non-blueprintable type" ); } - writeln!(output, "{cpp_ok_type} OkValue;"); + writeln!(output, "{cpp_ok_type} OkValue = {{}};"); writeln!(output); // The err value @@ -4607,7 +4709,7 @@ fn generate_result_type( "// NOTE: {cpp_err_type} field not exposed to Blueprint due to non-blueprintable type" ); } - writeln!(output, "{cpp_err_type} ErrValue;"); + writeln!(output, "{cpp_err_type} ErrValue = {{}};"); writeln!(output); // Constructors diff --git a/sdks/unreal/DEVELOP.md b/sdks/unreal/DEVELOP.md index ceb414e35cf..8fd9925fafe 100644 --- a/sdks/unreal/DEVELOP.md +++ b/sdks/unreal/DEVELOP.md @@ -1,14 +1,52 @@ # Notes for maintainers -The directory `sdk-unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings` is generated from [the SpacetimeDB client-api-messages](https://github.com/clockworklabs/SpacetimeDB/tree/master/crates/client-api-messages). -This is not automated. -Whenever the `client-api-messages` crate changes, you'll have to manually re-generate the definitions. -See that crate's DEVELOP.md for how to do this. - -**⚠️ IMPORTANT:** The following files/folders needs to be deleted everytime we re-generate: -- `crates/sdk-unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Private/ModuleBindings` -- `crates/sdk-unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/ReducerBase.g.h` -- `crates/sdk-unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/SpacetimeDBClient.g.h` +The generated Unreal bindings under: + +- `sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings` +- `sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Private/ModuleBindings` + +come from SpacetimeDB codegen (`--lang unrealcpp`) and websocket schema definitions in `crates/client-api-messages`. + +This is not automated; regenerate manually whenever websocket message schemas or Unreal codegen behavior changes. + +## WS v2 websocket schema regeneration workflow + +Run from repo root: + +```powershell +# 1) Produce WS v2 schema JSON from canonical source +cargo run -p spacetimedb-client-api-messages --example get_ws_schema_v2 > crates/client-api-messages/ws_schema_v2.json + +# 2) Regenerate Unreal bindings from WS v2 schema +cargo run -p spacetimedb-cli -- generate --lang unrealcpp ` + --module-def crates/client-api-messages/ws_schema_v2.json ` + --uproject-dir sdks/unreal/src/SpacetimeDbSdk ` + --unreal-module-name SpacetimeDbSdk ` + --yes +``` + +## Cleanup before regeneration + +Delete these generated paths before rerunning generation when schema/model changes are significant: + +- `sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Private/ModuleBindings` +- `sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/ReducerBase.g.h` +- `sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/SpacetimeDBClient.g.h` +- `sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Private/ModuleBindings/SpacetimeDBClient.g.cpp` + +This avoids UnrealHeaderTool duplicate symbol/header conflicts with the `sdks/unreal/tests/TestClient` generated module bindings. + +## Fast validation loop + +For rapid iteration, run a single Unreal harness test instead of the full suite: + +```powershell +cargo test -p sdk-unreal-test-harness --test test insert_primitive -- --nocapture +``` + +Prerequisite: + +- `UE_ROOT_PATH` must point to the Unreal Engine install root (for example `C:/Program Files/Epic Games/UE_5.6`). # How to use AdditionalPluginDirectories diff --git a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Private/ChatClientActor.cpp b/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Private/ChatClientActor.cpp index d564d0d51bc..d57ea035022 100644 --- a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Private/ChatClientActor.cpp +++ b/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Private/ChatClientActor.cpp @@ -90,11 +90,9 @@ void AChatClientActor::RegisterCallbacks() // Conn->Db->Message->OnDelete.RemoveAll(this); // UNBIND_DELEGATE_SAFE(Conn->Db->Message->OnDelete, this, AChatClientActor, OnMessageDelete); - // Opt in to receive the reducer result and any table updates - Conn->SetReducerFlags->SendMessage(ECallReducerFlags::FullUpdate); + // Bind reducer callbacks. Conn->Reducers->OnSendMessage.AddDynamic(this, &AChatClientActor::OnReducerOnSendMessage); - Conn->SetReducerFlags->SetName(ECallReducerFlags::FullUpdate); Conn->Reducers->OnSetName.AddDynamic(this, &AChatClientActor::OnReducerOnSetName); // Hook error delegate for any reducers without explicit bindings diff --git a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Private/ModuleBindings/SpacetimeDBClient.g.cpp b/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Private/ModuleBindings/SpacetimeDBClient.g.cpp index e5884473df4..0b792c07051 100644 --- a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Private/ModuleBindings/SpacetimeDBClient.g.cpp +++ b/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Private/ModuleBindings/SpacetimeDBClient.g.cpp @@ -4,60 +4,29 @@ #include "ModuleBindings/SpacetimeDBClient.g.h" #include "DBCache/WithBsatn.h" #include "BSATN/UEBSATNHelpers.h" -#include "ModuleBindings/Tables/UserTable.g.h" #include "ModuleBindings/Tables/MessageTable.g.h" - -static FReducer DecodeReducer(const FReducerEvent& Event) -{ - const FString& ReducerName = Event.ReducerCall.ReducerName; - - if (ReducerName == TEXT("ClientConnected")) - { - FClientConnectedArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::ClientConnected(Args); - } - - if (ReducerName == TEXT("ClientDisconnected")) - { - FClientDisconnectedArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::ClientDisconnected(Args); - } - - if (ReducerName == TEXT("SendMessage")) - { - FSendMessageArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::SendMessage(Args); - } - - if (ReducerName == TEXT("SetName")) - { - FSetNameArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::SetName(Args); - } - - return FReducer(); -} +#include "ModuleBindings/Tables/UserTable.g.h" UDbConnection::UDbConnection(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { - SetReducerFlags = ObjectInitializer.CreateDefaultSubobject(this, TEXT("SetReducerFlags")); - Db = ObjectInitializer.CreateDefaultSubobject(this, TEXT("RemoteTables")); Db->Initialize(); Reducers = ObjectInitializer.CreateDefaultSubobject(this, TEXT("RemoteReducers")); - Reducers->SetCallReducerFlags = SetReducerFlags; Reducers->Conn = this; - RegisterTable(TEXT("user"), Db->User); + Procedures = ObjectInitializer.CreateDefaultSubobject(this, TEXT("RemoteProcedures")); + Procedures->Conn = this; + RegisterTable(TEXT("message"), Db->Message); + RegisterTable(TEXT("user"), Db->User); } FContextBase::FContextBase(UDbConnection* InConn) { Db = InConn->Db; Reducers = InConn->Reducers; - SetReducerFlags = InConn->SetReducerFlags; + Procedures = InConn->Procedures; Conn = InConn; } bool FContextBase::IsActive() const @@ -85,34 +54,17 @@ void URemoteTables::Initialize() { /** Creating tables */ - User = NewObject(this); Message = NewObject(this); + User = NewObject(this); /**/ /** Initialization */ - User->PostInitialize(); Message->PostInitialize(); + User->PostInitialize(); /**/ } -void USetReducerFlags::ClientConnected(ECallReducerFlags Flag) -{ - FlagMap.Add("ClientConnected", Flag); -} -void USetReducerFlags::ClientDisconnected(ECallReducerFlags Flag) -{ - FlagMap.Add("ClientDisconnected", Flag); -} -void USetReducerFlags::SendMessage(ECallReducerFlags Flag) -{ - FlagMap.Add("SendMessage", Flag); -} -void USetReducerFlags::SetName(ECallReducerFlags Flag) -{ - FlagMap.Add("SetName", Flag); -} - -void URemoteReducers::ClientConnected() +void URemoteReducers::SendMessage(const FString& Text) { if (!Conn) { @@ -120,57 +72,45 @@ void URemoteReducers::ClientConnected() return; } - Conn->CallReducerTyped(TEXT("ClientConnected"), FClientConnectedArgs(), SetCallReducerFlags); + FSendMessageArgs ReducerArgs(Text); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("send_message"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::SendMessage(ReducerArgs)); } } -bool URemoteReducers::InvokeClientConnected(const FReducerEventContext& Context, const UClientConnectedReducer* Args) +bool URemoteReducers::InvokeSendMessage(const FReducerEventContext& Context, const USendMessageReducer* Args) { - if (!OnClientConnected.IsBound()) + if (!OnSendMessage.IsBound()) { // Handle unhandled reducer error if (InternalOnUnhandledReducerError.IsBound()) { // TODO: Check Context.Event.Status for Failed/OutOfEnergy cases // For now, just broadcast any error - InternalOnUnhandledReducerError.Broadcast(Context, TEXT("No handler registered for ClientConnected")); + InternalOnUnhandledReducerError.Broadcast(Context, TEXT("No handler registered for SendMessage")); } return false; } - OnClientConnected.Broadcast(Context); + OnSendMessage.Broadcast(Context, Args->Text); return true; } -void URemoteReducers::ClientDisconnected() -{ - if (!Conn) - { - UE_LOG(LogTemp, Error, TEXT("SpacetimeDB connection is null")); - return; - } - - Conn->CallReducerTyped(TEXT("ClientDisconnected"), FClientDisconnectedArgs(), SetCallReducerFlags); -} - -bool URemoteReducers::InvokeClientDisconnected(const FReducerEventContext& Context, const UClientDisconnectedReducer* Args) +bool URemoteReducers::InvokeSendMessageWithArgs(const FReducerEventContext& Context, const FSendMessageArgs& Args) { - if (!OnClientDisconnected.IsBound()) + if (!OnSendMessage.IsBound()) { - // Handle unhandled reducer error if (InternalOnUnhandledReducerError.IsBound()) { - // TODO: Check Context.Event.Status for Failed/OutOfEnergy cases - // For now, just broadcast any error - InternalOnUnhandledReducerError.Broadcast(Context, TEXT("No handler registered for ClientDisconnected")); + InternalOnUnhandledReducerError.Broadcast(Context, TEXT("No handler registered for SendMessage")); } return false; } - OnClientDisconnected.Broadcast(Context); + OnSendMessage.Broadcast(Context, Args.Text); return true; } -void URemoteReducers::SendMessage(const FString& Text) +void URemoteReducers::SetName(const FString& Name) { if (!Conn) { @@ -178,53 +118,41 @@ void URemoteReducers::SendMessage(const FString& Text) return; } - Conn->CallReducerTyped(TEXT("SendMessage"), FSendMessageArgs(Text), SetCallReducerFlags); + FSetNameArgs ReducerArgs(Name); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("set_name"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::SetName(ReducerArgs)); } } -bool URemoteReducers::InvokeSendMessage(const FReducerEventContext& Context, const USendMessageReducer* Args) +bool URemoteReducers::InvokeSetName(const FReducerEventContext& Context, const USetNameReducer* Args) { - if (!OnSendMessage.IsBound()) + if (!OnSetName.IsBound()) { // Handle unhandled reducer error if (InternalOnUnhandledReducerError.IsBound()) { // TODO: Check Context.Event.Status for Failed/OutOfEnergy cases // For now, just broadcast any error - InternalOnUnhandledReducerError.Broadcast(Context, TEXT("No handler registered for SendMessage")); + InternalOnUnhandledReducerError.Broadcast(Context, TEXT("No handler registered for SetName")); } return false; } - OnSendMessage.Broadcast(Context, Args->Text); + OnSetName.Broadcast(Context, Args->Name); return true; } -void URemoteReducers::SetName(const FString& Name) -{ - if (!Conn) - { - UE_LOG(LogTemp, Error, TEXT("SpacetimeDB connection is null")); - return; - } - - Conn->CallReducerTyped(TEXT("SetName"), FSetNameArgs(Name), SetCallReducerFlags); -} - -bool URemoteReducers::InvokeSetName(const FReducerEventContext& Context, const USetNameReducer* Args) +bool URemoteReducers::InvokeSetNameWithArgs(const FReducerEventContext& Context, const FSetNameArgs& Args) { if (!OnSetName.IsBound()) { - // Handle unhandled reducer error if (InternalOnUnhandledReducerError.IsBound()) { - // TODO: Check Context.Event.Status for Failed/OutOfEnergy cases - // For now, just broadcast any error InternalOnUnhandledReducerError.Broadcast(Context, TEXT("No handler registered for SetName")); } return false; } - OnSetName.Broadcast(Context, Args->Name); + OnSetName.Broadcast(Context, Args.Name); return true; } @@ -237,6 +165,12 @@ void UDbConnection::PostInitProperties() { Reducers->InternalOnUnhandledReducerError.AddDynamic(this, &UDbConnection::OnUnhandledReducerErrorHandler); } + + // Connect OnUnhandledProcedureError to Procedures.InternalOnUnhandledProcedureError + if (Procedures) + { + Procedures->InternalOnUnhandledProcedureError.AddDynamic(this, &UDbConnection::OnUnhandledProcedureErrorHandler); + } } UFUNCTION() @@ -248,11 +182,54 @@ void UDbConnection::OnUnhandledReducerErrorHandler(const FReducerEventContext& C } } +UFUNCTION() +void UDbConnection::OnUnhandledProcedureErrorHandler(const FProcedureEventContext& Context, const FString& Error) +{ + if (OnUnhandledProcedureError.IsBound()) + { + OnUnhandledProcedureError.Broadcast(Context, Error); + } +} + +void UDbConnection::RegisterPendingTypedReducer(uint32 RequestId, FReducer Reducer) +{ + Reducer.RequestId = RequestId; + PendingTypedReducers.Add(RequestId, MoveTemp(Reducer)); +} + +bool UDbConnection::TryGetPendingTypedReducer(uint32 RequestId, FReducer& OutReducer) const +{ + if (const FReducer* Found = PendingTypedReducers.Find(RequestId)) + { + OutReducer = *Found; + return true; + } + return false; +} + +bool UDbConnection::TryTakePendingTypedReducer(uint32 RequestId, FReducer& OutReducer) +{ + if (FReducer* Found = PendingTypedReducers.Find(RequestId)) + { + OutReducer = *Found; + PendingTypedReducers.Remove(RequestId); + return true; + } + return false; +} + void UDbConnection::ReducerEvent(const FReducerEvent& Event) { if (!Reducers) { return; } - FReducer DecodedReducer = DecodeReducer(Event); + FReducer DecodedReducer; + if (!TryTakePendingTypedReducer(Event.RequestId, DecodedReducer)) + { + const FString ErrorMessage = FString::Printf(TEXT("Reducer result for unknown request_id %u"), Event.RequestId); + UE_LOG(LogTemp, Error, TEXT("%s"), *ErrorMessage); + ReducerEventFailed(Event, ErrorMessage); + return; + } FQuickstartChatReducerEvent ReducerEvent; ReducerEvent.CallerConnectionId = Event.CallerConnectionId; @@ -264,37 +241,19 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) FReducerEventContext Context(this, ReducerEvent); - // Use hardcoded string matching for reducer dispatching - const FString& ReducerName = Event.ReducerCall.ReducerName; + // Dispatch by typed reducer metadata + const FString& ReducerName = ReducerEvent.Reducer.ReducerName; - if (ReducerName == TEXT("ClientConnected")) - { - FClientConnectedArgs Args = ReducerEvent.Reducer.GetAsClientConnected(); - UClientConnectedReducer* Reducer = NewObject(); - Reducers->InvokeClientConnected(Context, Reducer); - return; - } - if (ReducerName == TEXT("ClientDisconnected")) - { - FClientDisconnectedArgs Args = ReducerEvent.Reducer.GetAsClientDisconnected(); - UClientDisconnectedReducer* Reducer = NewObject(); - Reducers->InvokeClientDisconnected(Context, Reducer); - return; - } - if (ReducerName == TEXT("SendMessage")) + if (ReducerName == TEXT("send_message")) { FSendMessageArgs Args = ReducerEvent.Reducer.GetAsSendMessage(); - USendMessageReducer* Reducer = NewObject(); - Reducer->Text = Args.Text; - Reducers->InvokeSendMessage(Context, Reducer); + Reducers->InvokeSendMessageWithArgs(Context, Args); return; } - if (ReducerName == TEXT("SetName")) + if (ReducerName == TEXT("set_name")) { FSetNameArgs Args = ReducerEvent.Reducer.GetAsSetName(); - USetNameReducer* Reducer = NewObject(); - Reducer->Name = Args.Name; - Reducers->InvokeSetName(Context, Reducer); + Reducers->InvokeSetNameWithArgs(Context, Args); return; } @@ -320,6 +279,22 @@ void UDbConnection::ReducerEventFailed(const FReducerEvent& Event, const FString } } +void UDbConnection::ProcedureEventFailed(const FProcedureEvent& Event, const FString ErrorMessage) +{ + if (!Procedures) { return; } + + FQuickstartChatProcedureEvent ProcedureEvent; + ProcedureEvent.Status = FSpacetimeDBProcedureStatus::FromStatus(Event.Status); + ProcedureEvent.Timestamp = Event.Timestamp; + + FProcedureEventContext Context(this, ProcedureEvent); + + if (Procedures->InternalOnUnhandledProcedureError.IsBound()) + { + Procedures->InternalOnUnhandledProcedureError.Broadcast(Context, ErrorMessage); + } +} + UDbConnectionBuilder* UDbConnection::Builder() { return NewObject(); @@ -473,7 +448,13 @@ void UDbConnection::DbUpdate(const FDatabaseUpdateType& Update, const FSpacetime case ESpacetimeDBEventTag::Reducer: { FReducerEvent ReducerEvent = Event.GetAsReducer(); - FReducer Reducer = DecodeReducer(ReducerEvent); + FReducer Reducer; + if (!TryGetPendingTypedReducer(ReducerEvent.RequestId, Reducer)) + { + UE_LOG(LogTemp, Warning, TEXT("Missing typed reducer for request_id %u while building table-update event context; using UnknownTransaction event"), ReducerEvent.RequestId); + BaseEvent = FQuickstartChatEvent::UnknownTransaction(FSpacetimeDBUnit()); + break; + } BaseEvent = FQuickstartChatEvent::Reducer(Reducer); break; } @@ -490,6 +471,10 @@ void UDbConnection::DbUpdate(const FDatabaseUpdateType& Update, const FSpacetime BaseEvent = FQuickstartChatEvent::Disconnected(Event.GetAsDisconnected()); break; + case ESpacetimeDBEventTag::Transaction: + BaseEvent = FQuickstartChatEvent::Transaction(Event.GetAsTransaction()); + break; + case ESpacetimeDBEventTag::SubscribeError: BaseEvent = FQuickstartChatEvent::SubscribeError(Event.GetAsSubscribeError()); break; diff --git a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Optionals/QuickstartChatOptionalString.g.h b/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Optionals/QuickstartChatOptionalString.g.h index 3d9a1d9b368..b16ee691e59 100644 --- a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Optionals/QuickstartChatOptionalString.g.h +++ b/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Optionals/QuickstartChatOptionalString.g.h @@ -15,7 +15,7 @@ struct QUICKSTARTCHAT_API FQuickstartChatOptionalString bool bHasValue = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "bHasValue")) - FString Value; + FString Value = {}; FQuickstartChatOptionalString() = default; diff --git a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Reducers/ClientConnected.g.h b/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Reducers/ClientConnected.g.h deleted file mode 100644 index bc97b8e7ee7..00000000000 --- a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Reducers/ClientConnected.g.h +++ /dev/null @@ -1,43 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/ReducerBase.g.h" -#include "ClientConnected.g.generated.h" - -// Reducer arguments struct for ClientConnected -USTRUCT(BlueprintType) -struct QUICKSTARTCHAT_API FClientConnectedArgs -{ - GENERATED_BODY() - - FClientConnectedArgs() = default; - - - FORCEINLINE bool operator==(const FClientConnectedArgs& Other) const - { - return true; - } - FORCEINLINE bool operator!=(const FClientConnectedArgs& Other) const - { - return !(*this == Other); - } -}; - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_STRUCT_EMPTY(FClientConnectedArgs); -} - -// Reducer class for internal dispatching -UCLASS(BlueprintType) -class QUICKSTARTCHAT_API UClientConnectedReducer : public UReducerBase -{ - GENERATED_BODY() - -public: -}; - - diff --git a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Reducers/ClientDisconnected.g.h b/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Reducers/ClientDisconnected.g.h deleted file mode 100644 index 07687d50f03..00000000000 --- a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Reducers/ClientDisconnected.g.h +++ /dev/null @@ -1,43 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/ReducerBase.g.h" -#include "ClientDisconnected.g.generated.h" - -// Reducer arguments struct for ClientDisconnected -USTRUCT(BlueprintType) -struct QUICKSTARTCHAT_API FClientDisconnectedArgs -{ - GENERATED_BODY() - - FClientDisconnectedArgs() = default; - - - FORCEINLINE bool operator==(const FClientDisconnectedArgs& Other) const - { - return true; - } - FORCEINLINE bool operator!=(const FClientDisconnectedArgs& Other) const - { - return !(*this == Other); - } -}; - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_STRUCT_EMPTY(FClientDisconnectedArgs); -} - -// Reducer class for internal dispatching -UCLASS(BlueprintType) -class QUICKSTARTCHAT_API UClientDisconnectedReducer : public UReducerBase -{ - GENERATED_BODY() - -public: -}; - - diff --git a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/SpacetimeDBClient.g.h b/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/SpacetimeDBClient.g.h index fa1d8e3eb15..f7a94d243d6 100644 --- a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/SpacetimeDBClient.g.h +++ b/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/SpacetimeDBClient.g.h @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.4.0 (commit dc59211c1453848981aeb2efce2249c9a07947b2). +// This was generated using spacetimedb cli version 2.0.1 (commit 6f8639a69dac2047da00b1fc8550c94ea2505892). #pragma once #include "CoreMinimal.h" @@ -9,12 +9,9 @@ #include "Connection/Callback.h" #include "Connection/DbConnectionBase.h" #include "Connection/DbConnectionBuilder.h" -#include "Connection/SetReducerFlags.h" #include "Connection/Subscription.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "ModuleBindings/ReducerBase.g.h" -#include "ModuleBindings/Reducers/ClientConnected.g.h" -#include "ModuleBindings/Reducers/ClientDisconnected.g.h" #include "ModuleBindings/Reducers/SendMessage.g.h" #include "ModuleBindings/Reducers/SetName.g.h" #include "Types/Builtins.h" @@ -24,6 +21,7 @@ class UDbConnection; class URemoteTables; class URemoteReducers; +class URemoteProcedures; class USubscriptionBuilder; class USubscriptionHandle; @@ -54,7 +52,7 @@ struct QUICKSTARTCHAT_API FContextBase { GENERATED_BODY() - FContextBase() = default; + FContextBase() : Db(nullptr), Reducers(nullptr), Procedures(nullptr), Conn(nullptr) {}; FContextBase(UDbConnection* InConn); UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") @@ -64,7 +62,7 @@ struct QUICKSTARTCHAT_API FContextBase URemoteReducers* Reducers; UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") - USetReducerFlags* SetReducerFlags; + URemoteProcedures* Procedures; bool IsActive() const; void Disconnect(); @@ -78,11 +76,27 @@ struct QUICKSTARTCHAT_API FContextBase }; +UCLASS() +class QUICKSTARTCHAT_API UContextBaseBpLib : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +private: + UFUNCTION(BlueprintPure, Category="SpacetimeDB") + static URemoteTables* GetDb(const FContextBase& Ctx) { return Ctx.Db; } + + UFUNCTION(BlueprintPure, Category="SpacetimeDB") + static URemoteReducers* GetReducers(const FContextBase& Ctx) { return Ctx.Reducers; } + + static URemoteProcedures* GetProcedures(const FContextBase& Ctx) { return Ctx.Procedures; } + + UFUNCTION(BlueprintPure, Category="SpacetimeDB") + static bool IsActive(const FContextBase& Ctx) { return Ctx.IsActive(); } +}; + UENUM(BlueprintType, Category = "SpacetimeDB") enum class EReducerTag : uint8 { - ClientConnected, - ClientDisconnected, SendMessage, SetName }; @@ -94,9 +108,9 @@ struct QUICKSTARTCHAT_API FReducer public: UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") - EReducerTag Tag; + EReducerTag Tag = static_cast(0); - TVariant Data; + TVariant Data; // Optional metadata UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") @@ -104,44 +118,12 @@ struct QUICKSTARTCHAT_API FReducer uint32 ReducerId = 0; uint32 RequestId = 0; - static FReducer ClientConnected(const FClientConnectedArgs& Value) - { - FReducer Out; - Out.Tag = EReducerTag::ClientConnected; - Out.Data.Set(Value); - Out.ReducerName = TEXT("ClientConnected"); - return Out; - } - - FORCEINLINE bool IsClientConnected() const { return Tag == EReducerTag::ClientConnected; } - FORCEINLINE FClientConnectedArgs GetAsClientConnected() const - { - ensureMsgf(IsClientConnected(), TEXT("Reducer does not hold ClientConnected!")); - return Data.Get(); - } - - static FReducer ClientDisconnected(const FClientDisconnectedArgs& Value) - { - FReducer Out; - Out.Tag = EReducerTag::ClientDisconnected; - Out.Data.Set(Value); - Out.ReducerName = TEXT("ClientDisconnected"); - return Out; - } - - FORCEINLINE bool IsClientDisconnected() const { return Tag == EReducerTag::ClientDisconnected; } - FORCEINLINE FClientDisconnectedArgs GetAsClientDisconnected() const - { - ensureMsgf(IsClientDisconnected(), TEXT("Reducer does not hold ClientDisconnected!")); - return Data.Get(); - } - static FReducer SendMessage(const FSendMessageArgs& Value) { FReducer Out; Out.Tag = EReducerTag::SendMessage; Out.Data.Set(Value); - Out.ReducerName = TEXT("SendMessage"); + Out.ReducerName = TEXT("send_message"); return Out; } @@ -157,7 +139,7 @@ struct QUICKSTARTCHAT_API FReducer FReducer Out; Out.Tag = EReducerTag::SetName; Out.Data.Set(Value); - Out.ReducerName = TEXT("SetName"); + Out.ReducerName = TEXT("set_name"); return Out; } @@ -173,10 +155,6 @@ struct QUICKSTARTCHAT_API FReducer if (Tag != Other.Tag || ReducerId != Other.ReducerId || RequestId != Other.RequestId || ReducerName != Other.ReducerName) return false; switch (Tag) { - case EReducerTag::ClientConnected: - return GetAsClientConnected() == Other.GetAsClientConnected(); - case EReducerTag::ClientDisconnected: - return GetAsClientDisconnected() == Other.GetAsClientDisconnected(); case EReducerTag::SendMessage: return GetAsSendMessage() == Other.GetAsSendMessage(); case EReducerTag::SetName: @@ -194,32 +172,6 @@ class QUICKSTARTCHAT_API UReducerBpLib : public UBlueprintFunctionLibrary private: - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|Reducer") - static FReducer ClientConnected(const FClientConnectedArgs& Value) { - return FReducer::ClientConnected(Value); - } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|Reducer") - static bool IsClientConnected(const FReducer& Reducer) { return Reducer.IsClientConnected(); } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|Reducer") - static FClientConnectedArgs GetAsClientConnected(const FReducer& Reducer) { - return Reducer.GetAsClientConnected(); - } - - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|Reducer") - static FReducer ClientDisconnected(const FClientDisconnectedArgs& Value) { - return FReducer::ClientDisconnected(Value); - } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|Reducer") - static bool IsClientDisconnected(const FReducer& Reducer) { return Reducer.IsClientDisconnected(); } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|Reducer") - static FClientDisconnectedArgs GetAsClientDisconnected(const FReducer& Reducer) { - return Reducer.GetAsClientDisconnected(); - } - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|Reducer") static FReducer SendMessage(const FSendMessageArgs& Value) { return FReducer::SendMessage(Value); @@ -290,6 +242,44 @@ struct QUICKSTARTCHAT_API FQuickstartChatReducerEvent } }; +// No procedures defined in this module. +/** Metadata describing a procedure run. */ +USTRUCT(BlueprintType) +struct QUICKSTARTCHAT_API FQuickstartChatProcedureEvent +{ + GENERATED_BODY() + + /** Timestamp for when the procedure executed */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="SpacetimeDB") + FSpacetimeDBTimestamp Timestamp; + + /** Result status of the procedure */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="SpacetimeDB") + FSpacetimeDBProcedureStatus Status; + + /** Identity that initiated the call */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="SpacetimeDB") + FSpacetimeDBTimeDuration TotalHostExecutionDuration; + + FQuickstartChatProcedureEvent() { + } + FQuickstartChatProcedureEvent(FProcedureEvent Event) { + Timestamp = Event.Timestamp; + Status = FSpacetimeDBProcedureStatus::FromStatus(Event.Status); + TotalHostExecutionDuration = Event.TotalHostExecutionDuration; + } + FORCEINLINE bool operator==(const FQuickstartChatProcedureEvent& Other) const + { + return Status == Other.Status && Timestamp == Other.Timestamp && + TotalHostExecutionDuration == Other.TotalHostExecutionDuration; + } + + FORCEINLINE bool operator!=(const FQuickstartChatProcedureEvent& Other) const + { + return !(*this == Other); + } +}; + /** Represents event with variant message data. */ USTRUCT(BlueprintType) struct QUICKSTARTCHAT_API FQuickstartChatEvent @@ -336,6 +326,14 @@ struct QUICKSTARTCHAT_API FQuickstartChatEvent return Obj; } + static FQuickstartChatEvent Transaction(const FSpacetimeDBUnit& Value) + { + FQuickstartChatEvent Obj; + Obj.Tag = ESpacetimeDBEventTag::Transaction; + Obj.MessageData.Set(Value); + return Obj; + } + static FQuickstartChatEvent SubscribeError(const FString& Value) { FQuickstartChatEvent Obj; @@ -380,6 +378,13 @@ struct QUICKSTARTCHAT_API FQuickstartChatEvent return MessageData.Get(); } + FORCEINLINE bool IsTransaction() const { return Tag == ESpacetimeDBEventTag::Transaction; } + FORCEINLINE FSpacetimeDBUnit GetAsTransaction() const + { + ensureMsgf(IsTransaction(), TEXT("MessageData does not hold Transaction!")); + return MessageData.Get(); + } + FORCEINLINE bool IsSubscribeError() const { return Tag == ESpacetimeDBEventTag::SubscribeError; } FORCEINLINE FString GetAsSubscribeError() const { @@ -403,6 +408,7 @@ struct QUICKSTARTCHAT_API FQuickstartChatEvent case ESpacetimeDBEventTag::SubscribeApplied: return GetAsSubscribeApplied() == Other.GetAsSubscribeApplied(); case ESpacetimeDBEventTag::UnsubscribeApplied: return GetAsUnsubscribeApplied() == Other.GetAsUnsubscribeApplied(); case ESpacetimeDBEventTag::Disconnected: return GetAsDisconnected() == Other.GetAsDisconnected(); + case ESpacetimeDBEventTag::Transaction: return GetAsTransaction() == Other.GetAsTransaction(); case ESpacetimeDBEventTag::SubscribeError: return GetAsSubscribeError() == Other.GetAsSubscribeError(); case ESpacetimeDBEventTag::UnknownTransaction: return GetAsUnknownTransaction() == Other.GetAsUnknownTransaction(); default: return false; @@ -445,6 +451,12 @@ class QUICKSTARTCHAT_API UQuickstartChatEventBpLib : public UBlueprintFunctionLi return FQuickstartChatEvent::Disconnected(InValue); } + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|QuickstartChatEvent") + static FQuickstartChatEvent Transaction(const FSpacetimeDBUnit& InValue) + { + return FQuickstartChatEvent::Transaction(InValue); + } + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|QuickstartChatEvent") static FQuickstartChatEvent SubscribeError(const FString& InValue) { @@ -469,6 +481,9 @@ class QUICKSTARTCHAT_API UQuickstartChatEventBpLib : public UBlueprintFunctionLi UFUNCTION(BlueprintPure, Category = "SpacetimeDB|QuickstartChatEvent") static bool IsDisconnected(const FQuickstartChatEvent& Event) { return Event.IsDisconnected(); } + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|QuickstartChatEvent") + static bool IsTransaction(const FQuickstartChatEvent& Event) { return Event.IsTransaction(); } + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|QuickstartChatEvent") static bool IsSubscribeError(const FQuickstartChatEvent& Event) { return Event.IsSubscribeError(); } @@ -499,6 +514,12 @@ class QUICKSTARTCHAT_API UQuickstartChatEventBpLib : public UBlueprintFunctionLi return Event.GetAsDisconnected(); } + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|QuickstartChatEvent") + static FSpacetimeDBUnit GetAsTransaction(const FQuickstartChatEvent& Event) + { + return Event.GetAsTransaction(); + } + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|QuickstartChatEvent") static FString GetAsSubscribeError(const FQuickstartChatEvent& Event) { @@ -538,6 +559,18 @@ struct QUICKSTARTCHAT_API FReducerEventContext : public FContextBase FQuickstartChatReducerEvent Event; }; +USTRUCT(BlueprintType) +struct QUICKSTARTCHAT_API FProcedureEventContext : public FContextBase +{ + GENERATED_BODY() + + FProcedureEventContext() = default; + FProcedureEventContext(UDbConnection* InConn, FQuickstartChatProcedureEvent InEvent) : FContextBase(InConn), Event(InEvent) {} + + UPROPERTY(BlueprintReadOnly, Category="SpacetimeDB") + FQuickstartChatProcedureEvent Event; +}; + USTRUCT(BlueprintType) struct QUICKSTARTCHAT_API FErrorContext : public FContextBase { @@ -569,23 +602,6 @@ DECLARE_DYNAMIC_DELEGATE_OneParam( FOnSubscriptionError, FErrorContext, Context); -UCLASS(BlueprintType) -class QUICKSTARTCHAT_API USetReducerFlags : public USetReducerFlagsBase -{ - GENERATED_BODY() - -public: - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void ClientConnected(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void ClientDisconnected(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void SendMessage(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void SetName(ECallReducerFlags Flag); - -}; - // RemoteTables class UCLASS(BlueprintType) class QUICKSTARTCHAT_API URemoteTables : public UObject @@ -596,10 +612,10 @@ class QUICKSTARTCHAT_API URemoteTables : public UObject void Initialize(); UPROPERTY(BlueprintReadOnly, Category="SpacetimeDB") - UUserTable* User; + UMessageTable* Message; UPROPERTY(BlueprintReadOnly, Category="SpacetimeDB") - UMessageTable* Message; + UUserTable* User; }; @@ -611,30 +627,6 @@ class QUICKSTARTCHAT_API URemoteReducers : public UObject public: - DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam( - FClientConnectedHandler, - const FReducerEventContext&, Context - ); - UPROPERTY(BlueprintAssignable, Category="SpacetimeDB") - FClientConnectedHandler OnClientConnected; - - UFUNCTION(BlueprintCallable, Category="SpacetimeDB") - void ClientConnected(); - - bool InvokeClientConnected(const FReducerEventContext& Context, const UClientConnectedReducer* Args); - - DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam( - FClientDisconnectedHandler, - const FReducerEventContext&, Context - ); - UPROPERTY(BlueprintAssignable, Category="SpacetimeDB") - FClientDisconnectedHandler OnClientDisconnected; - - UFUNCTION(BlueprintCallable, Category="SpacetimeDB") - void ClientDisconnected(); - - bool InvokeClientDisconnected(const FReducerEventContext& Context, const UClientDisconnectedReducer* Args); - DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams( FSendMessageHandler, const FReducerEventContext&, Context, @@ -647,6 +639,7 @@ class QUICKSTARTCHAT_API URemoteReducers : public UObject void SendMessage(const FString& Text); bool InvokeSendMessage(const FReducerEventContext& Context, const USendMessageReducer* Args); + bool InvokeSendMessageWithArgs(const FReducerEventContext& Context, const FSendMessageArgs& Args); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams( FSetNameHandler, @@ -660,6 +653,7 @@ class QUICKSTARTCHAT_API URemoteReducers : public UObject void SetName(const FString& Name); bool InvokeSetName(const FReducerEventContext& Context, const USetNameReducer* Args); + bool InvokeSetNameWithArgs(const FReducerEventContext& Context, const FSetNameArgs& Args); // Internal error handling DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FInternalOnUnhandledReducerError, const FReducerEventContext&, Context, const FString&, Error); @@ -671,9 +665,26 @@ class QUICKSTARTCHAT_API URemoteReducers : public UObject UPROPERTY() class UDbConnection* Conn; +}; + +// RemoteProcedures class +UCLASS(BlueprintType) +class QUICKSTARTCHAT_API URemoteProcedures : public UObject +{ + GENERATED_BODY() + +public: + + // Internal error handling + DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FInternalOnUnhandledProcedureError, const FProcedureEventContext&, Context, const FString&, Error); + FInternalOnUnhandledProcedureError InternalOnUnhandledProcedureError; + +private: + + friend UDbConnection; UPROPERTY() - USetReducerFlags* SetCallReducerFlags; + class UDbConnection* Conn; }; // SubscriptionBuilder class @@ -789,7 +800,7 @@ class QUICKSTARTCHAT_API UDbConnection : public UDbConnectionBase URemoteReducers* Reducers; UPROPERTY(BlueprintReadOnly, Category="SpacetimeDB") - USetReducerFlags* SetReducerFlags; + URemoteProcedures* Procedures; // Delegates that allow users to bind with the concrete connection type. FOnConnectDelegate OnConnectDelegate; @@ -807,10 +818,15 @@ class QUICKSTARTCHAT_API UDbConnection : public UDbConnectionBase UPROPERTY(BlueprintAssignable, Category="SpacetimeDB") FOnUnhandledReducerError OnUnhandledReducerError; + // Error handling + DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnUnhandledProcedureError, const FProcedureEventContext&, Context, const FString&, Error); + UPROPERTY(BlueprintAssignable, Category="SpacetimeDB") + FOnUnhandledProcedureError OnUnhandledProcedureError; + protected: - // Hook up error handling to reducers + // Hook up error handling to reducers and procedures virtual void PostInitProperties() override; UFUNCTION() @@ -821,6 +837,9 @@ class QUICKSTARTCHAT_API UDbConnection : public UDbConnectionBase UFUNCTION() void OnUnhandledReducerErrorHandler(const FReducerEventContext& Context, const FString& Error); + UFUNCTION() + void OnUnhandledProcedureErrorHandler(const FProcedureEventContext& Context, const FString& Error); + // Override the DbConnectionBase methods to handle updates and events virtual void DbUpdate(const FDatabaseUpdateType& Update, const FSpacetimeDBEvent& Event) override; @@ -829,5 +848,17 @@ class QUICKSTARTCHAT_API UDbConnection : public UDbConnectionBase // Override the reducer event failed handler virtual void ReducerEventFailed(const FReducerEvent& Event, const FString ErrorMessage) override; + // Override the procedure event failed handler + virtual void ProcedureEventFailed(const FProcedureEvent& Event, const FString ErrorMessage) override; + + friend class URemoteReducers; + + // Internal reducer correlation helpers (request_id -> typed reducer) + void RegisterPendingTypedReducer(uint32 RequestId, FReducer Reducer); + bool TryGetPendingTypedReducer(uint32 RequestId, FReducer& OutReducer) const; + bool TryTakePendingTypedReducer(uint32 RequestId, FReducer& OutReducer); + +private: + TMap PendingTypedReducers; }; diff --git a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Tables/UserTable.g.h b/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Tables/UserTable.g.h index 7e567066cb9..41f03abb5d6 100644 --- a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Tables/UserTable.g.h +++ b/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Tables/UserTable.g.h @@ -25,7 +25,7 @@ class QUICKSTARTCHAT_API UUserIdentityUniqueIndex : public UObject public: UUserIdentityUniqueIndex() // Initialize the helper with the specific unique index name - : IdentityIndexHelper("Identity") { + : IdentityIndexHelper("identity") { } /** diff --git a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Types/UserType.g.h b/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Types/UserType.g.h index 06890176da4..d5cfb423336 100644 --- a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Types/UserType.g.h +++ b/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Public/ModuleBindings/Types/UserType.g.h @@ -20,7 +20,7 @@ struct QUICKSTARTCHAT_API FUserType FQuickstartChatOptionalString Name; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - bool Online; + bool Online = false; FORCEINLINE bool operator==(const FUserType& Other) const { diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Private/Connection/DbConnectionBase.cpp b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Private/Connection/DbConnectionBase.cpp index f66fd5d1d29..34d878e42cb 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Private/Connection/DbConnectionBase.cpp +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Private/Connection/DbConnectionBase.cpp @@ -1,20 +1,69 @@ #include "Connection/DbConnectionBase.h" #include "Connection/DbConnectionBuilder.h" -#include "Connection/Credentials.h" -#include "Connection/LogCategory.h" -#include "ModuleBindings/Types/ClientMessageType.g.h" -#include "ModuleBindings/Types/SubscribeMultiType.g.h" -#include "ModuleBindings/Types/UnsubscribeMultiType.g.h" -#include "ModuleBindings/Types/SubscribeMultiAppliedType.g.h" -#include "ModuleBindings/Types/UnsubscribeMultiAppliedType.g.h" -#include "ModuleBindings/Types/SubscriptionErrorType.g.h" -#include "ModuleBindings/Types/DatabaseUpdateType.g.h" -#include "ModuleBindings/Types/CompressableQueryUpdateType.g.h" -#include "Misc/Compression.h" -#include "Misc/ScopeLock.h" -#include "Async/Async.h" -#include "BSATN/UEBSATNHelpers.h" -#include "Connection/ProcedureFlags.h" +#include "Connection/Credentials.h" +#include "Connection/LogCategory.h" +#include "ModuleBindings/Types/ClientMessageType.g.h" +#include "ModuleBindings/Types/SubscriptionErrorType.g.h" +#include "Misc/Compression.h" +#include "Misc/ScopeLock.h" +#include "Async/Async.h" +#include "BSATN/UEBSATNHelpers.h" +#include "Connection/ProcedureFlags.h" + +namespace +{ +enum class EWsCompressionTag : uint8 +{ + Uncompressed = 0, + Brotli = 1, + Gzip = 2, +}; + +static FDatabaseUpdateType QueryRowsToDatabaseUpdate(const FQueryRowsType& Rows, bool bAsDeletes) +{ + FDatabaseUpdateType Update; + for (const FSingleTableRowsType& TableRows : Rows.Tables) + { + FTableUpdateType TableUpdate; + TableUpdate.TableName = TableRows.Table; + + FPersistentTableRowsType PersistentRows; + if (bAsDeletes) + { + PersistentRows.Deletes = TableRows.Rows; + } + else + { + PersistentRows.Inserts = TableRows.Rows; + } + TableUpdate.Rows.Add(FTableUpdateRowsType::PersistentTable(PersistentRows)); + Update.Tables.Add(TableUpdate); + } + return Update; +} + +static FDatabaseUpdateType TransactionUpdateToDatabaseUpdate(const FTransactionUpdateType& Update) +{ + FDatabaseUpdateType Out; + for (const FQuerySetUpdateType& QuerySet : Update.QuerySets) + { + for (const FTableUpdateType& TableUpdate : QuerySet.Tables) + { + Out.Tables.Add(TableUpdate); + } + } + return Out; +} + +static FString DecodeReducerErrorMessage(const TArray& ErrorBytes) +{ + if (ErrorBytes.Num() == 0) + { + return TEXT("Reducer returned empty error payload"); + } + return UE::SpacetimeDB::Deserialize(ErrorBytes); +} +} UDbConnectionBase::UDbConnectionBase(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -70,21 +119,48 @@ USubscriptionBuilderBase* UDbConnectionBase::SubscriptionBuilderBase() return NewObject(); } -void UDbConnectionBase::HandleWSError(const FString& Error) -{ - if (OnConnectErrorDelegate.IsBound()) - { - OnConnectErrorDelegate.Execute(Error); - } -} - -void UDbConnectionBase::HandleWSClosed(int32 /*StatusCode*/, const FString& Reason, bool /*bWasClean*/) -{ - if (OnDisconnectBaseDelegate.IsBound()) - { - OnDisconnectBaseDelegate.Execute(this, Reason); - } -} +void UDbConnectionBase::HandleWSError(const FString& Error) +{ + bProtocolViolationHandled = false; + ClearPendingOperations(Error); + if (OnConnectErrorDelegate.IsBound()) + { + OnConnectErrorDelegate.Execute(Error); + } +} + +void UDbConnectionBase::HandleWSClosed(int32 /*StatusCode*/, const FString& Reason, bool /*bWasClean*/) +{ + bProtocolViolationHandled = false; + ClearPendingOperations(Reason); + if (OnDisconnectBaseDelegate.IsBound()) + { + OnDisconnectBaseDelegate.Execute(this, Reason); + } +} + +void UDbConnectionBase::HandleProtocolViolation(const FString& ErrorMessage) +{ + if (bProtocolViolationHandled) + { + return; + } + bProtocolViolationHandled = true; + + UE_LOG(LogSpacetimeDb_Connection, Error, TEXT("%s"), *ErrorMessage); + TriggerError(ErrorMessage); + ClearPendingOperations(ErrorMessage); + + // Match Rust/C# behavior: parse/protocol violations are fatal for the connection. + if (WebSocket && WebSocket->IsConnected()) + { + WebSocket->Disconnect(); + } + else if (OnConnectErrorDelegate.IsBound()) + { + OnConnectErrorDelegate.Execute(ErrorMessage); + } +} void UDbConnectionBase::HandleWSBinaryMessage(const TArray& Message) { @@ -99,11 +175,24 @@ void UDbConnectionBase::HandleWSBinaryMessage(const TArray& Message) if (!WeakThis.IsValid()) { return; - } - UDbConnectionBase* This = WeakThis.Get(); - - //parse the message, decompress if needed - FServerMessageType Parsed = This->PreProcessMessage(Message); + } + UDbConnectionBase* This = WeakThis.Get(); + + //parse the message, decompress if needed + FServerMessageType Parsed; + if (!This->PreProcessMessage(Message, Parsed)) + { + AsyncTask(ENamedThreads::GameThread, [WeakThis]() + { + if (!WeakThis.IsValid()) + { + return; + } + UDbConnectionBase* Conn = WeakThis.Get(); + Conn->HandleProtocolViolation(TEXT("Failed to parse/decompress incoming WebSocket message")); + }); + return; + } //queue: re-order buffer TArray Ready; @@ -174,205 +263,207 @@ bool UDbConnectionBase::IsTickableInEditor() const } -void UDbConnectionBase::ProcessServerMessage(const FServerMessageType& Message) -{ - bool bIsValid = false; - switch (Message.Tag) - { - case EServerMessageTag::InitialSubscription: - { - //@Note: This is a legacy tag, used implemented in current server version - break; - } - case EServerMessageTag::TransactionUpdate: - { - // Process a transaction update message - const FTransactionUpdateType Payload = Message.GetAsTransactionUpdate(); - - // Create a status object based on the transaction status - FSpacetimeDBStatus StatusObj; - bool bSuccess = false; - FString ErrorMessage; - if (Payload.Status.IsCommitted()) - { - bSuccess = true; - StatusObj = FSpacetimeDBStatus::Committed(FSpacetimeDBUnit()); - } - else if (Payload.Status.IsFailed()) - { - ErrorMessage = Payload.Status.GetAsFailed(); - StatusObj = FSpacetimeDBStatus::Failed(ErrorMessage); - } - else if (Payload.Status.IsOutOfEnergy()) - { - Payload.Status.GetAsOutOfEnergy(); - StatusObj = FSpacetimeDBStatus::OutOfEnergy(FSpacetimeDBUnit()); - ErrorMessage = TEXT("Out of energy"); - } - - // Process the transaction update and create a reducer event - FReducerEvent RedEvent; - RedEvent.Timestamp = Payload.Timestamp; - RedEvent.Status = StatusObj; - RedEvent.CallerIdentity = Payload.CallerIdentity; - RedEvent.CallerConnectionId = Payload.CallerConnectionId; - RedEvent.EnergyConsumed = Payload.EnergyQuantaUsed; - RedEvent.ReducerCall = Payload.ReducerCall; - - // If the status is committed, we update the database - if (bSuccess) - { - DbUpdate(Payload.Status.GetAsCommitted(), FSpacetimeDBEvent::Reducer(RedEvent)); // Update table and trigger insert/update/delete - ReducerEvent(RedEvent); // Trigger the reducer event - } - else - { - ReducerEvent(RedEvent); // Trigger the reducer event - ReducerEventFailed(RedEvent, ErrorMessage); - } - break; - } - case EServerMessageTag::TransactionUpdateLight: - { - // Process a light transaction update message - const FTransactionUpdateLightType Payload = Message.GetAsTransactionUpdateLight(); - - //@TODO: Implement light update fully - DbUpdate(Payload.Update, FSpacetimeDBEvent::UnknownTransaction(FSpacetimeDBUnit())); - - break; - } - case EServerMessageTag::IdentityToken: - { - // Process an identity token message - const FIdentityTokenType Payload = Message.GetAsIdentityToken(); - - Token = Payload.Token; - UCredentials::SaveToken(Token); - Identity = Payload.Identity; - bIsIdentitySet = true; - UE_LOG(LogSpacetimeDb_Connection, Verbose, TEXT("IdentityToken: Identity set to: %s"), *Identity.ToHex()); - ConnectionId = Payload.ConnectionId; - if (OnConnectBaseDelegate.IsBound()) - { - OnConnectBaseDelegate.Execute(this, Identity, Token); - } - break; - } - case EServerMessageTag::OneOffQueryResponse: - { - //@Note: Not implemented in Rust version, skip for now here aswell - break; - } - case EServerMessageTag::SubscribeApplied: - { - //@Note: This is a legacy tag, not implemented in current server version - break; - } - case EServerMessageTag::UnsubscribeApplied: - { - //@Note: This is a legacy tag, not implemented in current server version - break; - } - case EServerMessageTag::SubscriptionError: - { - // Process a subscription error message - const FSubscriptionErrorType Payload = Message.GetAsSubscriptionError(); - if (TObjectPtr Handle = *ActiveSubscriptions.Find(Payload.QueryId.Value)) - { - if (!Handle) - { - UE_LOG(LogSpacetimeDb_Connection, Error, TEXT("SubscriptionError: Null handle for QueryId %u. Error: %s"), - Payload.QueryId.Value, - *Payload.Error); - return; - } - FErrorContextBase Ctx; Ctx.Error = Payload.Error; - Handle->TriggerError(Ctx); - ActiveSubscriptions.Remove(Payload.QueryId.Value); - } - break; - } - case EServerMessageTag::SubscribeMultiApplied: - { - // Process a multi-subscription applied message - const FSubscribeMultiAppliedType Payload = Message.GetAsSubscribeMultiApplied(); - // Update the database with the subscription applied event - DbUpdate(Payload.Update, FSpacetimeDBEvent::SubscribeApplied(FSpacetimeDBUnit())); - - if (TObjectPtr Handle = *ActiveSubscriptions.Find(Payload.QueryId.Id)) - { - if (!Handle) - { - UE_LOG(LogSpacetimeDb_Connection, Error, TEXT("SubscriptionError: Null handle for QueryId %u."), Payload.QueryId.Id); - return; - } - FSubscriptionEventContextBase Ctx; Ctx.Event = FSpacetimeDBEvent::SubscribeApplied(FSpacetimeDBUnit()); - Handle->TriggerApplied(Ctx); - } - - break; - } - case EServerMessageTag::UnsubscribeMultiApplied: - { - // Process a multi-unsubscription applied message - const FUnsubscribeMultiAppliedType Payload = Message.GetAsUnsubscribeMultiApplied(); - - // Update the database with the unsubscription applied event - DbUpdate(Payload.Update, FSpacetimeDBEvent::UnsubscribeApplied(FSpacetimeDBUnit())); - if (TObjectPtr Handle = *ActiveSubscriptions.Find(Payload.QueryId.Id)) - { - if (!Handle) - { - UE_LOG(LogSpacetimeDb_Connection, Error, TEXT("UnsubscribeMultiApplied: Null handle for QueryId %u."), Payload.QueryId.Id); - return; - } - Handle->bEnded = true; - Handle->bActive = false; - Handle->bUnsubscribeCalled = true; - FSubscriptionEventContextBase Ctx; Ctx.Event = FSpacetimeDBEvent::UnsubscribeApplied(FSpacetimeDBUnit()); - if (Handle->EndDelegate.IsBound()) - { - Handle->EndDelegate.Execute(Ctx); - } - ActiveSubscriptions.Remove(Payload.QueryId.Id); - } - break; - } - case EServerMessageTag::ProcedureResult: - { - const FProcedureResultType Payload = Message.GetAsProcedureResult(); - FProcedureEvent ProcEvent; - ProcEvent.Status = Payload.Status; - ProcEvent.Timestamp = Payload.Timestamp; - ProcEvent.TotalHostExecutionDuration = Payload.TotalHostExecutionDuration; - ProcEvent.Success = ProcEvent.Status.IsReturned(); - TArray PayloadData; - FString ErrorMessage = ""; - if (ProcEvent.Success) - PayloadData = ProcEvent.Status.GetAsReturned(); - if (Payload.Status.IsOutOfEnergy()) - { - ErrorMessage = TEXT("Out of energy"); - } - else if (Payload.Status.IsInternalError()) - { - ErrorMessage = Payload.Status.GetAsInternalError(); - } - - ProcedureCallbacks->ResolveCallback(Payload.RequestId, FSpacetimeDBEvent::Procedure(ProcEvent), PayloadData, ProcEvent.Success); - if (!ProcEvent.Success) - { - ProcedureEventFailed(ProcEvent, ErrorMessage); - } - break; - } - default: - // Unknown tag - bail out - UE_LOG(LogSpacetimeDb_Connection, Warning, TEXT("Unknown server-message tag")); - break; - } -} +void UDbConnectionBase::ProcessServerMessage(const FServerMessageType& Message) +{ + switch (Message.Tag) + { + case EServerMessageTag::InitialConnection: + { + const FInitialConnectionType Payload = Message.GetAsInitialConnection(); + Token = Payload.Token; + UCredentials::SaveToken(Token); + Identity = Payload.Identity; + bIsIdentitySet = true; + ConnectionId = Payload.ConnectionId; + if (OnConnectBaseDelegate.IsBound()) + { + OnConnectBaseDelegate.Execute(this, Identity, Token); + } + break; + } + case EServerMessageTag::TransactionUpdate: + { + const FTransactionUpdateType Payload = Message.GetAsTransactionUpdate(); + const FDatabaseUpdateType Update = TransactionUpdateToDatabaseUpdate(Payload); + DbUpdate(Update, FSpacetimeDBEvent::Transaction(FSpacetimeDBUnit())); + break; + } + case EServerMessageTag::OneOffQueryResult: + { + // One-off query results are request/response only and do not mutate cache by default. + break; + } + case EServerMessageTag::SubscribeApplied: + { + const FSubscribeAppliedType Payload = Message.GetAsSubscribeApplied(); + const FDatabaseUpdateType Update = QueryRowsToDatabaseUpdate(Payload.Rows, false); + DbUpdate(Update, FSpacetimeDBEvent::SubscribeApplied(FSpacetimeDBUnit())); + + if (TObjectPtr* HandlePtr = ActiveSubscriptions.Find(Payload.QuerySetId.Id)) + { + TObjectPtr Handle = *HandlePtr; + if (!Handle) + { + UE_LOG(LogSpacetimeDb_Connection, Error, TEXT("SubscribeApplied: Null handle for QuerySetId %u."), Payload.QuerySetId.Id); + return; + } + FSubscriptionEventContextBase Ctx; + Ctx.Event = FSpacetimeDBEvent::SubscribeApplied(FSpacetimeDBUnit()); + Handle->TriggerApplied(Ctx); + } + break; + } + case EServerMessageTag::UnsubscribeApplied: + { + const FUnsubscribeAppliedType Payload = Message.GetAsUnsubscribeApplied(); + if (Payload.Rows.IsSet()) + { + const FDatabaseUpdateType Update = QueryRowsToDatabaseUpdate(Payload.Rows.Value, true); + DbUpdate(Update, FSpacetimeDBEvent::UnsubscribeApplied(FSpacetimeDBUnit())); + } + + if (TObjectPtr* HandlePtr = ActiveSubscriptions.Find(Payload.QuerySetId.Id)) + { + TObjectPtr Handle = *HandlePtr; + if (!Handle) + { + UE_LOG(LogSpacetimeDb_Connection, Error, TEXT("UnsubscribeApplied: Null handle for QuerySetId %u."), Payload.QuerySetId.Id); + return; + } + Handle->bEnded = true; + Handle->bActive = false; + Handle->bUnsubscribeCalled = true; + FSubscriptionEventContextBase Ctx; + Ctx.Event = FSpacetimeDBEvent::UnsubscribeApplied(FSpacetimeDBUnit()); + if (Handle->EndDelegate.IsBound()) + { + Handle->EndDelegate.Execute(Ctx); + } + ActiveSubscriptions.Remove(Payload.QuerySetId.Id); + } + break; + } + case EServerMessageTag::SubscriptionError: + { + const FSubscriptionErrorType Payload = Message.GetAsSubscriptionError(); + UE_LOG(LogSpacetimeDb_Connection, Warning, TEXT("SubscriptionError received for QuerySetId=%u Error=%s"), + Payload.QuerySetId.Id, + *Payload.Error); + if (TObjectPtr* HandlePtr = ActiveSubscriptions.Find(Payload.QuerySetId.Id)) + { + TObjectPtr Handle = *HandlePtr; + if (!Handle) + { + UE_LOG(LogSpacetimeDb_Connection, Error, TEXT("SubscriptionError: Null handle for QuerySetId %u. Error: %s"), + Payload.QuerySetId.Id, + *Payload.Error); + return; + } + FErrorContextBase Ctx; Ctx.Error = Payload.Error; + Handle->TriggerError(Ctx); + ActiveSubscriptions.Remove(Payload.QuerySetId.Id); + } + break; + } + case EServerMessageTag::ReducerResult: + { + const FReducerResultType Payload = Message.GetAsReducerResult(); + const FReducerCallInfoType* FoundReducerCall = PendingReducerCalls.Find(Payload.RequestId); + if (!FoundReducerCall) + { + const FString ErrorMessage = FString::Printf( + TEXT("Reducer result for unknown request_id %u"), + Payload.RequestId); + HandleProtocolViolation(ErrorMessage); + return; + } + + const FReducerCallInfoType ReducerCall = *FoundReducerCall; + PendingReducerCalls.Remove(Payload.RequestId); + + FReducerEvent RedEvent; + RedEvent.RequestId = Payload.RequestId; + RedEvent.Timestamp = Payload.Timestamp; + RedEvent.CallerIdentity = Identity; + RedEvent.CallerConnectionId = ConnectionId; + RedEvent.ReducerCall = ReducerCall; + + if (Payload.Result.IsOk()) + { + RedEvent.Status = FSpacetimeDBStatus::Committed(FSpacetimeDBUnit()); + const FReducerOkType Ok = Payload.Result.GetAsOk(); + const FDatabaseUpdateType Update = TransactionUpdateToDatabaseUpdate(Ok.TransactionUpdate); + DbUpdate(Update, FSpacetimeDBEvent::Reducer(RedEvent)); + ReducerEvent(RedEvent); + } + else if (Payload.Result.IsOkEmpty()) + { + RedEvent.Status = FSpacetimeDBStatus::Committed(FSpacetimeDBUnit()); + ReducerEvent(RedEvent); + } + else + { + FString ErrorMessage; + if (Payload.Result.IsErr()) + { + ErrorMessage = DecodeReducerErrorMessage(Payload.Result.GetAsErr()); + } + else + { + ErrorMessage = Payload.Result.GetAsInternalError(); + } + RedEvent.Status = FSpacetimeDBStatus::Failed(ErrorMessage); + ReducerEvent(RedEvent); + ReducerEventFailed(RedEvent, ErrorMessage); + } + break; + } + case EServerMessageTag::ProcedureResult: + { + const FProcedureResultType Payload = Message.GetAsProcedureResult(); + FProcedureEvent ProcEvent; + ProcEvent.Status = Payload.Status; + ProcEvent.Timestamp = Payload.Timestamp; + ProcEvent.TotalHostExecutionDuration = Payload.TotalHostExecutionDuration; + ProcEvent.Success = ProcEvent.Status.IsReturned(); + + TArray PayloadData; + FString ErrorMessage; + if (ProcEvent.Success) + { + PayloadData = ProcEvent.Status.GetAsReturned(); + } + else if (Payload.Status.IsInternalError()) + { + ErrorMessage = Payload.Status.GetAsInternalError(); + } + + const bool bResolved = ProcedureCallbacks->ResolveCallback( + Payload.RequestId, + FSpacetimeDBEvent::Procedure(ProcEvent), + PayloadData, + ProcEvent.Success + ); + if (!bResolved) + { + UE_LOG( + LogSpacetimeDb_Connection, + Warning, + TEXT("Received ProcedureResult for unknown request ID: %u"), + Payload.RequestId + ); + } + if (!ProcEvent.Success) + { + ProcedureEventFailed(ProcEvent, ErrorMessage); + } + break; + } + default: + UE_LOG(LogSpacetimeDb_Connection, Warning, TEXT("Unknown server-message tag")); + break; + } +} bool UDbConnectionBase::DecompressBrotli(const TArray& InData, TArray& OutData) { @@ -405,71 +496,44 @@ bool UDbConnectionBase::DecompressGzip(const TArray& InData, TArray& In, TArray& Out) -{ - switch (Variant) - { - case ECompressableQueryUpdateTag::Uncompressed: - // No compression, just copy the data - Out = In; - return true; - case ECompressableQueryUpdateTag::Brotli: - return DecompressBrotli(In, Out); - case ECompressableQueryUpdateTag::Gzip: - return DecompressGzip(In, Out); - default: - UE_LOG(LogSpacetimeDb_Connection, Error, TEXT("Unknown compression variant")); - return false; - } -} - -void UDbConnectionBase::PreProcessDatabaseUpdate(const FDatabaseUpdateType& Update) -{ - for (const FTableUpdateType& TableUpdate : Update.Tables) - { - TArray UncompressedCQUs; - for (const FCompressableQueryUpdateType& CQU : TableUpdate.Updates) - { - - // Uncompress the CQU based on its tag - FQueryUpdateType UncompressedUpdate; - switch (CQU.Tag) - { - case ECompressableQueryUpdateTag::Uncompressed: - UncompressedUpdate = CQU.GetAsUncompressed(); - break; - case ECompressableQueryUpdateTag::Brotli: - { - TArray Data = CQU.GetAsBrotli(); - TArray Dec; - if (DecompressBrotli(Data, Dec)) - { - //@Note: This will never trigger until Brotli decompression is implemented - UncompressedUpdate = UE::SpacetimeDB::Deserialize(Dec); - } - break; - } - case ECompressableQueryUpdateTag::Gzip: - { - TArray Data = CQU.GetAsGzip(); - TArray Dec; - if (DecompressGzip(Data, Dec)) - { - UncompressedUpdate = UE::SpacetimeDB::Deserialize(Dec); - } - break; - } - default: - UE_LOG(LogSpacetimeDb_Connection, Error, TEXT("Unknown compression variant in CQU")); - break; - } - UncompressedCQUs.Add(FCompressableQueryUpdateType::Uncompressed(UncompressedUpdate)); - UE_LOG(LogSpacetimeDb_Connection, Verbose, TEXT("Table %s Inserts:%d Deletes:%d"), *TableUpdate.TableName, UncompressedUpdate.Inserts.RowsData.Num(), UncompressedUpdate.Deletes.RowsData.Num()); - } - - // After ensuring all updates are uncompressed, attempt to deserialize rows - TSharedPtr Deserializer; - { +bool UDbConnectionBase::DecompressPayload(uint8 Variant, const TArray& In, TArray& Out) +{ + switch (static_cast(Variant)) + { + case EWsCompressionTag::Uncompressed: + // No compression, just copy the data + Out = In; + return true; + case EWsCompressionTag::Brotli: + return DecompressBrotli(In, Out); + case EWsCompressionTag::Gzip: + return DecompressGzip(In, Out); + default: + UE_LOG(LogSpacetimeDb_Connection, Error, TEXT("Unknown compression variant")); + return false; + } +} + +void UDbConnectionBase::ClearPendingOperations(const FString& Reason) +{ + PendingReducerCalls.Empty(); + if (ProcedureCallbacks) + { + ProcedureCallbacks->ClearAllCallbacks(); + } + if (!Reason.IsEmpty()) + { + UE_LOG(LogSpacetimeDb_Connection, Warning, TEXT("Cleared pending operations due to connection issue: %s"), *Reason); + } +} + +void UDbConnectionBase::PreProcessDatabaseUpdate(const FDatabaseUpdateType& Update) +{ + for (const FTableUpdateType& TableUpdate : Update.Tables) + { + // Attempt to deserialize rows after payload decode. + TSharedPtr Deserializer; + { // Find the deserializer for this table FScopeLock Lock(&TableDeserializersMutex); if (TSharedPtr* Found = TableDeserializers.Find(TableUpdate.TableName)) @@ -481,19 +545,17 @@ void UDbConnectionBase::PreProcessDatabaseUpdate(const FDatabaseUpdateType& Upda { UE_LOG(LogSpacetimeDb_Connection, Error, TEXT("No deserializer found for table %s"), *TableUpdate.TableName); } - } - if (Deserializer) - { - // Preprocess the table data using the deserializer - TSharedPtr Data = Deserializer->PreProcess(UncompressedCQUs, TableUpdate.TableName); - if (Data.IsValid()) - { - // Store the preprocessed data in the mutex-protected map - FScopeLock Lock(&PreprocessedDataMutex); - FPreprocessedTableKey Key(TableUpdate.TableId, TableUpdate.TableName); - TArray>& Queue = PreprocessedTableData.FindOrAdd(Key); - Queue.Add(Data); - } + } + if (Deserializer) + { + TSharedPtr Data = Deserializer->PreProcess(TableUpdate.Rows, TableUpdate.TableName); + if (Data.IsValid()) + { + FScopeLock Lock(&PreprocessedDataMutex); + FPreprocessedTableKey Key(TableUpdate.TableName); + TArray>& Queue = PreprocessedTableData.FindOrAdd(Key); + Queue.Add(Data); + } } else { @@ -502,89 +564,80 @@ void UDbConnectionBase::PreProcessDatabaseUpdate(const FDatabaseUpdateType& Upda } } -FServerMessageType UDbConnectionBase::PreProcessMessage(const TArray& Message) -{ - if (Message.Num() == 0) - { - UE_LOG(LogSpacetimeDb_Connection, Error, TEXT("Empty message recived from server, ignored")); - return FServerMessageType{}; - } - // Check if the first byte is a valid compression tag - ECompressableQueryUpdateTag Compression = static_cast(Message[0]); - TArray CompressedPayload; - CompressedPayload.Append(Message.GetData() + 1, Message.Num() - 1); +bool UDbConnectionBase::PreProcessMessage(const TArray& Message, FServerMessageType& OutMessage) +{ + if (Message.Num() == 0) + { + UE_LOG(LogSpacetimeDb_Connection, Error, TEXT("Empty message recived from server, ignored")); + return false; + } + // The first byte indicates compression format for the payload. + const uint8 Compression = Message[0]; + TArray CompressedPayload; + CompressedPayload.Append(Message.GetData() + 1, Message.Num() - 1); // Decompress the payload based on the compression tag TArray Decompressed; - if (!DecompressPayload(Compression, CompressedPayload, Decompressed)) - { - UE_LOG(LogSpacetimeDb_Connection, Error, TEXT("Failed to decompress incoming message")); - return FServerMessageType{}; - } - - // Deserialize the decompressed data into a UServerMessageType object - FServerMessageType Parsed = UE::SpacetimeDB::Deserialize(Decompressed); - - // Process it based on its tag. Messages containing rows will be deserialized into rows based on registered type and table name. - bool bValid = false; - switch (Parsed.Tag) - { - case EServerMessageTag::InitialSubscription: - { - const FInitialSubscriptionType Payload = Parsed.GetAsInitialSubscription(); - // PreProcess the initial subscription payload - PreProcessDatabaseUpdate(Payload.DatabaseUpdate); - break; - } - case EServerMessageTag::TransactionUpdate: - { - - const FTransactionUpdateType Payload = Parsed.GetAsTransactionUpdate(); - if (Payload.Status.IsCommitted()) - { - // PreProcess the database update with the committed status - PreProcessDatabaseUpdate(Payload.Status.GetAsCommitted()); - } - break; - } - case EServerMessageTag::TransactionUpdateLight: - { - //@Note: Light tag in not implemented as an option in connection builder, this will never trigger but we keep this for future compatibility - const FTransactionUpdateLightType Payload = Parsed.GetAsTransactionUpdateLight(); - // PreProcess the light transaction update - PreProcessDatabaseUpdate(Payload.Update); - break; - } - case EServerMessageTag::SubscribeMultiApplied: - { - const FSubscribeMultiAppliedType Payload = Parsed.GetAsSubscribeMultiApplied(); - PreProcessDatabaseUpdate(Payload.Update); - break; - } - case EServerMessageTag::UnsubscribeMultiApplied: - { - const FUnsubscribeMultiAppliedType Payload = Parsed.GetAsUnsubscribeMultiApplied(); - PreProcessDatabaseUpdate(Payload.Update); - break; - } - default: - break; - } - return Parsed; -} - - -int32 UDbConnectionBase::GetNextRequestId() -{ - return NextRequestId++; -} - -int32 UDbConnectionBase::GetNextSubscriptionId() -{ - return NextSubscriptionId++; -} - -void UDbConnectionBase::StartSubscription(USubscriptionHandleBase* Handle) + if (!DecompressPayload(Compression, CompressedPayload, Decompressed)) + { + UE_LOG(LogSpacetimeDb_Connection, Error, TEXT("Failed to decompress incoming message")); + return false; + } + + // Deserialize the decompressed data into a UServerMessageType object + OutMessage = UE::SpacetimeDB::Deserialize(Decompressed); + + // Preprocess row-bearing payloads for table deserializers. + switch (OutMessage.Tag) + { + case EServerMessageTag::SubscribeApplied: + { + const FSubscribeAppliedType Payload = OutMessage.GetAsSubscribeApplied(); + PreProcessDatabaseUpdate(QueryRowsToDatabaseUpdate(Payload.Rows, false)); + break; + } + case EServerMessageTag::UnsubscribeApplied: + { + const FUnsubscribeAppliedType Payload = OutMessage.GetAsUnsubscribeApplied(); + if (Payload.Rows.IsSet()) + { + PreProcessDatabaseUpdate(QueryRowsToDatabaseUpdate(Payload.Rows.Value, true)); + } + break; + } + case EServerMessageTag::TransactionUpdate: + { + const FTransactionUpdateType Payload = OutMessage.GetAsTransactionUpdate(); + PreProcessDatabaseUpdate(TransactionUpdateToDatabaseUpdate(Payload)); + break; + } + case EServerMessageTag::ReducerResult: + { + const FReducerResultType Payload = OutMessage.GetAsReducerResult(); + if (Payload.Result.IsOk()) + { + PreProcessDatabaseUpdate(TransactionUpdateToDatabaseUpdate(Payload.Result.GetAsOk().TransactionUpdate)); + } + break; + } + default: + break; + } + return true; +} + + +uint32 UDbConnectionBase::GetNextRequestId() +{ + return NextRequestId++; +} + +uint32 UDbConnectionBase::GetNextSubscriptionId() +{ + return NextSubscriptionId++; +} + +void UDbConnectionBase::StartSubscription(USubscriptionHandleBase* Handle) { if (!Handle) { @@ -598,20 +651,20 @@ void UDbConnectionBase::StartSubscription(USubscriptionHandleBase* Handle) return; } - const int32 QueryId = GetNextSubscriptionId(); - Handle->QueryId = QueryId; - Handle->ConnInternal = this; - ActiveSubscriptions.Add(QueryId, Handle); - - FSubscribeMultiType SubMsg; - SubMsg.QueryStrings = Handle->QuerySqls; - SubMsg.RequestId = GetNextRequestId(); - SubMsg.QueryId.Id = QueryId; - - FClientMessageType Msg = FClientMessageType::SubscribeMulti(SubMsg); - TArray Data = UE::SpacetimeDB::Serialize(Msg); - SendRawMessage(Data); -} + const uint32 QuerySetId = GetNextSubscriptionId(); + Handle->QuerySetId = QuerySetId; + Handle->ConnInternal = this; + ActiveSubscriptions.Add(QuerySetId, Handle); + + FSubscribeType SubMsg; + SubMsg.RequestId = GetNextRequestId(); + SubMsg.QuerySetId.Id = QuerySetId; + SubMsg.QueryStrings = Handle->QuerySqls; + + FClientMessageType Msg = FClientMessageType::Subscribe(SubMsg); + TArray Data = UE::SpacetimeDB::Serialize(Msg); + SendRawMessage(Data); +} void UDbConnectionBase::UnsubscribeInternal(USubscriptionHandleBase* Handle) { @@ -620,42 +673,41 @@ void UDbConnectionBase::UnsubscribeInternal(USubscriptionHandleBase* Handle) return; } - const int32 QueryId = Handle->QueryId; - FUnsubscribeMultiType MsgData; - MsgData.RequestId = GetNextRequestId(); - MsgData.QueryId.Id = QueryId; - - FClientMessageType Msg = FClientMessageType::UnsubscribeMulti(MsgData); - TArray Data = UE::SpacetimeDB::Serialize(Msg); - SendRawMessage(Data); -} - -void UDbConnectionBase::InternalCallReducer(const FString& Reducer, TArray Args, USetReducerFlagsBase* Flags) -{ - if (!WebSocket || !WebSocket->IsConnected()) - { - UE_LOG(LogSpacetimeDb_Connection, Error, TEXT("Cannot call reducer, not connected to server!")); - return; - } - - uint8 FlagToUse = 0; // Default to FullUpdate - if (Flags && Flags->FlagMap.Contains(Reducer)) - { - //Select flag if set by user - ECallReducerFlags FlagFound = *Flags->FlagMap.Find(Reducer); - FlagToUse = static_cast(FlagFound); - } - - FCallReducerType MsgData; - MsgData.Reducer = Reducer; - MsgData.Args = Args; - MsgData.RequestId = GetNextRequestId(); - MsgData.Flags = FlagToUse; - - FClientMessageType Msg = FClientMessageType::CallReducer(MsgData); - TArray Data = UE::SpacetimeDB::Serialize(Msg); - SendRawMessage(Data); -} + const uint32 QuerySetId = Handle->QuerySetId; + FUnsubscribeType MsgData; + MsgData.RequestId = GetNextRequestId(); + MsgData.QuerySetId.Id = QuerySetId; + MsgData.Flags = EUnsubscribeFlagsType::SendDroppedRows; + + FClientMessageType Msg = FClientMessageType::Unsubscribe(MsgData); + TArray Data = UE::SpacetimeDB::Serialize(Msg); + SendRawMessage(Data); +} + +uint32 UDbConnectionBase::InternalCallReducer(const FString& Reducer, TArray Args) +{ + if (!WebSocket || !WebSocket->IsConnected()) + { + UE_LOG(LogSpacetimeDb_Connection, Error, TEXT("Cannot call reducer, not connected to server!")); + return 0; + } + + FCallReducerType MsgData; + MsgData.Reducer = Reducer; + MsgData.Args = Args; + MsgData.RequestId = GetNextRequestId(); + // v2 parity with Rust/C#: reducer flags are always default. + MsgData.Flags = 0; + FReducerCallInfoType CallInfo; + CallInfo.ReducerName = Reducer; + CallInfo.Args = Args; + PendingReducerCalls.Add(MsgData.RequestId, CallInfo); + + FClientMessageType Msg = FClientMessageType::CallReducer(MsgData); + TArray Data = UE::SpacetimeDB::Serialize(Msg); + SendRawMessage(Data); + return MsgData.RequestId; +} void UDbConnectionBase::InternalCallProcedure(const FString& ProcedureName, TArray Args, const FOnProcedureCompleteDelegate& Callback) { @@ -703,4 +755,4 @@ void UDbConnectionBase::ApplyRegisteredTableUpdates(const FDatabaseUpdateType& U // Broadcast the diff for each handler Handler->BroadcastDiff(this, Context); } -} \ No newline at end of file +} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Private/Connection/Websocket.cpp b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Private/Connection/Websocket.cpp index 9c1f4525f67..7b4bbe53f40 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Private/Connection/Websocket.cpp +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Private/Connection/Websocket.cpp @@ -1,30 +1,14 @@ -#include "Connection/Websocket.h" -#include "WebSocketsModule.h" // Required for FWebSocketsModule -#include "SpacetimeDbSdk/Public/BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/ServerMessageType.g.h" -#include "ModuleBindings/Types/CompressableQueryUpdateType.g.h" -#include "Misc/Compression.h" +#include "Connection/Websocket.h" +#include "WebSocketsModule.h" // Required for FWebSocketsModule +#include "SpacetimeDbSdk/Public/BSATN/UESpacetimeDB.h" +#include "ModuleBindings/Types/ServerMessageType.g.h" #include "Dom/JsonObject.h" #include "Serialization/JsonWriter.h" #include "Serialization/JsonSerializer.h" -static void LogIdentityTokenHex(const FIdentityTokenType& InToken, const TCHAR* TagName) -{ - // Logs the identity token in a structured format for debugging purposes. - TSharedRef Obj = MakeShared(); - Obj->SetStringField(TEXT("__identity__"), InToken.Identity.ToHex()); - Obj->SetStringField(TEXT("token"), InToken.Token); - Obj->SetStringField(TEXT("__connection_id__"), InToken.ConnectionId.ToHex()); - - FString Json; - TSharedRef> Writer = TJsonWriterFactory<>::Create(&Json); - FJsonSerializer::Serialize(Obj, Writer); - UE_LOG(LogSpacetimeDb_Connection, Log, TEXT("[%s] %s"), TagName, *Json); -} - -UWebsocketManager::UWebsocketManager() +UWebsocketManager::UWebsocketManager() { // Ensure the WebSockets module is loaded. FModuleManager::LoadModuleChecked(TEXT("WebSockets")); @@ -64,8 +48,8 @@ void UWebsocketManager::Connect(const FString& ServerUrl) UpgradeHeaders.Add("Authorization", HeaderToken); } - // using the v1.bsatn.spacetimedb protocol for WebSocket connections - const FString Protocol = "v1.bsatn.spacetimedb"; // @TODO: Implement JSON alternative, v1.json.spacetimedb + // Use websocket protocol v2 + const FString Protocol = "v2.bsatn.spacetimedb"; // Create the WebSocket connection WebSocket = FWebSocketsModule::Get().CreateWebSocket(ServerUrl, Protocol, UpgradeHeaders); @@ -212,4 +196,4 @@ void UWebsocketManager::HandleClosed(int32 StatusCode, const FString& Reason, bo OnClosed.Broadcast(StatusCode, Reason, bWasClean); // Reset on close to allow reconnection attempts WebSocket.Reset(); -} \ No newline at end of file +} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Private/Tests/SpacetimeDBBSATNTestOrg.cpp b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Private/Tests/SpacetimeDBBSATNTestOrg.cpp index e64359717f5..20583c7b92a 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Private/Tests/SpacetimeDBBSATNTestOrg.cpp +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Private/Tests/SpacetimeDBBSATNTestOrg.cpp @@ -7,36 +7,36 @@ #include "Types/LargeIntegers.h" #include "Types/Builtins.h" #include "ModuleBindings/Types/BsatnRowListType.g.h" +#include "ModuleBindings/Types/CallProcedureType.g.h" #include "ModuleBindings/Types/CallReducerType.g.h" #include "ModuleBindings/Types/ClientMessageType.g.h" -#include "ModuleBindings/Types/CompressableQueryUpdateType.g.h" -#include "ModuleBindings/Types/DatabaseUpdateType.g.h" -#include "ModuleBindings/Types/EnergyQuantaType.g.h" -#include "ModuleBindings/Types/IdentityTokenType.g.h" -#include "ModuleBindings/Types/InitialSubscriptionType.g.h" -#include "ModuleBindings/Types/OneOffQueryResponseType.g.h" +#include "ModuleBindings/Types/EventTableRowsType.g.h" +#include "ModuleBindings/Types/InitialConnectionType.g.h" #include "ModuleBindings/Types/OneOffQueryType.g.h" -#include "ModuleBindings/Types/OneOffTableType.g.h" -#include "ModuleBindings/Types/QueryIdType.g.h" -#include "ModuleBindings/Types/QueryUpdateType.g.h" -#include "ModuleBindings/Types/ReducerCallInfoType.g.h" +#include "ModuleBindings/Types/OneOffQueryResultType.g.h" +#include "ModuleBindings/Types/PersistentTableRowsType.g.h" +#include "ModuleBindings/Types/ProcedureResultType.g.h" +#include "ModuleBindings/Types/ProcedureStatusType.g.h" +#include "ModuleBindings/Types/QueryRowsType.g.h" +#include "ModuleBindings/Types/QuerySetIdType.g.h" +#include "ModuleBindings/Types/QuerySetUpdateType.g.h" +#include "ModuleBindings/Types/ReducerOkType.g.h" +#include "ModuleBindings/Types/ReducerOutcomeType.g.h" +#include "ModuleBindings/Types/ReducerResultType.g.h" +#include "ModuleBindings/Results/SpacetimeDbSdkResultQueryRowsString.g.h" #include "ModuleBindings/Types/RowSizeHintType.g.h" #include "ModuleBindings/Types/ServerMessageType.g.h" +#include "ModuleBindings/Types/SingleTableRowsType.g.h" #include "ModuleBindings/Types/SubscribeAppliedType.g.h" -#include "ModuleBindings/Types/SubscribeMultiAppliedType.g.h" -#include "ModuleBindings/Types/SubscribeMultiType.g.h" -#include "ModuleBindings/Types/SubscribeRowsType.g.h" -#include "ModuleBindings/Types/SubscribeSingleType.g.h" #include "ModuleBindings/Types/SubscribeType.g.h" #include "ModuleBindings/Types/SubscriptionErrorType.g.h" #include "ModuleBindings/Types/TableUpdateType.g.h" -#include "ModuleBindings/Types/TransactionUpdateLightType.g.h" +#include "ModuleBindings/Types/TableUpdateRowsType.g.h" #include "ModuleBindings/Types/TransactionUpdateType.g.h" #include "ModuleBindings/Types/UnsubscribeAppliedType.g.h" -#include "ModuleBindings/Types/UnsubscribeMultiAppliedType.g.h" -#include "ModuleBindings/Types/UnsubscribeMultiType.g.h" +#include "ModuleBindings/Types/UnsubscribeFlagsType.g.h" #include "ModuleBindings/Types/UnsubscribeType.g.h" -#include "ModuleBindings/Types/UpdateStatusType.g.h" +#include "ModuleBindings/Optionals/SpacetimeDbSdkOptionalQueryRows.g.h" // ────────────────────────────────────────────────────────────────────────────── @@ -172,279 +172,191 @@ IMPLEMENT_SIMPLE_AUTOMATION_TEST( ChartactarThingOrg.Type = OrgNpcChar; TEST_ROUNDTRIP(FCharacterThing, ChartactarThingOrg, "FCharacterThing struct with Tagged Enum"); - //Cliant API - LOG_Category("Cliant API"); - //QueryIdType - FQueryIdType QueryId; - QueryId.Id = 100; - TEST_ROUNDTRIP(FQueryIdType, QueryId, "FQueryId"); - - // SubscribeMultiType - FSubscribeMultiType SubscribeMulti; - SubscribeMulti.QueryStrings.Add("SELECT * FROM players"); - SubscribeMulti.QueryStrings.Add("SELECT * FROM guilds WHERE region = 'EU'"); - SubscribeMulti.RequestId = 500; - SubscribeMulti.QueryId = QueryId; - TEST_ROUNDTRIP(FSubscribeMultiType, SubscribeMulti, "FSubscribeMultiType"); - - // RowSizeHintType + // Client API (WS v2) + LOG_Category("Client API WS v2"); + + FQuerySetIdType QuerySetId; + QuerySetId.Id = 100; + TEST_ROUNDTRIP(FQuerySetIdType, QuerySetId, "FQuerySetIdType"); + FRowSizeHintType FixedSizeHint = FRowSizeHintType::FixedSize(static_cast(128)); TEST_ROUNDTRIP(FRowSizeHintType, FixedSizeHint, "FRowSizeHintType::FixedSize Variant"); - TArray RowOffsetsArray; // keep empty like before (or add offsets if you want) + TArray RowOffsetsArray; FRowSizeHintType RowOffsetsHint = FRowSizeHintType::RowOffsets(RowOffsetsArray); TEST_ROUNDTRIP(FRowSizeHintType, RowOffsetsHint, "FRowSizeHintType::RowOffsets Variant"); - // BsatnRowListType - FBsatnRowListType BsatnRowList; - BsatnRowList.SizeHint = FixedSizeHint; - BsatnRowList.RowsData.Init(0xAB, 10); - TEST_ROUNDTRIP(FBsatnRowListType, BsatnRowList, "FBsatnRowListType with FixedSize hint"); + FBsatnRowListType BsatnRowsFixed; + BsatnRowsFixed.SizeHint = FixedSizeHint; + BsatnRowsFixed.RowsData.Init(0xAB, 10); + TEST_ROUNDTRIP(FBsatnRowListType, BsatnRowsFixed, "FBsatnRowListType fixed"); + + FBsatnRowListType BsatnRowsOffsets; + BsatnRowsOffsets.SizeHint = RowOffsetsHint; + BsatnRowsOffsets.RowsData.Init(0xCD, 12); + TEST_ROUNDTRIP(FBsatnRowListType, BsatnRowsOffsets, "FBsatnRowListType offsets"); + + FSingleTableRowsType SingleTableRows; + SingleTableRows.Table = "PlayerStats"; + SingleTableRows.Rows = BsatnRowsFixed; + TEST_ROUNDTRIP(FSingleTableRowsType, SingleTableRows, "FSingleTableRowsType"); + + FQueryRowsType QueryRows; + QueryRows.Tables.Add(SingleTableRows); + TEST_ROUNDTRIP(FQueryRowsType, QueryRows, "FQueryRowsType"); - // CallReducerType FCallReducerType CallReducer; + CallReducer.RequestId = 200; + CallReducer.Flags = 0; CallReducer.Reducer = "MyGameReducer"; CallReducer.Args.Init(0xDE, 20); - CallReducer.RequestId = 200; - CallReducer.Flags = 0; TEST_ROUNDTRIP(FCallReducerType, CallReducer, "FCallReducerType"); - // SubscribeType + FCallProcedureType CallProcedure; + CallProcedure.RequestId = 201; + CallProcedure.Flags = 0; + CallProcedure.Procedure = "MyGameProcedure"; + CallProcedure.Args.Init(0xEF, 10); + TEST_ROUNDTRIP(FCallProcedureType, CallProcedure, "FCallProcedureType"); + FSubscribeType Subscribe; + Subscribe.RequestId = 300; + Subscribe.QuerySetId = QuerySetId; Subscribe.QueryStrings.Add("SELECT * FROM users WHERE status = 'online'"); Subscribe.QueryStrings.Add("SELECT item_name FROM inventory WHERE owner_id = 32"); - Subscribe.RequestId = 300; TEST_ROUNDTRIP(FSubscribeType, Subscribe, "FSubscribeType"); - // OneOffQueryType FOneOffQueryType OneOffQuery; - OneOffQuery.MessageId.Init(0xCC, 16); + OneOffQuery.RequestId = 301; OneOffQuery.QueryString = "SELECT * FROM game_settings"; TEST_ROUNDTRIP(FOneOffQueryType, OneOffQuery, "FOneOffQueryType"); - // SubscribeSingleType - FSubscribeSingleType SubscribeSingle; - SubscribeSingle.Query = "SELECT * FROM player_data WHERE player_id = 33"; - SubscribeSingle.RequestId = 400; - SubscribeSingle.QueryId = QueryId; - TEST_ROUNDTRIP(FSubscribeSingleType, SubscribeSingle, "FSubscribeSingleType"); - - // UnsubscribeType FUnsubscribeType Unsubscribe; Unsubscribe.RequestId = 600; - Unsubscribe.QueryId = QueryId; + Unsubscribe.QuerySetId = QuerySetId; + Unsubscribe.Flags = EUnsubscribeFlagsType::SendDroppedRows; TEST_ROUNDTRIP(FUnsubscribeType, Unsubscribe, "FUnsubscribeType"); - // UnsubscribeMultiType - FUnsubscribeMultiType UnsubscribeMulti; - UnsubscribeMulti.RequestId = 700; - UnsubscribeMulti.QueryId = QueryId; - TEST_ROUNDTRIP(FUnsubscribeMultiType, UnsubscribeMulti, "FUnsubscribeMultiType"); - - // CallReducer variant FClientMessageType ClientMessageCallReducer = FClientMessageType::CallReducer(CallReducer); TEST_ROUNDTRIP(FClientMessageType, ClientMessageCallReducer, "FClientMessageType::CallReducer Variant"); + FClientMessageType ClientMessageCallProcedure = FClientMessageType::CallProcedure(CallProcedure); + TEST_ROUNDTRIP(FClientMessageType, ClientMessageCallProcedure, "FClientMessageType::CallProcedure Variant"); FClientMessageType ClientMessageSubscribe = FClientMessageType::Subscribe(Subscribe); TEST_ROUNDTRIP(FClientMessageType, ClientMessageSubscribe, "FClientMessageType::Subscribe Variant"); FClientMessageType ClientMessageOneOffQuery = FClientMessageType::OneOffQuery(OneOffQuery); TEST_ROUNDTRIP(FClientMessageType, ClientMessageOneOffQuery, "FClientMessageType::OneOffQuery Variant"); - FClientMessageType ClientMessageSubscribeSingle = FClientMessageType::SubscribeSingle(SubscribeSingle); - TEST_ROUNDTRIP(FClientMessageType, ClientMessageSubscribeSingle, "FClientMessageType::SubscribeSingle Variant"); - FClientMessageType ClientMessageSubscribeMulti = FClientMessageType::SubscribeMulti(SubscribeMulti); - TEST_ROUNDTRIP(FClientMessageType, ClientMessageSubscribeMulti, "FClientMessageType::SubscribeMulti Variant"); FClientMessageType ClientMessageUnsubscribe = FClientMessageType::Unsubscribe(Unsubscribe); TEST_ROUNDTRIP(FClientMessageType, ClientMessageUnsubscribe, "FClientMessageType::Unsubscribe Variant"); - FClientMessageType ClientMessageUnsubscribeMulti = FClientMessageType::UnsubscribeMulti(UnsubscribeMulti); - TEST_ROUNDTRIP(FClientMessageType, ClientMessageUnsubscribeMulti, "FClientMessageType::UnsubscribeMulti Variant"); - - - // BsatnRowListType - FBsatnRowListType BsatnRowList1; - BsatnRowList1.SizeHint = FixedSizeHint; - BsatnRowList1.RowsData.Init(0xAB, 10); - TEST_ROUNDTRIP(FBsatnRowListType, BsatnRowList1, "FBsatnRowListType with FixedSize hint"); - FBsatnRowListType BsatnRowList2; - BsatnRowList2.SizeHint = RowOffsetsHint; - BsatnRowList2.RowsData.Init(0xAB, 10); - TEST_ROUNDTRIP(FBsatnRowListType, BsatnRowList2, "FBsatnRowListType with RowOffsets hint"); - - // QueryUpdateType - FQueryUpdateType QueryUpdate; - QueryUpdate.Deletes = BsatnRowList1; - QueryUpdate.Inserts = BsatnRowList2; - TEST_ROUNDTRIP(FQueryUpdateType, QueryUpdate, "FQueryUpdateType"); - - // CompressableQueryUpdateType - FCompressableQueryUpdateType UncompressedUpdate =FCompressableQueryUpdateType::Uncompressed(QueryUpdate); - TEST_ROUNDTRIP(FCompressableQueryUpdateType, UncompressedUpdate, "FCompressableQueryUpdateType::Uncompressed Variant"); - TArray BrotliData; - BrotliData.Add(0x11); - BrotliData.Add(0x22); - FCompressableQueryUpdateType BrotliUpdate =FCompressableQueryUpdateType::Brotli(BrotliData); - TEST_ROUNDTRIP(FCompressableQueryUpdateType, BrotliUpdate, "FCompressableQueryUpdateType::Brotli Variant"); - TArray GzipData; - GzipData.Add(0xA1); - GzipData.Add(0xB2); - FCompressableQueryUpdateType GzipUpdate = FCompressableQueryUpdateType::Gzip(GzipData); - TEST_ROUNDTRIP(FCompressableQueryUpdateType, GzipUpdate, "FCompressableQueryUpdateType::Gzip Variant"); - - // TableUpdateType + + FPersistentTableRowsType PersistentRows; + PersistentRows.Inserts = BsatnRowsFixed; + PersistentRows.Deletes = BsatnRowsOffsets; + TEST_ROUNDTRIP(FPersistentTableRowsType, PersistentRows, "FPersistentTableRowsType"); + + FEventTableRowsType EventRows; + EventRows.Events = BsatnRowsFixed; + TEST_ROUNDTRIP(FEventTableRowsType, EventRows, "FEventTableRowsType"); + + FTableUpdateRowsType PersistentTableUpdateRows = FTableUpdateRowsType::PersistentTable(PersistentRows); + TEST_ROUNDTRIP(FTableUpdateRowsType, PersistentTableUpdateRows, "FTableUpdateRowsType::PersistentTable"); + FTableUpdateRowsType EventTableUpdateRows = FTableUpdateRowsType::EventTable(EventRows); + TEST_ROUNDTRIP(FTableUpdateRowsType, EventTableUpdateRows, "FTableUpdateRowsType::EventTable"); + FTableUpdateType TableUpdate; - TableUpdate.TableId = 1; TableUpdate.TableName = "PlayerStats"; - TableUpdate.NumRows = 100; - TableUpdate.Updates.Add(UncompressedUpdate); - TableUpdate.Updates.Add(BrotliUpdate); - TableUpdate.Updates.Add(GzipUpdate); + TableUpdate.Rows.Add(PersistentTableUpdateRows); + TableUpdate.Rows.Add(EventTableUpdateRows); TEST_ROUNDTRIP(FTableUpdateType, TableUpdate, "FTableUpdateType"); - // DatabaseUpdateType - FDatabaseUpdateType DatabaseUpdate; - DatabaseUpdate.Tables.Add(TableUpdate); - TEST_ROUNDTRIP(FDatabaseUpdateType, DatabaseUpdate, "FDatabaseUpdateType"); - - // EnergyQuantaType - FEnergyQuantaType EnergyQuanta; - EnergyQuanta.Quanta = FSpacetimeDBUInt128(1000, 500); - TEST_ROUNDTRIP(FEnergyQuantaType, EnergyQuanta, "FEnergyQuantaType"); - - // IdentityTokenType - FIdentityTokenType IdentityToken; - IdentityToken.Identity = FSpacetimeDBIdentity(FSpacetimeDBUInt256(FSpacetimeDBUInt128(10, 9), FSpacetimeDBUInt128(8, 7))); - IdentityToken.Token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"; - IdentityToken.ConnectionId = FSpacetimeDBConnectionId(FSpacetimeDBUInt128(12345, 67890)); - TEST_ROUNDTRIP(FIdentityTokenType, IdentityToken, "FIdentityTokenType"); - - // InitialSubscriptionType - FInitialSubscriptionType InitialSubscription; - InitialSubscription.DatabaseUpdate = DatabaseUpdate; - InitialSubscription.RequestId = 101; - InitialSubscription.TotalHostExecutionDuration = FSpacetimeDBTimeDuration(500000); - TEST_ROUNDTRIP(FInitialSubscriptionType, InitialSubscription, "FInitialSubscriptionType"); - - - // OneOffTableType - FOneOffTableType OneOffTable; - OneOffTable.TableName = "GameScores"; - OneOffTable.Rows = BsatnRowList1; - TEST_ROUNDTRIP(FOneOffTableType, OneOffTable, "FOneOffTableType"); - - - // OneOffQueryResponseType - FOneOffQueryResponseType OneOffQueryResponse; - OneOffQueryResponse.MessageId.Init(0xDD, 16); - FSpacetimeDbSdkOptionalString SdkOptionalStringError; - SdkOptionalStringError.bHasValue = true; - SdkOptionalStringError.Value = "Error text"; - OneOffQueryResponse.Tables.Add(OneOffTable); - OneOffQueryResponse.TotalHostExecutionDuration = FSpacetimeDBTimeDuration(123456); - TEST_ROUNDTRIP(FOneOffQueryResponseType, OneOffQueryResponse, "FOneOffQueryResponseType"); - - // ReducerCallInfoType - FReducerCallInfoType ReducerCallInfo; - ReducerCallInfo.ReducerName = "UpdatePlayerScore"; - ReducerCallInfo.ReducerId = 123; - ReducerCallInfo.Args.Init(0xAB, 10); - ReducerCallInfo.RequestId = 789; - TEST_ROUNDTRIP(FReducerCallInfoType, ReducerCallInfo, "FReducerCallInfoType"); - - // UpdateStatusType - FUpdateStatusType StatusCommitted = FUpdateStatusType::Committed(DatabaseUpdate); - TEST_ROUNDTRIP(FUpdateStatusType, StatusCommitted, "FUpdateStatusType::Committed Variant"); - FString FailedMsg = TEXT("Reducer execution failed due to invalid input."); - FUpdateStatusType StatusFailed = FUpdateStatusType::Failed(FailedMsg); - TEST_ROUNDTRIP(FUpdateStatusType, StatusFailed, "FUpdateStatusType::Failed Variant"); - FSpacetimeDBUnit UnitValue{}; - FUpdateStatusType StatusOutOfEnergy = FUpdateStatusType::OutOfEnergy(UnitValue); - TEST_ROUNDTRIP(FUpdateStatusType, StatusOutOfEnergy, "FUpdateStatusType::OutOfEnergy Variant"); - - // TransactionUpdateType + FQuerySetUpdateType QuerySetUpdate; + QuerySetUpdate.QuerySetId = QuerySetId; + QuerySetUpdate.Tables.Add(TableUpdate); + TEST_ROUNDTRIP(FQuerySetUpdateType, QuerySetUpdate, "FQuerySetUpdateType"); + FTransactionUpdateType TransactionUpdate; - TransactionUpdate.Status = StatusCommitted; - TransactionUpdate.Timestamp = FSpacetimeDBTimestamp::FromFDateTime(FDateTime(2025, 6, 25, 9, 33, 0)); - TransactionUpdate.CallerIdentity = FSpacetimeDBIdentity(FSpacetimeDBUInt256(FSpacetimeDBUInt128(1, 2), FSpacetimeDBUInt128(3, 4))); - TransactionUpdate.CallerConnectionId = FSpacetimeDBConnectionId(FSpacetimeDBUInt128(98765, 43210)); - TransactionUpdate.ReducerCall = ReducerCallInfo; - TransactionUpdate.EnergyQuantaUsed = EnergyQuanta; - TransactionUpdate.TotalHostExecutionDuration = FSpacetimeDBTimeDuration(75000); + TransactionUpdate.QuerySets.Add(QuerySetUpdate); TEST_ROUNDTRIP(FTransactionUpdateType, TransactionUpdate, "FTransactionUpdateType"); - // SubscribeRowsType - FSubscribeRowsType SubscribeRows; - SubscribeRows.TableId = 10; - SubscribeRows.TableName = "ConfigData"; - SubscribeRows.TableRows = TableUpdate; - TEST_ROUNDTRIP(FSubscribeRowsType, SubscribeRows, "FSubscribeRowsType"); - - // SubscribeAppliedType FSubscribeAppliedType SubscribeApplied; SubscribeApplied.RequestId = 12345; - SubscribeApplied.TotalHostExecutionDurationMicros = 250000; - SubscribeApplied.QueryId = QueryId; - SubscribeApplied.Rows = SubscribeRows; + SubscribeApplied.QuerySetId = QuerySetId; + SubscribeApplied.Rows = QueryRows; TEST_ROUNDTRIP(FSubscribeAppliedType, SubscribeApplied, "FSubscribeAppliedType"); - // SubscribeMultiAppliedType - FSubscribeMultiAppliedType SubscribeMultiApplied; - SubscribeMultiApplied.RequestId = 54321; - SubscribeMultiApplied.TotalHostExecutionDurationMicros = 300000; - SubscribeMultiApplied.QueryId = QueryId; - SubscribeMultiApplied.Update = DatabaseUpdate; - TEST_ROUNDTRIP(FSubscribeMultiAppliedType, SubscribeMultiApplied, "FSubscribeMultiAppliedType"); + FUnsubscribeAppliedType UnsubscribeApplied; + UnsubscribeApplied.RequestId = 3000; + UnsubscribeApplied.QuerySetId = QuerySetId; + UnsubscribeApplied.Rows = FSpacetimeDbSdkOptionalQueryRows(QueryRows); + TEST_ROUNDTRIP(FUnsubscribeAppliedType, UnsubscribeApplied, "FUnsubscribeAppliedType"); - // SubscriptionErrorType FSubscriptionErrorType SubscriptionError; - SubscriptionError.TotalHostExecutionDurationMicros = 50000; SubscriptionError.RequestId = FSpacetimeDbSdkOptionalUInt32(1001); - SubscriptionError.QueryId = FSpacetimeDbSdkOptionalUInt32(201); - SubscriptionError.TableId = FSpacetimeDbSdkOptionalUInt32(301); + SubscriptionError.QuerySetId = QuerySetId; SubscriptionError.Error = "SQL syntax error in subscription query."; TEST_ROUNDTRIP(FSubscriptionErrorType, SubscriptionError, "FSubscriptionErrorType"); - // TransactionUpdateLightType - FTransactionUpdateLightType TransactionUpdateLight; - TransactionUpdateLight.RequestId = 2000; - TransactionUpdateLight.Update = DatabaseUpdate; - TEST_ROUNDTRIP(FTransactionUpdateLightType, TransactionUpdateLight, "FTransactionUpdateLightType"); - - - // UnsubscribeAppliedType - FUnsubscribeAppliedType UnsubscribeApplied; - UnsubscribeApplied.RequestId = 3000; - UnsubscribeApplied.TotalHostExecutionDurationMicros = 80000; - UnsubscribeApplied.QueryId = QueryId; - UnsubscribeApplied.Rows = SubscribeRows; - TEST_ROUNDTRIP(FUnsubscribeAppliedType, UnsubscribeApplied, "FUnsubscribeAppliedType"); - - // UnsubscribeMultiAppliedType - FUnsubscribeMultiAppliedType UnsubscribeMultiApplied; - UnsubscribeMultiApplied.RequestId = 4000; - UnsubscribeMultiApplied.TotalHostExecutionDurationMicros = 100000; - UnsubscribeMultiApplied.QueryId = QueryId; - UnsubscribeMultiApplied.Update = DatabaseUpdate; - TEST_ROUNDTRIP(FUnsubscribeMultiAppliedType, UnsubscribeMultiApplied, "FUnsubscribeMultiAppliedType"); - - - // UServerMessageType - FServerMessageType MessageInitialSubscription = FServerMessageType::InitialSubscription(InitialSubscription); - TEST_ROUNDTRIP(FServerMessageType, MessageInitialSubscription, "FServerMessageType::InitialSubscription Variant"); + FInitialConnectionType InitialConnection; + InitialConnection.Identity = FSpacetimeDBIdentity(FSpacetimeDBUInt256(FSpacetimeDBUInt128(10, 9), FSpacetimeDBUInt128(8, 7))); + InitialConnection.Token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"; + InitialConnection.ConnectionId = FSpacetimeDBConnectionId(FSpacetimeDBUInt128(12345, 67890)); + TEST_ROUNDTRIP(FInitialConnectionType, InitialConnection, "FInitialConnectionType"); + + FSpacetimeDbSdkResultQueryRowsString OneOffResult = FSpacetimeDbSdkResultQueryRowsString::Ok(QueryRows); + TEST_ROUNDTRIP(FSpacetimeDbSdkResultQueryRowsString, OneOffResult, "FSpacetimeDbSdkResultQueryRowsString::Ok"); + + FOneOffQueryResultType OneOffQueryResult; + OneOffQueryResult.RequestId = 901; + OneOffQueryResult.Result = OneOffResult; + TEST_ROUNDTRIP(FOneOffQueryResultType, OneOffQueryResult, "FOneOffQueryResultType"); + + FReducerOkType ReducerOk; + ReducerOk.RetValue.Init(0xAA, 8); + ReducerOk.TransactionUpdate = TransactionUpdate; + TEST_ROUNDTRIP(FReducerOkType, ReducerOk, "FReducerOkType"); + + FReducerOutcomeType ReducerOutcomeOk = FReducerOutcomeType::Ok(ReducerOk); + TEST_ROUNDTRIP(FReducerOutcomeType, ReducerOutcomeOk, "FReducerOutcomeType::Ok"); + TArray ReducerErrBytes; + ReducerErrBytes.Add(0x11); + ReducerErrBytes.Add(0x22); + FReducerOutcomeType ReducerOutcomeErr = FReducerOutcomeType::Err(ReducerErrBytes); + TEST_ROUNDTRIP(FReducerOutcomeType, ReducerOutcomeErr, "FReducerOutcomeType::Err"); + FReducerOutcomeType ReducerOutcomeInternal = FReducerOutcomeType::InternalError("Reducer crashed"); + TEST_ROUNDTRIP(FReducerOutcomeType, ReducerOutcomeInternal, "FReducerOutcomeType::InternalError"); + + FReducerResultType ReducerResult; + ReducerResult.RequestId = 777; + ReducerResult.Timestamp = FSpacetimeDBTimestamp::FromFDateTime(FDateTime(2025, 6, 25, 9, 33, 0)); + ReducerResult.Result = ReducerOutcomeOk; + TEST_ROUNDTRIP(FReducerResultType, ReducerResult, "FReducerResultType"); + + FProcedureStatusType ProcedureStatusReturned = FProcedureStatusType::Returned(TArray{0x10, 0x20}); + TEST_ROUNDTRIP(FProcedureStatusType, ProcedureStatusReturned, "FProcedureStatusType::Returned"); + FProcedureStatusType ProcedureStatusInternal = FProcedureStatusType::InternalError("Procedure crashed"); + TEST_ROUNDTRIP(FProcedureStatusType, ProcedureStatusInternal, "FProcedureStatusType::InternalError"); + + FProcedureResultType ProcedureResult; + ProcedureResult.Status = ProcedureStatusReturned; + ProcedureResult.Timestamp = FSpacetimeDBTimestamp::FromFDateTime(FDateTime(2025, 6, 25, 9, 35, 0)); + ProcedureResult.TotalHostExecutionDuration = FSpacetimeDBTimeDuration(75000); + ProcedureResult.RequestId = 888; + TEST_ROUNDTRIP(FProcedureResultType, ProcedureResult, "FProcedureResultType"); + + FServerMessageType MessageInitialConnection = FServerMessageType::InitialConnection(InitialConnection); + TEST_ROUNDTRIP(FServerMessageType, MessageInitialConnection, "FServerMessageType::InitialConnection Variant"); FServerMessageType MessageTransactionUpdate = FServerMessageType::TransactionUpdate(TransactionUpdate); TEST_ROUNDTRIP(FServerMessageType, MessageTransactionUpdate, "FServerMessageType::TransactionUpdate Variant"); - FServerMessageType MessageTransactionUpdateLight = FServerMessageType::TransactionUpdateLight(TransactionUpdateLight); - TEST_ROUNDTRIP(FServerMessageType, MessageTransactionUpdateLight, "FServerMessageType::TransactionUpdateLight Variant"); - FServerMessageType MessageIdentityToken = FServerMessageType::IdentityToken(IdentityToken); - TEST_ROUNDTRIP(FServerMessageType, MessageIdentityToken, "FServerMessageType::IdentityToken Variant"); - FServerMessageType MessageOneOffQueryResponse = FServerMessageType::OneOffQueryResponse(OneOffQueryResponse); - TEST_ROUNDTRIP(FServerMessageType, MessageOneOffQueryResponse, "FServerMessageType::OneOffQueryResponse Variant"); + FServerMessageType MessageOneOffQueryResult = FServerMessageType::OneOffQueryResult(OneOffQueryResult); + TEST_ROUNDTRIP(FServerMessageType, MessageOneOffQueryResult, "FServerMessageType::OneOffQueryResult Variant"); FServerMessageType MessageSubscribeApplied = FServerMessageType::SubscribeApplied(SubscribeApplied); TEST_ROUNDTRIP(FServerMessageType, MessageSubscribeApplied, "FServerMessageType::SubscribeApplied Variant"); FServerMessageType MessageUnsubscribeApplied = FServerMessageType::UnsubscribeApplied(UnsubscribeApplied); TEST_ROUNDTRIP(FServerMessageType, MessageUnsubscribeApplied, "FServerMessageType::UnsubscribeApplied Variant"); FServerMessageType MessageSubscriptionError = FServerMessageType::SubscriptionError(SubscriptionError); TEST_ROUNDTRIP(FServerMessageType, MessageSubscriptionError, "FServerMessageType::SubscriptionError Variant"); - FServerMessageType MessageSubscribeMultiApplied = FServerMessageType::SubscribeMultiApplied(SubscribeMultiApplied); - TEST_ROUNDTRIP(FServerMessageType, MessageSubscribeMultiApplied, "FServerMessageType::SubscribeMultiApplied Variant"); - FServerMessageType MessageUnsubscribeMultiApplied = FServerMessageType::UnsubscribeMultiApplied(UnsubscribeMultiApplied); - TEST_ROUNDTRIP(FServerMessageType, MessageUnsubscribeMultiApplied, "FServerMessageType::UnsubscribeMultiApplied Variant"); + FServerMessageType MessageReducerResult = FServerMessageType::ReducerResult(ReducerResult); + TEST_ROUNDTRIP(FServerMessageType, MessageReducerResult, "FServerMessageType::ReducerResult Variant"); + FServerMessageType MessageProcedureResult = FServerMessageType::ProcedureResult(ProcedureResult); + TEST_ROUNDTRIP(FServerMessageType, MessageProcedureResult, "FServerMessageType::ProcedureResult Variant"); return true; } diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/BSATN/UEBSATNHelpers.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/BSATN/UEBSATNHelpers.h index b31efce382e..7d44d69c24f 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/BSATN/UEBSATNHelpers.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/BSATN/UEBSATNHelpers.h @@ -2,8 +2,7 @@ #include "CoreMinimal.h" #include "ModuleBindings/Types/TableUpdateType.g.h" -#include "ModuleBindings/Types/QueryUpdateType.g.h" -#include "ModuleBindings/Types/CompressableQueryUpdateType.g.h" +#include "ModuleBindings/Types/TableUpdateRowsType.g.h" #include "DBCache/WithBsatn.h" /** Helper utilities for working with BSATN encoded row data in Unreal. */ @@ -69,18 +68,6 @@ namespace UE::SpacetimeDB } } - /** Parse a query update into row arrays */ - template - static void ParseQueryUpdateWithBsatn( - const FQueryUpdateType& Query, - TArray>& OutInserts, - TArray>& OutDeletes) - { - // Parse inserts and deletes from the query update, retaining BSATN bytes - ParseRowListWithBsatn(Query.Inserts, OutInserts); - ParseRowListWithBsatn(Query.Deletes, OutDeletes); - } - /** Apply a table update keeping BSATN bytes */ template void ProcessTableUpdateWithBsatn( @@ -88,20 +75,24 @@ namespace UE::SpacetimeDB TArray>& Inserts, TArray>& Deletes) { - for (FCompressableQueryUpdateType CQU : TableUpdate.Updates) + for (const FTableUpdateRowsType& RowSet : TableUpdate.Rows) { - FQueryUpdateType QueryUpdate; - //Should be uncompressed at this point - if (CQU.IsUncompressed()) + if (RowSet.IsPersistentTable()) + { + const FPersistentTableRowsType Persistent = RowSet.GetAsPersistentTable(); + ParseRowListWithBsatn(Persistent.Inserts, Inserts); + ParseRowListWithBsatn(Persistent.Deletes, Deletes); + } + // Event-table rows are callback-only inserts and should not create delete paths. + else if (RowSet.IsEventTable()) { - QueryUpdate = CQU.GetAsUncompressed(); + const FEventTableRowsType EventRows = RowSet.GetAsEventTable(); + ParseRowListWithBsatn(EventRows.Events, Inserts); } else { - UE_LOG(LogTemp, Error, TEXT("Compresstion state for row in table %s not uncompressed at parsing step"), *TableUpdate.TableName); - continue; + UE_LOG(LogTemp, Warning, TEXT("Unknown row-set tag for table %s"), *TableUpdate.TableName); } - ParseQueryUpdateWithBsatn(QueryUpdate, Inserts, Deletes); } } @@ -126,7 +117,7 @@ namespace UE::SpacetimeDB public: virtual ~ITableRowDeserializer() {} /** Preprocess the table update and return a shared pointer to preprocessed data. */ - virtual TSharedPtr PreProcess(const TArray& Updates, const FString TableName) const = 0; + virtual TSharedPtr PreProcess(const TArray& RowSets, const FString TableName) const = 0; }; /** Specialization of ITableRowDeserializer for a specific row type not defined in SDK. Used to deserialize rows of a specific type from a database update. */ @@ -134,24 +125,31 @@ namespace UE::SpacetimeDB class TTableRowDeserializer : public ITableRowDeserializer { public: - virtual TSharedPtr PreProcess(const TArray& Updates, const FString TableName) const override + virtual TSharedPtr PreProcess(const TArray& RowSets, const FString TableName) const override { // Create a new preprocessed table data object for the specific row type TSharedPtr> Result = MakeShared>(); - // Process each compressable query update in the table update - for (const FCompressableQueryUpdateType& CQU : Updates) + // Process each row-set update in the table update + for (const FTableUpdateRowsType& RowSet : RowSets) { - if (!CQU.IsUncompressed()) - { - UE_LOG(LogTemp, Error, TEXT("Compresstion state for row in table %s not uncompressed at parsing step"), *TableName); - continue; + if (RowSet.IsPersistentTable()) + { + const FPersistentTableRowsType Persistent = RowSet.GetAsPersistentTable(); + ParseRowListWithBsatn(Persistent.Inserts, Result->Inserts); + ParseRowListWithBsatn(Persistent.Deletes, Result->Deletes); + } + else if (RowSet.IsEventTable()) + { + // Event rows are insert-style callback payloads only. + const FEventTableRowsType Events = RowSet.GetAsEventTable(); + ParseRowListWithBsatn(Events.Events, Result->Inserts); + } + else + { + UE_LOG(LogTemp, Warning, TEXT("Unknown row-set tag for table %s"), *TableName); } - // Get the uncompressed query update from the compressable query update - FQueryUpdateType Query = CQU.GetAsUncompressed(); - // Parse the query update into inserts and deletes, retaining BSATN bytes - ParseQueryUpdateWithBsatn(Query, Result->Inserts, Result->Deletes); } return Result; } }; -} \ No newline at end of file +} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/Callback.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/Callback.h index 3fdcba2979b..c0fa384db4f 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/Callback.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/Callback.h @@ -1,11 +1,7 @@ #pragma once #include "CoreMinimal.h" -#include "ModuleBindings/Types/ServerMessageType.g.h" -#include "ModuleBindings/Types/TransactionUpdateType.g.h" -#include "ModuleBindings/Types/ReducerCallInfoType.g.h" -#include "ModuleBindings/Types/UpdateStatusType.g.h" -#include "ModuleBindings/Types/EnergyQuantaType.g.h" +#include "ModuleBindings/Types/ProcedureStatusType.g.h" #include "Types/Builtins.h" #include "Types/UnitType.h" #include @@ -19,6 +15,61 @@ //Forward declare class UDbConnectionBase; +/** Local reducer call metadata correlated by request_id for generated client dispatch. */ +USTRUCT(BlueprintType) +struct SPACETIMEDBSDK_API FReducerCallInfoType +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FString ReducerName; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + TArray Args; + + FORCEINLINE bool operator==(const FReducerCallInfoType& Other) const + { + return ReducerName == Other.ReducerName && Args == Other.Args; + } + + FORCEINLINE bool operator!=(const FReducerCallInfoType& Other) const + { + return !(*this == Other); + } +}; + +FORCEINLINE uint32 GetTypeHash(const FReducerCallInfoType& ReducerCallInfo) +{ + uint32 Hash = GetTypeHash(ReducerCallInfo.ReducerName); + Hash = HashCombine(Hash, GetTypeHash(ReducerCallInfo.Args)); + return Hash; +} + +/** Local energy field used by generated reducer-event wrappers. */ +USTRUCT(BlueprintType) +struct SPACETIMEDBSDK_API FEnergyQuantaType +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + int64 Value = 0; + + FORCEINLINE bool operator==(const FEnergyQuantaType& Other) const + { + return Value == Other.Value; + } + + FORCEINLINE bool operator!=(const FEnergyQuantaType& Other) const + { + return !(*this == Other); + } +}; + +FORCEINLINE uint32 GetTypeHash(const FEnergyQuantaType& EnergyQuanta) +{ + return GetTypeHash(EnergyQuanta.Value); +} + /** Termination status for a reducer event. */ UENUM(BlueprintType) @@ -194,6 +245,9 @@ struct SPACETIMEDBSDK_API FReducerEvent { GENERATED_BODY() + /** Request id correlated to the originating reducer call (not Blueprint-exposed). */ + uint32 RequestId = 0; + /** Timestamp for when the reducer executed */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") FSpacetimeDBTimestamp Timestamp; @@ -220,7 +274,7 @@ struct SPACETIMEDBSDK_API FReducerEvent FORCEINLINE bool operator==(const FReducerEvent& Other) const { - return Status == Other.Status && Timestamp == Other.Timestamp && CallerIdentity == Other.CallerIdentity && + return RequestId == Other.RequestId && Status == Other.Status && Timestamp == Other.Timestamp && CallerIdentity == Other.CallerIdentity && CallerConnectionId == Other.CallerConnectionId && EnergyConsumed == Other.EnergyConsumed && ReducerCall == Other.ReducerCall; } @@ -232,7 +286,8 @@ struct SPACETIMEDBSDK_API FReducerEvent FORCEINLINE uint32 GetTypeHash(const FReducerEvent& ReducerEvent) { - uint32 Hash = GetTypeHash(ReducerEvent.Status); + uint32 Hash = GetTypeHash(ReducerEvent.RequestId); + Hash = HashCombine(Hash, GetTypeHash(ReducerEvent.Status)); Hash = HashCombine(Hash, GetTypeHash(ReducerEvent.Timestamp)); Hash = HashCombine(Hash, GetTypeHash(ReducerEvent.CallerIdentity)); Hash = HashCombine(Hash, GetTypeHash(ReducerEvent.CallerConnectionId)); @@ -289,6 +344,8 @@ enum class ESpacetimeDBEventTag : uint8 UnsubscribeApplied, /** Connection lost */ Disconnected, + /** Non-reducer transaction update */ + Transaction, /** Subscription error */ SubscribeError, /** Unknown transaction type */ @@ -348,6 +405,14 @@ struct SPACETIMEDBSDK_API FSpacetimeDBEvent return Obj; } + static FSpacetimeDBEvent Transaction(const FSpacetimeDBUnit& Value) + { + FSpacetimeDBEvent Obj; + Obj.Tag = ESpacetimeDBEventTag::Transaction; + Obj.MessageData.Set(Value); + return Obj; + } + static FSpacetimeDBEvent SubscribeError(const FString& InError) { FSpacetimeDBEvent Obj; @@ -402,6 +467,13 @@ struct SPACETIMEDBSDK_API FSpacetimeDBEvent return MessageData.Get(); } + FORCEINLINE bool IsTransaction() const { return Tag == ESpacetimeDBEventTag::Transaction; } + FORCEINLINE FSpacetimeDBUnit GetAsTransaction() const + { + ensureMsgf(IsTransaction(), TEXT("MessageData does not hold Transaction!")); + return MessageData.Get(); + } + FORCEINLINE bool IsSubscribeError() const { return Tag == ESpacetimeDBEventTag::SubscribeError; } FORCEINLINE FString GetAsSubscribeError() const { @@ -437,6 +509,8 @@ struct SPACETIMEDBSDK_API FSpacetimeDBEvent return GetAsUnsubscribeApplied() == Other.GetAsUnsubscribeApplied(); case ESpacetimeDBEventTag::Disconnected: return GetAsDisconnected() == Other.GetAsDisconnected(); + case ESpacetimeDBEventTag::Transaction: + return GetAsTransaction() == Other.GetAsTransaction(); case ESpacetimeDBEventTag::SubscribeError: return GetAsSubscribeError() == Other.GetAsSubscribeError(); case ESpacetimeDBEventTag::UnknownTransaction: @@ -464,6 +538,7 @@ FORCEINLINE uint32 GetTypeHash(const FSpacetimeDBEvent& Event) case ESpacetimeDBEventTag::SubscribeApplied: return HashCombine(TagHash, ::GetTypeHash(Event.GetAsSubscribeApplied())); case ESpacetimeDBEventTag::UnsubscribeApplied: return HashCombine(TagHash, ::GetTypeHash(Event.GetAsUnsubscribeApplied())); case ESpacetimeDBEventTag::Disconnected: return HashCombine(TagHash, ::GetTypeHash(Event.GetAsDisconnected())); + case ESpacetimeDBEventTag::Transaction: return HashCombine(TagHash, ::GetTypeHash(Event.GetAsTransaction())); case ESpacetimeDBEventTag::SubscribeError: return HashCombine(TagHash, GetTypeHash(Event.GetAsSubscribeError())); case ESpacetimeDBEventTag::UnknownTransaction: return HashCombine(TagHash, ::GetTypeHash(Event.GetAsUnknownTransaction())); case ESpacetimeDBEventTag::Procedure: return HashCombine(TagHash, ::GetTypeHash(Event.GetAsProcedure())); @@ -558,10 +633,8 @@ struct SPACETIMEDBSDK_API FSpacetimeDBProcedureStatus public: FSpacetimeDBProcedureStatus() = default; - // NOTE: order matches ESpacetimeDBStatusTag: Committed, Failed, OutOfEnergy // Payloads: // Returned -> FSpacetimeDBUnit - // OutOfEnergy -> FSpacetimeDBUnit // InternalError -> FString TVariant MessageData; @@ -585,22 +658,12 @@ struct SPACETIMEDBSDK_API FSpacetimeDBProcedureStatus return Obj; } - static FSpacetimeDBProcedureStatus OutOfEnergy(const FSpacetimeDBUnit& Value) - { - FSpacetimeDBProcedureStatus Obj; - Obj.Tag = EProcedureStatusTag::OutOfEnergy; - Obj.MessageData.Set(Value); - return Obj; - } - static FSpacetimeDBProcedureStatus FromStatus(const FProcedureStatusType& Value) { switch (Value.Tag) { case EProcedureStatusTag::Returned: return Returned(FSpacetimeDBUnit()); - case EProcedureStatusTag::OutOfEnergy: - return OutOfEnergy(Value.GetAsOutOfEnergy()); case EProcedureStatusTag::InternalError: return InternalError(Value.GetAsInternalError()); default: @@ -609,7 +672,6 @@ struct SPACETIMEDBSDK_API FSpacetimeDBProcedureStatus } // -- Query helpers ---------------------- FORCEINLINE bool IsReturned() const { return Tag == EProcedureStatusTag::Returned; } - FORCEINLINE bool IsOutOfEnergy() const { return Tag == EProcedureStatusTag::OutOfEnergy; } FORCEINLINE bool IsInternalError() const { return Tag == EProcedureStatusTag::InternalError; } FORCEINLINE FSpacetimeDBUnit GetAsReturned() const @@ -618,12 +680,6 @@ struct SPACETIMEDBSDK_API FSpacetimeDBProcedureStatus return MessageData.Get(); } - FORCEINLINE FSpacetimeDBUnit GetAsOutOfEnergy() const - { - ensureMsgf(IsOutOfEnergy(), TEXT("MessageData does not hold OutOfEnergy!")); - return MessageData.Get(); - } - FORCEINLINE FString GetAsInternalError() const { ensureMsgf(IsInternalError(), TEXT("MessageData does not hold InternalError!")); @@ -639,8 +695,6 @@ struct SPACETIMEDBSDK_API FSpacetimeDBProcedureStatus { case EProcedureStatusTag::Returned: return GetAsReturned() == Other.GetAsReturned(); - case EProcedureStatusTag::OutOfEnergy: - return GetAsOutOfEnergy() == Other.GetAsOutOfEnergy(); case EProcedureStatusTag::InternalError: return GetAsInternalError() == Other.GetAsInternalError(); default: @@ -658,8 +712,6 @@ FORCEINLINE uint32 GetTypeHash(const FSpacetimeDBProcedureStatus& Status) { case EProcedureStatusTag::Returned: return HashCombine(TagHash, ::GetTypeHash(Status.GetAsReturned())); - case EProcedureStatusTag::OutOfEnergy: - return HashCombine(TagHash, ::GetTypeHash(Status.GetAsOutOfEnergy())); case EProcedureStatusTag::InternalError: return HashCombine(TagHash, GetTypeHash(Status.GetAsInternalError())); default: @@ -684,21 +736,6 @@ class SPACETIMEDBSDK_API USpacetimeDBProcedureStatusBpLib : public UBlueprintFun // We don't allow the raw value to be exported as GetAsReturned() from the ProcedureEventContext. - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ProcedureStatus") - static FSpacetimeDBProcedureStatus OutOfEnergy(const FSpacetimeDBUnit& InValue) - { - return FSpacetimeDBProcedureStatus::OutOfEnergy(InValue); - } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ProcedureStatus") - static bool IsOutOfEnergy(const FSpacetimeDBProcedureStatus& InValue) { return InValue.IsOutOfEnergy(); } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ProcedureStatus") - static FSpacetimeDBUnit GetAsOutOfEnergy(const FSpacetimeDBProcedureStatus& InValue) - { - return InValue.GetAsOutOfEnergy(); - } - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ProcedureStatus") static FSpacetimeDBProcedureStatus InternalError(const FString& InValue) { diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/DbConnectionBase.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/DbConnectionBase.h index 62caa10efa4..e8c26b3a988 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/DbConnectionBase.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/DbConnectionBase.h @@ -9,11 +9,11 @@ #include "DBCache/TableAppliedDiff.h" #include "HAL/CriticalSection.h" #include "Containers/Queue.h" -#include "HAL/ThreadSafeBool.h" -#include "BSATN/UEBSATNHelpers.h" -#include "Connection/SetReducerFlags.h" -#include "Connection/Callback.h" -#include "LogCategory.h" +#include "HAL/ThreadSafeBool.h" +#include "BSATN/UEBSATNHelpers.h" +#include "Connection/Callback.h" +#include "LogCategory.h" +#include #include "DbConnectionBase.generated.h" @@ -29,7 +29,7 @@ class UProcedureCallbacks; #define UNBIND_DELEGATE_SAFE(DelegateVar, Object, ClassType, FunctionName) \ DelegateVar.Remove(Object, GET_FUNCTION_NAME_CHECKED(ClassType, FunctionName)) -/** Delegate called when the connection attempt fails. */ +/** Delegate called when the connection attempt fails. */ DECLARE_DYNAMIC_DELEGATE_OneParam( FOnConnectErrorDelegate, const FString&, ErrorMessage); @@ -42,33 +42,77 @@ DECLARE_DYNAMIC_DELEGATE_ThreeParams( const FString&, Token); /** Called when a connection closes. */ -DECLARE_DYNAMIC_DELEGATE_TwoParams( - FOnDisconnectBaseDelegate, - UDbConnectionBase*, Connection, - const FString&, Error); - - -/** Key used to index preprocessed table data without relying on row addresses */ -struct FPreprocessedTableKey -{ - uint32 TableId; - FString TableName; - - FPreprocessedTableKey() : TableId(0) {} - FPreprocessedTableKey(uint32 InId, const FString& InName) - : TableId(InId), TableName(InName) { - } - - friend bool operator==(const FPreprocessedTableKey& A, const FPreprocessedTableKey& B) - { - return A.TableId == B.TableId && A.TableName == B.TableName; - } -}; - -FORCEINLINE uint32 GetTypeHash(const FPreprocessedTableKey& Key) -{ - return HashCombine(GetTypeHash(Key.TableId), GetTypeHash(Key.TableName)); -} +DECLARE_DYNAMIC_DELEGATE_TwoParams( + FOnDisconnectBaseDelegate, + UDbConnectionBase*, Connection, + const FString&, Error); + +/** Runtime-compatible database update wrapper used by table-update pipeline. */ +USTRUCT(BlueprintType) +struct SPACETIMEDBSDK_API FDatabaseUpdateType +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + TArray Tables; + + FORCEINLINE bool operator==(const FDatabaseUpdateType& Other) const + { + return Tables == Other.Tables; + } + + FORCEINLINE bool operator!=(const FDatabaseUpdateType& Other) const + { + return !(*this == Other); + } +}; + +FORCEINLINE uint32 GetTypeHash(const FDatabaseUpdateType& DatabaseUpdate) +{ + return GetTypeHash(DatabaseUpdate.Tables); +} + + +/** Key used to index preprocessed table data without relying on row addresses */ +struct FPreprocessedTableKey +{ + FString TableName; + + FPreprocessedTableKey() = default; + explicit FPreprocessedTableKey(const FString& InName) + : TableName(InName) { + } + + friend bool operator==(const FPreprocessedTableKey& A, const FPreprocessedTableKey& B) + { + return A.TableName == B.TableName; + } +}; + +FORCEINLINE uint32 GetTypeHash(const FPreprocessedTableKey& Key) +{ + return GetTypeHash(Key.TableName); +} + +template +struct THasOnDeleteDelegate : std::false_type +{ +}; + +template +struct THasOnDeleteDelegate> : std::true_type +{ +}; + +template +struct THasOnUpdateDelegate : std::false_type +{ +}; + +template +struct THasOnUpdateDelegate> : std::true_type +{ +}; UCLASS() class SPACETIMEDBSDK_API UDbConnectionBase : public UObject, public FTickableGameObject @@ -112,12 +156,12 @@ class SPACETIMEDBSDK_API UDbConnectionBase : public UObject, public FTickableGam FSpacetimeDBConnectionId GetConnectionId() const; // Typed reducer call helper: hides BSATN bytes from callers. - template - void CallReducerTyped(const FString& Reducer, const ArgsStruct& Args, USetReducerFlagsBase* Flags) - { - TArray Bytes = UE::SpacetimeDB::Serialize(Args); - InternalCallReducer(Reducer, MoveTemp(Bytes), Flags); - } + template + uint32 CallReducerTyped(const FString& Reducer, const ArgsStruct& Args) + { + TArray Bytes = UE::SpacetimeDB::Serialize(Args); + return InternalCallReducer(Reducer, MoveTemp(Bytes)); + } template void CallProcedureTyped(const FString& ProcedureName, const ArgsStruct& Args, const FOnProcedureCompleteDelegate& Callback) @@ -192,12 +236,12 @@ class SPACETIMEDBSDK_API UDbConnectionBase : public UObject, public FTickableGam } //** Take preprocessed table row data. */ template - bool TakePreprocessedTableData(const FTableUpdateType& Update, TSharedPtr>& OutData) - { - FScopeLock Lock(&PreprocessedDataMutex); - FPreprocessedTableKey Key(Update.TableId, Update.TableName); - if (TArray>* Found = PreprocessedTableData.Find(Key)) - { + bool TakePreprocessedTableData(const FTableUpdateType& Update, TSharedPtr>& OutData) + { + FScopeLock Lock(&PreprocessedDataMutex); + FPreprocessedTableKey Key(Update.TableName); + if (TArray>* Found = PreprocessedTableData.Find(Key)) + { if (Found->Num() > 0) { OutData = StaticCastSharedPtr>((*Found)[0]); @@ -240,14 +284,16 @@ class SPACETIMEDBSDK_API UDbConnectionBase : public UObject, public FTickableGam virtual bool IsTickableInEditor() const override; - /** Internal handler that processes a single server message. */ - void ProcessServerMessage(const FServerMessageType& Message); - void PreProcessDatabaseUpdate(const FDatabaseUpdateType& Update); - /** Decompress and parse a raw message. */ - FServerMessageType PreProcessMessage(const TArray& Message); - bool DecompressPayload(ECompressableQueryUpdateTag Variant, const TArray& In, TArray& Out); - bool DecompressGzip(const TArray& InData, TArray& OutData); - bool DecompressBrotli(const TArray& InData, TArray& OutData); + /** Internal handler that processes a single server message. */ + void ProcessServerMessage(const FServerMessageType& Message); + void PreProcessDatabaseUpdate(const FDatabaseUpdateType& Update); + /** Decompress and parse a raw message. */ + bool PreProcessMessage(const TArray& Message, FServerMessageType& OutMessage); + bool DecompressPayload(uint8 Variant, const TArray& In, TArray& Out); + bool DecompressGzip(const TArray& InData, TArray& OutData); + bool DecompressBrotli(const TArray& InData, TArray& OutData); + void ClearPendingOperations(const FString& Reason); + void HandleProtocolViolation(const FString& ErrorMessage); /** Pending messages awaiting processing on the game thread. */ TArray PendingMessages; @@ -286,7 +332,7 @@ class SPACETIMEDBSDK_API UDbConnectionBase : public UObject, public FTickableGam void UnsubscribeInternal(USubscriptionHandleBase* Handle); /** Call a reducer on the connected SpacetimeDB instance. */ - void InternalCallReducer(const FString& Reducer, TArray Args, USetReducerFlagsBase* Flags); + uint32 InternalCallReducer(const FString& Reducer, TArray Args); /** Call a reducer on the connected SpacetimeDB instance. */ void InternalCallProcedure(const FString& ProcedureName, TArray Args, const FOnProcedureCompleteDelegate& Callback); @@ -316,20 +362,24 @@ class SPACETIMEDBSDK_API UDbConnectionBase : public UObject, public FTickableGam /** Apply updates for all registered tables using the provided context pointer */ void ApplyRegisteredTableUpdates(const FDatabaseUpdateType& Update, void* Context); - /** Called when a subscription is updated. */ - UPROPERTY() - TMap> ActiveSubscriptions; + /** Called when a subscription is updated. */ + UPROPERTY() + TMap> ActiveSubscriptions; + + /** Pending reducer call metadata keyed by request id for ReducerResult correlation. */ + UPROPERTY() + TMap PendingReducerCalls; UPROPERTY() TObjectPtr ProcedureCallbacks; - /** Get the next request id for a message. This is used to track requests and responses. */ - int32 NextRequestId; - /** Get the next subscription id for a subscription. This is used to track subscriptions and their responses. */ - int32 NextSubscriptionId; - /** Get the next request id for a message. This is used to track requests and responses. */ - int32 GetNextRequestId(); - /** Get the next subscription id for a subscription. This is used to track subscriptions and their responses. */ - int32 GetNextSubscriptionId(); + /** Get the next request id for a message. This is used to track requests and responses. */ + uint32 NextRequestId; + /** Get the next subscription id for a subscription. This is used to track subscriptions and their responses. */ + uint32 NextSubscriptionId; + /** Get the next request id for a message. This is used to track requests and responses. */ + uint32 GetNextRequestId(); + /** Get the next subscription id for a subscription. This is used to track subscriptions and their responses. */ + uint32 GetNextSubscriptionId(); /** The WebSocket manager used to connect to the server. */ UPROPERTY() @@ -355,8 +405,10 @@ class SPACETIMEDBSDK_API UDbConnectionBase : public UObject, public FTickableGam UPROPERTY() FSpacetimeDBConnectionId ConnectionId; - UPROPERTY() - bool bIsAutoTicking = false; + UPROPERTY() + bool bIsAutoTicking = false; + /** Guard to avoid repeatedly handling the same fatal protocol error. */ + FThreadSafeBool bProtocolViolationHandled = false; UPROPERTY() FOnConnectErrorDelegate OnConnectErrorDelegate; @@ -380,25 +432,30 @@ class SPACETIMEDBSDK_API UDbConnectionBase : public UObject, public FTickableGam } } - // If the table has a delete delegate, broadcast deletes - if (Table->OnDelete.IsBound()) - { - for (const TPair, RowType>& Pair : Diff.Deletes) - { - Table->OnDelete.Broadcast(Context, Pair.Value); - } - } - - // If the table has an update delegate, broadcast updates - if (Table->OnUpdate.IsBound()) - { - int32 Count = FMath::Min(Diff.UpdateDeletes.Num(), Diff.UpdateInserts.Num()); - for (int32 Index = 0; Index < Count; ++Index) - { - const RowType& OldRow = Diff.UpdateDeletes[Index]; - const RowType& NewRow = Diff.UpdateInserts[Index]; - Table->OnUpdate.Broadcast(Context, OldRow, NewRow); - } - } - } -}; + // Event tables intentionally omit delete/update delegates. + if constexpr (THasOnDeleteDelegate::value) + { + if (Table->OnDelete.IsBound()) + { + for (const TPair, RowType>& Pair : Diff.Deletes) + { + Table->OnDelete.Broadcast(Context, Pair.Value); + } + } + } + + if constexpr (THasOnUpdateDelegate::value) + { + if (Table->OnUpdate.IsBound()) + { + int32 Count = FMath::Min(Diff.UpdateDeletes.Num(), Diff.UpdateInserts.Num()); + for (int32 Index = 0; Index < Count; ++Index) + { + const RowType& OldRow = Diff.UpdateDeletes[Index]; + const RowType& NewRow = Diff.UpdateInserts[Index]; + Table->OnUpdate.Broadcast(Context, OldRow, NewRow); + } + } + } + } +}; diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/DbConnectionBuilder.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/DbConnectionBuilder.h index 37b6c3ae76a..a828570bae1 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/DbConnectionBuilder.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/DbConnectionBuilder.h @@ -3,7 +3,6 @@ #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "Connection/DbConnectionBase.h" -#include "ModuleBindings/Types/CompressableQueryUpdateType.g.h" #include "DbConnectionBuilder.generated.h" UCLASS(BlueprintType) diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/README.md b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/README.md index 806c02675fa..85258bc9c36 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/README.md +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/README.md @@ -4,10 +4,9 @@ This folder contains the classes used to open and manage a connection to a Space ## Files -- `Callback.h` Defines `UStatus` and related enums used to report reducer results and statuses to the user. -- `Credentials.h` Static helper functions for persisting authentication tokens via Unreal's config system. -- `DbConnectionBase.h` Core connection object. Handles websocket events, table caches and reducer calls. Used as a base class for generated `DbConnection` class. -- `DbConnectionBuilder.h` Fluent builder used to configure a connection instance and bind event delegates. Used as a base class for generated `DbConnectionBuilder` class. -- `SetReducerFlags.h` Container for flags controlling reducer call behaviour (e.g. disabling/enabling success notifications). -- `Subscription.h` Classes for constructing and managing query subscriptions. -- `Websocket.h` Wrapper around UE's `IWebSocket` that sends/receives messages. \ No newline at end of file +- `Callback.h` � Defines `UStatus` and related enums used to report reducer results and statuses to the user. +- `Credentials.h` � Static helper functions for persisting authentication tokens via Unreal's config system. +- `DbConnectionBase.h` � Core connection object. Handles websocket events, table caches and reducer calls. Used as a base class for generated `DbConnection` class. +- `DbConnectionBuilder.h` � Fluent builder used to configure a connection instance and bind event delegates. Used as a base class for generated `DbConnectionBuilder` class. +- `Subscription.h` � Classes for constructing and managing query subscriptions. +- `Websocket.h` � Wrapper around UE's `IWebSocket` that sends/receives messages. diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/SetReducerFlags.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/SetReducerFlags.h deleted file mode 100644 index 27b8e26a93f..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/SetReducerFlags.h +++ /dev/null @@ -1,31 +0,0 @@ - -#pragma once - -#include "CoreMinimal.h" -#include "SetReducerFlags.generated.h" - - -/** Flags controlling reducer call behavior */ -UENUM(BlueprintType) -enum class ECallReducerFlags : uint8 -{ - /** Default behavior - server will send full update and success notification */ - FullUpdate UMETA(DisplayName = "FullUpdate"), - - /** Do not send success notification after reducer completes */ - NoSuccessNotify UMETA(DisplayName = "NoSuccessNotify"), -}; - -/** Container for per-reducer call flags */ -UCLASS(BlueprintType) -class SPACETIMEDBSDK_API USetReducerFlagsBase : public UObject -{ - GENERATED_BODY() - -protected: - - friend class UDbConnectionBase; - - UPROPERTY() - TMap FlagMap; -}; \ No newline at end of file diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/Subscription.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/Subscription.h index ba9096a22ee..18985312953 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/Subscription.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/Subscription.h @@ -70,7 +70,7 @@ class SPACETIMEDBSDK_API USubscriptionHandleBase : public UObject FSubscriptionEventDelegate EndDelegate; /** Identifier for this subscription */ - int32 QueryId = -1; + uint32 QuerySetId = 0; friend class USubscriptionBuilderBase; friend class UDbConnectionBase; diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/Websocket.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/Websocket.h index 8ac2b396416..b9e6f91378d 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/Websocket.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/Connection/Websocket.h @@ -1,10 +1,9 @@ #pragma once -#include "CoreMinimal.h" -#include "IWebSocket.h" -#include "ModuleBindings/Types/ServerMessageType.g.h" -#include "ModuleBindings/Types/CompressableQueryUpdateType.g.h" -#include "JsonObjectConverter.h" // for JSON debugging helpers +#include "CoreMinimal.h" +#include "IWebSocket.h" +#include "ModuleBindings/Types/ServerMessageType.g.h" +#include "JsonObjectConverter.h" // for JSON debugging helpers #include "Async/Async.h" #include "HAL/CriticalSection.h" #include "Misc/ScopeLock.h" @@ -111,13 +110,6 @@ class SPACETIMEDBSDK_API UWebsocketManager : public UObject /** Handler for socket close */ void HandleClosed(int32 StatusCode, const FString& Reason, bool bWasClean); - /** Decompresses a payload based on compression variant */ - bool DecompressPayload(ECompressableQueryUpdateTag Variant, const TArray& In, TArray& Out); - /** GZip decompression helper */ - bool DecompressGzip(const TArray& InData, TArray& OutData); - /** Brotli decompression helper */ - bool DecompressBrotli(const TArray& InData, TArray& OutData); - FString InitToken; /** Buffer used to accumulate binary fragments until a complete message @@ -172,4 +164,4 @@ static void LogAsJson(const StructType& InStruct, const TCHAR* TagName) UE_LOG(LogSpacetimeDb_Connection, Warning, TEXT("[%s] Failed to serialize object: %s"), TagName, *ObjectName); } } -} \ No newline at end of file +} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Optionals/SpacetimeDbSdkOptionalString.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Optionals/SpacetimeDbSdkOptionalQueryRows.g.h similarity index 56% rename from sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Optionals/SpacetimeDbSdkOptionalString.g.h rename to sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Optionals/SpacetimeDbSdkOptionalQueryRows.g.h index 8f152dad9c3..7a26f02d506 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Optionals/SpacetimeDbSdkOptionalString.g.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Optionals/SpacetimeDbSdkOptionalQueryRows.g.h @@ -4,10 +4,11 @@ #pragma once #include "CoreMinimal.h" #include "BSATN/UESpacetimeDB.h" -#include "SpacetimeDbSdkOptionalString.g.generated.h" +#include "ModuleBindings/Types/QueryRowsType.g.h" +#include "SpacetimeDbSdkOptionalQueryRows.g.generated.h" USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FSpacetimeDbSdkOptionalString +struct SPACETIMEDBSDK_API FSpacetimeDbSdkOptionalQueryRows { GENERATED_BODY() @@ -15,35 +16,35 @@ struct SPACETIMEDBSDK_API FSpacetimeDbSdkOptionalString bool bHasValue = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "bHasValue")) - FString Value; + FQueryRowsType Value; - FSpacetimeDbSdkOptionalString() = default; + FSpacetimeDbSdkOptionalQueryRows() = default; - explicit FSpacetimeDbSdkOptionalString(const FString& InValue) + explicit FSpacetimeDbSdkOptionalQueryRows(const FQueryRowsType& InValue) : bHasValue(true), Value(InValue) {} bool IsSet() const { return bHasValue; } void Reset() { bHasValue = false; } - FORCEINLINE bool operator==(const FSpacetimeDbSdkOptionalString& Other) const + FORCEINLINE bool operator==(const FSpacetimeDbSdkOptionalQueryRows& Other) const { if (bHasValue != Other.bHasValue) return false; return !bHasValue || Value == Other.Value; } - FORCEINLINE bool operator!=(const FSpacetimeDbSdkOptionalString& Other) const + FORCEINLINE bool operator!=(const FSpacetimeDbSdkOptionalQueryRows& Other) const { return !(*this == Other); } }; /** - * Custom hash function for FSpacetimeDbSdkOptionalString. + * Custom hash function for FSpacetimeDbSdkOptionalQueryRows. * Hashes the HasValue flag and the Value if present. - * @param Optional The FSpacetimeDbSdkOptionalString instance to hash. + * @param Optional The FSpacetimeDbSdkOptionalQueryRows instance to hash. * @return The combined hash value. */ -FORCEINLINE uint32 GetTypeHash(const FSpacetimeDbSdkOptionalString& Optional) +FORCEINLINE uint32 GetTypeHash(const FSpacetimeDbSdkOptionalQueryRows& Optional) { uint32 Hash = GetTypeHash(Optional.bHasValue); if (Optional.bHasValue) @@ -55,7 +56,7 @@ FORCEINLINE uint32 GetTypeHash(const FSpacetimeDbSdkOptionalString& Optional) namespace UE::SpacetimeDB { - UE_SPACETIMEDB_ENABLE_TARRAY(FSpacetimeDbSdkOptionalString); + UE_SPACETIMEDB_ENABLE_TARRAY(FSpacetimeDbSdkOptionalQueryRows); - UE_SPACETIMEDB_OPTIONAL(FSpacetimeDbSdkOptionalString, bHasValue, Value); + UE_SPACETIMEDB_OPTIONAL(FSpacetimeDbSdkOptionalQueryRows, bHasValue, Value); } diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Results/SpacetimeDbSdkResultQueryRowsString.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Results/SpacetimeDbSdkResultQueryRowsString.g.h new file mode 100644 index 00000000000..2f3d2ecb459 --- /dev/null +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Results/SpacetimeDbSdkResultQueryRowsString.g.h @@ -0,0 +1,101 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#pragma once +#include "CoreMinimal.h" +#include "BSATN/UESpacetimeDB.h" +#include "ModuleBindings/Types/QueryRowsType.g.h" +#include "SpacetimeDbSdkResultQueryRowsString.g.generated.h" + +USTRUCT(BlueprintType) +struct SPACETIMEDBSDK_API FSpacetimeDbSdkResultQueryRowsString +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + bool bIsOk = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "bIsOk")) + FQueryRowsType OkValue; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "!bIsOk")) + FString ErrValue; + + FSpacetimeDbSdkResultQueryRowsString() = default; + + static FSpacetimeDbSdkResultQueryRowsString Ok(const FQueryRowsType& InValue) + { + FSpacetimeDbSdkResultQueryRowsString Result; + Result.bIsOk = true; + Result.OkValue = InValue; + return Result; + } + + static FSpacetimeDbSdkResultQueryRowsString Err(const FString& InValue) + { + FSpacetimeDbSdkResultQueryRowsString Result; + Result.bIsOk = false; + Result.ErrValue = InValue; + return Result; + } + + bool IsOk() const { return bIsOk; } + bool IsErr() const { return !bIsOk; } + + const FQueryRowsType& GetOk() const + { + check(bIsOk); + return OkValue; + } + + const FString& GetErr() const + { + check(!bIsOk); + return ErrValue; + } + + FORCEINLINE bool operator==(const FSpacetimeDbSdkResultQueryRowsString& Other) const + { + if (bIsOk != Other.bIsOk) return false; + if (bIsOk) + { + return OkValue == Other.OkValue; + } + else + { + return ErrValue == Other.ErrValue; + } + } + + FORCEINLINE bool operator!=(const FSpacetimeDbSdkResultQueryRowsString& Other) const + { + return !(*this == Other); + } +}; + +/** + * Custom hash function for FSpacetimeDbSdkResultQueryRowsString. + * Hashes the bIsOk flag and the appropriate value. + * @param Result The FSpacetimeDbSdkResultQueryRowsString instance to hash. + * @return The combined hash value. + */ +FORCEINLINE uint32 GetTypeHash(const FSpacetimeDbSdkResultQueryRowsString& Result) +{ + uint32 Hash = GetTypeHash(Result.bIsOk); + if (Result.bIsOk) + { + Hash = HashCombine(Hash, GetTypeHash(Result.OkValue)); + } + else + { + Hash = HashCombine(Hash, GetTypeHash(Result.ErrValue)); + } + return Hash; +} + +namespace UE::SpacetimeDB +{ + UE_SPACETIMEDB_ENABLE_TARRAY(FSpacetimeDbSdkResultQueryRowsString); + + UE_SPACETIMEDB_RESULT(FSpacetimeDbSdkResultQueryRowsString, bIsOk, OkValue, ErrValue); +} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/CallProcedureType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/CallProcedureType.g.h index 10e8a529ba0..5584492e69f 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/CallProcedureType.g.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/CallProcedureType.g.h @@ -11,21 +11,21 @@ struct SPACETIMEDBSDK_API FCallProcedureType { GENERATED_BODY() - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FString Procedure; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - TArray Args; - // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements uint32 RequestId = 0; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") uint8 Flags = 0; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FString Procedure; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + TArray Args; + FORCEINLINE bool operator==(const FCallProcedureType& Other) const { - return Procedure == Other.Procedure && Args == Other.Args && RequestId == Other.RequestId && Flags == Other.Flags; + return RequestId == Other.RequestId && Flags == Other.Flags && Procedure == Other.Procedure && Args == Other.Args; } FORCEINLINE bool operator!=(const FCallProcedureType& Other) const @@ -42,10 +42,10 @@ struct SPACETIMEDBSDK_API FCallProcedureType */ FORCEINLINE uint32 GetTypeHash(const FCallProcedureType& CallProcedureType) { - uint32 Hash = GetTypeHash(CallProcedureType.Procedure); - Hash = HashCombine(Hash, GetTypeHash(CallProcedureType.Args)); - Hash = HashCombine(Hash, GetTypeHash(CallProcedureType.RequestId)); + uint32 Hash = GetTypeHash(CallProcedureType.RequestId); Hash = HashCombine(Hash, GetTypeHash(CallProcedureType.Flags)); + Hash = HashCombine(Hash, GetTypeHash(CallProcedureType.Procedure)); + Hash = HashCombine(Hash, GetTypeHash(CallProcedureType.Args)); return Hash; } @@ -53,5 +53,5 @@ namespace UE::SpacetimeDB { UE_SPACETIMEDB_ENABLE_TARRAY(FCallProcedureType); - UE_SPACETIMEDB_STRUCT(FCallProcedureType, Procedure, Args, RequestId, Flags); + UE_SPACETIMEDB_STRUCT(FCallProcedureType, RequestId, Flags, Procedure, Args); } diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/CallReducerType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/CallReducerType.g.h index c8221f41d65..da1431282d6 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/CallReducerType.g.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/CallReducerType.g.h @@ -11,21 +11,21 @@ struct SPACETIMEDBSDK_API FCallReducerType { GENERATED_BODY() - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FString Reducer; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - TArray Args; - // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements uint32 RequestId = 0; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") uint8 Flags = 0; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FString Reducer; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + TArray Args; + FORCEINLINE bool operator==(const FCallReducerType& Other) const { - return Reducer == Other.Reducer && Args == Other.Args && RequestId == Other.RequestId && Flags == Other.Flags; + return RequestId == Other.RequestId && Flags == Other.Flags && Reducer == Other.Reducer && Args == Other.Args; } FORCEINLINE bool operator!=(const FCallReducerType& Other) const @@ -42,10 +42,10 @@ struct SPACETIMEDBSDK_API FCallReducerType */ FORCEINLINE uint32 GetTypeHash(const FCallReducerType& CallReducerType) { - uint32 Hash = GetTypeHash(CallReducerType.Reducer); - Hash = HashCombine(Hash, GetTypeHash(CallReducerType.Args)); - Hash = HashCombine(Hash, GetTypeHash(CallReducerType.RequestId)); + uint32 Hash = GetTypeHash(CallReducerType.RequestId); Hash = HashCombine(Hash, GetTypeHash(CallReducerType.Flags)); + Hash = HashCombine(Hash, GetTypeHash(CallReducerType.Reducer)); + Hash = HashCombine(Hash, GetTypeHash(CallReducerType.Args)); return Hash; } @@ -53,5 +53,5 @@ namespace UE::SpacetimeDB { UE_SPACETIMEDB_ENABLE_TARRAY(FCallReducerType); - UE_SPACETIMEDB_STRUCT(FCallReducerType, Reducer, Args, RequestId, Flags); + UE_SPACETIMEDB_STRUCT(FCallReducerType, RequestId, Flags, Reducer, Args); } diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ClientMessageType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ClientMessageType.g.h index bc2d3a23330..08315cfcf36 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ClientMessageType.g.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ClientMessageType.g.h @@ -4,27 +4,21 @@ #pragma once #include "CoreMinimal.h" #include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/SubscribeMultiType.g.h" +#include "ModuleBindings/Types/UnsubscribeType.g.h" #include "ModuleBindings/Types/CallReducerType.g.h" -#include "ModuleBindings/Types/OneOffQueryType.g.h" #include "ModuleBindings/Types/CallProcedureType.g.h" -#include "ModuleBindings/Types/UnsubscribeType.g.h" #include "ModuleBindings/Types/SubscribeType.g.h" #include "Kismet/BlueprintFunctionLibrary.h" -#include "ModuleBindings/Types/SubscribeSingleType.g.h" -#include "ModuleBindings/Types/UnsubscribeMultiType.g.h" +#include "ModuleBindings/Types/OneOffQueryType.g.h" #include "ClientMessageType.g.generated.h" UENUM(BlueprintType) enum class EClientMessageTag : uint8 { - CallReducer, Subscribe, - OneOffQuery, - SubscribeSingle, - SubscribeMulti, Unsubscribe, - UnsubscribeMulti, + OneOffQuery, + CallReducer, CallProcedure }; @@ -36,19 +30,11 @@ struct SPACETIMEDBSDK_API FClientMessageType public: FClientMessageType() = default; - TVariant MessageData; + TVariant MessageData; - UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") + UPROPERTY(BlueprintReadOnly) EClientMessageTag Tag = static_cast(0); - static FClientMessageType CallReducer(const FCallReducerType& Value) - { - FClientMessageType Obj; - Obj.Tag = EClientMessageTag::CallReducer; - Obj.MessageData.Set(Value); - return Obj; - } - static FClientMessageType Subscribe(const FSubscribeType& Value) { FClientMessageType Obj; @@ -57,43 +43,27 @@ struct SPACETIMEDBSDK_API FClientMessageType return Obj; } - static FClientMessageType OneOffQuery(const FOneOffQueryType& Value) - { - FClientMessageType Obj; - Obj.Tag = EClientMessageTag::OneOffQuery; - Obj.MessageData.Set(Value); - return Obj; - } - - static FClientMessageType SubscribeSingle(const FSubscribeSingleType& Value) - { - FClientMessageType Obj; - Obj.Tag = EClientMessageTag::SubscribeSingle; - Obj.MessageData.Set(Value); - return Obj; - } - - static FClientMessageType SubscribeMulti(const FSubscribeMultiType& Value) + static FClientMessageType Unsubscribe(const FUnsubscribeType& Value) { FClientMessageType Obj; - Obj.Tag = EClientMessageTag::SubscribeMulti; - Obj.MessageData.Set(Value); + Obj.Tag = EClientMessageTag::Unsubscribe; + Obj.MessageData.Set(Value); return Obj; } - static FClientMessageType Unsubscribe(const FUnsubscribeType& Value) + static FClientMessageType OneOffQuery(const FOneOffQueryType& Value) { FClientMessageType Obj; - Obj.Tag = EClientMessageTag::Unsubscribe; - Obj.MessageData.Set(Value); + Obj.Tag = EClientMessageTag::OneOffQuery; + Obj.MessageData.Set(Value); return Obj; } - static FClientMessageType UnsubscribeMulti(const FUnsubscribeMultiType& Value) + static FClientMessageType CallReducer(const FCallReducerType& Value) { FClientMessageType Obj; - Obj.Tag = EClientMessageTag::UnsubscribeMulti; - Obj.MessageData.Set(Value); + Obj.Tag = EClientMessageTag::CallReducer; + Obj.MessageData.Set(Value); return Obj; } @@ -105,14 +75,6 @@ struct SPACETIMEDBSDK_API FClientMessageType return Obj; } - FORCEINLINE bool IsCallReducer() const { return Tag == EClientMessageTag::CallReducer; } - - FORCEINLINE FCallReducerType GetAsCallReducer() const - { - ensureMsgf(IsCallReducer(), TEXT("MessageData does not hold CallReducer!")); - return MessageData.Get(); - } - FORCEINLINE bool IsSubscribe() const { return Tag == EClientMessageTag::Subscribe; } FORCEINLINE FSubscribeType GetAsSubscribe() const @@ -121,30 +83,6 @@ struct SPACETIMEDBSDK_API FClientMessageType return MessageData.Get(); } - FORCEINLINE bool IsOneOffQuery() const { return Tag == EClientMessageTag::OneOffQuery; } - - FORCEINLINE FOneOffQueryType GetAsOneOffQuery() const - { - ensureMsgf(IsOneOffQuery(), TEXT("MessageData does not hold OneOffQuery!")); - return MessageData.Get(); - } - - FORCEINLINE bool IsSubscribeSingle() const { return Tag == EClientMessageTag::SubscribeSingle; } - - FORCEINLINE FSubscribeSingleType GetAsSubscribeSingle() const - { - ensureMsgf(IsSubscribeSingle(), TEXT("MessageData does not hold SubscribeSingle!")); - return MessageData.Get(); - } - - FORCEINLINE bool IsSubscribeMulti() const { return Tag == EClientMessageTag::SubscribeMulti; } - - FORCEINLINE FSubscribeMultiType GetAsSubscribeMulti() const - { - ensureMsgf(IsSubscribeMulti(), TEXT("MessageData does not hold SubscribeMulti!")); - return MessageData.Get(); - } - FORCEINLINE bool IsUnsubscribe() const { return Tag == EClientMessageTag::Unsubscribe; } FORCEINLINE FUnsubscribeType GetAsUnsubscribe() const @@ -153,12 +91,20 @@ struct SPACETIMEDBSDK_API FClientMessageType return MessageData.Get(); } - FORCEINLINE bool IsUnsubscribeMulti() const { return Tag == EClientMessageTag::UnsubscribeMulti; } + FORCEINLINE bool IsOneOffQuery() const { return Tag == EClientMessageTag::OneOffQuery; } - FORCEINLINE FUnsubscribeMultiType GetAsUnsubscribeMulti() const + FORCEINLINE FOneOffQueryType GetAsOneOffQuery() const { - ensureMsgf(IsUnsubscribeMulti(), TEXT("MessageData does not hold UnsubscribeMulti!")); - return MessageData.Get(); + ensureMsgf(IsOneOffQuery(), TEXT("MessageData does not hold OneOffQuery!")); + return MessageData.Get(); + } + + FORCEINLINE bool IsCallReducer() const { return Tag == EClientMessageTag::CallReducer; } + + FORCEINLINE FCallReducerType GetAsCallReducer() const + { + ensureMsgf(IsCallReducer(), TEXT("MessageData does not hold CallReducer!")); + return MessageData.Get(); } FORCEINLINE bool IsCallProcedure() const { return Tag == EClientMessageTag::CallProcedure; } @@ -176,20 +122,14 @@ struct SPACETIMEDBSDK_API FClientMessageType switch (Tag) { - case EClientMessageTag::CallReducer: - return GetAsCallReducer() == Other.GetAsCallReducer(); case EClientMessageTag::Subscribe: return GetAsSubscribe() == Other.GetAsSubscribe(); - case EClientMessageTag::OneOffQuery: - return GetAsOneOffQuery() == Other.GetAsOneOffQuery(); - case EClientMessageTag::SubscribeSingle: - return GetAsSubscribeSingle() == Other.GetAsSubscribeSingle(); - case EClientMessageTag::SubscribeMulti: - return GetAsSubscribeMulti() == Other.GetAsSubscribeMulti(); case EClientMessageTag::Unsubscribe: return GetAsUnsubscribe() == Other.GetAsUnsubscribe(); - case EClientMessageTag::UnsubscribeMulti: - return GetAsUnsubscribeMulti() == Other.GetAsUnsubscribeMulti(); + case EClientMessageTag::OneOffQuery: + return GetAsOneOffQuery() == Other.GetAsOneOffQuery(); + case EClientMessageTag::CallReducer: + return GetAsCallReducer() == Other.GetAsCallReducer(); case EClientMessageTag::CallProcedure: return GetAsCallProcedure() == Other.GetAsCallProcedure(); default: @@ -214,13 +154,10 @@ FORCEINLINE uint32 GetTypeHash(const FClientMessageType& ClientMessage) const uint32 TagHash = GetTypeHash(static_cast(ClientMessage.Tag)); switch (ClientMessage.Tag) { - case EClientMessageTag::CallReducer: return HashCombine(TagHash, ::GetTypeHash(ClientMessage.GetAsCallReducer())); case EClientMessageTag::Subscribe: return HashCombine(TagHash, ::GetTypeHash(ClientMessage.GetAsSubscribe())); - case EClientMessageTag::OneOffQuery: return HashCombine(TagHash, ::GetTypeHash(ClientMessage.GetAsOneOffQuery())); - case EClientMessageTag::SubscribeSingle: return HashCombine(TagHash, ::GetTypeHash(ClientMessage.GetAsSubscribeSingle())); - case EClientMessageTag::SubscribeMulti: return HashCombine(TagHash, ::GetTypeHash(ClientMessage.GetAsSubscribeMulti())); case EClientMessageTag::Unsubscribe: return HashCombine(TagHash, ::GetTypeHash(ClientMessage.GetAsUnsubscribe())); - case EClientMessageTag::UnsubscribeMulti: return HashCombine(TagHash, ::GetTypeHash(ClientMessage.GetAsUnsubscribeMulti())); + case EClientMessageTag::OneOffQuery: return HashCombine(TagHash, ::GetTypeHash(ClientMessage.GetAsOneOffQuery())); + case EClientMessageTag::CallReducer: return HashCombine(TagHash, ::GetTypeHash(ClientMessage.GetAsCallReducer())); case EClientMessageTag::CallProcedure: return HashCombine(TagHash, ::GetTypeHash(ClientMessage.GetAsCallProcedure())); default: return TagHash; } @@ -234,13 +171,10 @@ namespace UE::SpacetimeDB FClientMessageType, EClientMessageTag, MessageData, - CallReducer, FCallReducerType, Subscribe, FSubscribeType, - OneOffQuery, FOneOffQueryType, - SubscribeSingle, FSubscribeSingleType, - SubscribeMulti, FSubscribeMultiType, Unsubscribe, FUnsubscribeType, - UnsubscribeMulti, FUnsubscribeMultiType, + OneOffQuery, FOneOffQueryType, + CallReducer, FCallReducerType, CallProcedure, FCallProcedureType ); } @@ -251,21 +185,6 @@ class SPACETIMEDBSDK_API UClientMessageBpLib : public UBlueprintFunctionLibrary GENERATED_BODY() private: - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ClientMessage") - static FClientMessageType CallReducer(const FCallReducerType& InValue) - { - return FClientMessageType::CallReducer(InValue); - } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ClientMessage") - static bool IsCallReducer(const FClientMessageType& InValue) { return InValue.IsCallReducer(); } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ClientMessage") - static FCallReducerType GetAsCallReducer(const FClientMessageType& InValue) - { - return InValue.GetAsCallReducer(); - } - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ClientMessage") static FClientMessageType Subscribe(const FSubscribeType& InValue) { @@ -282,78 +201,48 @@ class SPACETIMEDBSDK_API UClientMessageBpLib : public UBlueprintFunctionLibrary } UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ClientMessage") - static FClientMessageType OneOffQuery(const FOneOffQueryType& InValue) - { - return FClientMessageType::OneOffQuery(InValue); - } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ClientMessage") - static bool IsOneOffQuery(const FClientMessageType& InValue) { return InValue.IsOneOffQuery(); } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ClientMessage") - static FOneOffQueryType GetAsOneOffQuery(const FClientMessageType& InValue) - { - return InValue.GetAsOneOffQuery(); - } - - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ClientMessage") - static FClientMessageType SubscribeSingle(const FSubscribeSingleType& InValue) - { - return FClientMessageType::SubscribeSingle(InValue); - } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ClientMessage") - static bool IsSubscribeSingle(const FClientMessageType& InValue) { return InValue.IsSubscribeSingle(); } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ClientMessage") - static FSubscribeSingleType GetAsSubscribeSingle(const FClientMessageType& InValue) - { - return InValue.GetAsSubscribeSingle(); - } - - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ClientMessage") - static FClientMessageType SubscribeMulti(const FSubscribeMultiType& InValue) + static FClientMessageType Unsubscribe(const FUnsubscribeType& InValue) { - return FClientMessageType::SubscribeMulti(InValue); + return FClientMessageType::Unsubscribe(InValue); } UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ClientMessage") - static bool IsSubscribeMulti(const FClientMessageType& InValue) { return InValue.IsSubscribeMulti(); } + static bool IsUnsubscribe(const FClientMessageType& InValue) { return InValue.IsUnsubscribe(); } UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ClientMessage") - static FSubscribeMultiType GetAsSubscribeMulti(const FClientMessageType& InValue) + static FUnsubscribeType GetAsUnsubscribe(const FClientMessageType& InValue) { - return InValue.GetAsSubscribeMulti(); + return InValue.GetAsUnsubscribe(); } UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ClientMessage") - static FClientMessageType Unsubscribe(const FUnsubscribeType& InValue) + static FClientMessageType OneOffQuery(const FOneOffQueryType& InValue) { - return FClientMessageType::Unsubscribe(InValue); + return FClientMessageType::OneOffQuery(InValue); } UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ClientMessage") - static bool IsUnsubscribe(const FClientMessageType& InValue) { return InValue.IsUnsubscribe(); } + static bool IsOneOffQuery(const FClientMessageType& InValue) { return InValue.IsOneOffQuery(); } UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ClientMessage") - static FUnsubscribeType GetAsUnsubscribe(const FClientMessageType& InValue) + static FOneOffQueryType GetAsOneOffQuery(const FClientMessageType& InValue) { - return InValue.GetAsUnsubscribe(); + return InValue.GetAsOneOffQuery(); } UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ClientMessage") - static FClientMessageType UnsubscribeMulti(const FUnsubscribeMultiType& InValue) + static FClientMessageType CallReducer(const FCallReducerType& InValue) { - return FClientMessageType::UnsubscribeMulti(InValue); + return FClientMessageType::CallReducer(InValue); } UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ClientMessage") - static bool IsUnsubscribeMulti(const FClientMessageType& InValue) { return InValue.IsUnsubscribeMulti(); } + static bool IsCallReducer(const FClientMessageType& InValue) { return InValue.IsCallReducer(); } UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ClientMessage") - static FUnsubscribeMultiType GetAsUnsubscribeMulti(const FClientMessageType& InValue) + static FCallReducerType GetAsCallReducer(const FClientMessageType& InValue) { - return InValue.GetAsUnsubscribeMulti(); + return InValue.GetAsCallReducer(); } UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ClientMessage") diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/CompressableQueryUpdateType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/CompressableQueryUpdateType.g.h deleted file mode 100644 index 7ffeefbd0a3..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/CompressableQueryUpdateType.g.h +++ /dev/null @@ -1,187 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/QueryUpdateType.g.h" -#include "Kismet/BlueprintFunctionLibrary.h" -#include "CompressableQueryUpdateType.g.generated.h" - -UENUM(BlueprintType) -enum class ECompressableQueryUpdateTag : uint8 -{ - Uncompressed, - Brotli, - Gzip -}; - -USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FCompressableQueryUpdateType -{ - GENERATED_BODY() - -public: - FCompressableQueryUpdateType() = default; - - TVariant> MessageData; - - UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") - ECompressableQueryUpdateTag Tag = static_cast(0); - - static FCompressableQueryUpdateType Uncompressed(const FQueryUpdateType& Value) - { - FCompressableQueryUpdateType Obj; - Obj.Tag = ECompressableQueryUpdateTag::Uncompressed; - Obj.MessageData.Set(Value); - return Obj; - } - - static FCompressableQueryUpdateType Brotli(const TArray& Value) - { - FCompressableQueryUpdateType Obj; - Obj.Tag = ECompressableQueryUpdateTag::Brotli; - Obj.MessageData.Set>(Value); - return Obj; - } - - static FCompressableQueryUpdateType Gzip(const TArray& Value) - { - FCompressableQueryUpdateType Obj; - Obj.Tag = ECompressableQueryUpdateTag::Gzip; - Obj.MessageData.Set>(Value); - return Obj; - } - - FORCEINLINE bool IsUncompressed() const { return Tag == ECompressableQueryUpdateTag::Uncompressed; } - - FORCEINLINE FQueryUpdateType GetAsUncompressed() const - { - ensureMsgf(IsUncompressed(), TEXT("MessageData does not hold Uncompressed!")); - return MessageData.Get(); - } - - FORCEINLINE bool IsBrotli() const { return Tag == ECompressableQueryUpdateTag::Brotli; } - - FORCEINLINE TArray GetAsBrotli() const - { - ensureMsgf(IsBrotli(), TEXT("MessageData does not hold Brotli!")); - return MessageData.Get>(); - } - - FORCEINLINE bool IsGzip() const { return Tag == ECompressableQueryUpdateTag::Gzip; } - - FORCEINLINE TArray GetAsGzip() const - { - ensureMsgf(IsGzip(), TEXT("MessageData does not hold Gzip!")); - return MessageData.Get>(); - } - - // Inline equality operators - FORCEINLINE bool operator==(const FCompressableQueryUpdateType& Other) const - { - if (Tag != Other.Tag) return false; - - switch (Tag) - { - case ECompressableQueryUpdateTag::Uncompressed: - return GetAsUncompressed() == Other.GetAsUncompressed(); - case ECompressableQueryUpdateTag::Brotli: - return GetAsBrotli() == Other.GetAsBrotli(); - case ECompressableQueryUpdateTag::Gzip: - return GetAsGzip() == Other.GetAsGzip(); - default: - return false; - } - } - - FORCEINLINE bool operator!=(const FCompressableQueryUpdateType& Other) const - { - return !(*this == Other); - } -}; - -/** - * Custom hash function for FCompressableQueryUpdateType. - * Combines the hashes of all fields that are compared in operator==. - * @param CompressableQueryUpdateType The FCompressableQueryUpdateType instance to hash. - * @return The combined hash value. - */ -FORCEINLINE uint32 GetTypeHash(const FCompressableQueryUpdateType& CompressableQueryUpdate) -{ - const uint32 TagHash = GetTypeHash(static_cast(CompressableQueryUpdate.Tag)); - switch (CompressableQueryUpdate.Tag) - { - case ECompressableQueryUpdateTag::Uncompressed: return HashCombine(TagHash, ::GetTypeHash(CompressableQueryUpdate.GetAsUncompressed())); - case ECompressableQueryUpdateTag::Brotli: return HashCombine(TagHash, ::GetTypeHash(CompressableQueryUpdate.GetAsBrotli())); - case ECompressableQueryUpdateTag::Gzip: return HashCombine(TagHash, ::GetTypeHash(CompressableQueryUpdate.GetAsGzip())); - default: return TagHash; - } -} - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_ENABLE_TARRAY(FCompressableQueryUpdateType); - - UE_SPACETIMEDB_TAGGED_ENUM( - FCompressableQueryUpdateType, - ECompressableQueryUpdateTag, - MessageData, - Uncompressed, FQueryUpdateType, - Brotli, TArray, - Gzip, TArray - ); -} - -UCLASS() -class SPACETIMEDBSDK_API UCompressableQueryUpdateBpLib : public UBlueprintFunctionLibrary -{ - GENERATED_BODY() - -private: - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|CompressableQueryUpdate") - static FCompressableQueryUpdateType Uncompressed(const FQueryUpdateType& InValue) - { - return FCompressableQueryUpdateType::Uncompressed(InValue); - } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|CompressableQueryUpdate") - static bool IsUncompressed(const FCompressableQueryUpdateType& InValue) { return InValue.IsUncompressed(); } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|CompressableQueryUpdate") - static FQueryUpdateType GetAsUncompressed(const FCompressableQueryUpdateType& InValue) - { - return InValue.GetAsUncompressed(); - } - - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|CompressableQueryUpdate") - static FCompressableQueryUpdateType Brotli(const TArray& InValue) - { - return FCompressableQueryUpdateType::Brotli(InValue); - } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|CompressableQueryUpdate") - static bool IsBrotli(const FCompressableQueryUpdateType& InValue) { return InValue.IsBrotli(); } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|CompressableQueryUpdate") - static TArray GetAsBrotli(const FCompressableQueryUpdateType& InValue) - { - return InValue.GetAsBrotli(); - } - - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|CompressableQueryUpdate") - static FCompressableQueryUpdateType Gzip(const TArray& InValue) - { - return FCompressableQueryUpdateType::Gzip(InValue); - } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|CompressableQueryUpdate") - static bool IsGzip(const FCompressableQueryUpdateType& InValue) { return InValue.IsGzip(); } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|CompressableQueryUpdate") - static TArray GetAsGzip(const FCompressableQueryUpdateType& InValue) - { - return InValue.GetAsGzip(); - } - -}; diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/DatabaseUpdateType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/DatabaseUpdateType.g.h deleted file mode 100644 index 4342fde61d0..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/DatabaseUpdateType.g.h +++ /dev/null @@ -1,46 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/TableUpdateType.g.h" -#include "DatabaseUpdateType.g.generated.h" - -USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FDatabaseUpdateType -{ - GENERATED_BODY() - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - TArray Tables; - - FORCEINLINE bool operator==(const FDatabaseUpdateType& Other) const - { - return Tables == Other.Tables; - } - - FORCEINLINE bool operator!=(const FDatabaseUpdateType& Other) const - { - return !(*this == Other); - } -}; - -/** - * Custom hash function for FDatabaseUpdateType. - * Combines the hashes of all fields that are compared in operator==. - * @param DatabaseUpdateType The FDatabaseUpdateType instance to hash. - * @return The combined hash value. - */ -FORCEINLINE uint32 GetTypeHash(const FDatabaseUpdateType& DatabaseUpdateType) -{ - uint32 Hash = GetTypeHash(DatabaseUpdateType.Tables); - return Hash; -} - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_ENABLE_TARRAY(FDatabaseUpdateType); - - UE_SPACETIMEDB_STRUCT(FDatabaseUpdateType, Tables); -} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/EnergyQuantaType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/EnergyQuantaType.g.h deleted file mode 100644 index 3183608322f..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/EnergyQuantaType.g.h +++ /dev/null @@ -1,46 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "Types/Builtins.h" -#include "EnergyQuantaType.g.generated.h" - -USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FEnergyQuantaType -{ - GENERATED_BODY() - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FSpacetimeDBUInt128 Quanta; - - FORCEINLINE bool operator==(const FEnergyQuantaType& Other) const - { - return Quanta == Other.Quanta; - } - - FORCEINLINE bool operator!=(const FEnergyQuantaType& Other) const - { - return !(*this == Other); - } -}; - -/** - * Custom hash function for FEnergyQuantaType. - * Combines the hashes of all fields that are compared in operator==. - * @param EnergyQuantaType The FEnergyQuantaType instance to hash. - * @return The combined hash value. - */ -FORCEINLINE uint32 GetTypeHash(const FEnergyQuantaType& EnergyQuantaType) -{ - uint32 Hash = GetTypeHash(EnergyQuantaType.Quanta); - return Hash; -} - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_ENABLE_TARRAY(FEnergyQuantaType); - - UE_SPACETIMEDB_STRUCT(FEnergyQuantaType, Quanta); -} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/EventTableRowsType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/EventTableRowsType.g.h new file mode 100644 index 00000000000..b333d4d17ff --- /dev/null +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/EventTableRowsType.g.h @@ -0,0 +1,46 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#pragma once +#include "CoreMinimal.h" +#include "BSATN/UESpacetimeDB.h" +#include "ModuleBindings/Types/BsatnRowListType.g.h" +#include "EventTableRowsType.g.generated.h" + +USTRUCT(BlueprintType) +struct SPACETIMEDBSDK_API FEventTableRowsType +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FBsatnRowListType Events; + + FORCEINLINE bool operator==(const FEventTableRowsType& Other) const + { + return Events == Other.Events; + } + + FORCEINLINE bool operator!=(const FEventTableRowsType& Other) const + { + return !(*this == Other); + } +}; + +/** + * Custom hash function for FEventTableRowsType. + * Combines the hashes of all fields that are compared in operator==. + * @param EventTableRowsType The FEventTableRowsType instance to hash. + * @return The combined hash value. + */ +FORCEINLINE uint32 GetTypeHash(const FEventTableRowsType& EventTableRowsType) +{ + uint32 Hash = GetTypeHash(EventTableRowsType.Events); + return Hash; +} + +namespace UE::SpacetimeDB +{ + UE_SPACETIMEDB_ENABLE_TARRAY(FEventTableRowsType); + + UE_SPACETIMEDB_STRUCT(FEventTableRowsType, Events); +} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/IdentityTokenType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/IdentityTokenType.g.h deleted file mode 100644 index bc1aeac671f..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/IdentityTokenType.g.h +++ /dev/null @@ -1,54 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "Types/Builtins.h" -#include "IdentityTokenType.g.generated.h" - -USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FIdentityTokenType -{ - GENERATED_BODY() - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FSpacetimeDBIdentity Identity; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FString Token; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FSpacetimeDBConnectionId ConnectionId; - - FORCEINLINE bool operator==(const FIdentityTokenType& Other) const - { - return Identity == Other.Identity && Token == Other.Token && ConnectionId == Other.ConnectionId; - } - - FORCEINLINE bool operator!=(const FIdentityTokenType& Other) const - { - return !(*this == Other); - } -}; - -/** - * Custom hash function for FIdentityTokenType. - * Combines the hashes of all fields that are compared in operator==. - * @param IdentityTokenType The FIdentityTokenType instance to hash. - * @return The combined hash value. - */ -FORCEINLINE uint32 GetTypeHash(const FIdentityTokenType& IdentityTokenType) -{ - uint32 Hash = GetTypeHash(IdentityTokenType.Identity); - Hash = HashCombine(Hash, GetTypeHash(IdentityTokenType.Token)); - Hash = HashCombine(Hash, GetTypeHash(IdentityTokenType.ConnectionId)); - return Hash; -} - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_ENABLE_TARRAY(FIdentityTokenType); - - UE_SPACETIMEDB_STRUCT(FIdentityTokenType, Identity, Token, ConnectionId); -} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/InitialConnectionType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/InitialConnectionType.g.h new file mode 100644 index 00000000000..0aaa1c010f9 --- /dev/null +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/InitialConnectionType.g.h @@ -0,0 +1,54 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#pragma once +#include "CoreMinimal.h" +#include "BSATN/UESpacetimeDB.h" +#include "Types/Builtins.h" +#include "InitialConnectionType.g.generated.h" + +USTRUCT(BlueprintType) +struct SPACETIMEDBSDK_API FInitialConnectionType +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FSpacetimeDBIdentity Identity; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FSpacetimeDBConnectionId ConnectionId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FString Token; + + FORCEINLINE bool operator==(const FInitialConnectionType& Other) const + { + return Identity == Other.Identity && ConnectionId == Other.ConnectionId && Token == Other.Token; + } + + FORCEINLINE bool operator!=(const FInitialConnectionType& Other) const + { + return !(*this == Other); + } +}; + +/** + * Custom hash function for FInitialConnectionType. + * Combines the hashes of all fields that are compared in operator==. + * @param InitialConnectionType The FInitialConnectionType instance to hash. + * @return The combined hash value. + */ +FORCEINLINE uint32 GetTypeHash(const FInitialConnectionType& InitialConnectionType) +{ + uint32 Hash = GetTypeHash(InitialConnectionType.Identity); + Hash = HashCombine(Hash, GetTypeHash(InitialConnectionType.ConnectionId)); + Hash = HashCombine(Hash, GetTypeHash(InitialConnectionType.Token)); + return Hash; +} + +namespace UE::SpacetimeDB +{ + UE_SPACETIMEDB_ENABLE_TARRAY(FInitialConnectionType); + + UE_SPACETIMEDB_STRUCT(FInitialConnectionType, Identity, ConnectionId, Token); +} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/InitialSubscriptionType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/InitialSubscriptionType.g.h deleted file mode 100644 index 6222c3aea2c..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/InitialSubscriptionType.g.h +++ /dev/null @@ -1,55 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/DatabaseUpdateType.g.h" -#include "Types/Builtins.h" -#include "InitialSubscriptionType.g.generated.h" - -USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FInitialSubscriptionType -{ - GENERATED_BODY() - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FDatabaseUpdateType DatabaseUpdate; - - // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements - uint32 RequestId = 0; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FSpacetimeDBTimeDuration TotalHostExecutionDuration; - - FORCEINLINE bool operator==(const FInitialSubscriptionType& Other) const - { - return DatabaseUpdate == Other.DatabaseUpdate && RequestId == Other.RequestId && TotalHostExecutionDuration == Other.TotalHostExecutionDuration; - } - - FORCEINLINE bool operator!=(const FInitialSubscriptionType& Other) const - { - return !(*this == Other); - } -}; - -/** - * Custom hash function for FInitialSubscriptionType. - * Combines the hashes of all fields that are compared in operator==. - * @param InitialSubscriptionType The FInitialSubscriptionType instance to hash. - * @return The combined hash value. - */ -FORCEINLINE uint32 GetTypeHash(const FInitialSubscriptionType& InitialSubscriptionType) -{ - uint32 Hash = GetTypeHash(InitialSubscriptionType.DatabaseUpdate); - Hash = HashCombine(Hash, GetTypeHash(InitialSubscriptionType.RequestId)); - Hash = HashCombine(Hash, GetTypeHash(InitialSubscriptionType.TotalHostExecutionDuration)); - return Hash; -} - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_ENABLE_TARRAY(FInitialSubscriptionType); - - UE_SPACETIMEDB_STRUCT(FInitialSubscriptionType, DatabaseUpdate, RequestId, TotalHostExecutionDuration); -} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/OneOffQueryResponseType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/OneOffQueryResponseType.g.h deleted file mode 100644 index 52cf4140c6d..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/OneOffQueryResponseType.g.h +++ /dev/null @@ -1,60 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Optionals/SpacetimeDbSdkOptionalString.g.h" -#include "ModuleBindings/Types/OneOffTableType.g.h" -#include "Types/Builtins.h" -#include "OneOffQueryResponseType.g.generated.h" - -USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FOneOffQueryResponseType -{ - GENERATED_BODY() - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - TArray MessageId; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FSpacetimeDbSdkOptionalString Error; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - TArray Tables; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FSpacetimeDBTimeDuration TotalHostExecutionDuration; - - FORCEINLINE bool operator==(const FOneOffQueryResponseType& Other) const - { - return MessageId == Other.MessageId && Error == Other.Error && Tables == Other.Tables && TotalHostExecutionDuration == Other.TotalHostExecutionDuration; - } - - FORCEINLINE bool operator!=(const FOneOffQueryResponseType& Other) const - { - return !(*this == Other); - } -}; - -/** - * Custom hash function for FOneOffQueryResponseType. - * Combines the hashes of all fields that are compared in operator==. - * @param OneOffQueryResponseType The FOneOffQueryResponseType instance to hash. - * @return The combined hash value. - */ -FORCEINLINE uint32 GetTypeHash(const FOneOffQueryResponseType& OneOffQueryResponseType) -{ - uint32 Hash = GetTypeHash(OneOffQueryResponseType.MessageId); - Hash = HashCombine(Hash, GetTypeHash(OneOffQueryResponseType.Error)); - Hash = HashCombine(Hash, GetTypeHash(OneOffQueryResponseType.Tables)); - Hash = HashCombine(Hash, GetTypeHash(OneOffQueryResponseType.TotalHostExecutionDuration)); - return Hash; -} - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_ENABLE_TARRAY(FOneOffQueryResponseType); - - UE_SPACETIMEDB_STRUCT(FOneOffQueryResponseType, MessageId, Error, Tables, TotalHostExecutionDuration); -} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/OneOffQueryResultType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/OneOffQueryResultType.g.h new file mode 100644 index 00000000000..5dd4abc07cb --- /dev/null +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/OneOffQueryResultType.g.h @@ -0,0 +1,51 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#pragma once +#include "CoreMinimal.h" +#include "BSATN/UESpacetimeDB.h" +#include "ModuleBindings/Results/SpacetimeDbSdkResultQueryRowsString.g.h" +#include "ModuleBindings/Types/QueryRowsType.g.h" +#include "OneOffQueryResultType.g.generated.h" + +USTRUCT(BlueprintType) +struct SPACETIMEDBSDK_API FOneOffQueryResultType +{ + GENERATED_BODY() + + // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements + uint32 RequestId = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FSpacetimeDbSdkResultQueryRowsString Result; + + FORCEINLINE bool operator==(const FOneOffQueryResultType& Other) const + { + return RequestId == Other.RequestId && Result == Other.Result; + } + + FORCEINLINE bool operator!=(const FOneOffQueryResultType& Other) const + { + return !(*this == Other); + } +}; + +/** + * Custom hash function for FOneOffQueryResultType. + * Combines the hashes of all fields that are compared in operator==. + * @param OneOffQueryResultType The FOneOffQueryResultType instance to hash. + * @return The combined hash value. + */ +FORCEINLINE uint32 GetTypeHash(const FOneOffQueryResultType& OneOffQueryResultType) +{ + uint32 Hash = GetTypeHash(OneOffQueryResultType.RequestId); + Hash = HashCombine(Hash, GetTypeHash(OneOffQueryResultType.Result)); + return Hash; +} + +namespace UE::SpacetimeDB +{ + UE_SPACETIMEDB_ENABLE_TARRAY(FOneOffQueryResultType); + + UE_SPACETIMEDB_STRUCT(FOneOffQueryResultType, RequestId, Result); +} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/OneOffQueryType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/OneOffQueryType.g.h index f32539e1fa0..242346cefb6 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/OneOffQueryType.g.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/OneOffQueryType.g.h @@ -11,15 +11,15 @@ struct SPACETIMEDBSDK_API FOneOffQueryType { GENERATED_BODY() - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - TArray MessageId; + // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements + uint32 RequestId = 0; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") FString QueryString; FORCEINLINE bool operator==(const FOneOffQueryType& Other) const { - return MessageId == Other.MessageId && QueryString == Other.QueryString; + return RequestId == Other.RequestId && QueryString == Other.QueryString; } FORCEINLINE bool operator!=(const FOneOffQueryType& Other) const @@ -36,7 +36,7 @@ struct SPACETIMEDBSDK_API FOneOffQueryType */ FORCEINLINE uint32 GetTypeHash(const FOneOffQueryType& OneOffQueryType) { - uint32 Hash = GetTypeHash(OneOffQueryType.MessageId); + uint32 Hash = GetTypeHash(OneOffQueryType.RequestId); Hash = HashCombine(Hash, GetTypeHash(OneOffQueryType.QueryString)); return Hash; } @@ -45,5 +45,5 @@ namespace UE::SpacetimeDB { UE_SPACETIMEDB_ENABLE_TARRAY(FOneOffQueryType); - UE_SPACETIMEDB_STRUCT(FOneOffQueryType, MessageId, QueryString); + UE_SPACETIMEDB_STRUCT(FOneOffQueryType, RequestId, QueryString); } diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/OneOffTableType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/OneOffTableType.g.h deleted file mode 100644 index 5f4f93a2672..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/OneOffTableType.g.h +++ /dev/null @@ -1,50 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/BsatnRowListType.g.h" -#include "OneOffTableType.g.generated.h" - -USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FOneOffTableType -{ - GENERATED_BODY() - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FString TableName; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FBsatnRowListType Rows; - - FORCEINLINE bool operator==(const FOneOffTableType& Other) const - { - return TableName == Other.TableName && Rows == Other.Rows; - } - - FORCEINLINE bool operator!=(const FOneOffTableType& Other) const - { - return !(*this == Other); - } -}; - -/** - * Custom hash function for FOneOffTableType. - * Combines the hashes of all fields that are compared in operator==. - * @param OneOffTableType The FOneOffTableType instance to hash. - * @return The combined hash value. - */ -FORCEINLINE uint32 GetTypeHash(const FOneOffTableType& OneOffTableType) -{ - uint32 Hash = GetTypeHash(OneOffTableType.TableName); - Hash = HashCombine(Hash, GetTypeHash(OneOffTableType.Rows)); - return Hash; -} - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_ENABLE_TARRAY(FOneOffTableType); - - UE_SPACETIMEDB_STRUCT(FOneOffTableType, TableName, Rows); -} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/PersistentTableRowsType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/PersistentTableRowsType.g.h new file mode 100644 index 00000000000..062402e47ad --- /dev/null +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/PersistentTableRowsType.g.h @@ -0,0 +1,50 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#pragma once +#include "CoreMinimal.h" +#include "BSATN/UESpacetimeDB.h" +#include "ModuleBindings/Types/BsatnRowListType.g.h" +#include "PersistentTableRowsType.g.generated.h" + +USTRUCT(BlueprintType) +struct SPACETIMEDBSDK_API FPersistentTableRowsType +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FBsatnRowListType Inserts; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FBsatnRowListType Deletes; + + FORCEINLINE bool operator==(const FPersistentTableRowsType& Other) const + { + return Inserts == Other.Inserts && Deletes == Other.Deletes; + } + + FORCEINLINE bool operator!=(const FPersistentTableRowsType& Other) const + { + return !(*this == Other); + } +}; + +/** + * Custom hash function for FPersistentTableRowsType. + * Combines the hashes of all fields that are compared in operator==. + * @param PersistentTableRowsType The FPersistentTableRowsType instance to hash. + * @return The combined hash value. + */ +FORCEINLINE uint32 GetTypeHash(const FPersistentTableRowsType& PersistentTableRowsType) +{ + uint32 Hash = GetTypeHash(PersistentTableRowsType.Inserts); + Hash = HashCombine(Hash, GetTypeHash(PersistentTableRowsType.Deletes)); + return Hash; +} + +namespace UE::SpacetimeDB +{ + UE_SPACETIMEDB_ENABLE_TARRAY(FPersistentTableRowsType); + + UE_SPACETIMEDB_STRUCT(FPersistentTableRowsType, Inserts, Deletes); +} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ProcedureStatusType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ProcedureStatusType.g.h index 76ff482d388..3f3936204bc 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ProcedureStatusType.g.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ProcedureStatusType.g.h @@ -5,14 +5,12 @@ #include "CoreMinimal.h" #include "BSATN/UESpacetimeDB.h" #include "Kismet/BlueprintFunctionLibrary.h" -#include "Types/UnitType.h" #include "ProcedureStatusType.g.generated.h" UENUM(BlueprintType) enum class EProcedureStatusTag : uint8 { Returned, - OutOfEnergy, InternalError }; @@ -24,9 +22,9 @@ struct SPACETIMEDBSDK_API FProcedureStatusType public: FProcedureStatusType() = default; - TVariant> MessageData; + TVariant> MessageData; - UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") + UPROPERTY(BlueprintReadOnly) EProcedureStatusTag Tag = static_cast(0); static FProcedureStatusType Returned(const TArray& Value) @@ -37,14 +35,6 @@ struct SPACETIMEDBSDK_API FProcedureStatusType return Obj; } - static FProcedureStatusType OutOfEnergy(const FSpacetimeDBUnit& Value) - { - FProcedureStatusType Obj; - Obj.Tag = EProcedureStatusTag::OutOfEnergy; - Obj.MessageData.Set(Value); - return Obj; - } - static FProcedureStatusType InternalError(const FString& Value) { FProcedureStatusType Obj; @@ -61,14 +51,6 @@ struct SPACETIMEDBSDK_API FProcedureStatusType return MessageData.Get>(); } - FORCEINLINE bool IsOutOfEnergy() const { return Tag == EProcedureStatusTag::OutOfEnergy; } - - FORCEINLINE FSpacetimeDBUnit GetAsOutOfEnergy() const - { - ensureMsgf(IsOutOfEnergy(), TEXT("MessageData does not hold OutOfEnergy!")); - return MessageData.Get(); - } - FORCEINLINE bool IsInternalError() const { return Tag == EProcedureStatusTag::InternalError; } FORCEINLINE FString GetAsInternalError() const @@ -86,8 +68,6 @@ struct SPACETIMEDBSDK_API FProcedureStatusType { case EProcedureStatusTag::Returned: return GetAsReturned() == Other.GetAsReturned(); - case EProcedureStatusTag::OutOfEnergy: - return GetAsOutOfEnergy() == Other.GetAsOutOfEnergy(); case EProcedureStatusTag::InternalError: return GetAsInternalError() == Other.GetAsInternalError(); default: @@ -113,7 +93,6 @@ FORCEINLINE uint32 GetTypeHash(const FProcedureStatusType& ProcedureStatus) switch (ProcedureStatus.Tag) { case EProcedureStatusTag::Returned: return HashCombine(TagHash, ::GetTypeHash(ProcedureStatus.GetAsReturned())); - case EProcedureStatusTag::OutOfEnergy: return HashCombine(TagHash, ::GetTypeHash(ProcedureStatus.GetAsOutOfEnergy())); case EProcedureStatusTag::InternalError: return HashCombine(TagHash, GetTypeHash(ProcedureStatus.GetAsInternalError())); default: return TagHash; } @@ -128,8 +107,44 @@ namespace UE::SpacetimeDB EProcedureStatusTag, MessageData, Returned, TArray, - OutOfEnergy, FSpacetimeDBUnit, InternalError, FString ); } +UCLASS() +class SPACETIMEDBSDK_API UProcedureStatusBpLib : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +private: + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ProcedureStatus") + static FProcedureStatusType Returned(const TArray& InValue) + { + return FProcedureStatusType::Returned(InValue); + } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ProcedureStatus") + static bool IsReturned(const FProcedureStatusType& InValue) { return InValue.IsReturned(); } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ProcedureStatus") + static TArray GetAsReturned(const FProcedureStatusType& InValue) + { + return InValue.GetAsReturned(); + } + + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ProcedureStatus") + static FProcedureStatusType InternalError(const FString& InValue) + { + return FProcedureStatusType::InternalError(InValue); + } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ProcedureStatus") + static bool IsInternalError(const FProcedureStatusType& InValue) { return InValue.IsInternalError(); } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ProcedureStatus") + static FString GetAsInternalError(const FProcedureStatusType& InValue) + { + return InValue.GetAsInternalError(); + } + +}; diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QueryRowsType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QueryRowsType.g.h new file mode 100644 index 00000000000..c90e50c70d0 --- /dev/null +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QueryRowsType.g.h @@ -0,0 +1,46 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#pragma once +#include "CoreMinimal.h" +#include "BSATN/UESpacetimeDB.h" +#include "ModuleBindings/Types/SingleTableRowsType.g.h" +#include "QueryRowsType.g.generated.h" + +USTRUCT(BlueprintType) +struct SPACETIMEDBSDK_API FQueryRowsType +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + TArray Tables; + + FORCEINLINE bool operator==(const FQueryRowsType& Other) const + { + return Tables == Other.Tables; + } + + FORCEINLINE bool operator!=(const FQueryRowsType& Other) const + { + return !(*this == Other); + } +}; + +/** + * Custom hash function for FQueryRowsType. + * Combines the hashes of all fields that are compared in operator==. + * @param QueryRowsType The FQueryRowsType instance to hash. + * @return The combined hash value. + */ +FORCEINLINE uint32 GetTypeHash(const FQueryRowsType& QueryRowsType) +{ + uint32 Hash = GetTypeHash(QueryRowsType.Tables); + return Hash; +} + +namespace UE::SpacetimeDB +{ + UE_SPACETIMEDB_ENABLE_TARRAY(FQueryRowsType); + + UE_SPACETIMEDB_STRUCT(FQueryRowsType, Tables); +} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QueryIdType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QuerySetIdType.g.h similarity index 53% rename from sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QueryIdType.g.h rename to sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QuerySetIdType.g.h index 2c5db9fbc1a..b0890f46132 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QueryIdType.g.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QuerySetIdType.g.h @@ -4,42 +4,42 @@ #pragma once #include "CoreMinimal.h" #include "BSATN/UESpacetimeDB.h" -#include "QueryIdType.g.generated.h" +#include "QuerySetIdType.g.generated.h" USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FQueryIdType +struct SPACETIMEDBSDK_API FQuerySetIdType { GENERATED_BODY() // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements uint32 Id = 0; - FORCEINLINE bool operator==(const FQueryIdType& Other) const + FORCEINLINE bool operator==(const FQuerySetIdType& Other) const { return Id == Other.Id; } - FORCEINLINE bool operator!=(const FQueryIdType& Other) const + FORCEINLINE bool operator!=(const FQuerySetIdType& Other) const { return !(*this == Other); } }; /** - * Custom hash function for FQueryIdType. + * Custom hash function for FQuerySetIdType. * Combines the hashes of all fields that are compared in operator==. - * @param QueryIdType The FQueryIdType instance to hash. + * @param QuerySetIdType The FQuerySetIdType instance to hash. * @return The combined hash value. */ -FORCEINLINE uint32 GetTypeHash(const FQueryIdType& QueryIdType) +FORCEINLINE uint32 GetTypeHash(const FQuerySetIdType& QuerySetIdType) { - uint32 Hash = GetTypeHash(QueryIdType.Id); + uint32 Hash = GetTypeHash(QuerySetIdType.Id); return Hash; } namespace UE::SpacetimeDB { - UE_SPACETIMEDB_ENABLE_TARRAY(FQueryIdType); + UE_SPACETIMEDB_ENABLE_TARRAY(FQuerySetIdType); - UE_SPACETIMEDB_STRUCT(FQueryIdType, Id); + UE_SPACETIMEDB_STRUCT(FQuerySetIdType, Id); } diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QuerySetUpdateType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QuerySetUpdateType.g.h new file mode 100644 index 00000000000..6c3573697a0 --- /dev/null +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QuerySetUpdateType.g.h @@ -0,0 +1,51 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#pragma once +#include "CoreMinimal.h" +#include "BSATN/UESpacetimeDB.h" +#include "ModuleBindings/Types/QuerySetIdType.g.h" +#include "ModuleBindings/Types/TableUpdateType.g.h" +#include "QuerySetUpdateType.g.generated.h" + +USTRUCT(BlueprintType) +struct SPACETIMEDBSDK_API FQuerySetUpdateType +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FQuerySetIdType QuerySetId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + TArray Tables; + + FORCEINLINE bool operator==(const FQuerySetUpdateType& Other) const + { + return QuerySetId == Other.QuerySetId && Tables == Other.Tables; + } + + FORCEINLINE bool operator!=(const FQuerySetUpdateType& Other) const + { + return !(*this == Other); + } +}; + +/** + * Custom hash function for FQuerySetUpdateType. + * Combines the hashes of all fields that are compared in operator==. + * @param QuerySetUpdateType The FQuerySetUpdateType instance to hash. + * @return The combined hash value. + */ +FORCEINLINE uint32 GetTypeHash(const FQuerySetUpdateType& QuerySetUpdateType) +{ + uint32 Hash = GetTypeHash(QuerySetUpdateType.QuerySetId); + Hash = HashCombine(Hash, GetTypeHash(QuerySetUpdateType.Tables)); + return Hash; +} + +namespace UE::SpacetimeDB +{ + UE_SPACETIMEDB_ENABLE_TARRAY(FQuerySetUpdateType); + + UE_SPACETIMEDB_STRUCT(FQuerySetUpdateType, QuerySetId, Tables); +} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QueryUpdateType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QueryUpdateType.g.h deleted file mode 100644 index d710b49a324..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/QueryUpdateType.g.h +++ /dev/null @@ -1,50 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/BsatnRowListType.g.h" -#include "QueryUpdateType.g.generated.h" - -USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FQueryUpdateType -{ - GENERATED_BODY() - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FBsatnRowListType Deletes; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FBsatnRowListType Inserts; - - FORCEINLINE bool operator==(const FQueryUpdateType& Other) const - { - return Deletes == Other.Deletes && Inserts == Other.Inserts; - } - - FORCEINLINE bool operator!=(const FQueryUpdateType& Other) const - { - return !(*this == Other); - } -}; - -/** - * Custom hash function for FQueryUpdateType. - * Combines the hashes of all fields that are compared in operator==. - * @param QueryUpdateType The FQueryUpdateType instance to hash. - * @return The combined hash value. - */ -FORCEINLINE uint32 GetTypeHash(const FQueryUpdateType& QueryUpdateType) -{ - uint32 Hash = GetTypeHash(QueryUpdateType.Deletes); - Hash = HashCombine(Hash, GetTypeHash(QueryUpdateType.Inserts)); - return Hash; -} - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_ENABLE_TARRAY(FQueryUpdateType); - - UE_SPACETIMEDB_STRUCT(FQueryUpdateType, Deletes, Inserts); -} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ReducerCallInfoType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ReducerCallInfoType.g.h deleted file mode 100644 index 8eb26e8c05c..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ReducerCallInfoType.g.h +++ /dev/null @@ -1,57 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "ReducerCallInfoType.g.generated.h" - -USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FReducerCallInfoType -{ - GENERATED_BODY() - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FString ReducerName; - - // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements - uint32 ReducerId = 0; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - TArray Args; - - // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements - uint32 RequestId = 0; - - FORCEINLINE bool operator==(const FReducerCallInfoType& Other) const - { - return ReducerName == Other.ReducerName && ReducerId == Other.ReducerId && Args == Other.Args && RequestId == Other.RequestId; - } - - FORCEINLINE bool operator!=(const FReducerCallInfoType& Other) const - { - return !(*this == Other); - } -}; - -/** - * Custom hash function for FReducerCallInfoType. - * Combines the hashes of all fields that are compared in operator==. - * @param ReducerCallInfoType The FReducerCallInfoType instance to hash. - * @return The combined hash value. - */ -FORCEINLINE uint32 GetTypeHash(const FReducerCallInfoType& ReducerCallInfoType) -{ - uint32 Hash = GetTypeHash(ReducerCallInfoType.ReducerName); - Hash = HashCombine(Hash, GetTypeHash(ReducerCallInfoType.ReducerId)); - Hash = HashCombine(Hash, GetTypeHash(ReducerCallInfoType.Args)); - Hash = HashCombine(Hash, GetTypeHash(ReducerCallInfoType.RequestId)); - return Hash; -} - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_ENABLE_TARRAY(FReducerCallInfoType); - - UE_SPACETIMEDB_STRUCT(FReducerCallInfoType, ReducerName, ReducerId, Args, RequestId); -} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ReducerOkType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ReducerOkType.g.h new file mode 100644 index 00000000000..84e56ac72f9 --- /dev/null +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ReducerOkType.g.h @@ -0,0 +1,50 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#pragma once +#include "CoreMinimal.h" +#include "BSATN/UESpacetimeDB.h" +#include "ModuleBindings/Types/TransactionUpdateType.g.h" +#include "ReducerOkType.g.generated.h" + +USTRUCT(BlueprintType) +struct SPACETIMEDBSDK_API FReducerOkType +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + TArray RetValue; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FTransactionUpdateType TransactionUpdate; + + FORCEINLINE bool operator==(const FReducerOkType& Other) const + { + return RetValue == Other.RetValue && TransactionUpdate == Other.TransactionUpdate; + } + + FORCEINLINE bool operator!=(const FReducerOkType& Other) const + { + return !(*this == Other); + } +}; + +/** + * Custom hash function for FReducerOkType. + * Combines the hashes of all fields that are compared in operator==. + * @param ReducerOkType The FReducerOkType instance to hash. + * @return The combined hash value. + */ +FORCEINLINE uint32 GetTypeHash(const FReducerOkType& ReducerOkType) +{ + uint32 Hash = GetTypeHash(ReducerOkType.RetValue); + Hash = HashCombine(Hash, GetTypeHash(ReducerOkType.TransactionUpdate)); + return Hash; +} + +namespace UE::SpacetimeDB +{ + UE_SPACETIMEDB_ENABLE_TARRAY(FReducerOkType); + + UE_SPACETIMEDB_STRUCT(FReducerOkType, RetValue, TransactionUpdate); +} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ReducerOutcomeType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ReducerOutcomeType.g.h new file mode 100644 index 00000000000..6f52f95f93c --- /dev/null +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ReducerOutcomeType.g.h @@ -0,0 +1,224 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#pragma once +#include "CoreMinimal.h" +#include "BSATN/UESpacetimeDB.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "Types/UnitType.h" +#include "ModuleBindings/Types/ReducerOkType.g.h" +#include "ReducerOutcomeType.g.generated.h" + +UENUM(BlueprintType) +enum class EReducerOutcomeTag : uint8 +{ + Ok, + OkEmpty, + Err, + InternalError +}; + +USTRUCT(BlueprintType) +struct SPACETIMEDBSDK_API FReducerOutcomeType +{ + GENERATED_BODY() + +public: + FReducerOutcomeType() = default; + + TVariant, FSpacetimeDBUnit> MessageData; + + UPROPERTY(BlueprintReadOnly) + EReducerOutcomeTag Tag = static_cast(0); + + static FReducerOutcomeType Ok(const FReducerOkType& Value) + { + FReducerOutcomeType Obj; + Obj.Tag = EReducerOutcomeTag::Ok; + Obj.MessageData.Set(Value); + return Obj; + } + + static FReducerOutcomeType OkEmpty(const FSpacetimeDBUnit& Value) + { + FReducerOutcomeType Obj; + Obj.Tag = EReducerOutcomeTag::OkEmpty; + Obj.MessageData.Set(Value); + return Obj; + } + + static FReducerOutcomeType Err(const TArray& Value) + { + FReducerOutcomeType Obj; + Obj.Tag = EReducerOutcomeTag::Err; + Obj.MessageData.Set>(Value); + return Obj; + } + + static FReducerOutcomeType InternalError(const FString& Value) + { + FReducerOutcomeType Obj; + Obj.Tag = EReducerOutcomeTag::InternalError; + Obj.MessageData.Set(Value); + return Obj; + } + + FORCEINLINE bool IsOk() const { return Tag == EReducerOutcomeTag::Ok; } + + FORCEINLINE FReducerOkType GetAsOk() const + { + ensureMsgf(IsOk(), TEXT("MessageData does not hold Ok!")); + return MessageData.Get(); + } + + FORCEINLINE bool IsOkEmpty() const { return Tag == EReducerOutcomeTag::OkEmpty; } + + FORCEINLINE FSpacetimeDBUnit GetAsOkEmpty() const + { + ensureMsgf(IsOkEmpty(), TEXT("MessageData does not hold OkEmpty!")); + return MessageData.Get(); + } + + FORCEINLINE bool IsErr() const { return Tag == EReducerOutcomeTag::Err; } + + FORCEINLINE TArray GetAsErr() const + { + ensureMsgf(IsErr(), TEXT("MessageData does not hold Err!")); + return MessageData.Get>(); + } + + FORCEINLINE bool IsInternalError() const { return Tag == EReducerOutcomeTag::InternalError; } + + FORCEINLINE FString GetAsInternalError() const + { + ensureMsgf(IsInternalError(), TEXT("MessageData does not hold InternalError!")); + return MessageData.Get(); + } + + // Inline equality operators + FORCEINLINE bool operator==(const FReducerOutcomeType& Other) const + { + if (Tag != Other.Tag) return false; + + switch (Tag) + { + case EReducerOutcomeTag::Ok: + return GetAsOk() == Other.GetAsOk(); + case EReducerOutcomeTag::OkEmpty: + return GetAsOkEmpty() == Other.GetAsOkEmpty(); + case EReducerOutcomeTag::Err: + return GetAsErr() == Other.GetAsErr(); + case EReducerOutcomeTag::InternalError: + return GetAsInternalError() == Other.GetAsInternalError(); + default: + return false; + } + } + + FORCEINLINE bool operator!=(const FReducerOutcomeType& Other) const + { + return !(*this == Other); + } +}; + +/** + * Custom hash function for FReducerOutcomeType. + * Combines the hashes of all fields that are compared in operator==. + * @param ReducerOutcomeType The FReducerOutcomeType instance to hash. + * @return The combined hash value. + */ +FORCEINLINE uint32 GetTypeHash(const FReducerOutcomeType& ReducerOutcome) +{ + const uint32 TagHash = GetTypeHash(static_cast(ReducerOutcome.Tag)); + switch (ReducerOutcome.Tag) + { + case EReducerOutcomeTag::Ok: return HashCombine(TagHash, ::GetTypeHash(ReducerOutcome.GetAsOk())); + case EReducerOutcomeTag::OkEmpty: return HashCombine(TagHash, ::GetTypeHash(ReducerOutcome.GetAsOkEmpty())); + case EReducerOutcomeTag::Err: return HashCombine(TagHash, ::GetTypeHash(ReducerOutcome.GetAsErr())); + case EReducerOutcomeTag::InternalError: return HashCombine(TagHash, GetTypeHash(ReducerOutcome.GetAsInternalError())); + default: return TagHash; + } +} + +namespace UE::SpacetimeDB +{ + UE_SPACETIMEDB_ENABLE_TARRAY(FReducerOutcomeType); + + UE_SPACETIMEDB_TAGGED_ENUM( + FReducerOutcomeType, + EReducerOutcomeTag, + MessageData, + Ok, FReducerOkType, + OkEmpty, FSpacetimeDBUnit, + Err, TArray, + InternalError, FString + ); +} + +UCLASS() +class SPACETIMEDBSDK_API UReducerOutcomeBpLib : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +private: + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ReducerOutcome") + static FReducerOutcomeType Ok(const FReducerOkType& InValue) + { + return FReducerOutcomeType::Ok(InValue); + } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ReducerOutcome") + static bool IsOk(const FReducerOutcomeType& InValue) { return InValue.IsOk(); } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ReducerOutcome") + static FReducerOkType GetAsOk(const FReducerOutcomeType& InValue) + { + return InValue.GetAsOk(); + } + + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ReducerOutcome") + static FReducerOutcomeType OkEmpty(const FSpacetimeDBUnit& InValue) + { + return FReducerOutcomeType::OkEmpty(InValue); + } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ReducerOutcome") + static bool IsOkEmpty(const FReducerOutcomeType& InValue) { return InValue.IsOkEmpty(); } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ReducerOutcome") + static FSpacetimeDBUnit GetAsOkEmpty(const FReducerOutcomeType& InValue) + { + return InValue.GetAsOkEmpty(); + } + + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ReducerOutcome") + static FReducerOutcomeType Err(const TArray& InValue) + { + return FReducerOutcomeType::Err(InValue); + } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ReducerOutcome") + static bool IsErr(const FReducerOutcomeType& InValue) { return InValue.IsErr(); } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ReducerOutcome") + static TArray GetAsErr(const FReducerOutcomeType& InValue) + { + return InValue.GetAsErr(); + } + + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ReducerOutcome") + static FReducerOutcomeType InternalError(const FString& InValue) + { + return FReducerOutcomeType::InternalError(InValue); + } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ReducerOutcome") + static bool IsInternalError(const FReducerOutcomeType& InValue) { return InValue.IsInternalError(); } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ReducerOutcome") + static FString GetAsInternalError(const FReducerOutcomeType& InValue) + { + return InValue.GetAsInternalError(); + } + +}; diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ReducerResultType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ReducerResultType.g.h new file mode 100644 index 00000000000..415d30bb692 --- /dev/null +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ReducerResultType.g.h @@ -0,0 +1,55 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#pragma once +#include "CoreMinimal.h" +#include "BSATN/UESpacetimeDB.h" +#include "ModuleBindings/Types/ReducerOutcomeType.g.h" +#include "Types/Builtins.h" +#include "ReducerResultType.g.generated.h" + +USTRUCT(BlueprintType) +struct SPACETIMEDBSDK_API FReducerResultType +{ + GENERATED_BODY() + + // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements + uint32 RequestId = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FSpacetimeDBTimestamp Timestamp; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FReducerOutcomeType Result; + + FORCEINLINE bool operator==(const FReducerResultType& Other) const + { + return RequestId == Other.RequestId && Timestamp == Other.Timestamp && Result == Other.Result; + } + + FORCEINLINE bool operator!=(const FReducerResultType& Other) const + { + return !(*this == Other); + } +}; + +/** + * Custom hash function for FReducerResultType. + * Combines the hashes of all fields that are compared in operator==. + * @param ReducerResultType The FReducerResultType instance to hash. + * @return The combined hash value. + */ +FORCEINLINE uint32 GetTypeHash(const FReducerResultType& ReducerResultType) +{ + uint32 Hash = GetTypeHash(ReducerResultType.RequestId); + Hash = HashCombine(Hash, GetTypeHash(ReducerResultType.Timestamp)); + Hash = HashCombine(Hash, GetTypeHash(ReducerResultType.Result)); + return Hash; +} + +namespace UE::SpacetimeDB +{ + UE_SPACETIMEDB_ENABLE_TARRAY(FReducerResultType); + + UE_SPACETIMEDB_STRUCT(FReducerResultType, RequestId, Timestamp, Result); +} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/RowSizeHintType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/RowSizeHintType.g.h index 1a7fd221198..45166ef6ec0 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/RowSizeHintType.g.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/RowSizeHintType.g.h @@ -22,9 +22,9 @@ struct SPACETIMEDBSDK_API FRowSizeHintType public: FRowSizeHintType() = default; - TVariant, uint16> MessageData; + TVariant> MessageData; - UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") + UPROPERTY(BlueprintReadOnly) ERowSizeHintTag Tag = static_cast(0); static FRowSizeHintType FixedSize(const uint16& Value) diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ServerMessageType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ServerMessageType.g.h index e8cb743fdbd..a53ebf9ed0e 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ServerMessageType.g.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/ServerMessageType.g.h @@ -4,33 +4,27 @@ #pragma once #include "CoreMinimal.h" #include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/SubscribeMultiAppliedType.g.h" -#include "ModuleBindings/Types/TransactionUpdateLightType.g.h" +#include "ModuleBindings/Types/SubscribeAppliedType.g.h" +#include "ModuleBindings/Types/SubscriptionErrorType.g.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "ModuleBindings/Types/ReducerResultType.g.h" #include "ModuleBindings/Types/TransactionUpdateType.g.h" -#include "ModuleBindings/Types/InitialSubscriptionType.g.h" #include "ModuleBindings/Types/UnsubscribeAppliedType.g.h" -#include "ModuleBindings/Types/SubscriptionErrorType.g.h" -#include "ModuleBindings/Types/OneOffQueryResponseType.g.h" -#include "ModuleBindings/Types/SubscribeAppliedType.g.h" -#include "ModuleBindings/Types/IdentityTokenType.g.h" -#include "ModuleBindings/Types/UnsubscribeMultiAppliedType.g.h" #include "ModuleBindings/Types/ProcedureResultType.g.h" -#include "Kismet/BlueprintFunctionLibrary.h" +#include "ModuleBindings/Types/InitialConnectionType.g.h" +#include "ModuleBindings/Types/OneOffQueryResultType.g.h" #include "ServerMessageType.g.generated.h" UENUM(BlueprintType) enum class EServerMessageTag : uint8 { - InitialSubscription, - TransactionUpdate, - TransactionUpdateLight, - IdentityToken, - OneOffQueryResponse, + InitialConnection, SubscribeApplied, UnsubscribeApplied, SubscriptionError, - SubscribeMultiApplied, - UnsubscribeMultiApplied, + TransactionUpdate, + OneOffQueryResult, + ReducerResult, ProcedureResult }; @@ -42,48 +36,16 @@ struct SPACETIMEDBSDK_API FServerMessageType public: FServerMessageType() = default; - TVariant MessageData; + TVariant MessageData; - UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") + UPROPERTY(BlueprintReadOnly) EServerMessageTag Tag = static_cast(0); - static FServerMessageType InitialSubscription(const FInitialSubscriptionType& Value) - { - FServerMessageType Obj; - Obj.Tag = EServerMessageTag::InitialSubscription; - Obj.MessageData.Set(Value); - return Obj; - } - - static FServerMessageType TransactionUpdate(const FTransactionUpdateType& Value) - { - FServerMessageType Obj; - Obj.Tag = EServerMessageTag::TransactionUpdate; - Obj.MessageData.Set(Value); - return Obj; - } - - static FServerMessageType TransactionUpdateLight(const FTransactionUpdateLightType& Value) - { - FServerMessageType Obj; - Obj.Tag = EServerMessageTag::TransactionUpdateLight; - Obj.MessageData.Set(Value); - return Obj; - } - - static FServerMessageType IdentityToken(const FIdentityTokenType& Value) + static FServerMessageType InitialConnection(const FInitialConnectionType& Value) { FServerMessageType Obj; - Obj.Tag = EServerMessageTag::IdentityToken; - Obj.MessageData.Set(Value); - return Obj; - } - - static FServerMessageType OneOffQueryResponse(const FOneOffQueryResponseType& Value) - { - FServerMessageType Obj; - Obj.Tag = EServerMessageTag::OneOffQueryResponse; - Obj.MessageData.Set(Value); + Obj.Tag = EServerMessageTag::InitialConnection; + Obj.MessageData.Set(Value); return Obj; } @@ -111,19 +73,27 @@ struct SPACETIMEDBSDK_API FServerMessageType return Obj; } - static FServerMessageType SubscribeMultiApplied(const FSubscribeMultiAppliedType& Value) + static FServerMessageType TransactionUpdate(const FTransactionUpdateType& Value) + { + FServerMessageType Obj; + Obj.Tag = EServerMessageTag::TransactionUpdate; + Obj.MessageData.Set(Value); + return Obj; + } + + static FServerMessageType OneOffQueryResult(const FOneOffQueryResultType& Value) { FServerMessageType Obj; - Obj.Tag = EServerMessageTag::SubscribeMultiApplied; - Obj.MessageData.Set(Value); + Obj.Tag = EServerMessageTag::OneOffQueryResult; + Obj.MessageData.Set(Value); return Obj; } - static FServerMessageType UnsubscribeMultiApplied(const FUnsubscribeMultiAppliedType& Value) + static FServerMessageType ReducerResult(const FReducerResultType& Value) { FServerMessageType Obj; - Obj.Tag = EServerMessageTag::UnsubscribeMultiApplied; - Obj.MessageData.Set(Value); + Obj.Tag = EServerMessageTag::ReducerResult; + Obj.MessageData.Set(Value); return Obj; } @@ -135,44 +105,12 @@ struct SPACETIMEDBSDK_API FServerMessageType return Obj; } - FORCEINLINE bool IsInitialSubscription() const { return Tag == EServerMessageTag::InitialSubscription; } - - FORCEINLINE FInitialSubscriptionType GetAsInitialSubscription() const - { - ensureMsgf(IsInitialSubscription(), TEXT("MessageData does not hold InitialSubscription!")); - return MessageData.Get(); - } - - FORCEINLINE bool IsTransactionUpdate() const { return Tag == EServerMessageTag::TransactionUpdate; } - - FORCEINLINE FTransactionUpdateType GetAsTransactionUpdate() const - { - ensureMsgf(IsTransactionUpdate(), TEXT("MessageData does not hold TransactionUpdate!")); - return MessageData.Get(); - } - - FORCEINLINE bool IsTransactionUpdateLight() const { return Tag == EServerMessageTag::TransactionUpdateLight; } + FORCEINLINE bool IsInitialConnection() const { return Tag == EServerMessageTag::InitialConnection; } - FORCEINLINE FTransactionUpdateLightType GetAsTransactionUpdateLight() const + FORCEINLINE FInitialConnectionType GetAsInitialConnection() const { - ensureMsgf(IsTransactionUpdateLight(), TEXT("MessageData does not hold TransactionUpdateLight!")); - return MessageData.Get(); - } - - FORCEINLINE bool IsIdentityToken() const { return Tag == EServerMessageTag::IdentityToken; } - - FORCEINLINE FIdentityTokenType GetAsIdentityToken() const - { - ensureMsgf(IsIdentityToken(), TEXT("MessageData does not hold IdentityToken!")); - return MessageData.Get(); - } - - FORCEINLINE bool IsOneOffQueryResponse() const { return Tag == EServerMessageTag::OneOffQueryResponse; } - - FORCEINLINE FOneOffQueryResponseType GetAsOneOffQueryResponse() const - { - ensureMsgf(IsOneOffQueryResponse(), TEXT("MessageData does not hold OneOffQueryResponse!")); - return MessageData.Get(); + ensureMsgf(IsInitialConnection(), TEXT("MessageData does not hold InitialConnection!")); + return MessageData.Get(); } FORCEINLINE bool IsSubscribeApplied() const { return Tag == EServerMessageTag::SubscribeApplied; } @@ -199,20 +137,28 @@ struct SPACETIMEDBSDK_API FServerMessageType return MessageData.Get(); } - FORCEINLINE bool IsSubscribeMultiApplied() const { return Tag == EServerMessageTag::SubscribeMultiApplied; } + FORCEINLINE bool IsTransactionUpdate() const { return Tag == EServerMessageTag::TransactionUpdate; } - FORCEINLINE FSubscribeMultiAppliedType GetAsSubscribeMultiApplied() const + FORCEINLINE FTransactionUpdateType GetAsTransactionUpdate() const + { + ensureMsgf(IsTransactionUpdate(), TEXT("MessageData does not hold TransactionUpdate!")); + return MessageData.Get(); + } + + FORCEINLINE bool IsOneOffQueryResult() const { return Tag == EServerMessageTag::OneOffQueryResult; } + + FORCEINLINE FOneOffQueryResultType GetAsOneOffQueryResult() const { - ensureMsgf(IsSubscribeMultiApplied(), TEXT("MessageData does not hold SubscribeMultiApplied!")); - return MessageData.Get(); + ensureMsgf(IsOneOffQueryResult(), TEXT("MessageData does not hold OneOffQueryResult!")); + return MessageData.Get(); } - FORCEINLINE bool IsUnsubscribeMultiApplied() const { return Tag == EServerMessageTag::UnsubscribeMultiApplied; } + FORCEINLINE bool IsReducerResult() const { return Tag == EServerMessageTag::ReducerResult; } - FORCEINLINE FUnsubscribeMultiAppliedType GetAsUnsubscribeMultiApplied() const + FORCEINLINE FReducerResultType GetAsReducerResult() const { - ensureMsgf(IsUnsubscribeMultiApplied(), TEXT("MessageData does not hold UnsubscribeMultiApplied!")); - return MessageData.Get(); + ensureMsgf(IsReducerResult(), TEXT("MessageData does not hold ReducerResult!")); + return MessageData.Get(); } FORCEINLINE bool IsProcedureResult() const { return Tag == EServerMessageTag::ProcedureResult; } @@ -230,26 +176,20 @@ struct SPACETIMEDBSDK_API FServerMessageType switch (Tag) { - case EServerMessageTag::InitialSubscription: - return GetAsInitialSubscription() == Other.GetAsInitialSubscription(); - case EServerMessageTag::TransactionUpdate: - return GetAsTransactionUpdate() == Other.GetAsTransactionUpdate(); - case EServerMessageTag::TransactionUpdateLight: - return GetAsTransactionUpdateLight() == Other.GetAsTransactionUpdateLight(); - case EServerMessageTag::IdentityToken: - return GetAsIdentityToken() == Other.GetAsIdentityToken(); - case EServerMessageTag::OneOffQueryResponse: - return GetAsOneOffQueryResponse() == Other.GetAsOneOffQueryResponse(); + case EServerMessageTag::InitialConnection: + return GetAsInitialConnection() == Other.GetAsInitialConnection(); case EServerMessageTag::SubscribeApplied: return GetAsSubscribeApplied() == Other.GetAsSubscribeApplied(); case EServerMessageTag::UnsubscribeApplied: return GetAsUnsubscribeApplied() == Other.GetAsUnsubscribeApplied(); case EServerMessageTag::SubscriptionError: return GetAsSubscriptionError() == Other.GetAsSubscriptionError(); - case EServerMessageTag::SubscribeMultiApplied: - return GetAsSubscribeMultiApplied() == Other.GetAsSubscribeMultiApplied(); - case EServerMessageTag::UnsubscribeMultiApplied: - return GetAsUnsubscribeMultiApplied() == Other.GetAsUnsubscribeMultiApplied(); + case EServerMessageTag::TransactionUpdate: + return GetAsTransactionUpdate() == Other.GetAsTransactionUpdate(); + case EServerMessageTag::OneOffQueryResult: + return GetAsOneOffQueryResult() == Other.GetAsOneOffQueryResult(); + case EServerMessageTag::ReducerResult: + return GetAsReducerResult() == Other.GetAsReducerResult(); case EServerMessageTag::ProcedureResult: return GetAsProcedureResult() == Other.GetAsProcedureResult(); default: @@ -274,16 +214,13 @@ FORCEINLINE uint32 GetTypeHash(const FServerMessageType& ServerMessage) const uint32 TagHash = GetTypeHash(static_cast(ServerMessage.Tag)); switch (ServerMessage.Tag) { - case EServerMessageTag::InitialSubscription: return HashCombine(TagHash, ::GetTypeHash(ServerMessage.GetAsInitialSubscription())); - case EServerMessageTag::TransactionUpdate: return HashCombine(TagHash, ::GetTypeHash(ServerMessage.GetAsTransactionUpdate())); - case EServerMessageTag::TransactionUpdateLight: return HashCombine(TagHash, ::GetTypeHash(ServerMessage.GetAsTransactionUpdateLight())); - case EServerMessageTag::IdentityToken: return HashCombine(TagHash, ::GetTypeHash(ServerMessage.GetAsIdentityToken())); - case EServerMessageTag::OneOffQueryResponse: return HashCombine(TagHash, ::GetTypeHash(ServerMessage.GetAsOneOffQueryResponse())); + case EServerMessageTag::InitialConnection: return HashCombine(TagHash, ::GetTypeHash(ServerMessage.GetAsInitialConnection())); case EServerMessageTag::SubscribeApplied: return HashCombine(TagHash, ::GetTypeHash(ServerMessage.GetAsSubscribeApplied())); case EServerMessageTag::UnsubscribeApplied: return HashCombine(TagHash, ::GetTypeHash(ServerMessage.GetAsUnsubscribeApplied())); case EServerMessageTag::SubscriptionError: return HashCombine(TagHash, ::GetTypeHash(ServerMessage.GetAsSubscriptionError())); - case EServerMessageTag::SubscribeMultiApplied: return HashCombine(TagHash, ::GetTypeHash(ServerMessage.GetAsSubscribeMultiApplied())); - case EServerMessageTag::UnsubscribeMultiApplied: return HashCombine(TagHash, ::GetTypeHash(ServerMessage.GetAsUnsubscribeMultiApplied())); + case EServerMessageTag::TransactionUpdate: return HashCombine(TagHash, ::GetTypeHash(ServerMessage.GetAsTransactionUpdate())); + case EServerMessageTag::OneOffQueryResult: return HashCombine(TagHash, ::GetTypeHash(ServerMessage.GetAsOneOffQueryResult())); + case EServerMessageTag::ReducerResult: return HashCombine(TagHash, ::GetTypeHash(ServerMessage.GetAsReducerResult())); case EServerMessageTag::ProcedureResult: return HashCombine(TagHash, ::GetTypeHash(ServerMessage.GetAsProcedureResult())); default: return TagHash; } @@ -297,16 +234,13 @@ namespace UE::SpacetimeDB FServerMessageType, EServerMessageTag, MessageData, - InitialSubscription, FInitialSubscriptionType, - TransactionUpdate, FTransactionUpdateType, - TransactionUpdateLight, FTransactionUpdateLightType, - IdentityToken, FIdentityTokenType, - OneOffQueryResponse, FOneOffQueryResponseType, + InitialConnection, FInitialConnectionType, SubscribeApplied, FSubscribeAppliedType, UnsubscribeApplied, FUnsubscribeAppliedType, SubscriptionError, FSubscriptionErrorType, - SubscribeMultiApplied, FSubscribeMultiAppliedType, - UnsubscribeMultiApplied, FUnsubscribeMultiAppliedType, + TransactionUpdate, FTransactionUpdateType, + OneOffQueryResult, FOneOffQueryResultType, + ReducerResult, FReducerResultType, ProcedureResult, FProcedureResultType ); } @@ -318,78 +252,18 @@ class SPACETIMEDBSDK_API UServerMessageBpLib : public UBlueprintFunctionLibrary private: UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ServerMessage") - static FServerMessageType InitialSubscription(const FInitialSubscriptionType& InValue) - { - return FServerMessageType::InitialSubscription(InValue); - } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ServerMessage") - static bool IsInitialSubscription(const FServerMessageType& InValue) { return InValue.IsInitialSubscription(); } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ServerMessage") - static FInitialSubscriptionType GetAsInitialSubscription(const FServerMessageType& InValue) - { - return InValue.GetAsInitialSubscription(); - } - - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ServerMessage") - static FServerMessageType TransactionUpdate(const FTransactionUpdateType& InValue) + static FServerMessageType InitialConnection(const FInitialConnectionType& InValue) { - return FServerMessageType::TransactionUpdate(InValue); + return FServerMessageType::InitialConnection(InValue); } UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ServerMessage") - static bool IsTransactionUpdate(const FServerMessageType& InValue) { return InValue.IsTransactionUpdate(); } + static bool IsInitialConnection(const FServerMessageType& InValue) { return InValue.IsInitialConnection(); } UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ServerMessage") - static FTransactionUpdateType GetAsTransactionUpdate(const FServerMessageType& InValue) + static FInitialConnectionType GetAsInitialConnection(const FServerMessageType& InValue) { - return InValue.GetAsTransactionUpdate(); - } - - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ServerMessage") - static FServerMessageType TransactionUpdateLight(const FTransactionUpdateLightType& InValue) - { - return FServerMessageType::TransactionUpdateLight(InValue); - } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ServerMessage") - static bool IsTransactionUpdateLight(const FServerMessageType& InValue) { return InValue.IsTransactionUpdateLight(); } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ServerMessage") - static FTransactionUpdateLightType GetAsTransactionUpdateLight(const FServerMessageType& InValue) - { - return InValue.GetAsTransactionUpdateLight(); - } - - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ServerMessage") - static FServerMessageType IdentityToken(const FIdentityTokenType& InValue) - { - return FServerMessageType::IdentityToken(InValue); - } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ServerMessage") - static bool IsIdentityToken(const FServerMessageType& InValue) { return InValue.IsIdentityToken(); } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ServerMessage") - static FIdentityTokenType GetAsIdentityToken(const FServerMessageType& InValue) - { - return InValue.GetAsIdentityToken(); - } - - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ServerMessage") - static FServerMessageType OneOffQueryResponse(const FOneOffQueryResponseType& InValue) - { - return FServerMessageType::OneOffQueryResponse(InValue); - } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ServerMessage") - static bool IsOneOffQueryResponse(const FServerMessageType& InValue) { return InValue.IsOneOffQueryResponse(); } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ServerMessage") - static FOneOffQueryResponseType GetAsOneOffQueryResponse(const FServerMessageType& InValue) - { - return InValue.GetAsOneOffQueryResponse(); + return InValue.GetAsInitialConnection(); } UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ServerMessage") @@ -438,33 +312,48 @@ class SPACETIMEDBSDK_API UServerMessageBpLib : public UBlueprintFunctionLibrary } UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ServerMessage") - static FServerMessageType SubscribeMultiApplied(const FSubscribeMultiAppliedType& InValue) + static FServerMessageType TransactionUpdate(const FTransactionUpdateType& InValue) + { + return FServerMessageType::TransactionUpdate(InValue); + } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ServerMessage") + static bool IsTransactionUpdate(const FServerMessageType& InValue) { return InValue.IsTransactionUpdate(); } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ServerMessage") + static FTransactionUpdateType GetAsTransactionUpdate(const FServerMessageType& InValue) + { + return InValue.GetAsTransactionUpdate(); + } + + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ServerMessage") + static FServerMessageType OneOffQueryResult(const FOneOffQueryResultType& InValue) { - return FServerMessageType::SubscribeMultiApplied(InValue); + return FServerMessageType::OneOffQueryResult(InValue); } UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ServerMessage") - static bool IsSubscribeMultiApplied(const FServerMessageType& InValue) { return InValue.IsSubscribeMultiApplied(); } + static bool IsOneOffQueryResult(const FServerMessageType& InValue) { return InValue.IsOneOffQueryResult(); } UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ServerMessage") - static FSubscribeMultiAppliedType GetAsSubscribeMultiApplied(const FServerMessageType& InValue) + static FOneOffQueryResultType GetAsOneOffQueryResult(const FServerMessageType& InValue) { - return InValue.GetAsSubscribeMultiApplied(); + return InValue.GetAsOneOffQueryResult(); } UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ServerMessage") - static FServerMessageType UnsubscribeMultiApplied(const FUnsubscribeMultiAppliedType& InValue) + static FServerMessageType ReducerResult(const FReducerResultType& InValue) { - return FServerMessageType::UnsubscribeMultiApplied(InValue); + return FServerMessageType::ReducerResult(InValue); } UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ServerMessage") - static bool IsUnsubscribeMultiApplied(const FServerMessageType& InValue) { return InValue.IsUnsubscribeMultiApplied(); } + static bool IsReducerResult(const FServerMessageType& InValue) { return InValue.IsReducerResult(); } UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ServerMessage") - static FUnsubscribeMultiAppliedType GetAsUnsubscribeMultiApplied(const FServerMessageType& InValue) + static FReducerResultType GetAsReducerResult(const FServerMessageType& InValue) { - return InValue.GetAsUnsubscribeMultiApplied(); + return InValue.GetAsReducerResult(); } UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ServerMessage") diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SingleTableRowsType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SingleTableRowsType.g.h new file mode 100644 index 00000000000..a1e6151fc61 --- /dev/null +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SingleTableRowsType.g.h @@ -0,0 +1,50 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#pragma once +#include "CoreMinimal.h" +#include "BSATN/UESpacetimeDB.h" +#include "ModuleBindings/Types/BsatnRowListType.g.h" +#include "SingleTableRowsType.g.generated.h" + +USTRUCT(BlueprintType) +struct SPACETIMEDBSDK_API FSingleTableRowsType +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FString Table; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FBsatnRowListType Rows; + + FORCEINLINE bool operator==(const FSingleTableRowsType& Other) const + { + return Table == Other.Table && Rows == Other.Rows; + } + + FORCEINLINE bool operator!=(const FSingleTableRowsType& Other) const + { + return !(*this == Other); + } +}; + +/** + * Custom hash function for FSingleTableRowsType. + * Combines the hashes of all fields that are compared in operator==. + * @param SingleTableRowsType The FSingleTableRowsType instance to hash. + * @return The combined hash value. + */ +FORCEINLINE uint32 GetTypeHash(const FSingleTableRowsType& SingleTableRowsType) +{ + uint32 Hash = GetTypeHash(SingleTableRowsType.Table); + Hash = HashCombine(Hash, GetTypeHash(SingleTableRowsType.Rows)); + return Hash; +} + +namespace UE::SpacetimeDB +{ + UE_SPACETIMEDB_ENABLE_TARRAY(FSingleTableRowsType); + + UE_SPACETIMEDB_STRUCT(FSingleTableRowsType, Table, Rows); +} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeAppliedType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeAppliedType.g.h index fcc7107e437..64636c51f09 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeAppliedType.g.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeAppliedType.g.h @@ -4,8 +4,8 @@ #pragma once #include "CoreMinimal.h" #include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/QueryIdType.g.h" -#include "ModuleBindings/Types/SubscribeRowsType.g.h" +#include "ModuleBindings/Types/QueryRowsType.g.h" +#include "ModuleBindings/Types/QuerySetIdType.g.h" #include "SubscribeAppliedType.g.generated.h" USTRUCT(BlueprintType) @@ -16,18 +16,15 @@ struct SPACETIMEDBSDK_API FSubscribeAppliedType // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements uint32 RequestId = 0; - // NOTE: uint64 field not exposed to Blueprint due to non-blueprintable elements - uint64 TotalHostExecutionDurationMicros = 0; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FQueryIdType QueryId; + FQuerySetIdType QuerySetId; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FSubscribeRowsType Rows; + FQueryRowsType Rows; FORCEINLINE bool operator==(const FSubscribeAppliedType& Other) const { - return RequestId == Other.RequestId && TotalHostExecutionDurationMicros == Other.TotalHostExecutionDurationMicros && QueryId == Other.QueryId && Rows == Other.Rows; + return RequestId == Other.RequestId && QuerySetId == Other.QuerySetId && Rows == Other.Rows; } FORCEINLINE bool operator!=(const FSubscribeAppliedType& Other) const @@ -45,8 +42,7 @@ struct SPACETIMEDBSDK_API FSubscribeAppliedType FORCEINLINE uint32 GetTypeHash(const FSubscribeAppliedType& SubscribeAppliedType) { uint32 Hash = GetTypeHash(SubscribeAppliedType.RequestId); - Hash = HashCombine(Hash, GetTypeHash(SubscribeAppliedType.TotalHostExecutionDurationMicros)); - Hash = HashCombine(Hash, GetTypeHash(SubscribeAppliedType.QueryId)); + Hash = HashCombine(Hash, GetTypeHash(SubscribeAppliedType.QuerySetId)); Hash = HashCombine(Hash, GetTypeHash(SubscribeAppliedType.Rows)); return Hash; } @@ -55,5 +51,5 @@ namespace UE::SpacetimeDB { UE_SPACETIMEDB_ENABLE_TARRAY(FSubscribeAppliedType); - UE_SPACETIMEDB_STRUCT(FSubscribeAppliedType, RequestId, TotalHostExecutionDurationMicros, QueryId, Rows); + UE_SPACETIMEDB_STRUCT(FSubscribeAppliedType, RequestId, QuerySetId, Rows); } diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeMultiAppliedType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeMultiAppliedType.g.h deleted file mode 100644 index b97c25dc8aa..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeMultiAppliedType.g.h +++ /dev/null @@ -1,59 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/DatabaseUpdateType.g.h" -#include "ModuleBindings/Types/QueryIdType.g.h" -#include "SubscribeMultiAppliedType.g.generated.h" - -USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FSubscribeMultiAppliedType -{ - GENERATED_BODY() - - // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements - uint32 RequestId = 0; - - // NOTE: uint64 field not exposed to Blueprint due to non-blueprintable elements - uint64 TotalHostExecutionDurationMicros = 0; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FQueryIdType QueryId; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FDatabaseUpdateType Update; - - FORCEINLINE bool operator==(const FSubscribeMultiAppliedType& Other) const - { - return RequestId == Other.RequestId && TotalHostExecutionDurationMicros == Other.TotalHostExecutionDurationMicros && QueryId == Other.QueryId && Update == Other.Update; - } - - FORCEINLINE bool operator!=(const FSubscribeMultiAppliedType& Other) const - { - return !(*this == Other); - } -}; - -/** - * Custom hash function for FSubscribeMultiAppliedType. - * Combines the hashes of all fields that are compared in operator==. - * @param SubscribeMultiAppliedType The FSubscribeMultiAppliedType instance to hash. - * @return The combined hash value. - */ -FORCEINLINE uint32 GetTypeHash(const FSubscribeMultiAppliedType& SubscribeMultiAppliedType) -{ - uint32 Hash = GetTypeHash(SubscribeMultiAppliedType.RequestId); - Hash = HashCombine(Hash, GetTypeHash(SubscribeMultiAppliedType.TotalHostExecutionDurationMicros)); - Hash = HashCombine(Hash, GetTypeHash(SubscribeMultiAppliedType.QueryId)); - Hash = HashCombine(Hash, GetTypeHash(SubscribeMultiAppliedType.Update)); - return Hash; -} - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_ENABLE_TARRAY(FSubscribeMultiAppliedType); - - UE_SPACETIMEDB_STRUCT(FSubscribeMultiAppliedType, RequestId, TotalHostExecutionDurationMicros, QueryId, Update); -} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeMultiType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeMultiType.g.h deleted file mode 100644 index 1794d8f39f0..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeMultiType.g.h +++ /dev/null @@ -1,54 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/QueryIdType.g.h" -#include "SubscribeMultiType.g.generated.h" - -USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FSubscribeMultiType -{ - GENERATED_BODY() - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - TArray QueryStrings; - - // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements - uint32 RequestId = 0; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FQueryIdType QueryId; - - FORCEINLINE bool operator==(const FSubscribeMultiType& Other) const - { - return QueryStrings == Other.QueryStrings && RequestId == Other.RequestId && QueryId == Other.QueryId; - } - - FORCEINLINE bool operator!=(const FSubscribeMultiType& Other) const - { - return !(*this == Other); - } -}; - -/** - * Custom hash function for FSubscribeMultiType. - * Combines the hashes of all fields that are compared in operator==. - * @param SubscribeMultiType The FSubscribeMultiType instance to hash. - * @return The combined hash value. - */ -FORCEINLINE uint32 GetTypeHash(const FSubscribeMultiType& SubscribeMultiType) -{ - uint32 Hash = GetTypeHash(SubscribeMultiType.QueryStrings); - Hash = HashCombine(Hash, GetTypeHash(SubscribeMultiType.RequestId)); - Hash = HashCombine(Hash, GetTypeHash(SubscribeMultiType.QueryId)); - return Hash; -} - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_ENABLE_TARRAY(FSubscribeMultiType); - - UE_SPACETIMEDB_STRUCT(FSubscribeMultiType, QueryStrings, RequestId, QueryId); -} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeRowsType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeRowsType.g.h deleted file mode 100644 index 70a463d2bc2..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeRowsType.g.h +++ /dev/null @@ -1,54 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/TableUpdateType.g.h" -#include "SubscribeRowsType.g.generated.h" - -USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FSubscribeRowsType -{ - GENERATED_BODY() - - // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements - uint32 TableId = 0; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FString TableName; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FTableUpdateType TableRows; - - FORCEINLINE bool operator==(const FSubscribeRowsType& Other) const - { - return TableId == Other.TableId && TableName == Other.TableName && TableRows == Other.TableRows; - } - - FORCEINLINE bool operator!=(const FSubscribeRowsType& Other) const - { - return !(*this == Other); - } -}; - -/** - * Custom hash function for FSubscribeRowsType. - * Combines the hashes of all fields that are compared in operator==. - * @param SubscribeRowsType The FSubscribeRowsType instance to hash. - * @return The combined hash value. - */ -FORCEINLINE uint32 GetTypeHash(const FSubscribeRowsType& SubscribeRowsType) -{ - uint32 Hash = GetTypeHash(SubscribeRowsType.TableId); - Hash = HashCombine(Hash, GetTypeHash(SubscribeRowsType.TableName)); - Hash = HashCombine(Hash, GetTypeHash(SubscribeRowsType.TableRows)); - return Hash; -} - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_ENABLE_TARRAY(FSubscribeRowsType); - - UE_SPACETIMEDB_STRUCT(FSubscribeRowsType, TableId, TableName, TableRows); -} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeSingleType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeSingleType.g.h deleted file mode 100644 index 828171789bc..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeSingleType.g.h +++ /dev/null @@ -1,54 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/QueryIdType.g.h" -#include "SubscribeSingleType.g.generated.h" - -USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FSubscribeSingleType -{ - GENERATED_BODY() - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FString Query; - - // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements - uint32 RequestId = 0; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FQueryIdType QueryId; - - FORCEINLINE bool operator==(const FSubscribeSingleType& Other) const - { - return Query == Other.Query && RequestId == Other.RequestId && QueryId == Other.QueryId; - } - - FORCEINLINE bool operator!=(const FSubscribeSingleType& Other) const - { - return !(*this == Other); - } -}; - -/** - * Custom hash function for FSubscribeSingleType. - * Combines the hashes of all fields that are compared in operator==. - * @param SubscribeSingleType The FSubscribeSingleType instance to hash. - * @return The combined hash value. - */ -FORCEINLINE uint32 GetTypeHash(const FSubscribeSingleType& SubscribeSingleType) -{ - uint32 Hash = GetTypeHash(SubscribeSingleType.Query); - Hash = HashCombine(Hash, GetTypeHash(SubscribeSingleType.RequestId)); - Hash = HashCombine(Hash, GetTypeHash(SubscribeSingleType.QueryId)); - return Hash; -} - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_ENABLE_TARRAY(FSubscribeSingleType); - - UE_SPACETIMEDB_STRUCT(FSubscribeSingleType, Query, RequestId, QueryId); -} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeType.g.h index a7e09710577..07487d3b347 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeType.g.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscribeType.g.h @@ -4,6 +4,7 @@ #pragma once #include "CoreMinimal.h" #include "BSATN/UESpacetimeDB.h" +#include "ModuleBindings/Types/QuerySetIdType.g.h" #include "SubscribeType.g.generated.h" USTRUCT(BlueprintType) @@ -11,15 +12,18 @@ struct SPACETIMEDBSDK_API FSubscribeType { GENERATED_BODY() - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - TArray QueryStrings; - // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements uint32 RequestId = 0; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FQuerySetIdType QuerySetId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + TArray QueryStrings; + FORCEINLINE bool operator==(const FSubscribeType& Other) const { - return QueryStrings == Other.QueryStrings && RequestId == Other.RequestId; + return RequestId == Other.RequestId && QuerySetId == Other.QuerySetId && QueryStrings == Other.QueryStrings; } FORCEINLINE bool operator!=(const FSubscribeType& Other) const @@ -36,8 +40,9 @@ struct SPACETIMEDBSDK_API FSubscribeType */ FORCEINLINE uint32 GetTypeHash(const FSubscribeType& SubscribeType) { - uint32 Hash = GetTypeHash(SubscribeType.QueryStrings); - Hash = HashCombine(Hash, GetTypeHash(SubscribeType.RequestId)); + uint32 Hash = GetTypeHash(SubscribeType.RequestId); + Hash = HashCombine(Hash, GetTypeHash(SubscribeType.QuerySetId)); + Hash = HashCombine(Hash, GetTypeHash(SubscribeType.QueryStrings)); return Hash; } @@ -45,5 +50,5 @@ namespace UE::SpacetimeDB { UE_SPACETIMEDB_ENABLE_TARRAY(FSubscribeType); - UE_SPACETIMEDB_STRUCT(FSubscribeType, QueryStrings, RequestId); + UE_SPACETIMEDB_STRUCT(FSubscribeType, RequestId, QuerySetId, QueryStrings); } diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscriptionErrorType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscriptionErrorType.g.h index d8a9bc82066..2827ca93d46 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscriptionErrorType.g.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/SubscriptionErrorType.g.h @@ -5,6 +5,7 @@ #include "CoreMinimal.h" #include "BSATN/UESpacetimeDB.h" #include "ModuleBindings/Optionals/SpacetimeDbSdkOptionalUInt32.g.h" +#include "ModuleBindings/Types/QuerySetIdType.g.h" #include "SubscriptionErrorType.g.generated.h" USTRUCT(BlueprintType) @@ -12,24 +13,18 @@ struct SPACETIMEDBSDK_API FSubscriptionErrorType { GENERATED_BODY() - // NOTE: uint64 field not exposed to Blueprint due to non-blueprintable elements - uint64 TotalHostExecutionDurationMicros = 0; - // NOTE: FSpacetimeDbSdkOptionalUInt32 field not exposed to Blueprint due to non-blueprintable elements FSpacetimeDbSdkOptionalUInt32 RequestId; - // NOTE: FSpacetimeDbSdkOptionalUInt32 field not exposed to Blueprint due to non-blueprintable elements - FSpacetimeDbSdkOptionalUInt32 QueryId; - - // NOTE: FSpacetimeDbSdkOptionalUInt32 field not exposed to Blueprint due to non-blueprintable elements - FSpacetimeDbSdkOptionalUInt32 TableId; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + FQuerySetIdType QuerySetId; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") FString Error; FORCEINLINE bool operator==(const FSubscriptionErrorType& Other) const { - return TotalHostExecutionDurationMicros == Other.TotalHostExecutionDurationMicros && RequestId == Other.RequestId && QueryId == Other.QueryId && TableId == Other.TableId && Error == Other.Error; + return RequestId == Other.RequestId && QuerySetId == Other.QuerySetId && Error == Other.Error; } FORCEINLINE bool operator!=(const FSubscriptionErrorType& Other) const @@ -46,10 +41,8 @@ struct SPACETIMEDBSDK_API FSubscriptionErrorType */ FORCEINLINE uint32 GetTypeHash(const FSubscriptionErrorType& SubscriptionErrorType) { - uint32 Hash = GetTypeHash(SubscriptionErrorType.TotalHostExecutionDurationMicros); - Hash = HashCombine(Hash, GetTypeHash(SubscriptionErrorType.RequestId)); - Hash = HashCombine(Hash, GetTypeHash(SubscriptionErrorType.QueryId)); - Hash = HashCombine(Hash, GetTypeHash(SubscriptionErrorType.TableId)); + uint32 Hash = GetTypeHash(SubscriptionErrorType.RequestId); + Hash = HashCombine(Hash, GetTypeHash(SubscriptionErrorType.QuerySetId)); Hash = HashCombine(Hash, GetTypeHash(SubscriptionErrorType.Error)); return Hash; } @@ -58,5 +51,5 @@ namespace UE::SpacetimeDB { UE_SPACETIMEDB_ENABLE_TARRAY(FSubscriptionErrorType); - UE_SPACETIMEDB_STRUCT(FSubscriptionErrorType, TotalHostExecutionDurationMicros, RequestId, QueryId, TableId, Error); + UE_SPACETIMEDB_STRUCT(FSubscriptionErrorType, RequestId, QuerySetId, Error); } diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/TableUpdateRowsType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/TableUpdateRowsType.g.h new file mode 100644 index 00000000000..d4a2589a73a --- /dev/null +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/TableUpdateRowsType.g.h @@ -0,0 +1,152 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#pragma once +#include "CoreMinimal.h" +#include "BSATN/UESpacetimeDB.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "ModuleBindings/Types/PersistentTableRowsType.g.h" +#include "ModuleBindings/Types/EventTableRowsType.g.h" +#include "TableUpdateRowsType.g.generated.h" + +UENUM(BlueprintType) +enum class ETableUpdateRowsTag : uint8 +{ + PersistentTable, + EventTable +}; + +USTRUCT(BlueprintType) +struct SPACETIMEDBSDK_API FTableUpdateRowsType +{ + GENERATED_BODY() + +public: + FTableUpdateRowsType() = default; + + TVariant MessageData; + + UPROPERTY(BlueprintReadOnly) + ETableUpdateRowsTag Tag = static_cast(0); + + static FTableUpdateRowsType PersistentTable(const FPersistentTableRowsType& Value) + { + FTableUpdateRowsType Obj; + Obj.Tag = ETableUpdateRowsTag::PersistentTable; + Obj.MessageData.Set(Value); + return Obj; + } + + static FTableUpdateRowsType EventTable(const FEventTableRowsType& Value) + { + FTableUpdateRowsType Obj; + Obj.Tag = ETableUpdateRowsTag::EventTable; + Obj.MessageData.Set(Value); + return Obj; + } + + FORCEINLINE bool IsPersistentTable() const { return Tag == ETableUpdateRowsTag::PersistentTable; } + + FORCEINLINE FPersistentTableRowsType GetAsPersistentTable() const + { + ensureMsgf(IsPersistentTable(), TEXT("MessageData does not hold PersistentTable!")); + return MessageData.Get(); + } + + FORCEINLINE bool IsEventTable() const { return Tag == ETableUpdateRowsTag::EventTable; } + + FORCEINLINE FEventTableRowsType GetAsEventTable() const + { + ensureMsgf(IsEventTable(), TEXT("MessageData does not hold EventTable!")); + return MessageData.Get(); + } + + // Inline equality operators + FORCEINLINE bool operator==(const FTableUpdateRowsType& Other) const + { + if (Tag != Other.Tag) return false; + + switch (Tag) + { + case ETableUpdateRowsTag::PersistentTable: + return GetAsPersistentTable() == Other.GetAsPersistentTable(); + case ETableUpdateRowsTag::EventTable: + return GetAsEventTable() == Other.GetAsEventTable(); + default: + return false; + } + } + + FORCEINLINE bool operator!=(const FTableUpdateRowsType& Other) const + { + return !(*this == Other); + } +}; + +/** + * Custom hash function for FTableUpdateRowsType. + * Combines the hashes of all fields that are compared in operator==. + * @param TableUpdateRowsType The FTableUpdateRowsType instance to hash. + * @return The combined hash value. + */ +FORCEINLINE uint32 GetTypeHash(const FTableUpdateRowsType& TableUpdateRows) +{ + const uint32 TagHash = GetTypeHash(static_cast(TableUpdateRows.Tag)); + switch (TableUpdateRows.Tag) + { + case ETableUpdateRowsTag::PersistentTable: return HashCombine(TagHash, ::GetTypeHash(TableUpdateRows.GetAsPersistentTable())); + case ETableUpdateRowsTag::EventTable: return HashCombine(TagHash, ::GetTypeHash(TableUpdateRows.GetAsEventTable())); + default: return TagHash; + } +} + +namespace UE::SpacetimeDB +{ + UE_SPACETIMEDB_ENABLE_TARRAY(FTableUpdateRowsType); + + UE_SPACETIMEDB_TAGGED_ENUM( + FTableUpdateRowsType, + ETableUpdateRowsTag, + MessageData, + PersistentTable, FPersistentTableRowsType, + EventTable, FEventTableRowsType + ); +} + +UCLASS() +class SPACETIMEDBSDK_API UTableUpdateRowsBpLib : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +private: + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|TableUpdateRows") + static FTableUpdateRowsType PersistentTable(const FPersistentTableRowsType& InValue) + { + return FTableUpdateRowsType::PersistentTable(InValue); + } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|TableUpdateRows") + static bool IsPersistentTable(const FTableUpdateRowsType& InValue) { return InValue.IsPersistentTable(); } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|TableUpdateRows") + static FPersistentTableRowsType GetAsPersistentTable(const FTableUpdateRowsType& InValue) + { + return InValue.GetAsPersistentTable(); + } + + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|TableUpdateRows") + static FTableUpdateRowsType EventTable(const FEventTableRowsType& InValue) + { + return FTableUpdateRowsType::EventTable(InValue); + } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|TableUpdateRows") + static bool IsEventTable(const FTableUpdateRowsType& InValue) { return InValue.IsEventTable(); } + + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|TableUpdateRows") + static FEventTableRowsType GetAsEventTable(const FTableUpdateRowsType& InValue) + { + return InValue.GetAsEventTable(); + } + +}; diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/TableUpdateType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/TableUpdateType.g.h index 029c672e60f..25be9117a8a 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/TableUpdateType.g.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/TableUpdateType.g.h @@ -4,7 +4,7 @@ #pragma once #include "CoreMinimal.h" #include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/CompressableQueryUpdateType.g.h" +#include "ModuleBindings/Types/TableUpdateRowsType.g.h" #include "TableUpdateType.g.generated.h" USTRUCT(BlueprintType) @@ -12,21 +12,15 @@ struct SPACETIMEDBSDK_API FTableUpdateType { GENERATED_BODY() - // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements - uint32 TableId = 0; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") FString TableName; - // NOTE: uint64 field not exposed to Blueprint due to non-blueprintable elements - uint64 NumRows = 0; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - TArray Updates; + TArray Rows; FORCEINLINE bool operator==(const FTableUpdateType& Other) const { - return TableId == Other.TableId && TableName == Other.TableName && NumRows == Other.NumRows && Updates == Other.Updates; + return TableName == Other.TableName && Rows == Other.Rows; } FORCEINLINE bool operator!=(const FTableUpdateType& Other) const @@ -43,10 +37,8 @@ struct SPACETIMEDBSDK_API FTableUpdateType */ FORCEINLINE uint32 GetTypeHash(const FTableUpdateType& TableUpdateType) { - uint32 Hash = GetTypeHash(TableUpdateType.TableId); - Hash = HashCombine(Hash, GetTypeHash(TableUpdateType.TableName)); - Hash = HashCombine(Hash, GetTypeHash(TableUpdateType.NumRows)); - Hash = HashCombine(Hash, GetTypeHash(TableUpdateType.Updates)); + uint32 Hash = GetTypeHash(TableUpdateType.TableName); + Hash = HashCombine(Hash, GetTypeHash(TableUpdateType.Rows)); return Hash; } @@ -54,5 +46,5 @@ namespace UE::SpacetimeDB { UE_SPACETIMEDB_ENABLE_TARRAY(FTableUpdateType); - UE_SPACETIMEDB_STRUCT(FTableUpdateType, TableId, TableName, NumRows, Updates); + UE_SPACETIMEDB_STRUCT(FTableUpdateType, TableName, Rows); } diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/TransactionUpdateLightType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/TransactionUpdateLightType.g.h deleted file mode 100644 index 8e3f8fa32b5..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/TransactionUpdateLightType.g.h +++ /dev/null @@ -1,50 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/DatabaseUpdateType.g.h" -#include "TransactionUpdateLightType.g.generated.h" - -USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FTransactionUpdateLightType -{ - GENERATED_BODY() - - // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements - uint32 RequestId = 0; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FDatabaseUpdateType Update; - - FORCEINLINE bool operator==(const FTransactionUpdateLightType& Other) const - { - return RequestId == Other.RequestId && Update == Other.Update; - } - - FORCEINLINE bool operator!=(const FTransactionUpdateLightType& Other) const - { - return !(*this == Other); - } -}; - -/** - * Custom hash function for FTransactionUpdateLightType. - * Combines the hashes of all fields that are compared in operator==. - * @param TransactionUpdateLightType The FTransactionUpdateLightType instance to hash. - * @return The combined hash value. - */ -FORCEINLINE uint32 GetTypeHash(const FTransactionUpdateLightType& TransactionUpdateLightType) -{ - uint32 Hash = GetTypeHash(TransactionUpdateLightType.RequestId); - Hash = HashCombine(Hash, GetTypeHash(TransactionUpdateLightType.Update)); - return Hash; -} - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_ENABLE_TARRAY(FTransactionUpdateLightType); - - UE_SPACETIMEDB_STRUCT(FTransactionUpdateLightType, RequestId, Update); -} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/TransactionUpdateType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/TransactionUpdateType.g.h index 18c0d727cd3..d449805bad8 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/TransactionUpdateType.g.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/TransactionUpdateType.g.h @@ -4,10 +4,7 @@ #pragma once #include "CoreMinimal.h" #include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/EnergyQuantaType.g.h" -#include "ModuleBindings/Types/ReducerCallInfoType.g.h" -#include "ModuleBindings/Types/UpdateStatusType.g.h" -#include "Types/Builtins.h" +#include "ModuleBindings/Types/QuerySetUpdateType.g.h" #include "TransactionUpdateType.g.generated.h" USTRUCT(BlueprintType) @@ -16,29 +13,11 @@ struct SPACETIMEDBSDK_API FTransactionUpdateType GENERATED_BODY() UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FUpdateStatusType Status; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FSpacetimeDBTimestamp Timestamp; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FSpacetimeDBIdentity CallerIdentity; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FSpacetimeDBConnectionId CallerConnectionId; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FReducerCallInfoType ReducerCall; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FEnergyQuantaType EnergyQuantaUsed; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FSpacetimeDBTimeDuration TotalHostExecutionDuration; + TArray QuerySets; FORCEINLINE bool operator==(const FTransactionUpdateType& Other) const { - return Status == Other.Status && Timestamp == Other.Timestamp && CallerIdentity == Other.CallerIdentity && CallerConnectionId == Other.CallerConnectionId && ReducerCall == Other.ReducerCall && EnergyQuantaUsed == Other.EnergyQuantaUsed && TotalHostExecutionDuration == Other.TotalHostExecutionDuration; + return QuerySets == Other.QuerySets; } FORCEINLINE bool operator!=(const FTransactionUpdateType& Other) const @@ -55,13 +34,7 @@ struct SPACETIMEDBSDK_API FTransactionUpdateType */ FORCEINLINE uint32 GetTypeHash(const FTransactionUpdateType& TransactionUpdateType) { - uint32 Hash = GetTypeHash(TransactionUpdateType.Status); - Hash = HashCombine(Hash, GetTypeHash(TransactionUpdateType.Timestamp)); - Hash = HashCombine(Hash, GetTypeHash(TransactionUpdateType.CallerIdentity)); - Hash = HashCombine(Hash, GetTypeHash(TransactionUpdateType.CallerConnectionId)); - Hash = HashCombine(Hash, GetTypeHash(TransactionUpdateType.ReducerCall)); - Hash = HashCombine(Hash, GetTypeHash(TransactionUpdateType.EnergyQuantaUsed)); - Hash = HashCombine(Hash, GetTypeHash(TransactionUpdateType.TotalHostExecutionDuration)); + uint32 Hash = GetTypeHash(TransactionUpdateType.QuerySets); return Hash; } @@ -69,5 +42,5 @@ namespace UE::SpacetimeDB { UE_SPACETIMEDB_ENABLE_TARRAY(FTransactionUpdateType); - UE_SPACETIMEDB_STRUCT(FTransactionUpdateType, Status, Timestamp, CallerIdentity, CallerConnectionId, ReducerCall, EnergyQuantaUsed, TotalHostExecutionDuration); + UE_SPACETIMEDB_STRUCT(FTransactionUpdateType, QuerySets); } diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeAppliedType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeAppliedType.g.h index 6aee42d8a67..db0992379b0 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeAppliedType.g.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeAppliedType.g.h @@ -4,8 +4,9 @@ #pragma once #include "CoreMinimal.h" #include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/QueryIdType.g.h" -#include "ModuleBindings/Types/SubscribeRowsType.g.h" +#include "ModuleBindings/Optionals/SpacetimeDbSdkOptionalQueryRows.g.h" +#include "ModuleBindings/Types/QueryRowsType.g.h" +#include "ModuleBindings/Types/QuerySetIdType.g.h" #include "UnsubscribeAppliedType.g.generated.h" USTRUCT(BlueprintType) @@ -16,18 +17,15 @@ struct SPACETIMEDBSDK_API FUnsubscribeAppliedType // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements uint32 RequestId = 0; - // NOTE: uint64 field not exposed to Blueprint due to non-blueprintable elements - uint64 TotalHostExecutionDurationMicros = 0; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FQueryIdType QueryId; + FQuerySetIdType QuerySetId; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FSubscribeRowsType Rows; + FSpacetimeDbSdkOptionalQueryRows Rows; FORCEINLINE bool operator==(const FUnsubscribeAppliedType& Other) const { - return RequestId == Other.RequestId && TotalHostExecutionDurationMicros == Other.TotalHostExecutionDurationMicros && QueryId == Other.QueryId && Rows == Other.Rows; + return RequestId == Other.RequestId && QuerySetId == Other.QuerySetId && Rows == Other.Rows; } FORCEINLINE bool operator!=(const FUnsubscribeAppliedType& Other) const @@ -45,8 +43,7 @@ struct SPACETIMEDBSDK_API FUnsubscribeAppliedType FORCEINLINE uint32 GetTypeHash(const FUnsubscribeAppliedType& UnsubscribeAppliedType) { uint32 Hash = GetTypeHash(UnsubscribeAppliedType.RequestId); - Hash = HashCombine(Hash, GetTypeHash(UnsubscribeAppliedType.TotalHostExecutionDurationMicros)); - Hash = HashCombine(Hash, GetTypeHash(UnsubscribeAppliedType.QueryId)); + Hash = HashCombine(Hash, GetTypeHash(UnsubscribeAppliedType.QuerySetId)); Hash = HashCombine(Hash, GetTypeHash(UnsubscribeAppliedType.Rows)); return Hash; } @@ -55,5 +52,5 @@ namespace UE::SpacetimeDB { UE_SPACETIMEDB_ENABLE_TARRAY(FUnsubscribeAppliedType); - UE_SPACETIMEDB_STRUCT(FUnsubscribeAppliedType, RequestId, TotalHostExecutionDurationMicros, QueryId, Rows); + UE_SPACETIMEDB_STRUCT(FUnsubscribeAppliedType, RequestId, QuerySetId, Rows); } diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeFlagsType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeFlagsType.g.h new file mode 100644 index 00000000000..46120a986af --- /dev/null +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeFlagsType.g.h @@ -0,0 +1,19 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#pragma once +#include "CoreMinimal.h" +#include "BSATN/UESpacetimeDB.h" +#include "UnsubscribeFlagsType.g.generated.h" + +UENUM(BlueprintType) +enum class EUnsubscribeFlagsType : uint8 +{ + Default, + SendDroppedRows, +}; + +namespace UE::SpacetimeDB +{ + UE_SPACETIMEDB_ENABLE_TARRAY(EUnsubscribeFlagsType); +} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeMultiAppliedType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeMultiAppliedType.g.h deleted file mode 100644 index 80415dec1bf..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeMultiAppliedType.g.h +++ /dev/null @@ -1,59 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/DatabaseUpdateType.g.h" -#include "ModuleBindings/Types/QueryIdType.g.h" -#include "UnsubscribeMultiAppliedType.g.generated.h" - -USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FUnsubscribeMultiAppliedType -{ - GENERATED_BODY() - - // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements - uint32 RequestId = 0; - - // NOTE: uint64 field not exposed to Blueprint due to non-blueprintable elements - uint64 TotalHostExecutionDurationMicros = 0; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FQueryIdType QueryId; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FDatabaseUpdateType Update; - - FORCEINLINE bool operator==(const FUnsubscribeMultiAppliedType& Other) const - { - return RequestId == Other.RequestId && TotalHostExecutionDurationMicros == Other.TotalHostExecutionDurationMicros && QueryId == Other.QueryId && Update == Other.Update; - } - - FORCEINLINE bool operator!=(const FUnsubscribeMultiAppliedType& Other) const - { - return !(*this == Other); - } -}; - -/** - * Custom hash function for FUnsubscribeMultiAppliedType. - * Combines the hashes of all fields that are compared in operator==. - * @param UnsubscribeMultiAppliedType The FUnsubscribeMultiAppliedType instance to hash. - * @return The combined hash value. - */ -FORCEINLINE uint32 GetTypeHash(const FUnsubscribeMultiAppliedType& UnsubscribeMultiAppliedType) -{ - uint32 Hash = GetTypeHash(UnsubscribeMultiAppliedType.RequestId); - Hash = HashCombine(Hash, GetTypeHash(UnsubscribeMultiAppliedType.TotalHostExecutionDurationMicros)); - Hash = HashCombine(Hash, GetTypeHash(UnsubscribeMultiAppliedType.QueryId)); - Hash = HashCombine(Hash, GetTypeHash(UnsubscribeMultiAppliedType.Update)); - return Hash; -} - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_ENABLE_TARRAY(FUnsubscribeMultiAppliedType); - - UE_SPACETIMEDB_STRUCT(FUnsubscribeMultiAppliedType, RequestId, TotalHostExecutionDurationMicros, QueryId, Update); -} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeMultiType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeMultiType.g.h deleted file mode 100644 index a490a73daaa..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeMultiType.g.h +++ /dev/null @@ -1,50 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/QueryIdType.g.h" -#include "UnsubscribeMultiType.g.generated.h" - -USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FUnsubscribeMultiType -{ - GENERATED_BODY() - - // NOTE: uint32 field not exposed to Blueprint due to non-blueprintable elements - uint32 RequestId = 0; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FQueryIdType QueryId; - - FORCEINLINE bool operator==(const FUnsubscribeMultiType& Other) const - { - return RequestId == Other.RequestId && QueryId == Other.QueryId; - } - - FORCEINLINE bool operator!=(const FUnsubscribeMultiType& Other) const - { - return !(*this == Other); - } -}; - -/** - * Custom hash function for FUnsubscribeMultiType. - * Combines the hashes of all fields that are compared in operator==. - * @param UnsubscribeMultiType The FUnsubscribeMultiType instance to hash. - * @return The combined hash value. - */ -FORCEINLINE uint32 GetTypeHash(const FUnsubscribeMultiType& UnsubscribeMultiType) -{ - uint32 Hash = GetTypeHash(UnsubscribeMultiType.RequestId); - Hash = HashCombine(Hash, GetTypeHash(UnsubscribeMultiType.QueryId)); - return Hash; -} - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_ENABLE_TARRAY(FUnsubscribeMultiType); - - UE_SPACETIMEDB_STRUCT(FUnsubscribeMultiType, RequestId, QueryId); -} diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeType.g.h index 37530918737..04ce34c727f 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeType.g.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UnsubscribeType.g.h @@ -4,7 +4,8 @@ #pragma once #include "CoreMinimal.h" #include "BSATN/UESpacetimeDB.h" -#include "ModuleBindings/Types/QueryIdType.g.h" +#include "ModuleBindings/Types/QuerySetIdType.g.h" +#include "ModuleBindings/Types/UnsubscribeFlagsType.g.h" #include "UnsubscribeType.g.generated.h" USTRUCT(BlueprintType) @@ -16,11 +17,14 @@ struct SPACETIMEDBSDK_API FUnsubscribeType uint32 RequestId = 0; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") - FQueryIdType QueryId; + FQuerySetIdType QuerySetId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB") + EUnsubscribeFlagsType Flags = EUnsubscribeFlagsType::Default; FORCEINLINE bool operator==(const FUnsubscribeType& Other) const { - return RequestId == Other.RequestId && QueryId == Other.QueryId; + return RequestId == Other.RequestId && QuerySetId == Other.QuerySetId && Flags == Other.Flags; } FORCEINLINE bool operator!=(const FUnsubscribeType& Other) const @@ -38,7 +42,8 @@ struct SPACETIMEDBSDK_API FUnsubscribeType FORCEINLINE uint32 GetTypeHash(const FUnsubscribeType& UnsubscribeType) { uint32 Hash = GetTypeHash(UnsubscribeType.RequestId); - Hash = HashCombine(Hash, GetTypeHash(UnsubscribeType.QueryId)); + Hash = HashCombine(Hash, GetTypeHash(UnsubscribeType.QuerySetId)); + Hash = HashCombine(Hash, GetTypeHash(UnsubscribeType.Flags)); return Hash; } @@ -46,5 +51,5 @@ namespace UE::SpacetimeDB { UE_SPACETIMEDB_ENABLE_TARRAY(FUnsubscribeType); - UE_SPACETIMEDB_STRUCT(FUnsubscribeType, RequestId, QueryId); + UE_SPACETIMEDB_STRUCT(FUnsubscribeType, RequestId, QuerySetId, Flags); } diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UpdateStatusType.g.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UpdateStatusType.g.h deleted file mode 100644 index 3ad273dd2d8..00000000000 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/ModuleBindings/Types/UpdateStatusType.g.h +++ /dev/null @@ -1,188 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#pragma once -#include "CoreMinimal.h" -#include "BSATN/UESpacetimeDB.h" -#include "Kismet/BlueprintFunctionLibrary.h" -#include "ModuleBindings/Types/DatabaseUpdateType.g.h" -#include "Types/UnitType.h" -#include "UpdateStatusType.g.generated.h" - -UENUM(BlueprintType) -enum class EUpdateStatusTag : uint8 -{ - Committed, - Failed, - OutOfEnergy -}; - -USTRUCT(BlueprintType) -struct SPACETIMEDBSDK_API FUpdateStatusType -{ - GENERATED_BODY() - -public: - FUpdateStatusType() = default; - - TVariant MessageData; - - UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") - EUpdateStatusTag Tag = static_cast(0); - - static FUpdateStatusType Committed(const FDatabaseUpdateType& Value) - { - FUpdateStatusType Obj; - Obj.Tag = EUpdateStatusTag::Committed; - Obj.MessageData.Set(Value); - return Obj; - } - - static FUpdateStatusType Failed(const FString& Value) - { - FUpdateStatusType Obj; - Obj.Tag = EUpdateStatusTag::Failed; - Obj.MessageData.Set(Value); - return Obj; - } - - static FUpdateStatusType OutOfEnergy(const FSpacetimeDBUnit& Value) - { - FUpdateStatusType Obj; - Obj.Tag = EUpdateStatusTag::OutOfEnergy; - Obj.MessageData.Set(Value); - return Obj; - } - - FORCEINLINE bool IsCommitted() const { return Tag == EUpdateStatusTag::Committed; } - - FORCEINLINE FDatabaseUpdateType GetAsCommitted() const - { - ensureMsgf(IsCommitted(), TEXT("MessageData does not hold Committed!")); - return MessageData.Get(); - } - - FORCEINLINE bool IsFailed() const { return Tag == EUpdateStatusTag::Failed; } - - FORCEINLINE FString GetAsFailed() const - { - ensureMsgf(IsFailed(), TEXT("MessageData does not hold Failed!")); - return MessageData.Get(); - } - - FORCEINLINE bool IsOutOfEnergy() const { return Tag == EUpdateStatusTag::OutOfEnergy; } - - FORCEINLINE FSpacetimeDBUnit GetAsOutOfEnergy() const - { - ensureMsgf(IsOutOfEnergy(), TEXT("MessageData does not hold OutOfEnergy!")); - return MessageData.Get(); - } - - // Inline equality operators - FORCEINLINE bool operator==(const FUpdateStatusType& Other) const - { - if (Tag != Other.Tag) return false; - - switch (Tag) - { - case EUpdateStatusTag::Committed: - return GetAsCommitted() == Other.GetAsCommitted(); - case EUpdateStatusTag::Failed: - return GetAsFailed() == Other.GetAsFailed(); - case EUpdateStatusTag::OutOfEnergy: - return GetAsOutOfEnergy() == Other.GetAsOutOfEnergy(); - default: - return false; - } - } - - FORCEINLINE bool operator!=(const FUpdateStatusType& Other) const - { - return !(*this == Other); - } -}; - -/** - * Custom hash function for FUpdateStatusType. - * Combines the hashes of all fields that are compared in operator==. - * @param UpdateStatusType The FUpdateStatusType instance to hash. - * @return The combined hash value. - */ -FORCEINLINE uint32 GetTypeHash(const FUpdateStatusType& UpdateStatus) -{ - const uint32 TagHash = GetTypeHash(static_cast(UpdateStatus.Tag)); - switch (UpdateStatus.Tag) - { - case EUpdateStatusTag::Committed: return HashCombine(TagHash, ::GetTypeHash(UpdateStatus.GetAsCommitted())); - case EUpdateStatusTag::Failed: return HashCombine(TagHash, GetTypeHash(UpdateStatus.GetAsFailed())); - case EUpdateStatusTag::OutOfEnergy: return HashCombine(TagHash, ::GetTypeHash(UpdateStatus.GetAsOutOfEnergy())); - default: return TagHash; - } -} - -namespace UE::SpacetimeDB -{ - UE_SPACETIMEDB_ENABLE_TARRAY(FUpdateStatusType); - - UE_SPACETIMEDB_TAGGED_ENUM( - FUpdateStatusType, - EUpdateStatusTag, - MessageData, - Committed, FDatabaseUpdateType, - Failed, FString, - OutOfEnergy, FSpacetimeDBUnit - ); -} - -UCLASS() -class SPACETIMEDBSDK_API UUpdateStatusBpLib : public UBlueprintFunctionLibrary -{ - GENERATED_BODY() - -private: - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|UpdateStatus") - static FUpdateStatusType Committed(const FDatabaseUpdateType& InValue) - { - return FUpdateStatusType::Committed(InValue); - } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|UpdateStatus") - static bool IsCommitted(const FUpdateStatusType& InValue) { return InValue.IsCommitted(); } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|UpdateStatus") - static FDatabaseUpdateType GetAsCommitted(const FUpdateStatusType& InValue) - { - return InValue.GetAsCommitted(); - } - - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|UpdateStatus") - static FUpdateStatusType Failed(const FString& InValue) - { - return FUpdateStatusType::Failed(InValue); - } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|UpdateStatus") - static bool IsFailed(const FUpdateStatusType& InValue) { return InValue.IsFailed(); } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|UpdateStatus") - static FString GetAsFailed(const FUpdateStatusType& InValue) - { - return InValue.GetAsFailed(); - } - - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|UpdateStatus") - static FUpdateStatusType OutOfEnergy(const FSpacetimeDBUnit& InValue) - { - return FUpdateStatusType::OutOfEnergy(InValue); - } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|UpdateStatus") - static bool IsOutOfEnergy(const FUpdateStatusType& InValue) { return InValue.IsOutOfEnergy(); } - - UFUNCTION(BlueprintPure, Category = "SpacetimeDB|UpdateStatus") - static FSpacetimeDBUnit GetAsOutOfEnergy(const FUpdateStatusType& InValue) - { - return InValue.GetAsOutOfEnergy(); - } - -}; diff --git a/sdks/unreal/tests/TestClient/Config/DefaultEngine.ini b/sdks/unreal/tests/TestClient/Config/DefaultEngine.ini index 92c3bae9b3e..0239c099c52 100644 --- a/sdks/unreal/tests/TestClient/Config/DefaultEngine.ini +++ b/sdks/unreal/tests/TestClient/Config/DefaultEngine.ini @@ -23,7 +23,7 @@ DefaultGraphicsRHI=DefaultGraphicsRHI_DX12 [/Script/Engine.RendererSettings] r.AllowStaticLighting=0 -r.GenerateMeshDistanceFields=True +r.GenerateMeshDistanceFields=False r.DynamicGlobalIlluminationMethod=1 r.ReflectionMethod=1 r.Shadow.Virtual.Enable=1 diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Private/ModuleBindings/SpacetimeDBClient.g.cpp b/sdks/unreal/tests/TestClient/Source/TestClient/Private/ModuleBindings/SpacetimeDBClient.g.cpp index 91dc96f168e..73ff83aeee0 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Private/ModuleBindings/SpacetimeDBClient.g.cpp +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Private/ModuleBindings/SpacetimeDBClient.g.cpp @@ -112,2358 +112,376 @@ #include "ModuleBindings/Tables/VecUnitStructTable.g.h" #include "ModuleBindings/Tables/VecUuidTable.g.h" -static FReducer DecodeReducer(const FReducerEvent& Event) +UDbConnection::UDbConnection(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { - const FString& ReducerName = Event.ReducerCall.ReducerName; - - if (ReducerName == TEXT("delete_from_btree_u32")) - { - FDeleteFromBtreeU32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteFromBtreeU32(Args); - } - - if (ReducerName == TEXT("delete_large_table")) - { - FDeleteLargeTableArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteLargeTable(Args); - } - - if (ReducerName == TEXT("delete_pk_bool")) - { - FDeletePkBoolArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkBool(Args); - } - - if (ReducerName == TEXT("delete_pk_connection_id")) - { - FDeletePkConnectionIdArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkConnectionId(Args); - } - - if (ReducerName == TEXT("delete_pk_i128")) - { - FDeletePkI128Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkI128(Args); - } - - if (ReducerName == TEXT("delete_pk_i16")) - { - FDeletePkI16Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkI16(Args); - } - - if (ReducerName == TEXT("delete_pk_i256")) - { - FDeletePkI256Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkI256(Args); - } - - if (ReducerName == TEXT("delete_pk_i32")) - { - FDeletePkI32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkI32(Args); - } - - if (ReducerName == TEXT("delete_pk_i64")) - { - FDeletePkI64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkI64(Args); - } - - if (ReducerName == TEXT("delete_pk_i8")) - { - FDeletePkI8Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkI8(Args); - } - - if (ReducerName == TEXT("delete_pk_identity")) - { - FDeletePkIdentityArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkIdentity(Args); - } - - if (ReducerName == TEXT("delete_pk_string")) - { - FDeletePkStringArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkString(Args); - } - - if (ReducerName == TEXT("delete_pk_u128")) - { - FDeletePkU128Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkU128(Args); - } - - if (ReducerName == TEXT("delete_pk_u16")) - { - FDeletePkU16Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkU16(Args); - } - - if (ReducerName == TEXT("delete_pk_u256")) - { - FDeletePkU256Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkU256(Args); - } - - if (ReducerName == TEXT("delete_pk_u32")) - { - FDeletePkU32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkU32(Args); - } - - if (ReducerName == TEXT("delete_pk_u32_insert_pk_u32_two")) - { - FDeletePkU32InsertPkU32TwoArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkU32InsertPkU32Two(Args); - } - - if (ReducerName == TEXT("delete_pk_u32_two")) - { - FDeletePkU32TwoArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkU32Two(Args); - } - - if (ReducerName == TEXT("delete_pk_u64")) - { - FDeletePkU64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkU64(Args); - } - - if (ReducerName == TEXT("delete_pk_u8")) - { - FDeletePkU8Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkU8(Args); - } - - if (ReducerName == TEXT("delete_pk_uuid")) - { - FDeletePkUuidArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeletePkUuid(Args); - } - - if (ReducerName == TEXT("delete_unique_bool")) - { - FDeleteUniqueBoolArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteUniqueBool(Args); - } - - if (ReducerName == TEXT("delete_unique_connection_id")) - { - FDeleteUniqueConnectionIdArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteUniqueConnectionId(Args); - } - - if (ReducerName == TEXT("delete_unique_i128")) - { - FDeleteUniqueI128Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteUniqueI128(Args); - } - - if (ReducerName == TEXT("delete_unique_i16")) - { - FDeleteUniqueI16Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteUniqueI16(Args); - } - - if (ReducerName == TEXT("delete_unique_i256")) - { - FDeleteUniqueI256Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteUniqueI256(Args); - } - - if (ReducerName == TEXT("delete_unique_i32")) - { - FDeleteUniqueI32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteUniqueI32(Args); - } - - if (ReducerName == TEXT("delete_unique_i64")) - { - FDeleteUniqueI64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteUniqueI64(Args); - } - - if (ReducerName == TEXT("delete_unique_i8")) - { - FDeleteUniqueI8Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteUniqueI8(Args); - } - - if (ReducerName == TEXT("delete_unique_identity")) - { - FDeleteUniqueIdentityArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteUniqueIdentity(Args); - } - - if (ReducerName == TEXT("delete_unique_string")) - { - FDeleteUniqueStringArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteUniqueString(Args); - } - - if (ReducerName == TEXT("delete_unique_u128")) - { - FDeleteUniqueU128Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteUniqueU128(Args); - } - - if (ReducerName == TEXT("delete_unique_u16")) - { - FDeleteUniqueU16Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteUniqueU16(Args); - } - - if (ReducerName == TEXT("delete_unique_u256")) - { - FDeleteUniqueU256Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteUniqueU256(Args); - } - - if (ReducerName == TEXT("delete_unique_u32")) - { - FDeleteUniqueU32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteUniqueU32(Args); - } - - if (ReducerName == TEXT("delete_unique_u64")) - { - FDeleteUniqueU64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteUniqueU64(Args); - } - - if (ReducerName == TEXT("delete_unique_u8")) - { - FDeleteUniqueU8Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteUniqueU8(Args); - } - - if (ReducerName == TEXT("delete_unique_uuid")) - { - FDeleteUniqueUuidArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::DeleteUniqueUuid(Args); - } - - if (ReducerName == TEXT("insert_call_timestamp")) - { - FInsertCallTimestampArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertCallTimestamp(Args); - } - - if (ReducerName == TEXT("insert_call_uuid_v4")) - { - FInsertCallUuidV4Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertCallUuidV4(Args); - } - - if (ReducerName == TEXT("insert_call_uuid_v7")) - { - FInsertCallUuidV7Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertCallUuidV7(Args); - } - - if (ReducerName == TEXT("insert_caller_one_connection_id")) - { - FInsertCallerOneConnectionIdArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertCallerOneConnectionId(Args); - } - - if (ReducerName == TEXT("insert_caller_one_identity")) - { - FInsertCallerOneIdentityArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertCallerOneIdentity(Args); - } - - if (ReducerName == TEXT("insert_caller_pk_connection_id")) - { - FInsertCallerPkConnectionIdArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertCallerPkConnectionId(Args); - } - - if (ReducerName == TEXT("insert_caller_pk_identity")) - { - FInsertCallerPkIdentityArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertCallerPkIdentity(Args); - } - - if (ReducerName == TEXT("insert_caller_unique_connection_id")) - { - FInsertCallerUniqueConnectionIdArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertCallerUniqueConnectionId(Args); - } - - if (ReducerName == TEXT("insert_caller_unique_identity")) - { - FInsertCallerUniqueIdentityArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertCallerUniqueIdentity(Args); - } - - if (ReducerName == TEXT("insert_caller_vec_connection_id")) - { - FInsertCallerVecConnectionIdArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertCallerVecConnectionId(Args); - } - - if (ReducerName == TEXT("insert_caller_vec_identity")) - { - FInsertCallerVecIdentityArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertCallerVecIdentity(Args); - } - - if (ReducerName == TEXT("insert_into_btree_u32")) - { - FInsertIntoBtreeU32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertIntoBtreeU32(Args); - } - - if (ReducerName == TEXT("insert_into_indexed_simple_enum")) - { - FInsertIntoIndexedSimpleEnumArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertIntoIndexedSimpleEnum(Args); - } - - if (ReducerName == TEXT("insert_into_pk_btree_u32")) - { - FInsertIntoPkBtreeU32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertIntoPkBtreeU32(Args); - } - - if (ReducerName == TEXT("insert_large_table")) - { - FInsertLargeTableArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertLargeTable(Args); - } - - if (ReducerName == TEXT("insert_one_bool")) - { - FInsertOneBoolArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneBool(Args); - } - - if (ReducerName == TEXT("insert_one_byte_struct")) - { - FInsertOneByteStructArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneByteStruct(Args); - } - - if (ReducerName == TEXT("insert_one_connection_id")) - { - FInsertOneConnectionIdArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneConnectionId(Args); - } + Db = ObjectInitializer.CreateDefaultSubobject(this, TEXT("RemoteTables")); + Db->Initialize(); + + Reducers = ObjectInitializer.CreateDefaultSubobject(this, TEXT("RemoteReducers")); + Reducers->Conn = this; - if (ReducerName == TEXT("insert_one_enum_with_payload")) - { - FInsertOneEnumWithPayloadArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneEnumWithPayload(Args); - } + Procedures = ObjectInitializer.CreateDefaultSubobject(this, TEXT("RemoteProcedures")); + Procedures->Conn = this; - if (ReducerName == TEXT("insert_one_every_primitive_struct")) - { - FInsertOneEveryPrimitiveStructArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneEveryPrimitiveStruct(Args); - } + RegisterTable(TEXT("btree_u_32"), Db->BtreeU32); + RegisterTable(TEXT("indexed_simple_enum"), Db->IndexedSimpleEnum); + RegisterTable(TEXT("large_table"), Db->LargeTable); + RegisterTable(TEXT("one_bool"), Db->OneBool); + RegisterTable(TEXT("one_byte_struct"), Db->OneByteStruct); + RegisterTable(TEXT("one_connection_id"), Db->OneConnectionId); + RegisterTable(TEXT("one_enum_with_payload"), Db->OneEnumWithPayload); + RegisterTable(TEXT("one_every_primitive_struct"), Db->OneEveryPrimitiveStruct); + RegisterTable(TEXT("one_every_vec_struct"), Db->OneEveryVecStruct); + RegisterTable(TEXT("one_f_32"), Db->OneF32); + RegisterTable(TEXT("one_f_64"), Db->OneF64); + RegisterTable(TEXT("one_i_128"), Db->OneI128); + RegisterTable(TEXT("one_i_16"), Db->OneI16); + RegisterTable(TEXT("one_i_256"), Db->OneI256); + RegisterTable(TEXT("one_i_32"), Db->OneI32); + RegisterTable(TEXT("one_i_64"), Db->OneI64); + RegisterTable(TEXT("one_i_8"), Db->OneI8); + RegisterTable(TEXT("one_identity"), Db->OneIdentity); + RegisterTable(TEXT("one_simple_enum"), Db->OneSimpleEnum); + RegisterTable(TEXT("one_string"), Db->OneString); + RegisterTable(TEXT("one_timestamp"), Db->OneTimestamp); + RegisterTable(TEXT("one_u_128"), Db->OneU128); + RegisterTable(TEXT("one_u_16"), Db->OneU16); + RegisterTable(TEXT("one_u_256"), Db->OneU256); + RegisterTable(TEXT("one_u_32"), Db->OneU32); + RegisterTable(TEXT("one_u_64"), Db->OneU64); + RegisterTable(TEXT("one_u_8"), Db->OneU8); + RegisterTable(TEXT("one_unit_struct"), Db->OneUnitStruct); + RegisterTable(TEXT("one_uuid"), Db->OneUuid); + RegisterTable(TEXT("option_every_primitive_struct"), Db->OptionEveryPrimitiveStruct); + RegisterTable(TEXT("option_i_32"), Db->OptionI32); + RegisterTable(TEXT("option_identity"), Db->OptionIdentity); + RegisterTable(TEXT("option_simple_enum"), Db->OptionSimpleEnum); + RegisterTable(TEXT("option_string"), Db->OptionString); + RegisterTable(TEXT("option_uuid"), Db->OptionUuid); + RegisterTable(TEXT("option_vec_option_i_32"), Db->OptionVecOptionI32); + RegisterTable(TEXT("pk_bool"), Db->PkBool); + RegisterTable(TEXT("pk_connection_id"), Db->PkConnectionId); + RegisterTable(TEXT("pk_i_128"), Db->PkI128); + RegisterTable(TEXT("pk_i_16"), Db->PkI16); + RegisterTable(TEXT("pk_i_256"), Db->PkI256); + RegisterTable(TEXT("pk_i_32"), Db->PkI32); + RegisterTable(TEXT("pk_i_64"), Db->PkI64); + RegisterTable(TEXT("pk_i_8"), Db->PkI8); + RegisterTable(TEXT("pk_identity"), Db->PkIdentity); + RegisterTable(TEXT("pk_simple_enum"), Db->PkSimpleEnum); + RegisterTable(TEXT("pk_string"), Db->PkString); + RegisterTable(TEXT("pk_u_128"), Db->PkU128); + RegisterTable(TEXT("pk_u_16"), Db->PkU16); + RegisterTable(TEXT("pk_u_256"), Db->PkU256); + RegisterTable(TEXT("pk_u_32"), Db->PkU32); + RegisterTable(TEXT("pk_u_32_two"), Db->PkU32Two); + RegisterTable(TEXT("pk_u_64"), Db->PkU64); + RegisterTable(TEXT("pk_u_8"), Db->PkU8); + RegisterTable(TEXT("pk_uuid"), Db->PkUuid); + RegisterTable(TEXT("result_every_primitive_struct_string"), Db->ResultEveryPrimitiveStructString); + RegisterTable(TEXT("result_i_32_string"), Db->ResultI32String); + RegisterTable(TEXT("result_identity_string"), Db->ResultIdentityString); + RegisterTable(TEXT("result_simple_enum_i_32"), Db->ResultSimpleEnumI32); + RegisterTable(TEXT("result_string_i_32"), Db->ResultStringI32); + RegisterTable(TEXT("result_vec_i_32_string"), Db->ResultVecI32String); + RegisterTable(TEXT("scheduled_table"), Db->ScheduledTable); + RegisterTable(TEXT("table_holds_table"), Db->TableHoldsTable); + RegisterTable(TEXT("unique_bool"), Db->UniqueBool); + RegisterTable(TEXT("unique_connection_id"), Db->UniqueConnectionId); + RegisterTable(TEXT("unique_i_128"), Db->UniqueI128); + RegisterTable(TEXT("unique_i_16"), Db->UniqueI16); + RegisterTable(TEXT("unique_i_256"), Db->UniqueI256); + RegisterTable(TEXT("unique_i_32"), Db->UniqueI32); + RegisterTable(TEXT("unique_i_64"), Db->UniqueI64); + RegisterTable(TEXT("unique_i_8"), Db->UniqueI8); + RegisterTable(TEXT("unique_identity"), Db->UniqueIdentity); + RegisterTable(TEXT("unique_string"), Db->UniqueString); + RegisterTable(TEXT("unique_u_128"), Db->UniqueU128); + RegisterTable(TEXT("unique_u_16"), Db->UniqueU16); + RegisterTable(TEXT("unique_u_256"), Db->UniqueU256); + RegisterTable(TEXT("unique_u_32"), Db->UniqueU32); + RegisterTable(TEXT("unique_u_64"), Db->UniqueU64); + RegisterTable(TEXT("unique_u_8"), Db->UniqueU8); + RegisterTable(TEXT("unique_uuid"), Db->UniqueUuid); + RegisterTable(TEXT("users"), Db->Users); + RegisterTable(TEXT("vec_bool"), Db->VecBool); + RegisterTable(TEXT("vec_byte_struct"), Db->VecByteStruct); + RegisterTable(TEXT("vec_connection_id"), Db->VecConnectionId); + RegisterTable(TEXT("vec_enum_with_payload"), Db->VecEnumWithPayload); + RegisterTable(TEXT("vec_every_primitive_struct"), Db->VecEveryPrimitiveStruct); + RegisterTable(TEXT("vec_every_vec_struct"), Db->VecEveryVecStruct); + RegisterTable(TEXT("vec_f_32"), Db->VecF32); + RegisterTable(TEXT("vec_f_64"), Db->VecF64); + RegisterTable(TEXT("vec_i_128"), Db->VecI128); + RegisterTable(TEXT("vec_i_16"), Db->VecI16); + RegisterTable(TEXT("vec_i_256"), Db->VecI256); + RegisterTable(TEXT("vec_i_32"), Db->VecI32); + RegisterTable(TEXT("vec_i_64"), Db->VecI64); + RegisterTable(TEXT("vec_i_8"), Db->VecI8); + RegisterTable(TEXT("vec_identity"), Db->VecIdentity); + RegisterTable(TEXT("vec_simple_enum"), Db->VecSimpleEnum); + RegisterTable(TEXT("vec_string"), Db->VecString); + RegisterTable(TEXT("vec_timestamp"), Db->VecTimestamp); + RegisterTable(TEXT("vec_u_128"), Db->VecU128); + RegisterTable(TEXT("vec_u_16"), Db->VecU16); + RegisterTable(TEXT("vec_u_256"), Db->VecU256); + RegisterTable(TEXT("vec_u_32"), Db->VecU32); + RegisterTable(TEXT("vec_u_64"), Db->VecU64); + RegisterTable(TEXT("vec_u_8"), Db->VecU8); + RegisterTable(TEXT("vec_unit_struct"), Db->VecUnitStruct); + RegisterTable(TEXT("vec_uuid"), Db->VecUuid); +} - if (ReducerName == TEXT("insert_one_every_vec_struct")) - { - FInsertOneEveryVecStructArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneEveryVecStruct(Args); - } - - if (ReducerName == TEXT("insert_one_f32")) - { - FInsertOneF32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneF32(Args); - } - - if (ReducerName == TEXT("insert_one_f64")) - { - FInsertOneF64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneF64(Args); - } - - if (ReducerName == TEXT("insert_one_i128")) - { - FInsertOneI128Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneI128(Args); - } - - if (ReducerName == TEXT("insert_one_i16")) - { - FInsertOneI16Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneI16(Args); - } - - if (ReducerName == TEXT("insert_one_i256")) - { - FInsertOneI256Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneI256(Args); - } - - if (ReducerName == TEXT("insert_one_i32")) - { - FInsertOneI32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneI32(Args); - } - - if (ReducerName == TEXT("insert_one_i64")) - { - FInsertOneI64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneI64(Args); - } - - if (ReducerName == TEXT("insert_one_i8")) - { - FInsertOneI8Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneI8(Args); - } - - if (ReducerName == TEXT("insert_one_identity")) - { - FInsertOneIdentityArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneIdentity(Args); - } - - if (ReducerName == TEXT("insert_one_simple_enum")) - { - FInsertOneSimpleEnumArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneSimpleEnum(Args); - } - - if (ReducerName == TEXT("insert_one_string")) - { - FInsertOneStringArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneString(Args); - } - - if (ReducerName == TEXT("insert_one_timestamp")) - { - FInsertOneTimestampArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneTimestamp(Args); - } - - if (ReducerName == TEXT("insert_one_u128")) - { - FInsertOneU128Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneU128(Args); - } - - if (ReducerName == TEXT("insert_one_u16")) - { - FInsertOneU16Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneU16(Args); - } - - if (ReducerName == TEXT("insert_one_u256")) - { - FInsertOneU256Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneU256(Args); - } - - if (ReducerName == TEXT("insert_one_u32")) - { - FInsertOneU32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneU32(Args); - } - - if (ReducerName == TEXT("insert_one_u64")) - { - FInsertOneU64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneU64(Args); - } - - if (ReducerName == TEXT("insert_one_u8")) - { - FInsertOneU8Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneU8(Args); - } - - if (ReducerName == TEXT("insert_one_unit_struct")) - { - FInsertOneUnitStructArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneUnitStruct(Args); - } - - if (ReducerName == TEXT("insert_one_uuid")) - { - FInsertOneUuidArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOneUuid(Args); - } - - if (ReducerName == TEXT("insert_option_every_primitive_struct")) - { - FInsertOptionEveryPrimitiveStructArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOptionEveryPrimitiveStruct(Args); - } - - if (ReducerName == TEXT("insert_option_i32")) - { - FInsertOptionI32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOptionI32(Args); - } - - if (ReducerName == TEXT("insert_option_identity")) - { - FInsertOptionIdentityArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOptionIdentity(Args); - } - - if (ReducerName == TEXT("insert_option_simple_enum")) - { - FInsertOptionSimpleEnumArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOptionSimpleEnum(Args); - } - - if (ReducerName == TEXT("insert_option_string")) - { - FInsertOptionStringArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOptionString(Args); - } - - if (ReducerName == TEXT("insert_option_uuid")) - { - FInsertOptionUuidArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOptionUuid(Args); - } - - if (ReducerName == TEXT("insert_option_vec_option_i32")) - { - FInsertOptionVecOptionI32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertOptionVecOptionI32(Args); - } - - if (ReducerName == TEXT("insert_pk_bool")) - { - FInsertPkBoolArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkBool(Args); - } - - if (ReducerName == TEXT("insert_pk_connection_id")) - { - FInsertPkConnectionIdArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkConnectionId(Args); - } - - if (ReducerName == TEXT("insert_pk_i128")) - { - FInsertPkI128Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkI128(Args); - } - - if (ReducerName == TEXT("insert_pk_i16")) - { - FInsertPkI16Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkI16(Args); - } - - if (ReducerName == TEXT("insert_pk_i256")) - { - FInsertPkI256Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkI256(Args); - } - - if (ReducerName == TEXT("insert_pk_i32")) - { - FInsertPkI32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkI32(Args); - } - - if (ReducerName == TEXT("insert_pk_i64")) - { - FInsertPkI64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkI64(Args); - } - - if (ReducerName == TEXT("insert_pk_i8")) - { - FInsertPkI8Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkI8(Args); - } - - if (ReducerName == TEXT("insert_pk_identity")) - { - FInsertPkIdentityArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkIdentity(Args); - } - - if (ReducerName == TEXT("insert_pk_simple_enum")) - { - FInsertPkSimpleEnumArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkSimpleEnum(Args); - } - - if (ReducerName == TEXT("insert_pk_string")) - { - FInsertPkStringArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkString(Args); - } - - if (ReducerName == TEXT("insert_pk_u128")) - { - FInsertPkU128Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkU128(Args); - } - - if (ReducerName == TEXT("insert_pk_u16")) - { - FInsertPkU16Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkU16(Args); - } - - if (ReducerName == TEXT("insert_pk_u256")) - { - FInsertPkU256Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkU256(Args); - } - - if (ReducerName == TEXT("insert_pk_u32")) - { - FInsertPkU32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkU32(Args); - } - - if (ReducerName == TEXT("insert_pk_u32_two")) - { - FInsertPkU32TwoArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkU32Two(Args); - } - - if (ReducerName == TEXT("insert_pk_u64")) - { - FInsertPkU64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkU64(Args); - } - - if (ReducerName == TEXT("insert_pk_u8")) - { - FInsertPkU8Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkU8(Args); - } - - if (ReducerName == TEXT("insert_pk_uuid")) - { - FInsertPkUuidArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPkUuid(Args); - } - - if (ReducerName == TEXT("insert_primitives_as_strings")) - { - FInsertPrimitivesAsStringsArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertPrimitivesAsStrings(Args); - } - - if (ReducerName == TEXT("insert_result_every_primitive_struct_string")) - { - FInsertResultEveryPrimitiveStructStringArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertResultEveryPrimitiveStructString(Args); - } - - if (ReducerName == TEXT("insert_result_i32_string")) - { - FInsertResultI32StringArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertResultI32String(Args); - } - - if (ReducerName == TEXT("insert_result_identity_string")) - { - FInsertResultIdentityStringArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertResultIdentityString(Args); - } - - if (ReducerName == TEXT("insert_result_simple_enum_i32")) - { - FInsertResultSimpleEnumI32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertResultSimpleEnumI32(Args); - } - - if (ReducerName == TEXT("insert_result_string_i32")) - { - FInsertResultStringI32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertResultStringI32(Args); - } - - if (ReducerName == TEXT("insert_result_vec_i32_string")) - { - FInsertResultVecI32StringArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertResultVecI32String(Args); - } - - if (ReducerName == TEXT("insert_table_holds_table")) - { - FInsertTableHoldsTableArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertTableHoldsTable(Args); - } - - if (ReducerName == TEXT("insert_unique_bool")) - { - FInsertUniqueBoolArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueBool(Args); - } - - if (ReducerName == TEXT("insert_unique_connection_id")) - { - FInsertUniqueConnectionIdArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueConnectionId(Args); - } - - if (ReducerName == TEXT("insert_unique_i128")) - { - FInsertUniqueI128Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueI128(Args); - } - - if (ReducerName == TEXT("insert_unique_i16")) - { - FInsertUniqueI16Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueI16(Args); - } - - if (ReducerName == TEXT("insert_unique_i256")) - { - FInsertUniqueI256Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueI256(Args); - } - - if (ReducerName == TEXT("insert_unique_i32")) - { - FInsertUniqueI32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueI32(Args); - } - - if (ReducerName == TEXT("insert_unique_i64")) - { - FInsertUniqueI64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueI64(Args); - } - - if (ReducerName == TEXT("insert_unique_i8")) - { - FInsertUniqueI8Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueI8(Args); - } - - if (ReducerName == TEXT("insert_unique_identity")) - { - FInsertUniqueIdentityArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueIdentity(Args); - } - - if (ReducerName == TEXT("insert_unique_string")) - { - FInsertUniqueStringArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueString(Args); - } - - if (ReducerName == TEXT("insert_unique_u128")) - { - FInsertUniqueU128Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueU128(Args); - } - - if (ReducerName == TEXT("insert_unique_u16")) - { - FInsertUniqueU16Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueU16(Args); - } - - if (ReducerName == TEXT("insert_unique_u256")) - { - FInsertUniqueU256Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueU256(Args); - } - - if (ReducerName == TEXT("insert_unique_u32")) - { - FInsertUniqueU32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueU32(Args); - } - - if (ReducerName == TEXT("insert_unique_u32_update_pk_u32")) - { - FInsertUniqueU32UpdatePkU32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueU32UpdatePkU32(Args); - } - - if (ReducerName == TEXT("insert_unique_u64")) - { - FInsertUniqueU64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueU64(Args); - } - - if (ReducerName == TEXT("insert_unique_u8")) - { - FInsertUniqueU8Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueU8(Args); - } - - if (ReducerName == TEXT("insert_unique_uuid")) - { - FInsertUniqueUuidArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUniqueUuid(Args); - } - - if (ReducerName == TEXT("insert_user")) - { - FInsertUserArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertUser(Args); - } - - if (ReducerName == TEXT("insert_vec_bool")) - { - FInsertVecBoolArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecBool(Args); - } - - if (ReducerName == TEXT("insert_vec_byte_struct")) - { - FInsertVecByteStructArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecByteStruct(Args); - } - - if (ReducerName == TEXT("insert_vec_connection_id")) - { - FInsertVecConnectionIdArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecConnectionId(Args); - } - - if (ReducerName == TEXT("insert_vec_enum_with_payload")) - { - FInsertVecEnumWithPayloadArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecEnumWithPayload(Args); - } - - if (ReducerName == TEXT("insert_vec_every_primitive_struct")) - { - FInsertVecEveryPrimitiveStructArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecEveryPrimitiveStruct(Args); - } - - if (ReducerName == TEXT("insert_vec_every_vec_struct")) - { - FInsertVecEveryVecStructArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecEveryVecStruct(Args); - } - - if (ReducerName == TEXT("insert_vec_f32")) - { - FInsertVecF32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecF32(Args); - } - - if (ReducerName == TEXT("insert_vec_f64")) - { - FInsertVecF64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecF64(Args); - } - - if (ReducerName == TEXT("insert_vec_i128")) - { - FInsertVecI128Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecI128(Args); - } - - if (ReducerName == TEXT("insert_vec_i16")) - { - FInsertVecI16Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecI16(Args); - } - - if (ReducerName == TEXT("insert_vec_i256")) - { - FInsertVecI256Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecI256(Args); - } - - if (ReducerName == TEXT("insert_vec_i32")) - { - FInsertVecI32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecI32(Args); - } - - if (ReducerName == TEXT("insert_vec_i64")) - { - FInsertVecI64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecI64(Args); - } - - if (ReducerName == TEXT("insert_vec_i8")) - { - FInsertVecI8Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecI8(Args); - } - - if (ReducerName == TEXT("insert_vec_identity")) - { - FInsertVecIdentityArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecIdentity(Args); - } - - if (ReducerName == TEXT("insert_vec_simple_enum")) - { - FInsertVecSimpleEnumArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecSimpleEnum(Args); - } - - if (ReducerName == TEXT("insert_vec_string")) - { - FInsertVecStringArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecString(Args); - } - - if (ReducerName == TEXT("insert_vec_timestamp")) - { - FInsertVecTimestampArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecTimestamp(Args); - } - - if (ReducerName == TEXT("insert_vec_u128")) - { - FInsertVecU128Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecU128(Args); - } - - if (ReducerName == TEXT("insert_vec_u16")) - { - FInsertVecU16Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecU16(Args); - } - - if (ReducerName == TEXT("insert_vec_u256")) - { - FInsertVecU256Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecU256(Args); - } - - if (ReducerName == TEXT("insert_vec_u32")) - { - FInsertVecU32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecU32(Args); - } - - if (ReducerName == TEXT("insert_vec_u64")) - { - FInsertVecU64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecU64(Args); - } - - if (ReducerName == TEXT("insert_vec_u8")) - { - FInsertVecU8Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecU8(Args); - } - - if (ReducerName == TEXT("insert_vec_unit_struct")) - { - FInsertVecUnitStructArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecUnitStruct(Args); - } - - if (ReducerName == TEXT("insert_vec_uuid")) - { - FInsertVecUuidArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::InsertVecUuid(Args); - } - - if (ReducerName == TEXT("no_op_succeeds")) - { - FNoOpSucceedsArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::NoOpSucceeds(Args); - } - - if (ReducerName == TEXT("sorted_uuids_insert")) - { - FSortedUuidsInsertArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::SortedUuidsInsert(Args); - } - - if (ReducerName == TEXT("update_indexed_simple_enum")) - { - FUpdateIndexedSimpleEnumArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateIndexedSimpleEnum(Args); - } - - if (ReducerName == TEXT("update_pk_bool")) - { - FUpdatePkBoolArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkBool(Args); - } - - if (ReducerName == TEXT("update_pk_connection_id")) - { - FUpdatePkConnectionIdArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkConnectionId(Args); - } - - if (ReducerName == TEXT("update_pk_i128")) - { - FUpdatePkI128Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkI128(Args); - } - - if (ReducerName == TEXT("update_pk_i16")) - { - FUpdatePkI16Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkI16(Args); - } - - if (ReducerName == TEXT("update_pk_i256")) - { - FUpdatePkI256Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkI256(Args); - } - - if (ReducerName == TEXT("update_pk_i32")) - { - FUpdatePkI32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkI32(Args); - } - - if (ReducerName == TEXT("update_pk_i64")) - { - FUpdatePkI64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkI64(Args); - } - - if (ReducerName == TEXT("update_pk_i8")) - { - FUpdatePkI8Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkI8(Args); - } - - if (ReducerName == TEXT("update_pk_identity")) - { - FUpdatePkIdentityArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkIdentity(Args); - } - - if (ReducerName == TEXT("update_pk_simple_enum")) - { - FUpdatePkSimpleEnumArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkSimpleEnum(Args); - } - - if (ReducerName == TEXT("update_pk_string")) - { - FUpdatePkStringArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkString(Args); - } - - if (ReducerName == TEXT("update_pk_u128")) - { - FUpdatePkU128Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkU128(Args); - } - - if (ReducerName == TEXT("update_pk_u16")) - { - FUpdatePkU16Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkU16(Args); - } - - if (ReducerName == TEXT("update_pk_u256")) - { - FUpdatePkU256Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkU256(Args); - } - - if (ReducerName == TEXT("update_pk_u32")) - { - FUpdatePkU32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkU32(Args); - } - - if (ReducerName == TEXT("update_pk_u32_two")) - { - FUpdatePkU32TwoArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkU32Two(Args); - } - - if (ReducerName == TEXT("update_pk_u64")) - { - FUpdatePkU64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkU64(Args); - } - - if (ReducerName == TEXT("update_pk_u8")) - { - FUpdatePkU8Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkU8(Args); - } - - if (ReducerName == TEXT("update_pk_uuid")) - { - FUpdatePkUuidArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePkUuid(Args); - } - - if (ReducerName == TEXT("update_unique_bool")) - { - FUpdateUniqueBoolArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateUniqueBool(Args); - } - - if (ReducerName == TEXT("update_unique_connection_id")) - { - FUpdateUniqueConnectionIdArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateUniqueConnectionId(Args); - } - - if (ReducerName == TEXT("update_unique_i128")) - { - FUpdateUniqueI128Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateUniqueI128(Args); - } - - if (ReducerName == TEXT("update_unique_i16")) - { - FUpdateUniqueI16Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateUniqueI16(Args); - } - - if (ReducerName == TEXT("update_unique_i256")) - { - FUpdateUniqueI256Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateUniqueI256(Args); - } - - if (ReducerName == TEXT("update_unique_i32")) - { - FUpdateUniqueI32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateUniqueI32(Args); - } - - if (ReducerName == TEXT("update_unique_i64")) - { - FUpdateUniqueI64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateUniqueI64(Args); - } - - if (ReducerName == TEXT("update_unique_i8")) - { - FUpdateUniqueI8Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateUniqueI8(Args); - } - - if (ReducerName == TEXT("update_unique_identity")) - { - FUpdateUniqueIdentityArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateUniqueIdentity(Args); - } - - if (ReducerName == TEXT("update_unique_string")) - { - FUpdateUniqueStringArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateUniqueString(Args); - } - - if (ReducerName == TEXT("update_unique_u128")) - { - FUpdateUniqueU128Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateUniqueU128(Args); - } - - if (ReducerName == TEXT("update_unique_u16")) - { - FUpdateUniqueU16Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateUniqueU16(Args); - } - - if (ReducerName == TEXT("update_unique_u256")) - { - FUpdateUniqueU256Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateUniqueU256(Args); - } - - if (ReducerName == TEXT("update_unique_u32")) - { - FUpdateUniqueU32Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateUniqueU32(Args); - } - - if (ReducerName == TEXT("update_unique_u64")) - { - FUpdateUniqueU64Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateUniqueU64(Args); - } - - if (ReducerName == TEXT("update_unique_u8")) - { - FUpdateUniqueU8Args Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateUniqueU8(Args); - } - - if (ReducerName == TEXT("update_unique_uuid")) - { - FUpdateUniqueUuidArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdateUniqueUuid(Args); - } - - return FReducer(); -} - -UDbConnection::UDbConnection(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) -{ - SetReducerFlags = ObjectInitializer.CreateDefaultSubobject(this, TEXT("SetReducerFlags")); - - Db = ObjectInitializer.CreateDefaultSubobject(this, TEXT("RemoteTables")); - Db->Initialize(); - - Reducers = ObjectInitializer.CreateDefaultSubobject(this, TEXT("RemoteReducers")); - Reducers->SetCallReducerFlags = SetReducerFlags; - Reducers->Conn = this; - - Procedures = ObjectInitializer.CreateDefaultSubobject(this, TEXT("RemoteProcedures")); - Procedures->Conn = this; - - RegisterTable(TEXT("btree_u32"), Db->BtreeU32); - RegisterTable(TEXT("indexed_simple_enum"), Db->IndexedSimpleEnum); - RegisterTable(TEXT("large_table"), Db->LargeTable); - RegisterTable(TEXT("one_bool"), Db->OneBool); - RegisterTable(TEXT("one_byte_struct"), Db->OneByteStruct); - RegisterTable(TEXT("one_connection_id"), Db->OneConnectionId); - RegisterTable(TEXT("one_enum_with_payload"), Db->OneEnumWithPayload); - RegisterTable(TEXT("one_every_primitive_struct"), Db->OneEveryPrimitiveStruct); - RegisterTable(TEXT("one_every_vec_struct"), Db->OneEveryVecStruct); - RegisterTable(TEXT("one_f32"), Db->OneF32); - RegisterTable(TEXT("one_f64"), Db->OneF64); - RegisterTable(TEXT("one_i128"), Db->OneI128); - RegisterTable(TEXT("one_i16"), Db->OneI16); - RegisterTable(TEXT("one_i256"), Db->OneI256); - RegisterTable(TEXT("one_i32"), Db->OneI32); - RegisterTable(TEXT("one_i64"), Db->OneI64); - RegisterTable(TEXT("one_i8"), Db->OneI8); - RegisterTable(TEXT("one_identity"), Db->OneIdentity); - RegisterTable(TEXT("one_simple_enum"), Db->OneSimpleEnum); - RegisterTable(TEXT("one_string"), Db->OneString); - RegisterTable(TEXT("one_timestamp"), Db->OneTimestamp); - RegisterTable(TEXT("one_u128"), Db->OneU128); - RegisterTable(TEXT("one_u16"), Db->OneU16); - RegisterTable(TEXT("one_u256"), Db->OneU256); - RegisterTable(TEXT("one_u32"), Db->OneU32); - RegisterTable(TEXT("one_u64"), Db->OneU64); - RegisterTable(TEXT("one_u8"), Db->OneU8); - RegisterTable(TEXT("one_unit_struct"), Db->OneUnitStruct); - RegisterTable(TEXT("one_uuid"), Db->OneUuid); - RegisterTable(TEXT("option_every_primitive_struct"), Db->OptionEveryPrimitiveStruct); - RegisterTable(TEXT("option_i32"), Db->OptionI32); - RegisterTable(TEXT("option_identity"), Db->OptionIdentity); - RegisterTable(TEXT("option_simple_enum"), Db->OptionSimpleEnum); - RegisterTable(TEXT("option_string"), Db->OptionString); - RegisterTable(TEXT("option_uuid"), Db->OptionUuid); - RegisterTable(TEXT("option_vec_option_i32"), Db->OptionVecOptionI32); - RegisterTable(TEXT("pk_bool"), Db->PkBool); - RegisterTable(TEXT("pk_connection_id"), Db->PkConnectionId); - RegisterTable(TEXT("pk_i128"), Db->PkI128); - RegisterTable(TEXT("pk_i16"), Db->PkI16); - RegisterTable(TEXT("pk_i256"), Db->PkI256); - RegisterTable(TEXT("pk_i32"), Db->PkI32); - RegisterTable(TEXT("pk_i64"), Db->PkI64); - RegisterTable(TEXT("pk_i8"), Db->PkI8); - RegisterTable(TEXT("pk_identity"), Db->PkIdentity); - RegisterTable(TEXT("pk_simple_enum"), Db->PkSimpleEnum); - RegisterTable(TEXT("pk_string"), Db->PkString); - RegisterTable(TEXT("pk_u128"), Db->PkU128); - RegisterTable(TEXT("pk_u16"), Db->PkU16); - RegisterTable(TEXT("pk_u256"), Db->PkU256); - RegisterTable(TEXT("pk_u32"), Db->PkU32); - RegisterTable(TEXT("pk_u32_two"), Db->PkU32Two); - RegisterTable(TEXT("pk_u64"), Db->PkU64); - RegisterTable(TEXT("pk_u8"), Db->PkU8); - RegisterTable(TEXT("pk_uuid"), Db->PkUuid); - RegisterTable(TEXT("result_every_primitive_struct_string"), Db->ResultEveryPrimitiveStructString); - RegisterTable(TEXT("result_i32_string"), Db->ResultI32String); - RegisterTable(TEXT("result_identity_string"), Db->ResultIdentityString); - RegisterTable(TEXT("result_simple_enum_i32"), Db->ResultSimpleEnumI32); - RegisterTable(TEXT("result_string_i32"), Db->ResultStringI32); - RegisterTable(TEXT("result_vec_i32_string"), Db->ResultVecI32String); - RegisterTable(TEXT("scheduled_table"), Db->ScheduledTable); - RegisterTable(TEXT("table_holds_table"), Db->TableHoldsTable); - RegisterTable(TEXT("unique_bool"), Db->UniqueBool); - RegisterTable(TEXT("unique_connection_id"), Db->UniqueConnectionId); - RegisterTable(TEXT("unique_i128"), Db->UniqueI128); - RegisterTable(TEXT("unique_i16"), Db->UniqueI16); - RegisterTable(TEXT("unique_i256"), Db->UniqueI256); - RegisterTable(TEXT("unique_i32"), Db->UniqueI32); - RegisterTable(TEXT("unique_i64"), Db->UniqueI64); - RegisterTable(TEXT("unique_i8"), Db->UniqueI8); - RegisterTable(TEXT("unique_identity"), Db->UniqueIdentity); - RegisterTable(TEXT("unique_string"), Db->UniqueString); - RegisterTable(TEXT("unique_u128"), Db->UniqueU128); - RegisterTable(TEXT("unique_u16"), Db->UniqueU16); - RegisterTable(TEXT("unique_u256"), Db->UniqueU256); - RegisterTable(TEXT("unique_u32"), Db->UniqueU32); - RegisterTable(TEXT("unique_u64"), Db->UniqueU64); - RegisterTable(TEXT("unique_u8"), Db->UniqueU8); - RegisterTable(TEXT("unique_uuid"), Db->UniqueUuid); - RegisterTable(TEXT("users"), Db->Users); - RegisterTable(TEXT("vec_bool"), Db->VecBool); - RegisterTable(TEXT("vec_byte_struct"), Db->VecByteStruct); - RegisterTable(TEXT("vec_connection_id"), Db->VecConnectionId); - RegisterTable(TEXT("vec_enum_with_payload"), Db->VecEnumWithPayload); - RegisterTable(TEXT("vec_every_primitive_struct"), Db->VecEveryPrimitiveStruct); - RegisterTable(TEXT("vec_every_vec_struct"), Db->VecEveryVecStruct); - RegisterTable(TEXT("vec_f32"), Db->VecF32); - RegisterTable(TEXT("vec_f64"), Db->VecF64); - RegisterTable(TEXT("vec_i128"), Db->VecI128); - RegisterTable(TEXT("vec_i16"), Db->VecI16); - RegisterTable(TEXT("vec_i256"), Db->VecI256); - RegisterTable(TEXT("vec_i32"), Db->VecI32); - RegisterTable(TEXT("vec_i64"), Db->VecI64); - RegisterTable(TEXT("vec_i8"), Db->VecI8); - RegisterTable(TEXT("vec_identity"), Db->VecIdentity); - RegisterTable(TEXT("vec_simple_enum"), Db->VecSimpleEnum); - RegisterTable(TEXT("vec_string"), Db->VecString); - RegisterTable(TEXT("vec_timestamp"), Db->VecTimestamp); - RegisterTable(TEXT("vec_u128"), Db->VecU128); - RegisterTable(TEXT("vec_u16"), Db->VecU16); - RegisterTable(TEXT("vec_u256"), Db->VecU256); - RegisterTable(TEXT("vec_u32"), Db->VecU32); - RegisterTable(TEXT("vec_u64"), Db->VecU64); - RegisterTable(TEXT("vec_u8"), Db->VecU8); - RegisterTable(TEXT("vec_unit_struct"), Db->VecUnitStruct); - RegisterTable(TEXT("vec_uuid"), Db->VecUuid); -} - -FContextBase::FContextBase(UDbConnection* InConn) -{ - Db = InConn->Db; - Reducers = InConn->Reducers; - SetReducerFlags = InConn->SetReducerFlags; - Procedures = InConn->Procedures; - Conn = InConn; -} -bool FContextBase::IsActive() const -{ - return Conn->IsActive(); -} -void FContextBase::Disconnect() -{ - Conn->Disconnect(); -} -USubscriptionBuilder* FContextBase::SubscriptionBuilder() -{ - return Conn->SubscriptionBuilder(); -} -bool FContextBase::TryGetIdentity(FSpacetimeDBIdentity& OutIdentity) const -{ - return Conn->TryGetIdentity(OutIdentity); -} -FSpacetimeDBConnectionId FContextBase::GetConnectionId() const -{ - return Conn->GetConnectionId(); -} - -void URemoteTables::Initialize() -{ - - /** Creating tables */ - BtreeU32 = NewObject(this); - IndexedSimpleEnum = NewObject(this); - LargeTable = NewObject(this); - OneBool = NewObject(this); - OneByteStruct = NewObject(this); - OneConnectionId = NewObject(this); - OneEnumWithPayload = NewObject(this); - OneEveryPrimitiveStruct = NewObject(this); - OneEveryVecStruct = NewObject(this); - OneF32 = NewObject(this); - OneF64 = NewObject(this); - OneI128 = NewObject(this); - OneI16 = NewObject(this); - OneI256 = NewObject(this); - OneI32 = NewObject(this); - OneI64 = NewObject(this); - OneI8 = NewObject(this); - OneIdentity = NewObject(this); - OneSimpleEnum = NewObject(this); - OneString = NewObject(this); - OneTimestamp = NewObject(this); - OneU128 = NewObject(this); - OneU16 = NewObject(this); - OneU256 = NewObject(this); - OneU32 = NewObject(this); - OneU64 = NewObject(this); - OneU8 = NewObject(this); - OneUnitStruct = NewObject(this); - OneUuid = NewObject(this); - OptionEveryPrimitiveStruct = NewObject(this); - OptionI32 = NewObject(this); - OptionIdentity = NewObject(this); - OptionSimpleEnum = NewObject(this); - OptionString = NewObject(this); - OptionUuid = NewObject(this); - OptionVecOptionI32 = NewObject(this); - PkBool = NewObject(this); - PkConnectionId = NewObject(this); - PkI128 = NewObject(this); - PkI16 = NewObject(this); - PkI256 = NewObject(this); - PkI32 = NewObject(this); - PkI64 = NewObject(this); - PkI8 = NewObject(this); - PkIdentity = NewObject(this); - PkSimpleEnum = NewObject(this); - PkString = NewObject(this); - PkU128 = NewObject(this); - PkU16 = NewObject(this); - PkU256 = NewObject(this); - PkU32 = NewObject(this); - PkU32Two = NewObject(this); - PkU64 = NewObject(this); - PkU8 = NewObject(this); - PkUuid = NewObject(this); - ResultEveryPrimitiveStructString = NewObject(this); - ResultI32String = NewObject(this); - ResultIdentityString = NewObject(this); - ResultSimpleEnumI32 = NewObject(this); - ResultStringI32 = NewObject(this); - ResultVecI32String = NewObject(this); - ScheduledTable = NewObject(this); - TableHoldsTable = NewObject(this); - UniqueBool = NewObject(this); - UniqueConnectionId = NewObject(this); - UniqueI128 = NewObject(this); - UniqueI16 = NewObject(this); - UniqueI256 = NewObject(this); - UniqueI32 = NewObject(this); - UniqueI64 = NewObject(this); - UniqueI8 = NewObject(this); - UniqueIdentity = NewObject(this); - UniqueString = NewObject(this); - UniqueU128 = NewObject(this); - UniqueU16 = NewObject(this); - UniqueU256 = NewObject(this); - UniqueU32 = NewObject(this); - UniqueU64 = NewObject(this); - UniqueU8 = NewObject(this); - UniqueUuid = NewObject(this); - Users = NewObject(this); - VecBool = NewObject(this); - VecByteStruct = NewObject(this); - VecConnectionId = NewObject(this); - VecEnumWithPayload = NewObject(this); - VecEveryPrimitiveStruct = NewObject(this); - VecEveryVecStruct = NewObject(this); - VecF32 = NewObject(this); - VecF64 = NewObject(this); - VecI128 = NewObject(this); - VecI16 = NewObject(this); - VecI256 = NewObject(this); - VecI32 = NewObject(this); - VecI64 = NewObject(this); - VecI8 = NewObject(this); - VecIdentity = NewObject(this); - VecSimpleEnum = NewObject(this); - VecString = NewObject(this); - VecTimestamp = NewObject(this); - VecU128 = NewObject(this); - VecU16 = NewObject(this); - VecU256 = NewObject(this); - VecU32 = NewObject(this); - VecU64 = NewObject(this); - VecU8 = NewObject(this); - VecUnitStruct = NewObject(this); - VecUuid = NewObject(this); - /**/ - - /** Initialization */ - BtreeU32->PostInitialize(); - IndexedSimpleEnum->PostInitialize(); - LargeTable->PostInitialize(); - OneBool->PostInitialize(); - OneByteStruct->PostInitialize(); - OneConnectionId->PostInitialize(); - OneEnumWithPayload->PostInitialize(); - OneEveryPrimitiveStruct->PostInitialize(); - OneEveryVecStruct->PostInitialize(); - OneF32->PostInitialize(); - OneF64->PostInitialize(); - OneI128->PostInitialize(); - OneI16->PostInitialize(); - OneI256->PostInitialize(); - OneI32->PostInitialize(); - OneI64->PostInitialize(); - OneI8->PostInitialize(); - OneIdentity->PostInitialize(); - OneSimpleEnum->PostInitialize(); - OneString->PostInitialize(); - OneTimestamp->PostInitialize(); - OneU128->PostInitialize(); - OneU16->PostInitialize(); - OneU256->PostInitialize(); - OneU32->PostInitialize(); - OneU64->PostInitialize(); - OneU8->PostInitialize(); - OneUnitStruct->PostInitialize(); - OneUuid->PostInitialize(); - OptionEveryPrimitiveStruct->PostInitialize(); - OptionI32->PostInitialize(); - OptionIdentity->PostInitialize(); - OptionSimpleEnum->PostInitialize(); - OptionString->PostInitialize(); - OptionUuid->PostInitialize(); - OptionVecOptionI32->PostInitialize(); - PkBool->PostInitialize(); - PkConnectionId->PostInitialize(); - PkI128->PostInitialize(); - PkI16->PostInitialize(); - PkI256->PostInitialize(); - PkI32->PostInitialize(); - PkI64->PostInitialize(); - PkI8->PostInitialize(); - PkIdentity->PostInitialize(); - PkSimpleEnum->PostInitialize(); - PkString->PostInitialize(); - PkU128->PostInitialize(); - PkU16->PostInitialize(); - PkU256->PostInitialize(); - PkU32->PostInitialize(); - PkU32Two->PostInitialize(); - PkU64->PostInitialize(); - PkU8->PostInitialize(); - PkUuid->PostInitialize(); - ResultEveryPrimitiveStructString->PostInitialize(); - ResultI32String->PostInitialize(); - ResultIdentityString->PostInitialize(); - ResultSimpleEnumI32->PostInitialize(); - ResultStringI32->PostInitialize(); - ResultVecI32String->PostInitialize(); - ScheduledTable->PostInitialize(); - TableHoldsTable->PostInitialize(); - UniqueBool->PostInitialize(); - UniqueConnectionId->PostInitialize(); - UniqueI128->PostInitialize(); - UniqueI16->PostInitialize(); - UniqueI256->PostInitialize(); - UniqueI32->PostInitialize(); - UniqueI64->PostInitialize(); - UniqueI8->PostInitialize(); - UniqueIdentity->PostInitialize(); - UniqueString->PostInitialize(); - UniqueU128->PostInitialize(); - UniqueU16->PostInitialize(); - UniqueU256->PostInitialize(); - UniqueU32->PostInitialize(); - UniqueU64->PostInitialize(); - UniqueU8->PostInitialize(); - UniqueUuid->PostInitialize(); - Users->PostInitialize(); - VecBool->PostInitialize(); - VecByteStruct->PostInitialize(); - VecConnectionId->PostInitialize(); - VecEnumWithPayload->PostInitialize(); - VecEveryPrimitiveStruct->PostInitialize(); - VecEveryVecStruct->PostInitialize(); - VecF32->PostInitialize(); - VecF64->PostInitialize(); - VecI128->PostInitialize(); - VecI16->PostInitialize(); - VecI256->PostInitialize(); - VecI32->PostInitialize(); - VecI64->PostInitialize(); - VecI8->PostInitialize(); - VecIdentity->PostInitialize(); - VecSimpleEnum->PostInitialize(); - VecString->PostInitialize(); - VecTimestamp->PostInitialize(); - VecU128->PostInitialize(); - VecU16->PostInitialize(); - VecU256->PostInitialize(); - VecU32->PostInitialize(); - VecU64->PostInitialize(); - VecU8->PostInitialize(); - VecUnitStruct->PostInitialize(); - VecUuid->PostInitialize(); - /**/ -} - -void USetReducerFlags::DeleteFromBtreeU32(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteFromBtreeU32", Flag); -} -void USetReducerFlags::DeleteLargeTable(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteLargeTable", Flag); -} -void USetReducerFlags::DeletePkBool(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkBool", Flag); -} -void USetReducerFlags::DeletePkConnectionId(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkConnectionId", Flag); -} -void USetReducerFlags::DeletePkI128(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkI128", Flag); -} -void USetReducerFlags::DeletePkI16(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkI16", Flag); -} -void USetReducerFlags::DeletePkI256(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkI256", Flag); -} -void USetReducerFlags::DeletePkI32(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkI32", Flag); -} -void USetReducerFlags::DeletePkI64(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkI64", Flag); -} -void USetReducerFlags::DeletePkI8(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkI8", Flag); -} -void USetReducerFlags::DeletePkIdentity(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkIdentity", Flag); -} -void USetReducerFlags::DeletePkString(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkString", Flag); -} -void USetReducerFlags::DeletePkU128(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkU128", Flag); -} -void USetReducerFlags::DeletePkU16(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkU16", Flag); -} -void USetReducerFlags::DeletePkU256(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkU256", Flag); -} -void USetReducerFlags::DeletePkU32(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkU32", Flag); -} -void USetReducerFlags::DeletePkU32InsertPkU32Two(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkU32InsertPkU32Two", Flag); -} -void USetReducerFlags::DeletePkU32Two(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkU32Two", Flag); -} -void USetReducerFlags::DeletePkU64(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkU64", Flag); -} -void USetReducerFlags::DeletePkU8(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkU8", Flag); -} -void USetReducerFlags::DeletePkUuid(ECallReducerFlags Flag) -{ - FlagMap.Add("DeletePkUuid", Flag); -} -void USetReducerFlags::DeleteUniqueBool(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteUniqueBool", Flag); -} -void USetReducerFlags::DeleteUniqueConnectionId(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteUniqueConnectionId", Flag); -} -void USetReducerFlags::DeleteUniqueI128(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteUniqueI128", Flag); -} -void USetReducerFlags::DeleteUniqueI16(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteUniqueI16", Flag); -} -void USetReducerFlags::DeleteUniqueI256(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteUniqueI256", Flag); -} -void USetReducerFlags::DeleteUniqueI32(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteUniqueI32", Flag); -} -void USetReducerFlags::DeleteUniqueI64(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteUniqueI64", Flag); -} -void USetReducerFlags::DeleteUniqueI8(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteUniqueI8", Flag); -} -void USetReducerFlags::DeleteUniqueIdentity(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteUniqueIdentity", Flag); -} -void USetReducerFlags::DeleteUniqueString(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteUniqueString", Flag); -} -void USetReducerFlags::DeleteUniqueU128(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteUniqueU128", Flag); -} -void USetReducerFlags::DeleteUniqueU16(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteUniqueU16", Flag); -} -void USetReducerFlags::DeleteUniqueU256(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteUniqueU256", Flag); -} -void USetReducerFlags::DeleteUniqueU32(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteUniqueU32", Flag); -} -void USetReducerFlags::DeleteUniqueU64(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteUniqueU64", Flag); -} -void USetReducerFlags::DeleteUniqueU8(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteUniqueU8", Flag); -} -void USetReducerFlags::DeleteUniqueUuid(ECallReducerFlags Flag) -{ - FlagMap.Add("DeleteUniqueUuid", Flag); -} -void USetReducerFlags::InsertCallTimestamp(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertCallTimestamp", Flag); -} -void USetReducerFlags::InsertCallUuidV4(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertCallUuidV4", Flag); -} -void USetReducerFlags::InsertCallUuidV7(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertCallUuidV7", Flag); -} -void USetReducerFlags::InsertCallerOneConnectionId(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertCallerOneConnectionId", Flag); -} -void USetReducerFlags::InsertCallerOneIdentity(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertCallerOneIdentity", Flag); -} -void USetReducerFlags::InsertCallerPkConnectionId(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertCallerPkConnectionId", Flag); -} -void USetReducerFlags::InsertCallerPkIdentity(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertCallerPkIdentity", Flag); -} -void USetReducerFlags::InsertCallerUniqueConnectionId(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertCallerUniqueConnectionId", Flag); -} -void USetReducerFlags::InsertCallerUniqueIdentity(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertCallerUniqueIdentity", Flag); -} -void USetReducerFlags::InsertCallerVecConnectionId(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertCallerVecConnectionId", Flag); -} -void USetReducerFlags::InsertCallerVecIdentity(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertCallerVecIdentity", Flag); -} -void USetReducerFlags::InsertIntoBtreeU32(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertIntoBtreeU32", Flag); -} -void USetReducerFlags::InsertIntoIndexedSimpleEnum(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertIntoIndexedSimpleEnum", Flag); -} -void USetReducerFlags::InsertIntoPkBtreeU32(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertIntoPkBtreeU32", Flag); -} -void USetReducerFlags::InsertLargeTable(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertLargeTable", Flag); -} -void USetReducerFlags::InsertOneBool(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneBool", Flag); -} -void USetReducerFlags::InsertOneByteStruct(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneByteStruct", Flag); -} -void USetReducerFlags::InsertOneConnectionId(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneConnectionId", Flag); -} -void USetReducerFlags::InsertOneEnumWithPayload(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneEnumWithPayload", Flag); -} -void USetReducerFlags::InsertOneEveryPrimitiveStruct(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneEveryPrimitiveStruct", Flag); -} -void USetReducerFlags::InsertOneEveryVecStruct(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneEveryVecStruct", Flag); -} -void USetReducerFlags::InsertOneF32(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneF32", Flag); -} -void USetReducerFlags::InsertOneF64(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneF64", Flag); -} -void USetReducerFlags::InsertOneI128(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneI128", Flag); -} -void USetReducerFlags::InsertOneI16(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneI16", Flag); -} -void USetReducerFlags::InsertOneI256(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneI256", Flag); -} -void USetReducerFlags::InsertOneI32(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneI32", Flag); -} -void USetReducerFlags::InsertOneI64(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneI64", Flag); -} -void USetReducerFlags::InsertOneI8(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneI8", Flag); -} -void USetReducerFlags::InsertOneIdentity(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneIdentity", Flag); -} -void USetReducerFlags::InsertOneSimpleEnum(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneSimpleEnum", Flag); -} -void USetReducerFlags::InsertOneString(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneString", Flag); -} -void USetReducerFlags::InsertOneTimestamp(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneTimestamp", Flag); -} -void USetReducerFlags::InsertOneU128(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneU128", Flag); -} -void USetReducerFlags::InsertOneU16(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneU16", Flag); -} -void USetReducerFlags::InsertOneU256(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneU256", Flag); -} -void USetReducerFlags::InsertOneU32(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneU32", Flag); -} -void USetReducerFlags::InsertOneU64(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneU64", Flag); -} -void USetReducerFlags::InsertOneU8(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneU8", Flag); -} -void USetReducerFlags::InsertOneUnitStruct(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneUnitStruct", Flag); -} -void USetReducerFlags::InsertOneUuid(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOneUuid", Flag); -} -void USetReducerFlags::InsertOptionEveryPrimitiveStruct(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOptionEveryPrimitiveStruct", Flag); -} -void USetReducerFlags::InsertOptionI32(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOptionI32", Flag); -} -void USetReducerFlags::InsertOptionIdentity(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOptionIdentity", Flag); -} -void USetReducerFlags::InsertOptionSimpleEnum(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOptionSimpleEnum", Flag); -} -void USetReducerFlags::InsertOptionString(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOptionString", Flag); -} -void USetReducerFlags::InsertOptionUuid(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOptionUuid", Flag); -} -void USetReducerFlags::InsertOptionVecOptionI32(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertOptionVecOptionI32", Flag); -} -void USetReducerFlags::InsertPkBool(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkBool", Flag); -} -void USetReducerFlags::InsertPkConnectionId(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkConnectionId", Flag); -} -void USetReducerFlags::InsertPkI128(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkI128", Flag); -} -void USetReducerFlags::InsertPkI16(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkI16", Flag); -} -void USetReducerFlags::InsertPkI256(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkI256", Flag); -} -void USetReducerFlags::InsertPkI32(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkI32", Flag); -} -void USetReducerFlags::InsertPkI64(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkI64", Flag); -} -void USetReducerFlags::InsertPkI8(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkI8", Flag); -} -void USetReducerFlags::InsertPkIdentity(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkIdentity", Flag); -} -void USetReducerFlags::InsertPkSimpleEnum(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkSimpleEnum", Flag); -} -void USetReducerFlags::InsertPkString(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkString", Flag); -} -void USetReducerFlags::InsertPkU128(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkU128", Flag); -} -void USetReducerFlags::InsertPkU16(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkU16", Flag); -} -void USetReducerFlags::InsertPkU256(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkU256", Flag); -} -void USetReducerFlags::InsertPkU32(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkU32", Flag); -} -void USetReducerFlags::InsertPkU32Two(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkU32Two", Flag); -} -void USetReducerFlags::InsertPkU64(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkU64", Flag); -} -void USetReducerFlags::InsertPkU8(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkU8", Flag); -} -void USetReducerFlags::InsertPkUuid(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPkUuid", Flag); -} -void USetReducerFlags::InsertPrimitivesAsStrings(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertPrimitivesAsStrings", Flag); -} -void USetReducerFlags::InsertResultEveryPrimitiveStructString(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertResultEveryPrimitiveStructString", Flag); -} -void USetReducerFlags::InsertResultI32String(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertResultI32String", Flag); -} -void USetReducerFlags::InsertResultIdentityString(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertResultIdentityString", Flag); -} -void USetReducerFlags::InsertResultSimpleEnumI32(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertResultSimpleEnumI32", Flag); -} -void USetReducerFlags::InsertResultStringI32(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertResultStringI32", Flag); -} -void USetReducerFlags::InsertResultVecI32String(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertResultVecI32String", Flag); -} -void USetReducerFlags::InsertTableHoldsTable(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertTableHoldsTable", Flag); -} -void USetReducerFlags::InsertUniqueBool(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueBool", Flag); -} -void USetReducerFlags::InsertUniqueConnectionId(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueConnectionId", Flag); -} -void USetReducerFlags::InsertUniqueI128(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueI128", Flag); -} -void USetReducerFlags::InsertUniqueI16(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueI16", Flag); -} -void USetReducerFlags::InsertUniqueI256(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueI256", Flag); -} -void USetReducerFlags::InsertUniqueI32(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueI32", Flag); -} -void USetReducerFlags::InsertUniqueI64(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueI64", Flag); -} -void USetReducerFlags::InsertUniqueI8(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueI8", Flag); -} -void USetReducerFlags::InsertUniqueIdentity(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueIdentity", Flag); -} -void USetReducerFlags::InsertUniqueString(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueString", Flag); -} -void USetReducerFlags::InsertUniqueU128(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueU128", Flag); -} -void USetReducerFlags::InsertUniqueU16(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueU16", Flag); -} -void USetReducerFlags::InsertUniqueU256(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueU256", Flag); -} -void USetReducerFlags::InsertUniqueU32(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueU32", Flag); -} -void USetReducerFlags::InsertUniqueU32UpdatePkU32(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueU32UpdatePkU32", Flag); -} -void USetReducerFlags::InsertUniqueU64(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueU64", Flag); -} -void USetReducerFlags::InsertUniqueU8(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueU8", Flag); -} -void USetReducerFlags::InsertUniqueUuid(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUniqueUuid", Flag); -} -void USetReducerFlags::InsertUser(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertUser", Flag); -} -void USetReducerFlags::InsertVecBool(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecBool", Flag); -} -void USetReducerFlags::InsertVecByteStruct(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecByteStruct", Flag); -} -void USetReducerFlags::InsertVecConnectionId(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecConnectionId", Flag); -} -void USetReducerFlags::InsertVecEnumWithPayload(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecEnumWithPayload", Flag); -} -void USetReducerFlags::InsertVecEveryPrimitiveStruct(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecEveryPrimitiveStruct", Flag); -} -void USetReducerFlags::InsertVecEveryVecStruct(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecEveryVecStruct", Flag); -} -void USetReducerFlags::InsertVecF32(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecF32", Flag); -} -void USetReducerFlags::InsertVecF64(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecF64", Flag); -} -void USetReducerFlags::InsertVecI128(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecI128", Flag); -} -void USetReducerFlags::InsertVecI16(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecI16", Flag); -} -void USetReducerFlags::InsertVecI256(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecI256", Flag); -} -void USetReducerFlags::InsertVecI32(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecI32", Flag); -} -void USetReducerFlags::InsertVecI64(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecI64", Flag); -} -void USetReducerFlags::InsertVecI8(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecI8", Flag); -} -void USetReducerFlags::InsertVecIdentity(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecIdentity", Flag); -} -void USetReducerFlags::InsertVecSimpleEnum(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecSimpleEnum", Flag); -} -void USetReducerFlags::InsertVecString(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecString", Flag); -} -void USetReducerFlags::InsertVecTimestamp(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecTimestamp", Flag); -} -void USetReducerFlags::InsertVecU128(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecU128", Flag); -} -void USetReducerFlags::InsertVecU16(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecU16", Flag); -} -void USetReducerFlags::InsertVecU256(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecU256", Flag); -} -void USetReducerFlags::InsertVecU32(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecU32", Flag); -} -void USetReducerFlags::InsertVecU64(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecU64", Flag); -} -void USetReducerFlags::InsertVecU8(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecU8", Flag); -} -void USetReducerFlags::InsertVecUnitStruct(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecUnitStruct", Flag); -} -void USetReducerFlags::InsertVecUuid(ECallReducerFlags Flag) -{ - FlagMap.Add("InsertVecUuid", Flag); -} -void USetReducerFlags::NoOpSucceeds(ECallReducerFlags Flag) -{ - FlagMap.Add("NoOpSucceeds", Flag); -} -void USetReducerFlags::SortedUuidsInsert(ECallReducerFlags Flag) -{ - FlagMap.Add("SortedUuidsInsert", Flag); -} -void USetReducerFlags::UpdateIndexedSimpleEnum(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdateIndexedSimpleEnum", Flag); -} -void USetReducerFlags::UpdatePkBool(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkBool", Flag); -} -void USetReducerFlags::UpdatePkConnectionId(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkConnectionId", Flag); -} -void USetReducerFlags::UpdatePkI128(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkI128", Flag); -} -void USetReducerFlags::UpdatePkI16(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkI16", Flag); -} -void USetReducerFlags::UpdatePkI256(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkI256", Flag); -} -void USetReducerFlags::UpdatePkI32(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkI32", Flag); -} -void USetReducerFlags::UpdatePkI64(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkI64", Flag); -} -void USetReducerFlags::UpdatePkI8(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkI8", Flag); -} -void USetReducerFlags::UpdatePkIdentity(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkIdentity", Flag); -} -void USetReducerFlags::UpdatePkSimpleEnum(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkSimpleEnum", Flag); -} -void USetReducerFlags::UpdatePkString(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkString", Flag); -} -void USetReducerFlags::UpdatePkU128(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkU128", Flag); -} -void USetReducerFlags::UpdatePkU16(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkU16", Flag); -} -void USetReducerFlags::UpdatePkU256(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkU256", Flag); -} -void USetReducerFlags::UpdatePkU32(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkU32", Flag); -} -void USetReducerFlags::UpdatePkU32Two(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkU32Two", Flag); -} -void USetReducerFlags::UpdatePkU64(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkU64", Flag); -} -void USetReducerFlags::UpdatePkU8(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkU8", Flag); -} -void USetReducerFlags::UpdatePkUuid(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePkUuid", Flag); -} -void USetReducerFlags::UpdateUniqueBool(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdateUniqueBool", Flag); -} -void USetReducerFlags::UpdateUniqueConnectionId(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdateUniqueConnectionId", Flag); -} -void USetReducerFlags::UpdateUniqueI128(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdateUniqueI128", Flag); -} -void USetReducerFlags::UpdateUniqueI16(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdateUniqueI16", Flag); -} -void USetReducerFlags::UpdateUniqueI256(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdateUniqueI256", Flag); -} -void USetReducerFlags::UpdateUniqueI32(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdateUniqueI32", Flag); -} -void USetReducerFlags::UpdateUniqueI64(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdateUniqueI64", Flag); -} -void USetReducerFlags::UpdateUniqueI8(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdateUniqueI8", Flag); -} -void USetReducerFlags::UpdateUniqueIdentity(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdateUniqueIdentity", Flag); -} -void USetReducerFlags::UpdateUniqueString(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdateUniqueString", Flag); -} -void USetReducerFlags::UpdateUniqueU128(ECallReducerFlags Flag) +FContextBase::FContextBase(UDbConnection* InConn) { - FlagMap.Add("UpdateUniqueU128", Flag); + Db = InConn->Db; + Reducers = InConn->Reducers; + Procedures = InConn->Procedures; + Conn = InConn; } -void USetReducerFlags::UpdateUniqueU16(ECallReducerFlags Flag) +bool FContextBase::IsActive() const { - FlagMap.Add("UpdateUniqueU16", Flag); + return Conn->IsActive(); } -void USetReducerFlags::UpdateUniqueU256(ECallReducerFlags Flag) +void FContextBase::Disconnect() { - FlagMap.Add("UpdateUniqueU256", Flag); + Conn->Disconnect(); } -void USetReducerFlags::UpdateUniqueU32(ECallReducerFlags Flag) +USubscriptionBuilder* FContextBase::SubscriptionBuilder() { - FlagMap.Add("UpdateUniqueU32", Flag); + return Conn->SubscriptionBuilder(); } -void USetReducerFlags::UpdateUniqueU64(ECallReducerFlags Flag) +bool FContextBase::TryGetIdentity(FSpacetimeDBIdentity& OutIdentity) const { - FlagMap.Add("UpdateUniqueU64", Flag); + return Conn->TryGetIdentity(OutIdentity); } -void USetReducerFlags::UpdateUniqueU8(ECallReducerFlags Flag) +FSpacetimeDBConnectionId FContextBase::GetConnectionId() const { - FlagMap.Add("UpdateUniqueU8", Flag); + return Conn->GetConnectionId(); } -void USetReducerFlags::UpdateUniqueUuid(ECallReducerFlags Flag) + +void URemoteTables::Initialize() { - FlagMap.Add("UpdateUniqueUuid", Flag); + + /** Creating tables */ + BtreeU32 = NewObject(this); + IndexedSimpleEnum = NewObject(this); + LargeTable = NewObject(this); + OneBool = NewObject(this); + OneByteStruct = NewObject(this); + OneConnectionId = NewObject(this); + OneEnumWithPayload = NewObject(this); + OneEveryPrimitiveStruct = NewObject(this); + OneEveryVecStruct = NewObject(this); + OneF32 = NewObject(this); + OneF64 = NewObject(this); + OneI128 = NewObject(this); + OneI16 = NewObject(this); + OneI256 = NewObject(this); + OneI32 = NewObject(this); + OneI64 = NewObject(this); + OneI8 = NewObject(this); + OneIdentity = NewObject(this); + OneSimpleEnum = NewObject(this); + OneString = NewObject(this); + OneTimestamp = NewObject(this); + OneU128 = NewObject(this); + OneU16 = NewObject(this); + OneU256 = NewObject(this); + OneU32 = NewObject(this); + OneU64 = NewObject(this); + OneU8 = NewObject(this); + OneUnitStruct = NewObject(this); + OneUuid = NewObject(this); + OptionEveryPrimitiveStruct = NewObject(this); + OptionI32 = NewObject(this); + OptionIdentity = NewObject(this); + OptionSimpleEnum = NewObject(this); + OptionString = NewObject(this); + OptionUuid = NewObject(this); + OptionVecOptionI32 = NewObject(this); + PkBool = NewObject(this); + PkConnectionId = NewObject(this); + PkI128 = NewObject(this); + PkI16 = NewObject(this); + PkI256 = NewObject(this); + PkI32 = NewObject(this); + PkI64 = NewObject(this); + PkI8 = NewObject(this); + PkIdentity = NewObject(this); + PkSimpleEnum = NewObject(this); + PkString = NewObject(this); + PkU128 = NewObject(this); + PkU16 = NewObject(this); + PkU256 = NewObject(this); + PkU32 = NewObject(this); + PkU32Two = NewObject(this); + PkU64 = NewObject(this); + PkU8 = NewObject(this); + PkUuid = NewObject(this); + ResultEveryPrimitiveStructString = NewObject(this); + ResultI32String = NewObject(this); + ResultIdentityString = NewObject(this); + ResultSimpleEnumI32 = NewObject(this); + ResultStringI32 = NewObject(this); + ResultVecI32String = NewObject(this); + ScheduledTable = NewObject(this); + TableHoldsTable = NewObject(this); + UniqueBool = NewObject(this); + UniqueConnectionId = NewObject(this); + UniqueI128 = NewObject(this); + UniqueI16 = NewObject(this); + UniqueI256 = NewObject(this); + UniqueI32 = NewObject(this); + UniqueI64 = NewObject(this); + UniqueI8 = NewObject(this); + UniqueIdentity = NewObject(this); + UniqueString = NewObject(this); + UniqueU128 = NewObject(this); + UniqueU16 = NewObject(this); + UniqueU256 = NewObject(this); + UniqueU32 = NewObject(this); + UniqueU64 = NewObject(this); + UniqueU8 = NewObject(this); + UniqueUuid = NewObject(this); + Users = NewObject(this); + VecBool = NewObject(this); + VecByteStruct = NewObject(this); + VecConnectionId = NewObject(this); + VecEnumWithPayload = NewObject(this); + VecEveryPrimitiveStruct = NewObject(this); + VecEveryVecStruct = NewObject(this); + VecF32 = NewObject(this); + VecF64 = NewObject(this); + VecI128 = NewObject(this); + VecI16 = NewObject(this); + VecI256 = NewObject(this); + VecI32 = NewObject(this); + VecI64 = NewObject(this); + VecI8 = NewObject(this); + VecIdentity = NewObject(this); + VecSimpleEnum = NewObject(this); + VecString = NewObject(this); + VecTimestamp = NewObject(this); + VecU128 = NewObject(this); + VecU16 = NewObject(this); + VecU256 = NewObject(this); + VecU32 = NewObject(this); + VecU64 = NewObject(this); + VecU8 = NewObject(this); + VecUnitStruct = NewObject(this); + VecUuid = NewObject(this); + /**/ + + /** Initialization */ + BtreeU32->PostInitialize(); + IndexedSimpleEnum->PostInitialize(); + LargeTable->PostInitialize(); + OneBool->PostInitialize(); + OneByteStruct->PostInitialize(); + OneConnectionId->PostInitialize(); + OneEnumWithPayload->PostInitialize(); + OneEveryPrimitiveStruct->PostInitialize(); + OneEveryVecStruct->PostInitialize(); + OneF32->PostInitialize(); + OneF64->PostInitialize(); + OneI128->PostInitialize(); + OneI16->PostInitialize(); + OneI256->PostInitialize(); + OneI32->PostInitialize(); + OneI64->PostInitialize(); + OneI8->PostInitialize(); + OneIdentity->PostInitialize(); + OneSimpleEnum->PostInitialize(); + OneString->PostInitialize(); + OneTimestamp->PostInitialize(); + OneU128->PostInitialize(); + OneU16->PostInitialize(); + OneU256->PostInitialize(); + OneU32->PostInitialize(); + OneU64->PostInitialize(); + OneU8->PostInitialize(); + OneUnitStruct->PostInitialize(); + OneUuid->PostInitialize(); + OptionEveryPrimitiveStruct->PostInitialize(); + OptionI32->PostInitialize(); + OptionIdentity->PostInitialize(); + OptionSimpleEnum->PostInitialize(); + OptionString->PostInitialize(); + OptionUuid->PostInitialize(); + OptionVecOptionI32->PostInitialize(); + PkBool->PostInitialize(); + PkConnectionId->PostInitialize(); + PkI128->PostInitialize(); + PkI16->PostInitialize(); + PkI256->PostInitialize(); + PkI32->PostInitialize(); + PkI64->PostInitialize(); + PkI8->PostInitialize(); + PkIdentity->PostInitialize(); + PkSimpleEnum->PostInitialize(); + PkString->PostInitialize(); + PkU128->PostInitialize(); + PkU16->PostInitialize(); + PkU256->PostInitialize(); + PkU32->PostInitialize(); + PkU32Two->PostInitialize(); + PkU64->PostInitialize(); + PkU8->PostInitialize(); + PkUuid->PostInitialize(); + ResultEveryPrimitiveStructString->PostInitialize(); + ResultI32String->PostInitialize(); + ResultIdentityString->PostInitialize(); + ResultSimpleEnumI32->PostInitialize(); + ResultStringI32->PostInitialize(); + ResultVecI32String->PostInitialize(); + ScheduledTable->PostInitialize(); + TableHoldsTable->PostInitialize(); + UniqueBool->PostInitialize(); + UniqueConnectionId->PostInitialize(); + UniqueI128->PostInitialize(); + UniqueI16->PostInitialize(); + UniqueI256->PostInitialize(); + UniqueI32->PostInitialize(); + UniqueI64->PostInitialize(); + UniqueI8->PostInitialize(); + UniqueIdentity->PostInitialize(); + UniqueString->PostInitialize(); + UniqueU128->PostInitialize(); + UniqueU16->PostInitialize(); + UniqueU256->PostInitialize(); + UniqueU32->PostInitialize(); + UniqueU64->PostInitialize(); + UniqueU8->PostInitialize(); + UniqueUuid->PostInitialize(); + Users->PostInitialize(); + VecBool->PostInitialize(); + VecByteStruct->PostInitialize(); + VecConnectionId->PostInitialize(); + VecEnumWithPayload->PostInitialize(); + VecEveryPrimitiveStruct->PostInitialize(); + VecEveryVecStruct->PostInitialize(); + VecF32->PostInitialize(); + VecF64->PostInitialize(); + VecI128->PostInitialize(); + VecI16->PostInitialize(); + VecI256->PostInitialize(); + VecI32->PostInitialize(); + VecI64->PostInitialize(); + VecI8->PostInitialize(); + VecIdentity->PostInitialize(); + VecSimpleEnum->PostInitialize(); + VecString->PostInitialize(); + VecTimestamp->PostInitialize(); + VecU128->PostInitialize(); + VecU16->PostInitialize(); + VecU256->PostInitialize(); + VecU32->PostInitialize(); + VecU64->PostInitialize(); + VecU8->PostInitialize(); + VecUnitStruct->PostInitialize(); + VecUuid->PostInitialize(); + /**/ } void URemoteReducers::DeleteFromBtreeU32(const TArray& Rows) @@ -2474,7 +492,9 @@ void URemoteReducers::DeleteFromBtreeU32(const TArray& Rows) return; } - Conn->CallReducerTyped(TEXT("delete_from_btree_u32"), FDeleteFromBtreeU32Args(Rows), SetCallReducerFlags); + FDeleteFromBtreeU32Args ReducerArgs(Rows); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_from_btree_u_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteFromBtreeU32(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteFromBtreeU32(const FReducerEventContext& Context, const UDeleteFromBtreeU32Reducer* Args) @@ -2518,7 +538,9 @@ void URemoteReducers::DeleteLargeTable(const uint8 A, const uint16 B, const uint return; } - Conn->CallReducerTyped(TEXT("delete_large_table"), FDeleteLargeTableArgs(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V), SetCallReducerFlags); + FDeleteLargeTableArgs ReducerArgs(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_large_table"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteLargeTable(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteLargeTable(const FReducerEventContext& Context, const UDeleteLargeTableReducer* Args) @@ -2585,7 +607,9 @@ void URemoteReducers::DeletePkBool(const bool B) return; } - Conn->CallReducerTyped(TEXT("delete_pk_bool"), FDeletePkBoolArgs(B), SetCallReducerFlags); + FDeletePkBoolArgs ReducerArgs(B); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_bool"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkBool(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkBool(const FReducerEventContext& Context, const UDeletePkBoolReducer* Args) @@ -2629,7 +653,9 @@ void URemoteReducers::DeletePkConnectionId(const FSpacetimeDBConnectionId& A) return; } - Conn->CallReducerTyped(TEXT("delete_pk_connection_id"), FDeletePkConnectionIdArgs(A), SetCallReducerFlags); + FDeletePkConnectionIdArgs ReducerArgs(A); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_connection_id"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkConnectionId(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkConnectionId(const FReducerEventContext& Context, const UDeletePkConnectionIdReducer* Args) @@ -2673,7 +699,9 @@ void URemoteReducers::DeletePkI128(const FSpacetimeDBInt128& N) return; } - Conn->CallReducerTyped(TEXT("delete_pk_i128"), FDeletePkI128Args(N), SetCallReducerFlags); + FDeletePkI128Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_i_128"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkI128(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkI128(const FReducerEventContext& Context, const UDeletePkI128Reducer* Args) @@ -2717,7 +745,9 @@ void URemoteReducers::DeletePkI16(const int16 N) return; } - Conn->CallReducerTyped(TEXT("delete_pk_i16"), FDeletePkI16Args(N), SetCallReducerFlags); + FDeletePkI16Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_i_16"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkI16(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkI16(const FReducerEventContext& Context, const UDeletePkI16Reducer* Args) @@ -2761,7 +791,9 @@ void URemoteReducers::DeletePkI256(const FSpacetimeDBInt256& N) return; } - Conn->CallReducerTyped(TEXT("delete_pk_i256"), FDeletePkI256Args(N), SetCallReducerFlags); + FDeletePkI256Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_i_256"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkI256(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkI256(const FReducerEventContext& Context, const UDeletePkI256Reducer* Args) @@ -2805,7 +837,9 @@ void URemoteReducers::DeletePkI32(const int32 N) return; } - Conn->CallReducerTyped(TEXT("delete_pk_i32"), FDeletePkI32Args(N), SetCallReducerFlags); + FDeletePkI32Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_i_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkI32(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkI32(const FReducerEventContext& Context, const UDeletePkI32Reducer* Args) @@ -2849,7 +883,9 @@ void URemoteReducers::DeletePkI64(const int64 N) return; } - Conn->CallReducerTyped(TEXT("delete_pk_i64"), FDeletePkI64Args(N), SetCallReducerFlags); + FDeletePkI64Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_i_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkI64(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkI64(const FReducerEventContext& Context, const UDeletePkI64Reducer* Args) @@ -2893,7 +929,9 @@ void URemoteReducers::DeletePkI8(const int8 N) return; } - Conn->CallReducerTyped(TEXT("delete_pk_i8"), FDeletePkI8Args(N), SetCallReducerFlags); + FDeletePkI8Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_i_8"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkI8(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkI8(const FReducerEventContext& Context, const UDeletePkI8Reducer* Args) @@ -2937,7 +975,9 @@ void URemoteReducers::DeletePkIdentity(const FSpacetimeDBIdentity& I) return; } - Conn->CallReducerTyped(TEXT("delete_pk_identity"), FDeletePkIdentityArgs(I), SetCallReducerFlags); + FDeletePkIdentityArgs ReducerArgs(I); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_identity"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkIdentity(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkIdentity(const FReducerEventContext& Context, const UDeletePkIdentityReducer* Args) @@ -2981,7 +1021,9 @@ void URemoteReducers::DeletePkString(const FString& S) return; } - Conn->CallReducerTyped(TEXT("delete_pk_string"), FDeletePkStringArgs(S), SetCallReducerFlags); + FDeletePkStringArgs ReducerArgs(S); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_string"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkString(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkString(const FReducerEventContext& Context, const UDeletePkStringReducer* Args) @@ -3025,7 +1067,9 @@ void URemoteReducers::DeletePkU128(const FSpacetimeDBUInt128& N) return; } - Conn->CallReducerTyped(TEXT("delete_pk_u128"), FDeletePkU128Args(N), SetCallReducerFlags); + FDeletePkU128Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_u_128"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkU128(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkU128(const FReducerEventContext& Context, const UDeletePkU128Reducer* Args) @@ -3069,7 +1113,9 @@ void URemoteReducers::DeletePkU16(const uint16 N) return; } - Conn->CallReducerTyped(TEXT("delete_pk_u16"), FDeletePkU16Args(N), SetCallReducerFlags); + FDeletePkU16Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_u_16"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkU16(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkU16(const FReducerEventContext& Context, const UDeletePkU16Reducer* Args) @@ -3113,7 +1159,9 @@ void URemoteReducers::DeletePkU256(const FSpacetimeDBUInt256& N) return; } - Conn->CallReducerTyped(TEXT("delete_pk_u256"), FDeletePkU256Args(N), SetCallReducerFlags); + FDeletePkU256Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_u_256"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkU256(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkU256(const FReducerEventContext& Context, const UDeletePkU256Reducer* Args) @@ -3157,7 +1205,9 @@ void URemoteReducers::DeletePkU32(const uint32 N) return; } - Conn->CallReducerTyped(TEXT("delete_pk_u32"), FDeletePkU32Args(N), SetCallReducerFlags); + FDeletePkU32Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_u_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkU32(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkU32(const FReducerEventContext& Context, const UDeletePkU32Reducer* Args) @@ -3201,7 +1251,9 @@ void URemoteReducers::DeletePkU32InsertPkU32Two(const uint32 N, const int32 Data return; } - Conn->CallReducerTyped(TEXT("delete_pk_u32_insert_pk_u32_two"), FDeletePkU32InsertPkU32TwoArgs(N, Data), SetCallReducerFlags); + FDeletePkU32InsertPkU32TwoArgs ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_u_32_insert_pk_u_32_two"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkU32InsertPkU32Two(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkU32InsertPkU32Two(const FReducerEventContext& Context, const UDeletePkU32InsertPkU32TwoReducer* Args) @@ -3245,7 +1297,9 @@ void URemoteReducers::DeletePkU32Two(const uint32 N) return; } - Conn->CallReducerTyped(TEXT("delete_pk_u32_two"), FDeletePkU32TwoArgs(N), SetCallReducerFlags); + FDeletePkU32TwoArgs ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_u_32_two"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkU32Two(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkU32Two(const FReducerEventContext& Context, const UDeletePkU32TwoReducer* Args) @@ -3289,7 +1343,9 @@ void URemoteReducers::DeletePkU64(const uint64 N) return; } - Conn->CallReducerTyped(TEXT("delete_pk_u64"), FDeletePkU64Args(N), SetCallReducerFlags); + FDeletePkU64Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_u_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkU64(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkU64(const FReducerEventContext& Context, const UDeletePkU64Reducer* Args) @@ -3333,7 +1389,9 @@ void URemoteReducers::DeletePkU8(const uint8 N) return; } - Conn->CallReducerTyped(TEXT("delete_pk_u8"), FDeletePkU8Args(N), SetCallReducerFlags); + FDeletePkU8Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_u_8"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkU8(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkU8(const FReducerEventContext& Context, const UDeletePkU8Reducer* Args) @@ -3377,7 +1435,9 @@ void URemoteReducers::DeletePkUuid(const FSpacetimeDBUuid& U) return; } - Conn->CallReducerTyped(TEXT("delete_pk_uuid"), FDeletePkUuidArgs(U), SetCallReducerFlags); + FDeletePkUuidArgs ReducerArgs(U); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_pk_uuid"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeletePkUuid(ReducerArgs)); } } bool URemoteReducers::InvokeDeletePkUuid(const FReducerEventContext& Context, const UDeletePkUuidReducer* Args) @@ -3421,7 +1481,9 @@ void URemoteReducers::DeleteUniqueBool(const bool B) return; } - Conn->CallReducerTyped(TEXT("delete_unique_bool"), FDeleteUniqueBoolArgs(B), SetCallReducerFlags); + FDeleteUniqueBoolArgs ReducerArgs(B); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_unique_bool"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteUniqueBool(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteUniqueBool(const FReducerEventContext& Context, const UDeleteUniqueBoolReducer* Args) @@ -3465,7 +1527,9 @@ void URemoteReducers::DeleteUniqueConnectionId(const FSpacetimeDBConnectionId& A return; } - Conn->CallReducerTyped(TEXT("delete_unique_connection_id"), FDeleteUniqueConnectionIdArgs(A), SetCallReducerFlags); + FDeleteUniqueConnectionIdArgs ReducerArgs(A); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_unique_connection_id"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteUniqueConnectionId(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteUniqueConnectionId(const FReducerEventContext& Context, const UDeleteUniqueConnectionIdReducer* Args) @@ -3509,7 +1573,9 @@ void URemoteReducers::DeleteUniqueI128(const FSpacetimeDBInt128& N) return; } - Conn->CallReducerTyped(TEXT("delete_unique_i128"), FDeleteUniqueI128Args(N), SetCallReducerFlags); + FDeleteUniqueI128Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_unique_i_128"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteUniqueI128(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteUniqueI128(const FReducerEventContext& Context, const UDeleteUniqueI128Reducer* Args) @@ -3553,7 +1619,9 @@ void URemoteReducers::DeleteUniqueI16(const int16 N) return; } - Conn->CallReducerTyped(TEXT("delete_unique_i16"), FDeleteUniqueI16Args(N), SetCallReducerFlags); + FDeleteUniqueI16Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_unique_i_16"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteUniqueI16(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteUniqueI16(const FReducerEventContext& Context, const UDeleteUniqueI16Reducer* Args) @@ -3597,7 +1665,9 @@ void URemoteReducers::DeleteUniqueI256(const FSpacetimeDBInt256& N) return; } - Conn->CallReducerTyped(TEXT("delete_unique_i256"), FDeleteUniqueI256Args(N), SetCallReducerFlags); + FDeleteUniqueI256Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_unique_i_256"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteUniqueI256(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteUniqueI256(const FReducerEventContext& Context, const UDeleteUniqueI256Reducer* Args) @@ -3641,7 +1711,9 @@ void URemoteReducers::DeleteUniqueI32(const int32 N) return; } - Conn->CallReducerTyped(TEXT("delete_unique_i32"), FDeleteUniqueI32Args(N), SetCallReducerFlags); + FDeleteUniqueI32Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_unique_i_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteUniqueI32(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteUniqueI32(const FReducerEventContext& Context, const UDeleteUniqueI32Reducer* Args) @@ -3685,7 +1757,9 @@ void URemoteReducers::DeleteUniqueI64(const int64 N) return; } - Conn->CallReducerTyped(TEXT("delete_unique_i64"), FDeleteUniqueI64Args(N), SetCallReducerFlags); + FDeleteUniqueI64Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_unique_i_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteUniqueI64(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteUniqueI64(const FReducerEventContext& Context, const UDeleteUniqueI64Reducer* Args) @@ -3729,7 +1803,9 @@ void URemoteReducers::DeleteUniqueI8(const int8 N) return; } - Conn->CallReducerTyped(TEXT("delete_unique_i8"), FDeleteUniqueI8Args(N), SetCallReducerFlags); + FDeleteUniqueI8Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_unique_i_8"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteUniqueI8(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteUniqueI8(const FReducerEventContext& Context, const UDeleteUniqueI8Reducer* Args) @@ -3773,7 +1849,9 @@ void URemoteReducers::DeleteUniqueIdentity(const FSpacetimeDBIdentity& I) return; } - Conn->CallReducerTyped(TEXT("delete_unique_identity"), FDeleteUniqueIdentityArgs(I), SetCallReducerFlags); + FDeleteUniqueIdentityArgs ReducerArgs(I); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_unique_identity"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteUniqueIdentity(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteUniqueIdentity(const FReducerEventContext& Context, const UDeleteUniqueIdentityReducer* Args) @@ -3817,7 +1895,9 @@ void URemoteReducers::DeleteUniqueString(const FString& S) return; } - Conn->CallReducerTyped(TEXT("delete_unique_string"), FDeleteUniqueStringArgs(S), SetCallReducerFlags); + FDeleteUniqueStringArgs ReducerArgs(S); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_unique_string"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteUniqueString(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteUniqueString(const FReducerEventContext& Context, const UDeleteUniqueStringReducer* Args) @@ -3861,7 +1941,9 @@ void URemoteReducers::DeleteUniqueU128(const FSpacetimeDBUInt128& N) return; } - Conn->CallReducerTyped(TEXT("delete_unique_u128"), FDeleteUniqueU128Args(N), SetCallReducerFlags); + FDeleteUniqueU128Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_unique_u_128"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteUniqueU128(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteUniqueU128(const FReducerEventContext& Context, const UDeleteUniqueU128Reducer* Args) @@ -3905,7 +1987,9 @@ void URemoteReducers::DeleteUniqueU16(const uint16 N) return; } - Conn->CallReducerTyped(TEXT("delete_unique_u16"), FDeleteUniqueU16Args(N), SetCallReducerFlags); + FDeleteUniqueU16Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_unique_u_16"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteUniqueU16(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteUniqueU16(const FReducerEventContext& Context, const UDeleteUniqueU16Reducer* Args) @@ -3949,7 +2033,9 @@ void URemoteReducers::DeleteUniqueU256(const FSpacetimeDBUInt256& N) return; } - Conn->CallReducerTyped(TEXT("delete_unique_u256"), FDeleteUniqueU256Args(N), SetCallReducerFlags); + FDeleteUniqueU256Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_unique_u_256"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteUniqueU256(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteUniqueU256(const FReducerEventContext& Context, const UDeleteUniqueU256Reducer* Args) @@ -3993,7 +2079,9 @@ void URemoteReducers::DeleteUniqueU32(const uint32 N) return; } - Conn->CallReducerTyped(TEXT("delete_unique_u32"), FDeleteUniqueU32Args(N), SetCallReducerFlags); + FDeleteUniqueU32Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_unique_u_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteUniqueU32(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteUniqueU32(const FReducerEventContext& Context, const UDeleteUniqueU32Reducer* Args) @@ -4037,7 +2125,9 @@ void URemoteReducers::DeleteUniqueU64(const uint64 N) return; } - Conn->CallReducerTyped(TEXT("delete_unique_u64"), FDeleteUniqueU64Args(N), SetCallReducerFlags); + FDeleteUniqueU64Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_unique_u_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteUniqueU64(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteUniqueU64(const FReducerEventContext& Context, const UDeleteUniqueU64Reducer* Args) @@ -4081,7 +2171,9 @@ void URemoteReducers::DeleteUniqueU8(const uint8 N) return; } - Conn->CallReducerTyped(TEXT("delete_unique_u8"), FDeleteUniqueU8Args(N), SetCallReducerFlags); + FDeleteUniqueU8Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_unique_u_8"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteUniqueU8(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteUniqueU8(const FReducerEventContext& Context, const UDeleteUniqueU8Reducer* Args) @@ -4125,7 +2217,9 @@ void URemoteReducers::DeleteUniqueUuid(const FSpacetimeDBUuid& U) return; } - Conn->CallReducerTyped(TEXT("delete_unique_uuid"), FDeleteUniqueUuidArgs(U), SetCallReducerFlags); + FDeleteUniqueUuidArgs ReducerArgs(U); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("delete_unique_uuid"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::DeleteUniqueUuid(ReducerArgs)); } } bool URemoteReducers::InvokeDeleteUniqueUuid(const FReducerEventContext& Context, const UDeleteUniqueUuidReducer* Args) @@ -4169,7 +2263,9 @@ void URemoteReducers::InsertCallTimestamp() return; } - Conn->CallReducerTyped(TEXT("insert_call_timestamp"), FInsertCallTimestampArgs(), SetCallReducerFlags); + FInsertCallTimestampArgs ReducerArgs; + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_call_timestamp"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertCallTimestamp(ReducerArgs)); } } bool URemoteReducers::InvokeInsertCallTimestamp(const FReducerEventContext& Context, const UInsertCallTimestampReducer* Args) @@ -4213,7 +2309,9 @@ void URemoteReducers::InsertCallUuidV4() return; } - Conn->CallReducerTyped(TEXT("insert_call_uuid_v4"), FInsertCallUuidV4Args(), SetCallReducerFlags); + FInsertCallUuidV4Args ReducerArgs; + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_call_uuid_v_4"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertCallUuidV4(ReducerArgs)); } } bool URemoteReducers::InvokeInsertCallUuidV4(const FReducerEventContext& Context, const UInsertCallUuidV4Reducer* Args) @@ -4257,7 +2355,9 @@ void URemoteReducers::InsertCallUuidV7() return; } - Conn->CallReducerTyped(TEXT("insert_call_uuid_v7"), FInsertCallUuidV7Args(), SetCallReducerFlags); + FInsertCallUuidV7Args ReducerArgs; + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_call_uuid_v_7"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertCallUuidV7(ReducerArgs)); } } bool URemoteReducers::InvokeInsertCallUuidV7(const FReducerEventContext& Context, const UInsertCallUuidV7Reducer* Args) @@ -4301,7 +2401,9 @@ void URemoteReducers::InsertCallerOneConnectionId() return; } - Conn->CallReducerTyped(TEXT("insert_caller_one_connection_id"), FInsertCallerOneConnectionIdArgs(), SetCallReducerFlags); + FInsertCallerOneConnectionIdArgs ReducerArgs; + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_caller_one_connection_id"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertCallerOneConnectionId(ReducerArgs)); } } bool URemoteReducers::InvokeInsertCallerOneConnectionId(const FReducerEventContext& Context, const UInsertCallerOneConnectionIdReducer* Args) @@ -4345,7 +2447,9 @@ void URemoteReducers::InsertCallerOneIdentity() return; } - Conn->CallReducerTyped(TEXT("insert_caller_one_identity"), FInsertCallerOneIdentityArgs(), SetCallReducerFlags); + FInsertCallerOneIdentityArgs ReducerArgs; + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_caller_one_identity"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertCallerOneIdentity(ReducerArgs)); } } bool URemoteReducers::InvokeInsertCallerOneIdentity(const FReducerEventContext& Context, const UInsertCallerOneIdentityReducer* Args) @@ -4389,7 +2493,9 @@ void URemoteReducers::InsertCallerPkConnectionId(const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_caller_pk_connection_id"), FInsertCallerPkConnectionIdArgs(Data), SetCallReducerFlags); + FInsertCallerPkConnectionIdArgs ReducerArgs(Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_caller_pk_connection_id"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertCallerPkConnectionId(ReducerArgs)); } } bool URemoteReducers::InvokeInsertCallerPkConnectionId(const FReducerEventContext& Context, const UInsertCallerPkConnectionIdReducer* Args) @@ -4433,7 +2539,9 @@ void URemoteReducers::InsertCallerPkIdentity(const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_caller_pk_identity"), FInsertCallerPkIdentityArgs(Data), SetCallReducerFlags); + FInsertCallerPkIdentityArgs ReducerArgs(Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_caller_pk_identity"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertCallerPkIdentity(ReducerArgs)); } } bool URemoteReducers::InvokeInsertCallerPkIdentity(const FReducerEventContext& Context, const UInsertCallerPkIdentityReducer* Args) @@ -4477,7 +2585,9 @@ void URemoteReducers::InsertCallerUniqueConnectionId(const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_caller_unique_connection_id"), FInsertCallerUniqueConnectionIdArgs(Data), SetCallReducerFlags); + FInsertCallerUniqueConnectionIdArgs ReducerArgs(Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_caller_unique_connection_id"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertCallerUniqueConnectionId(ReducerArgs)); } } bool URemoteReducers::InvokeInsertCallerUniqueConnectionId(const FReducerEventContext& Context, const UInsertCallerUniqueConnectionIdReducer* Args) @@ -4521,7 +2631,9 @@ void URemoteReducers::InsertCallerUniqueIdentity(const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_caller_unique_identity"), FInsertCallerUniqueIdentityArgs(Data), SetCallReducerFlags); + FInsertCallerUniqueIdentityArgs ReducerArgs(Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_caller_unique_identity"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertCallerUniqueIdentity(ReducerArgs)); } } bool URemoteReducers::InvokeInsertCallerUniqueIdentity(const FReducerEventContext& Context, const UInsertCallerUniqueIdentityReducer* Args) @@ -4565,7 +2677,9 @@ void URemoteReducers::InsertCallerVecConnectionId() return; } - Conn->CallReducerTyped(TEXT("insert_caller_vec_connection_id"), FInsertCallerVecConnectionIdArgs(), SetCallReducerFlags); + FInsertCallerVecConnectionIdArgs ReducerArgs; + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_caller_vec_connection_id"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertCallerVecConnectionId(ReducerArgs)); } } bool URemoteReducers::InvokeInsertCallerVecConnectionId(const FReducerEventContext& Context, const UInsertCallerVecConnectionIdReducer* Args) @@ -4609,7 +2723,9 @@ void URemoteReducers::InsertCallerVecIdentity() return; } - Conn->CallReducerTyped(TEXT("insert_caller_vec_identity"), FInsertCallerVecIdentityArgs(), SetCallReducerFlags); + FInsertCallerVecIdentityArgs ReducerArgs; + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_caller_vec_identity"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertCallerVecIdentity(ReducerArgs)); } } bool URemoteReducers::InvokeInsertCallerVecIdentity(const FReducerEventContext& Context, const UInsertCallerVecIdentityReducer* Args) @@ -4653,7 +2769,9 @@ void URemoteReducers::InsertIntoBtreeU32(const TArray& Rows) return; } - Conn->CallReducerTyped(TEXT("insert_into_btree_u32"), FInsertIntoBtreeU32Args(Rows), SetCallReducerFlags); + FInsertIntoBtreeU32Args ReducerArgs(Rows); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_into_btree_u_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertIntoBtreeU32(ReducerArgs)); } } bool URemoteReducers::InvokeInsertIntoBtreeU32(const FReducerEventContext& Context, const UInsertIntoBtreeU32Reducer* Args) @@ -4697,7 +2815,9 @@ void URemoteReducers::InsertIntoIndexedSimpleEnum(const ESimpleEnumType& N) return; } - Conn->CallReducerTyped(TEXT("insert_into_indexed_simple_enum"), FInsertIntoIndexedSimpleEnumArgs(N), SetCallReducerFlags); + FInsertIntoIndexedSimpleEnumArgs ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_into_indexed_simple_enum"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertIntoIndexedSimpleEnum(ReducerArgs)); } } bool URemoteReducers::InvokeInsertIntoIndexedSimpleEnum(const FReducerEventContext& Context, const UInsertIntoIndexedSimpleEnumReducer* Args) @@ -4741,7 +2861,9 @@ void URemoteReducers::InsertIntoPkBtreeU32(const TArray& PkU32, cons return; } - Conn->CallReducerTyped(TEXT("insert_into_pk_btree_u32"), FInsertIntoPkBtreeU32Args(PkU32, BtU32), SetCallReducerFlags); + FInsertIntoPkBtreeU32Args ReducerArgs(PkU32, BtU32); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_into_pk_btree_u_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertIntoPkBtreeU32(ReducerArgs)); } } bool URemoteReducers::InvokeInsertIntoPkBtreeU32(const FReducerEventContext& Context, const UInsertIntoPkBtreeU32Reducer* Args) @@ -4785,7 +2907,9 @@ void URemoteReducers::InsertLargeTable(const uint8 A, const uint16 B, const uint return; } - Conn->CallReducerTyped(TEXT("insert_large_table"), FInsertLargeTableArgs(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V), SetCallReducerFlags); + FInsertLargeTableArgs ReducerArgs(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_large_table"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertLargeTable(ReducerArgs)); } } bool URemoteReducers::InvokeInsertLargeTable(const FReducerEventContext& Context, const UInsertLargeTableReducer* Args) @@ -4852,7 +2976,9 @@ void URemoteReducers::InsertOneBool(const bool B) return; } - Conn->CallReducerTyped(TEXT("insert_one_bool"), FInsertOneBoolArgs(B), SetCallReducerFlags); + FInsertOneBoolArgs ReducerArgs(B); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_bool"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneBool(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneBool(const FReducerEventContext& Context, const UInsertOneBoolReducer* Args) @@ -4896,7 +3022,9 @@ void URemoteReducers::InsertOneByteStruct(const FByteStructType& S) return; } - Conn->CallReducerTyped(TEXT("insert_one_byte_struct"), FInsertOneByteStructArgs(S), SetCallReducerFlags); + FInsertOneByteStructArgs ReducerArgs(S); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_byte_struct"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneByteStruct(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneByteStruct(const FReducerEventContext& Context, const UInsertOneByteStructReducer* Args) @@ -4940,7 +3068,9 @@ void URemoteReducers::InsertOneConnectionId(const FSpacetimeDBConnectionId& A) return; } - Conn->CallReducerTyped(TEXT("insert_one_connection_id"), FInsertOneConnectionIdArgs(A), SetCallReducerFlags); + FInsertOneConnectionIdArgs ReducerArgs(A); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_connection_id"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneConnectionId(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneConnectionId(const FReducerEventContext& Context, const UInsertOneConnectionIdReducer* Args) @@ -4984,7 +3114,9 @@ void URemoteReducers::InsertOneEnumWithPayload(const FEnumWithPayloadType& E) return; } - Conn->CallReducerTyped(TEXT("insert_one_enum_with_payload"), FInsertOneEnumWithPayloadArgs(E), SetCallReducerFlags); + FInsertOneEnumWithPayloadArgs ReducerArgs(E); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_enum_with_payload"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneEnumWithPayload(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneEnumWithPayload(const FReducerEventContext& Context, const UInsertOneEnumWithPayloadReducer* Args) @@ -5028,7 +3160,9 @@ void URemoteReducers::InsertOneEveryPrimitiveStruct(const FEveryPrimitiveStructT return; } - Conn->CallReducerTyped(TEXT("insert_one_every_primitive_struct"), FInsertOneEveryPrimitiveStructArgs(S), SetCallReducerFlags); + FInsertOneEveryPrimitiveStructArgs ReducerArgs(S); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_every_primitive_struct"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneEveryPrimitiveStruct(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneEveryPrimitiveStruct(const FReducerEventContext& Context, const UInsertOneEveryPrimitiveStructReducer* Args) @@ -5072,7 +3206,9 @@ void URemoteReducers::InsertOneEveryVecStruct(const FEveryVecStructType& S) return; } - Conn->CallReducerTyped(TEXT("insert_one_every_vec_struct"), FInsertOneEveryVecStructArgs(S), SetCallReducerFlags); + FInsertOneEveryVecStructArgs ReducerArgs(S); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_every_vec_struct"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneEveryVecStruct(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneEveryVecStruct(const FReducerEventContext& Context, const UInsertOneEveryVecStructReducer* Args) @@ -5116,7 +3252,9 @@ void URemoteReducers::InsertOneF32(const float F) return; } - Conn->CallReducerTyped(TEXT("insert_one_f32"), FInsertOneF32Args(F), SetCallReducerFlags); + FInsertOneF32Args ReducerArgs(F); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_f_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneF32(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneF32(const FReducerEventContext& Context, const UInsertOneF32Reducer* Args) @@ -5160,7 +3298,9 @@ void URemoteReducers::InsertOneF64(const double F) return; } - Conn->CallReducerTyped(TEXT("insert_one_f64"), FInsertOneF64Args(F), SetCallReducerFlags); + FInsertOneF64Args ReducerArgs(F); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_f_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneF64(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneF64(const FReducerEventContext& Context, const UInsertOneF64Reducer* Args) @@ -5204,7 +3344,9 @@ void URemoteReducers::InsertOneI128(const FSpacetimeDBInt128& N) return; } - Conn->CallReducerTyped(TEXT("insert_one_i128"), FInsertOneI128Args(N), SetCallReducerFlags); + FInsertOneI128Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_i_128"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneI128(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneI128(const FReducerEventContext& Context, const UInsertOneI128Reducer* Args) @@ -5248,7 +3390,9 @@ void URemoteReducers::InsertOneI16(const int16 N) return; } - Conn->CallReducerTyped(TEXT("insert_one_i16"), FInsertOneI16Args(N), SetCallReducerFlags); + FInsertOneI16Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_i_16"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneI16(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneI16(const FReducerEventContext& Context, const UInsertOneI16Reducer* Args) @@ -5292,7 +3436,9 @@ void URemoteReducers::InsertOneI256(const FSpacetimeDBInt256& N) return; } - Conn->CallReducerTyped(TEXT("insert_one_i256"), FInsertOneI256Args(N), SetCallReducerFlags); + FInsertOneI256Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_i_256"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneI256(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneI256(const FReducerEventContext& Context, const UInsertOneI256Reducer* Args) @@ -5336,7 +3482,9 @@ void URemoteReducers::InsertOneI32(const int32 N) return; } - Conn->CallReducerTyped(TEXT("insert_one_i32"), FInsertOneI32Args(N), SetCallReducerFlags); + FInsertOneI32Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_i_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneI32(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneI32(const FReducerEventContext& Context, const UInsertOneI32Reducer* Args) @@ -5380,7 +3528,9 @@ void URemoteReducers::InsertOneI64(const int64 N) return; } - Conn->CallReducerTyped(TEXT("insert_one_i64"), FInsertOneI64Args(N), SetCallReducerFlags); + FInsertOneI64Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_i_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneI64(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneI64(const FReducerEventContext& Context, const UInsertOneI64Reducer* Args) @@ -5424,7 +3574,9 @@ void URemoteReducers::InsertOneI8(const int8 N) return; } - Conn->CallReducerTyped(TEXT("insert_one_i8"), FInsertOneI8Args(N), SetCallReducerFlags); + FInsertOneI8Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_i_8"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneI8(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneI8(const FReducerEventContext& Context, const UInsertOneI8Reducer* Args) @@ -5468,7 +3620,9 @@ void URemoteReducers::InsertOneIdentity(const FSpacetimeDBIdentity& I) return; } - Conn->CallReducerTyped(TEXT("insert_one_identity"), FInsertOneIdentityArgs(I), SetCallReducerFlags); + FInsertOneIdentityArgs ReducerArgs(I); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_identity"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneIdentity(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneIdentity(const FReducerEventContext& Context, const UInsertOneIdentityReducer* Args) @@ -5512,7 +3666,9 @@ void URemoteReducers::InsertOneSimpleEnum(const ESimpleEnumType& E) return; } - Conn->CallReducerTyped(TEXT("insert_one_simple_enum"), FInsertOneSimpleEnumArgs(E), SetCallReducerFlags); + FInsertOneSimpleEnumArgs ReducerArgs(E); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_simple_enum"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneSimpleEnum(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneSimpleEnum(const FReducerEventContext& Context, const UInsertOneSimpleEnumReducer* Args) @@ -5556,7 +3712,9 @@ void URemoteReducers::InsertOneString(const FString& S) return; } - Conn->CallReducerTyped(TEXT("insert_one_string"), FInsertOneStringArgs(S), SetCallReducerFlags); + FInsertOneStringArgs ReducerArgs(S); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_string"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneString(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneString(const FReducerEventContext& Context, const UInsertOneStringReducer* Args) @@ -5600,7 +3758,9 @@ void URemoteReducers::InsertOneTimestamp(const FSpacetimeDBTimestamp& T) return; } - Conn->CallReducerTyped(TEXT("insert_one_timestamp"), FInsertOneTimestampArgs(T), SetCallReducerFlags); + FInsertOneTimestampArgs ReducerArgs(T); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_timestamp"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneTimestamp(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneTimestamp(const FReducerEventContext& Context, const UInsertOneTimestampReducer* Args) @@ -5644,7 +3804,9 @@ void URemoteReducers::InsertOneU128(const FSpacetimeDBUInt128& N) return; } - Conn->CallReducerTyped(TEXT("insert_one_u128"), FInsertOneU128Args(N), SetCallReducerFlags); + FInsertOneU128Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_u_128"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneU128(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneU128(const FReducerEventContext& Context, const UInsertOneU128Reducer* Args) @@ -5688,7 +3850,9 @@ void URemoteReducers::InsertOneU16(const uint16 N) return; } - Conn->CallReducerTyped(TEXT("insert_one_u16"), FInsertOneU16Args(N), SetCallReducerFlags); + FInsertOneU16Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_u_16"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneU16(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneU16(const FReducerEventContext& Context, const UInsertOneU16Reducer* Args) @@ -5732,7 +3896,9 @@ void URemoteReducers::InsertOneU256(const FSpacetimeDBUInt256& N) return; } - Conn->CallReducerTyped(TEXT("insert_one_u256"), FInsertOneU256Args(N), SetCallReducerFlags); + FInsertOneU256Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_u_256"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneU256(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneU256(const FReducerEventContext& Context, const UInsertOneU256Reducer* Args) @@ -5776,7 +3942,9 @@ void URemoteReducers::InsertOneU32(const uint32 N) return; } - Conn->CallReducerTyped(TEXT("insert_one_u32"), FInsertOneU32Args(N), SetCallReducerFlags); + FInsertOneU32Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_u_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneU32(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneU32(const FReducerEventContext& Context, const UInsertOneU32Reducer* Args) @@ -5820,7 +3988,9 @@ void URemoteReducers::InsertOneU64(const uint64 N) return; } - Conn->CallReducerTyped(TEXT("insert_one_u64"), FInsertOneU64Args(N), SetCallReducerFlags); + FInsertOneU64Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_u_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneU64(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneU64(const FReducerEventContext& Context, const UInsertOneU64Reducer* Args) @@ -5864,7 +4034,9 @@ void URemoteReducers::InsertOneU8(const uint8 N) return; } - Conn->CallReducerTyped(TEXT("insert_one_u8"), FInsertOneU8Args(N), SetCallReducerFlags); + FInsertOneU8Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_u_8"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneU8(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneU8(const FReducerEventContext& Context, const UInsertOneU8Reducer* Args) @@ -5908,7 +4080,9 @@ void URemoteReducers::InsertOneUnitStruct(const FUnitStructType& S) return; } - Conn->CallReducerTyped(TEXT("insert_one_unit_struct"), FInsertOneUnitStructArgs(S), SetCallReducerFlags); + FInsertOneUnitStructArgs ReducerArgs(S); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_unit_struct"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneUnitStruct(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneUnitStruct(const FReducerEventContext& Context, const UInsertOneUnitStructReducer* Args) @@ -5952,7 +4126,9 @@ void URemoteReducers::InsertOneUuid(const FSpacetimeDBUuid& U) return; } - Conn->CallReducerTyped(TEXT("insert_one_uuid"), FInsertOneUuidArgs(U), SetCallReducerFlags); + FInsertOneUuidArgs ReducerArgs(U); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_one_uuid"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOneUuid(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOneUuid(const FReducerEventContext& Context, const UInsertOneUuidReducer* Args) @@ -5996,7 +4172,9 @@ void URemoteReducers::InsertOptionEveryPrimitiveStruct(const FTestClientOptional return; } - Conn->CallReducerTyped(TEXT("insert_option_every_primitive_struct"), FInsertOptionEveryPrimitiveStructArgs(S), SetCallReducerFlags); + FInsertOptionEveryPrimitiveStructArgs ReducerArgs(S); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_option_every_primitive_struct"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOptionEveryPrimitiveStruct(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOptionEveryPrimitiveStruct(const FReducerEventContext& Context, const UInsertOptionEveryPrimitiveStructReducer* Args) @@ -6040,7 +4218,9 @@ void URemoteReducers::InsertOptionI32(const FTestClientOptionalInt32 N) return; } - Conn->CallReducerTyped(TEXT("insert_option_i32"), FInsertOptionI32Args(N), SetCallReducerFlags); + FInsertOptionI32Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_option_i_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOptionI32(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOptionI32(const FReducerEventContext& Context, const UInsertOptionI32Reducer* Args) @@ -6084,7 +4264,9 @@ void URemoteReducers::InsertOptionIdentity(const FTestClientOptionalIdentity& I) return; } - Conn->CallReducerTyped(TEXT("insert_option_identity"), FInsertOptionIdentityArgs(I), SetCallReducerFlags); + FInsertOptionIdentityArgs ReducerArgs(I); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_option_identity"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOptionIdentity(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOptionIdentity(const FReducerEventContext& Context, const UInsertOptionIdentityReducer* Args) @@ -6128,7 +4310,9 @@ void URemoteReducers::InsertOptionSimpleEnum(const FTestClientOptionalSimpleEnum return; } - Conn->CallReducerTyped(TEXT("insert_option_simple_enum"), FInsertOptionSimpleEnumArgs(E), SetCallReducerFlags); + FInsertOptionSimpleEnumArgs ReducerArgs(E); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_option_simple_enum"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOptionSimpleEnum(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOptionSimpleEnum(const FReducerEventContext& Context, const UInsertOptionSimpleEnumReducer* Args) @@ -6172,7 +4356,9 @@ void URemoteReducers::InsertOptionString(const FTestClientOptionalString& S) return; } - Conn->CallReducerTyped(TEXT("insert_option_string"), FInsertOptionStringArgs(S), SetCallReducerFlags); + FInsertOptionStringArgs ReducerArgs(S); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_option_string"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOptionString(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOptionString(const FReducerEventContext& Context, const UInsertOptionStringReducer* Args) @@ -6216,7 +4402,9 @@ void URemoteReducers::InsertOptionUuid(const FTestClientOptionalUuid& U) return; } - Conn->CallReducerTyped(TEXT("insert_option_uuid"), FInsertOptionUuidArgs(U), SetCallReducerFlags); + FInsertOptionUuidArgs ReducerArgs(U); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_option_uuid"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOptionUuid(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOptionUuid(const FReducerEventContext& Context, const UInsertOptionUuidReducer* Args) @@ -6260,7 +4448,9 @@ void URemoteReducers::InsertOptionVecOptionI32(const FTestClientOptionalVecOptio return; } - Conn->CallReducerTyped(TEXT("insert_option_vec_option_i32"), FInsertOptionVecOptionI32Args(V), SetCallReducerFlags); + FInsertOptionVecOptionI32Args ReducerArgs(V); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_option_vec_option_i_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertOptionVecOptionI32(ReducerArgs)); } } bool URemoteReducers::InvokeInsertOptionVecOptionI32(const FReducerEventContext& Context, const UInsertOptionVecOptionI32Reducer* Args) @@ -6304,7 +4494,9 @@ void URemoteReducers::InsertPkBool(const bool B, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_pk_bool"), FInsertPkBoolArgs(B, Data), SetCallReducerFlags); + FInsertPkBoolArgs ReducerArgs(B, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_bool"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkBool(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkBool(const FReducerEventContext& Context, const UInsertPkBoolReducer* Args) @@ -6348,7 +4540,9 @@ void URemoteReducers::InsertPkConnectionId(const FSpacetimeDBConnectionId& A, co return; } - Conn->CallReducerTyped(TEXT("insert_pk_connection_id"), FInsertPkConnectionIdArgs(A, Data), SetCallReducerFlags); + FInsertPkConnectionIdArgs ReducerArgs(A, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_connection_id"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkConnectionId(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkConnectionId(const FReducerEventContext& Context, const UInsertPkConnectionIdReducer* Args) @@ -6392,7 +4586,9 @@ void URemoteReducers::InsertPkI128(const FSpacetimeDBInt128& N, const int32 Data return; } - Conn->CallReducerTyped(TEXT("insert_pk_i128"), FInsertPkI128Args(N, Data), SetCallReducerFlags); + FInsertPkI128Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_i_128"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkI128(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkI128(const FReducerEventContext& Context, const UInsertPkI128Reducer* Args) @@ -6436,7 +4632,9 @@ void URemoteReducers::InsertPkI16(const int16 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_pk_i16"), FInsertPkI16Args(N, Data), SetCallReducerFlags); + FInsertPkI16Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_i_16"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkI16(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkI16(const FReducerEventContext& Context, const UInsertPkI16Reducer* Args) @@ -6480,7 +4678,9 @@ void URemoteReducers::InsertPkI256(const FSpacetimeDBInt256& N, const int32 Data return; } - Conn->CallReducerTyped(TEXT("insert_pk_i256"), FInsertPkI256Args(N, Data), SetCallReducerFlags); + FInsertPkI256Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_i_256"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkI256(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkI256(const FReducerEventContext& Context, const UInsertPkI256Reducer* Args) @@ -6524,7 +4724,9 @@ void URemoteReducers::InsertPkI32(const int32 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_pk_i32"), FInsertPkI32Args(N, Data), SetCallReducerFlags); + FInsertPkI32Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_i_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkI32(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkI32(const FReducerEventContext& Context, const UInsertPkI32Reducer* Args) @@ -6568,7 +4770,9 @@ void URemoteReducers::InsertPkI64(const int64 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_pk_i64"), FInsertPkI64Args(N, Data), SetCallReducerFlags); + FInsertPkI64Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_i_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkI64(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkI64(const FReducerEventContext& Context, const UInsertPkI64Reducer* Args) @@ -6612,7 +4816,9 @@ void URemoteReducers::InsertPkI8(const int8 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_pk_i8"), FInsertPkI8Args(N, Data), SetCallReducerFlags); + FInsertPkI8Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_i_8"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkI8(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkI8(const FReducerEventContext& Context, const UInsertPkI8Reducer* Args) @@ -6656,7 +4862,9 @@ void URemoteReducers::InsertPkIdentity(const FSpacetimeDBIdentity& I, const int3 return; } - Conn->CallReducerTyped(TEXT("insert_pk_identity"), FInsertPkIdentityArgs(I, Data), SetCallReducerFlags); + FInsertPkIdentityArgs ReducerArgs(I, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_identity"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkIdentity(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkIdentity(const FReducerEventContext& Context, const UInsertPkIdentityReducer* Args) @@ -6700,7 +4908,9 @@ void URemoteReducers::InsertPkSimpleEnum(const ESimpleEnumType& A, const int32 D return; } - Conn->CallReducerTyped(TEXT("insert_pk_simple_enum"), FInsertPkSimpleEnumArgs(A, Data), SetCallReducerFlags); + FInsertPkSimpleEnumArgs ReducerArgs(A, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_simple_enum"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkSimpleEnum(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkSimpleEnum(const FReducerEventContext& Context, const UInsertPkSimpleEnumReducer* Args) @@ -6744,7 +4954,9 @@ void URemoteReducers::InsertPkString(const FString& S, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_pk_string"), FInsertPkStringArgs(S, Data), SetCallReducerFlags); + FInsertPkStringArgs ReducerArgs(S, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_string"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkString(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkString(const FReducerEventContext& Context, const UInsertPkStringReducer* Args) @@ -6788,7 +5000,9 @@ void URemoteReducers::InsertPkU128(const FSpacetimeDBUInt128& N, const int32 Dat return; } - Conn->CallReducerTyped(TEXT("insert_pk_u128"), FInsertPkU128Args(N, Data), SetCallReducerFlags); + FInsertPkU128Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_u_128"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkU128(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkU128(const FReducerEventContext& Context, const UInsertPkU128Reducer* Args) @@ -6832,7 +5046,9 @@ void URemoteReducers::InsertPkU16(const uint16 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_pk_u16"), FInsertPkU16Args(N, Data), SetCallReducerFlags); + FInsertPkU16Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_u_16"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkU16(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkU16(const FReducerEventContext& Context, const UInsertPkU16Reducer* Args) @@ -6876,7 +5092,9 @@ void URemoteReducers::InsertPkU256(const FSpacetimeDBUInt256& N, const int32 Dat return; } - Conn->CallReducerTyped(TEXT("insert_pk_u256"), FInsertPkU256Args(N, Data), SetCallReducerFlags); + FInsertPkU256Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_u_256"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkU256(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkU256(const FReducerEventContext& Context, const UInsertPkU256Reducer* Args) @@ -6920,7 +5138,9 @@ void URemoteReducers::InsertPkU32(const uint32 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_pk_u32"), FInsertPkU32Args(N, Data), SetCallReducerFlags); + FInsertPkU32Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_u_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkU32(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkU32(const FReducerEventContext& Context, const UInsertPkU32Reducer* Args) @@ -6964,7 +5184,9 @@ void URemoteReducers::InsertPkU32Two(const uint32 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_pk_u32_two"), FInsertPkU32TwoArgs(N, Data), SetCallReducerFlags); + FInsertPkU32TwoArgs ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_u_32_two"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkU32Two(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkU32Two(const FReducerEventContext& Context, const UInsertPkU32TwoReducer* Args) @@ -7008,7 +5230,9 @@ void URemoteReducers::InsertPkU64(const uint64 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_pk_u64"), FInsertPkU64Args(N, Data), SetCallReducerFlags); + FInsertPkU64Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_u_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkU64(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkU64(const FReducerEventContext& Context, const UInsertPkU64Reducer* Args) @@ -7052,7 +5276,9 @@ void URemoteReducers::InsertPkU8(const uint8 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_pk_u8"), FInsertPkU8Args(N, Data), SetCallReducerFlags); + FInsertPkU8Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_u_8"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkU8(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkU8(const FReducerEventContext& Context, const UInsertPkU8Reducer* Args) @@ -7096,7 +5322,9 @@ void URemoteReducers::InsertPkUuid(const FSpacetimeDBUuid& U, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_pk_uuid"), FInsertPkUuidArgs(U, Data), SetCallReducerFlags); + FInsertPkUuidArgs ReducerArgs(U, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_pk_uuid"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPkUuid(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPkUuid(const FReducerEventContext& Context, const UInsertPkUuidReducer* Args) @@ -7140,7 +5368,9 @@ void URemoteReducers::InsertPrimitivesAsStrings(const FEveryPrimitiveStructType& return; } - Conn->CallReducerTyped(TEXT("insert_primitives_as_strings"), FInsertPrimitivesAsStringsArgs(S), SetCallReducerFlags); + FInsertPrimitivesAsStringsArgs ReducerArgs(S); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_primitives_as_strings"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertPrimitivesAsStrings(ReducerArgs)); } } bool URemoteReducers::InvokeInsertPrimitivesAsStrings(const FReducerEventContext& Context, const UInsertPrimitivesAsStringsReducer* Args) @@ -7184,7 +5414,9 @@ void URemoteReducers::InsertResultEveryPrimitiveStructString(const FTestClientRe return; } - Conn->CallReducerTyped(TEXT("insert_result_every_primitive_struct_string"), FInsertResultEveryPrimitiveStructStringArgs(R), SetCallReducerFlags); + FInsertResultEveryPrimitiveStructStringArgs ReducerArgs(R); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_result_every_primitive_struct_string"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertResultEveryPrimitiveStructString(ReducerArgs)); } } bool URemoteReducers::InvokeInsertResultEveryPrimitiveStructString(const FReducerEventContext& Context, const UInsertResultEveryPrimitiveStructStringReducer* Args) @@ -7228,7 +5460,9 @@ void URemoteReducers::InsertResultI32String(const FTestClientResultInt32String& return; } - Conn->CallReducerTyped(TEXT("insert_result_i32_string"), FInsertResultI32StringArgs(R), SetCallReducerFlags); + FInsertResultI32StringArgs ReducerArgs(R); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_result_i_32_string"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertResultI32String(ReducerArgs)); } } bool URemoteReducers::InvokeInsertResultI32String(const FReducerEventContext& Context, const UInsertResultI32StringReducer* Args) @@ -7272,7 +5506,9 @@ void URemoteReducers::InsertResultIdentityString(const FTestClientResultIdentity return; } - Conn->CallReducerTyped(TEXT("insert_result_identity_string"), FInsertResultIdentityStringArgs(R), SetCallReducerFlags); + FInsertResultIdentityStringArgs ReducerArgs(R); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_result_identity_string"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertResultIdentityString(ReducerArgs)); } } bool URemoteReducers::InvokeInsertResultIdentityString(const FReducerEventContext& Context, const UInsertResultIdentityStringReducer* Args) @@ -7316,7 +5552,9 @@ void URemoteReducers::InsertResultSimpleEnumI32(const FTestClientResultSimpleEnu return; } - Conn->CallReducerTyped(TEXT("insert_result_simple_enum_i32"), FInsertResultSimpleEnumI32Args(R), SetCallReducerFlags); + FInsertResultSimpleEnumI32Args ReducerArgs(R); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_result_simple_enum_i_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertResultSimpleEnumI32(ReducerArgs)); } } bool URemoteReducers::InvokeInsertResultSimpleEnumI32(const FReducerEventContext& Context, const UInsertResultSimpleEnumI32Reducer* Args) @@ -7360,7 +5598,9 @@ void URemoteReducers::InsertResultStringI32(const FTestClientResultStringInt32& return; } - Conn->CallReducerTyped(TEXT("insert_result_string_i32"), FInsertResultStringI32Args(R), SetCallReducerFlags); + FInsertResultStringI32Args ReducerArgs(R); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_result_string_i_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertResultStringI32(ReducerArgs)); } } bool URemoteReducers::InvokeInsertResultStringI32(const FReducerEventContext& Context, const UInsertResultStringI32Reducer* Args) @@ -7404,7 +5644,9 @@ void URemoteReducers::InsertResultVecI32String(const FTestClientResultVecInt32St return; } - Conn->CallReducerTyped(TEXT("insert_result_vec_i32_string"), FInsertResultVecI32StringArgs(R), SetCallReducerFlags); + FInsertResultVecI32StringArgs ReducerArgs(R); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_result_vec_i_32_string"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertResultVecI32String(ReducerArgs)); } } bool URemoteReducers::InvokeInsertResultVecI32String(const FReducerEventContext& Context, const UInsertResultVecI32StringReducer* Args) @@ -7448,7 +5690,9 @@ void URemoteReducers::InsertTableHoldsTable(const FOneU8Type& A, const FVecU8Typ return; } - Conn->CallReducerTyped(TEXT("insert_table_holds_table"), FInsertTableHoldsTableArgs(A, B), SetCallReducerFlags); + FInsertTableHoldsTableArgs ReducerArgs(A, B); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_table_holds_table"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertTableHoldsTable(ReducerArgs)); } } bool URemoteReducers::InvokeInsertTableHoldsTable(const FReducerEventContext& Context, const UInsertTableHoldsTableReducer* Args) @@ -7492,7 +5736,9 @@ void URemoteReducers::InsertUniqueBool(const bool B, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_unique_bool"), FInsertUniqueBoolArgs(B, Data), SetCallReducerFlags); + FInsertUniqueBoolArgs ReducerArgs(B, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_bool"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueBool(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueBool(const FReducerEventContext& Context, const UInsertUniqueBoolReducer* Args) @@ -7536,7 +5782,9 @@ void URemoteReducers::InsertUniqueConnectionId(const FSpacetimeDBConnectionId& A return; } - Conn->CallReducerTyped(TEXT("insert_unique_connection_id"), FInsertUniqueConnectionIdArgs(A, Data), SetCallReducerFlags); + FInsertUniqueConnectionIdArgs ReducerArgs(A, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_connection_id"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueConnectionId(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueConnectionId(const FReducerEventContext& Context, const UInsertUniqueConnectionIdReducer* Args) @@ -7580,7 +5828,9 @@ void URemoteReducers::InsertUniqueI128(const FSpacetimeDBInt128& N, const int32 return; } - Conn->CallReducerTyped(TEXT("insert_unique_i128"), FInsertUniqueI128Args(N, Data), SetCallReducerFlags); + FInsertUniqueI128Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_i_128"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueI128(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueI128(const FReducerEventContext& Context, const UInsertUniqueI128Reducer* Args) @@ -7624,7 +5874,9 @@ void URemoteReducers::InsertUniqueI16(const int16 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_unique_i16"), FInsertUniqueI16Args(N, Data), SetCallReducerFlags); + FInsertUniqueI16Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_i_16"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueI16(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueI16(const FReducerEventContext& Context, const UInsertUniqueI16Reducer* Args) @@ -7668,7 +5920,9 @@ void URemoteReducers::InsertUniqueI256(const FSpacetimeDBInt256& N, const int32 return; } - Conn->CallReducerTyped(TEXT("insert_unique_i256"), FInsertUniqueI256Args(N, Data), SetCallReducerFlags); + FInsertUniqueI256Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_i_256"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueI256(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueI256(const FReducerEventContext& Context, const UInsertUniqueI256Reducer* Args) @@ -7712,7 +5966,9 @@ void URemoteReducers::InsertUniqueI32(const int32 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_unique_i32"), FInsertUniqueI32Args(N, Data), SetCallReducerFlags); + FInsertUniqueI32Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_i_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueI32(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueI32(const FReducerEventContext& Context, const UInsertUniqueI32Reducer* Args) @@ -7756,7 +6012,9 @@ void URemoteReducers::InsertUniqueI64(const int64 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_unique_i64"), FInsertUniqueI64Args(N, Data), SetCallReducerFlags); + FInsertUniqueI64Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_i_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueI64(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueI64(const FReducerEventContext& Context, const UInsertUniqueI64Reducer* Args) @@ -7800,7 +6058,9 @@ void URemoteReducers::InsertUniqueI8(const int8 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_unique_i8"), FInsertUniqueI8Args(N, Data), SetCallReducerFlags); + FInsertUniqueI8Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_i_8"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueI8(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueI8(const FReducerEventContext& Context, const UInsertUniqueI8Reducer* Args) @@ -7844,7 +6104,9 @@ void URemoteReducers::InsertUniqueIdentity(const FSpacetimeDBIdentity& I, const return; } - Conn->CallReducerTyped(TEXT("insert_unique_identity"), FInsertUniqueIdentityArgs(I, Data), SetCallReducerFlags); + FInsertUniqueIdentityArgs ReducerArgs(I, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_identity"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueIdentity(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueIdentity(const FReducerEventContext& Context, const UInsertUniqueIdentityReducer* Args) @@ -7888,7 +6150,9 @@ void URemoteReducers::InsertUniqueString(const FString& S, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_unique_string"), FInsertUniqueStringArgs(S, Data), SetCallReducerFlags); + FInsertUniqueStringArgs ReducerArgs(S, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_string"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueString(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueString(const FReducerEventContext& Context, const UInsertUniqueStringReducer* Args) @@ -7932,7 +6196,9 @@ void URemoteReducers::InsertUniqueU128(const FSpacetimeDBUInt128& N, const int32 return; } - Conn->CallReducerTyped(TEXT("insert_unique_u128"), FInsertUniqueU128Args(N, Data), SetCallReducerFlags); + FInsertUniqueU128Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_u_128"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueU128(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueU128(const FReducerEventContext& Context, const UInsertUniqueU128Reducer* Args) @@ -7976,7 +6242,9 @@ void URemoteReducers::InsertUniqueU16(const uint16 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_unique_u16"), FInsertUniqueU16Args(N, Data), SetCallReducerFlags); + FInsertUniqueU16Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_u_16"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueU16(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueU16(const FReducerEventContext& Context, const UInsertUniqueU16Reducer* Args) @@ -8020,7 +6288,9 @@ void URemoteReducers::InsertUniqueU256(const FSpacetimeDBUInt256& N, const int32 return; } - Conn->CallReducerTyped(TEXT("insert_unique_u256"), FInsertUniqueU256Args(N, Data), SetCallReducerFlags); + FInsertUniqueU256Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_u_256"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueU256(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueU256(const FReducerEventContext& Context, const UInsertUniqueU256Reducer* Args) @@ -8064,7 +6334,9 @@ void URemoteReducers::InsertUniqueU32(const uint32 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_unique_u32"), FInsertUniqueU32Args(N, Data), SetCallReducerFlags); + FInsertUniqueU32Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_u_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueU32(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueU32(const FReducerEventContext& Context, const UInsertUniqueU32Reducer* Args) @@ -8108,7 +6380,9 @@ void URemoteReducers::InsertUniqueU32UpdatePkU32(const uint32 N, const int32 DUn return; } - Conn->CallReducerTyped(TEXT("insert_unique_u32_update_pk_u32"), FInsertUniqueU32UpdatePkU32Args(N, DUnique, DPk), SetCallReducerFlags); + FInsertUniqueU32UpdatePkU32Args ReducerArgs(N, DUnique, DPk); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_u_32_update_pk_u_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueU32UpdatePkU32(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueU32UpdatePkU32(const FReducerEventContext& Context, const UInsertUniqueU32UpdatePkU32Reducer* Args) @@ -8152,7 +6426,9 @@ void URemoteReducers::InsertUniqueU64(const uint64 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_unique_u64"), FInsertUniqueU64Args(N, Data), SetCallReducerFlags); + FInsertUniqueU64Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_u_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueU64(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueU64(const FReducerEventContext& Context, const UInsertUniqueU64Reducer* Args) @@ -8196,7 +6472,9 @@ void URemoteReducers::InsertUniqueU8(const uint8 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("insert_unique_u8"), FInsertUniqueU8Args(N, Data), SetCallReducerFlags); + FInsertUniqueU8Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_u_8"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueU8(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueU8(const FReducerEventContext& Context, const UInsertUniqueU8Reducer* Args) @@ -8240,7 +6518,9 @@ void URemoteReducers::InsertUniqueUuid(const FSpacetimeDBUuid& U, const int32 Da return; } - Conn->CallReducerTyped(TEXT("insert_unique_uuid"), FInsertUniqueUuidArgs(U, Data), SetCallReducerFlags); + FInsertUniqueUuidArgs ReducerArgs(U, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_unique_uuid"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUniqueUuid(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUniqueUuid(const FReducerEventContext& Context, const UInsertUniqueUuidReducer* Args) @@ -8284,7 +6564,9 @@ void URemoteReducers::InsertUser(const FString& Name, const FSpacetimeDBIdentity return; } - Conn->CallReducerTyped(TEXT("insert_user"), FInsertUserArgs(Name, Identity), SetCallReducerFlags); + FInsertUserArgs ReducerArgs(Name, Identity); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_user"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertUser(ReducerArgs)); } } bool URemoteReducers::InvokeInsertUser(const FReducerEventContext& Context, const UInsertUserReducer* Args) @@ -8328,7 +6610,9 @@ void URemoteReducers::InsertVecBool(const TArray& B) return; } - Conn->CallReducerTyped(TEXT("insert_vec_bool"), FInsertVecBoolArgs(B), SetCallReducerFlags); + FInsertVecBoolArgs ReducerArgs(B); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_bool"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecBool(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecBool(const FReducerEventContext& Context, const UInsertVecBoolReducer* Args) @@ -8372,7 +6656,9 @@ void URemoteReducers::InsertVecByteStruct(const TArray& S) return; } - Conn->CallReducerTyped(TEXT("insert_vec_byte_struct"), FInsertVecByteStructArgs(S), SetCallReducerFlags); + FInsertVecByteStructArgs ReducerArgs(S); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_byte_struct"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecByteStruct(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecByteStruct(const FReducerEventContext& Context, const UInsertVecByteStructReducer* Args) @@ -8416,7 +6702,9 @@ void URemoteReducers::InsertVecConnectionId(const TArrayCallReducerTyped(TEXT("insert_vec_connection_id"), FInsertVecConnectionIdArgs(A), SetCallReducerFlags); + FInsertVecConnectionIdArgs ReducerArgs(A); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_connection_id"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecConnectionId(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecConnectionId(const FReducerEventContext& Context, const UInsertVecConnectionIdReducer* Args) @@ -8460,7 +6748,9 @@ void URemoteReducers::InsertVecEnumWithPayload(const TArrayCallReducerTyped(TEXT("insert_vec_enum_with_payload"), FInsertVecEnumWithPayloadArgs(E), SetCallReducerFlags); + FInsertVecEnumWithPayloadArgs ReducerArgs(E); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_enum_with_payload"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecEnumWithPayload(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecEnumWithPayload(const FReducerEventContext& Context, const UInsertVecEnumWithPayloadReducer* Args) @@ -8504,7 +6794,9 @@ void URemoteReducers::InsertVecEveryPrimitiveStruct(const TArrayCallReducerTyped(TEXT("insert_vec_every_primitive_struct"), FInsertVecEveryPrimitiveStructArgs(S), SetCallReducerFlags); + FInsertVecEveryPrimitiveStructArgs ReducerArgs(S); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_every_primitive_struct"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecEveryPrimitiveStruct(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecEveryPrimitiveStruct(const FReducerEventContext& Context, const UInsertVecEveryPrimitiveStructReducer* Args) @@ -8548,7 +6840,9 @@ void URemoteReducers::InsertVecEveryVecStruct(const TArray& return; } - Conn->CallReducerTyped(TEXT("insert_vec_every_vec_struct"), FInsertVecEveryVecStructArgs(S), SetCallReducerFlags); + FInsertVecEveryVecStructArgs ReducerArgs(S); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_every_vec_struct"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecEveryVecStruct(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecEveryVecStruct(const FReducerEventContext& Context, const UInsertVecEveryVecStructReducer* Args) @@ -8592,7 +6886,9 @@ void URemoteReducers::InsertVecF32(const TArray& F) return; } - Conn->CallReducerTyped(TEXT("insert_vec_f32"), FInsertVecF32Args(F), SetCallReducerFlags); + FInsertVecF32Args ReducerArgs(F); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_f_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecF32(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecF32(const FReducerEventContext& Context, const UInsertVecF32Reducer* Args) @@ -8636,7 +6932,9 @@ void URemoteReducers::InsertVecF64(const TArray& F) return; } - Conn->CallReducerTyped(TEXT("insert_vec_f64"), FInsertVecF64Args(F), SetCallReducerFlags); + FInsertVecF64Args ReducerArgs(F); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_f_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecF64(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecF64(const FReducerEventContext& Context, const UInsertVecF64Reducer* Args) @@ -8680,7 +6978,9 @@ void URemoteReducers::InsertVecI128(const TArray& N) return; } - Conn->CallReducerTyped(TEXT("insert_vec_i128"), FInsertVecI128Args(N), SetCallReducerFlags); + FInsertVecI128Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_i_128"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecI128(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecI128(const FReducerEventContext& Context, const UInsertVecI128Reducer* Args) @@ -8724,7 +7024,9 @@ void URemoteReducers::InsertVecI16(const TArray& N) return; } - Conn->CallReducerTyped(TEXT("insert_vec_i16"), FInsertVecI16Args(N), SetCallReducerFlags); + FInsertVecI16Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_i_16"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecI16(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecI16(const FReducerEventContext& Context, const UInsertVecI16Reducer* Args) @@ -8768,7 +7070,9 @@ void URemoteReducers::InsertVecI256(const TArray& N) return; } - Conn->CallReducerTyped(TEXT("insert_vec_i256"), FInsertVecI256Args(N), SetCallReducerFlags); + FInsertVecI256Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_i_256"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecI256(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecI256(const FReducerEventContext& Context, const UInsertVecI256Reducer* Args) @@ -8812,7 +7116,9 @@ void URemoteReducers::InsertVecI32(const TArray& N) return; } - Conn->CallReducerTyped(TEXT("insert_vec_i32"), FInsertVecI32Args(N), SetCallReducerFlags); + FInsertVecI32Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_i_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecI32(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecI32(const FReducerEventContext& Context, const UInsertVecI32Reducer* Args) @@ -8856,7 +7162,9 @@ void URemoteReducers::InsertVecI64(const TArray& N) return; } - Conn->CallReducerTyped(TEXT("insert_vec_i64"), FInsertVecI64Args(N), SetCallReducerFlags); + FInsertVecI64Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_i_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecI64(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecI64(const FReducerEventContext& Context, const UInsertVecI64Reducer* Args) @@ -8900,7 +7208,9 @@ void URemoteReducers::InsertVecI8(const TArray& N) return; } - Conn->CallReducerTyped(TEXT("insert_vec_i8"), FInsertVecI8Args(N), SetCallReducerFlags); + FInsertVecI8Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_i_8"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecI8(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecI8(const FReducerEventContext& Context, const UInsertVecI8Reducer* Args) @@ -8944,7 +7254,9 @@ void URemoteReducers::InsertVecIdentity(const TArray& I) return; } - Conn->CallReducerTyped(TEXT("insert_vec_identity"), FInsertVecIdentityArgs(I), SetCallReducerFlags); + FInsertVecIdentityArgs ReducerArgs(I); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_identity"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecIdentity(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecIdentity(const FReducerEventContext& Context, const UInsertVecIdentityReducer* Args) @@ -8988,7 +7300,9 @@ void URemoteReducers::InsertVecSimpleEnum(const TArray& E) return; } - Conn->CallReducerTyped(TEXT("insert_vec_simple_enum"), FInsertVecSimpleEnumArgs(E), SetCallReducerFlags); + FInsertVecSimpleEnumArgs ReducerArgs(E); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_simple_enum"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecSimpleEnum(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecSimpleEnum(const FReducerEventContext& Context, const UInsertVecSimpleEnumReducer* Args) @@ -9032,7 +7346,9 @@ void URemoteReducers::InsertVecString(const TArray& S) return; } - Conn->CallReducerTyped(TEXT("insert_vec_string"), FInsertVecStringArgs(S), SetCallReducerFlags); + FInsertVecStringArgs ReducerArgs(S); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_string"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecString(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecString(const FReducerEventContext& Context, const UInsertVecStringReducer* Args) @@ -9076,7 +7392,9 @@ void URemoteReducers::InsertVecTimestamp(const TArray& T) return; } - Conn->CallReducerTyped(TEXT("insert_vec_timestamp"), FInsertVecTimestampArgs(T), SetCallReducerFlags); + FInsertVecTimestampArgs ReducerArgs(T); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_timestamp"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecTimestamp(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecTimestamp(const FReducerEventContext& Context, const UInsertVecTimestampReducer* Args) @@ -9120,7 +7438,9 @@ void URemoteReducers::InsertVecU128(const TArray& N) return; } - Conn->CallReducerTyped(TEXT("insert_vec_u128"), FInsertVecU128Args(N), SetCallReducerFlags); + FInsertVecU128Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_u_128"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecU128(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecU128(const FReducerEventContext& Context, const UInsertVecU128Reducer* Args) @@ -9164,7 +7484,9 @@ void URemoteReducers::InsertVecU16(const TArray& N) return; } - Conn->CallReducerTyped(TEXT("insert_vec_u16"), FInsertVecU16Args(N), SetCallReducerFlags); + FInsertVecU16Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_u_16"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecU16(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecU16(const FReducerEventContext& Context, const UInsertVecU16Reducer* Args) @@ -9208,7 +7530,9 @@ void URemoteReducers::InsertVecU256(const TArray& N) return; } - Conn->CallReducerTyped(TEXT("insert_vec_u256"), FInsertVecU256Args(N), SetCallReducerFlags); + FInsertVecU256Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_u_256"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecU256(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecU256(const FReducerEventContext& Context, const UInsertVecU256Reducer* Args) @@ -9252,7 +7576,9 @@ void URemoteReducers::InsertVecU32(const TArray& N) return; } - Conn->CallReducerTyped(TEXT("insert_vec_u32"), FInsertVecU32Args(N), SetCallReducerFlags); + FInsertVecU32Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_u_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecU32(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecU32(const FReducerEventContext& Context, const UInsertVecU32Reducer* Args) @@ -9296,7 +7622,9 @@ void URemoteReducers::InsertVecU64(const TArray& N) return; } - Conn->CallReducerTyped(TEXT("insert_vec_u64"), FInsertVecU64Args(N), SetCallReducerFlags); + FInsertVecU64Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_u_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecU64(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecU64(const FReducerEventContext& Context, const UInsertVecU64Reducer* Args) @@ -9340,7 +7668,9 @@ void URemoteReducers::InsertVecU8(const TArray& N) return; } - Conn->CallReducerTyped(TEXT("insert_vec_u8"), FInsertVecU8Args(N), SetCallReducerFlags); + FInsertVecU8Args ReducerArgs(N); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_u_8"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecU8(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecU8(const FReducerEventContext& Context, const UInsertVecU8Reducer* Args) @@ -9384,7 +7714,9 @@ void URemoteReducers::InsertVecUnitStruct(const TArray& S) return; } - Conn->CallReducerTyped(TEXT("insert_vec_unit_struct"), FInsertVecUnitStructArgs(S), SetCallReducerFlags); + FInsertVecUnitStructArgs ReducerArgs(S); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_unit_struct"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecUnitStruct(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecUnitStruct(const FReducerEventContext& Context, const UInsertVecUnitStructReducer* Args) @@ -9428,7 +7760,9 @@ void URemoteReducers::InsertVecUuid(const TArray& U) return; } - Conn->CallReducerTyped(TEXT("insert_vec_uuid"), FInsertVecUuidArgs(U), SetCallReducerFlags); + FInsertVecUuidArgs ReducerArgs(U); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("insert_vec_uuid"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::InsertVecUuid(ReducerArgs)); } } bool URemoteReducers::InvokeInsertVecUuid(const FReducerEventContext& Context, const UInsertVecUuidReducer* Args) @@ -9472,7 +7806,9 @@ void URemoteReducers::NoOpSucceeds() return; } - Conn->CallReducerTyped(TEXT("no_op_succeeds"), FNoOpSucceedsArgs(), SetCallReducerFlags); + FNoOpSucceedsArgs ReducerArgs; + const uint32 RequestId = Conn->CallReducerTyped(TEXT("no_op_succeeds"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::NoOpSucceeds(ReducerArgs)); } } bool URemoteReducers::InvokeNoOpSucceeds(const FReducerEventContext& Context, const UNoOpSucceedsReducer* Args) @@ -9516,7 +7852,9 @@ void URemoteReducers::SortedUuidsInsert() return; } - Conn->CallReducerTyped(TEXT("sorted_uuids_insert"), FSortedUuidsInsertArgs(), SetCallReducerFlags); + FSortedUuidsInsertArgs ReducerArgs; + const uint32 RequestId = Conn->CallReducerTyped(TEXT("sorted_uuids_insert"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::SortedUuidsInsert(ReducerArgs)); } } bool URemoteReducers::InvokeSortedUuidsInsert(const FReducerEventContext& Context, const USortedUuidsInsertReducer* Args) @@ -9560,7 +7898,9 @@ void URemoteReducers::UpdateIndexedSimpleEnum(const ESimpleEnumType& A, const ES return; } - Conn->CallReducerTyped(TEXT("update_indexed_simple_enum"), FUpdateIndexedSimpleEnumArgs(A, B), SetCallReducerFlags); + FUpdateIndexedSimpleEnumArgs ReducerArgs(A, B); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_indexed_simple_enum"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateIndexedSimpleEnum(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateIndexedSimpleEnum(const FReducerEventContext& Context, const UUpdateIndexedSimpleEnumReducer* Args) @@ -9604,7 +7944,9 @@ void URemoteReducers::UpdatePkBool(const bool B, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_pk_bool"), FUpdatePkBoolArgs(B, Data), SetCallReducerFlags); + FUpdatePkBoolArgs ReducerArgs(B, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_bool"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkBool(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkBool(const FReducerEventContext& Context, const UUpdatePkBoolReducer* Args) @@ -9648,7 +7990,9 @@ void URemoteReducers::UpdatePkConnectionId(const FSpacetimeDBConnectionId& A, co return; } - Conn->CallReducerTyped(TEXT("update_pk_connection_id"), FUpdatePkConnectionIdArgs(A, Data), SetCallReducerFlags); + FUpdatePkConnectionIdArgs ReducerArgs(A, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_connection_id"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkConnectionId(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkConnectionId(const FReducerEventContext& Context, const UUpdatePkConnectionIdReducer* Args) @@ -9692,7 +8036,9 @@ void URemoteReducers::UpdatePkI128(const FSpacetimeDBInt128& N, const int32 Data return; } - Conn->CallReducerTyped(TEXT("update_pk_i128"), FUpdatePkI128Args(N, Data), SetCallReducerFlags); + FUpdatePkI128Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_i_128"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkI128(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkI128(const FReducerEventContext& Context, const UUpdatePkI128Reducer* Args) @@ -9736,7 +8082,9 @@ void URemoteReducers::UpdatePkI16(const int16 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_pk_i16"), FUpdatePkI16Args(N, Data), SetCallReducerFlags); + FUpdatePkI16Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_i_16"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkI16(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkI16(const FReducerEventContext& Context, const UUpdatePkI16Reducer* Args) @@ -9780,7 +8128,9 @@ void URemoteReducers::UpdatePkI256(const FSpacetimeDBInt256& N, const int32 Data return; } - Conn->CallReducerTyped(TEXT("update_pk_i256"), FUpdatePkI256Args(N, Data), SetCallReducerFlags); + FUpdatePkI256Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_i_256"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkI256(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkI256(const FReducerEventContext& Context, const UUpdatePkI256Reducer* Args) @@ -9824,7 +8174,9 @@ void URemoteReducers::UpdatePkI32(const int32 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_pk_i32"), FUpdatePkI32Args(N, Data), SetCallReducerFlags); + FUpdatePkI32Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_i_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkI32(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkI32(const FReducerEventContext& Context, const UUpdatePkI32Reducer* Args) @@ -9868,7 +8220,9 @@ void URemoteReducers::UpdatePkI64(const int64 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_pk_i64"), FUpdatePkI64Args(N, Data), SetCallReducerFlags); + FUpdatePkI64Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_i_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkI64(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkI64(const FReducerEventContext& Context, const UUpdatePkI64Reducer* Args) @@ -9912,7 +8266,9 @@ void URemoteReducers::UpdatePkI8(const int8 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_pk_i8"), FUpdatePkI8Args(N, Data), SetCallReducerFlags); + FUpdatePkI8Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_i_8"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkI8(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkI8(const FReducerEventContext& Context, const UUpdatePkI8Reducer* Args) @@ -9956,7 +8312,9 @@ void URemoteReducers::UpdatePkIdentity(const FSpacetimeDBIdentity& I, const int3 return; } - Conn->CallReducerTyped(TEXT("update_pk_identity"), FUpdatePkIdentityArgs(I, Data), SetCallReducerFlags); + FUpdatePkIdentityArgs ReducerArgs(I, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_identity"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkIdentity(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkIdentity(const FReducerEventContext& Context, const UUpdatePkIdentityReducer* Args) @@ -10000,7 +8358,9 @@ void URemoteReducers::UpdatePkSimpleEnum(const ESimpleEnumType& A, const int32 D return; } - Conn->CallReducerTyped(TEXT("update_pk_simple_enum"), FUpdatePkSimpleEnumArgs(A, Data), SetCallReducerFlags); + FUpdatePkSimpleEnumArgs ReducerArgs(A, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_simple_enum"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkSimpleEnum(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkSimpleEnum(const FReducerEventContext& Context, const UUpdatePkSimpleEnumReducer* Args) @@ -10044,7 +8404,9 @@ void URemoteReducers::UpdatePkString(const FString& S, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_pk_string"), FUpdatePkStringArgs(S, Data), SetCallReducerFlags); + FUpdatePkStringArgs ReducerArgs(S, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_string"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkString(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkString(const FReducerEventContext& Context, const UUpdatePkStringReducer* Args) @@ -10088,7 +8450,9 @@ void URemoteReducers::UpdatePkU128(const FSpacetimeDBUInt128& N, const int32 Dat return; } - Conn->CallReducerTyped(TEXT("update_pk_u128"), FUpdatePkU128Args(N, Data), SetCallReducerFlags); + FUpdatePkU128Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_u_128"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkU128(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkU128(const FReducerEventContext& Context, const UUpdatePkU128Reducer* Args) @@ -10132,7 +8496,9 @@ void URemoteReducers::UpdatePkU16(const uint16 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_pk_u16"), FUpdatePkU16Args(N, Data), SetCallReducerFlags); + FUpdatePkU16Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_u_16"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkU16(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkU16(const FReducerEventContext& Context, const UUpdatePkU16Reducer* Args) @@ -10176,7 +8542,9 @@ void URemoteReducers::UpdatePkU256(const FSpacetimeDBUInt256& N, const int32 Dat return; } - Conn->CallReducerTyped(TEXT("update_pk_u256"), FUpdatePkU256Args(N, Data), SetCallReducerFlags); + FUpdatePkU256Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_u_256"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkU256(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkU256(const FReducerEventContext& Context, const UUpdatePkU256Reducer* Args) @@ -10220,7 +8588,9 @@ void URemoteReducers::UpdatePkU32(const uint32 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_pk_u32"), FUpdatePkU32Args(N, Data), SetCallReducerFlags); + FUpdatePkU32Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_u_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkU32(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkU32(const FReducerEventContext& Context, const UUpdatePkU32Reducer* Args) @@ -10264,7 +8634,9 @@ void URemoteReducers::UpdatePkU32Two(const uint32 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_pk_u32_two"), FUpdatePkU32TwoArgs(N, Data), SetCallReducerFlags); + FUpdatePkU32TwoArgs ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_u_32_two"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkU32Two(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkU32Two(const FReducerEventContext& Context, const UUpdatePkU32TwoReducer* Args) @@ -10308,7 +8680,9 @@ void URemoteReducers::UpdatePkU64(const uint64 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_pk_u64"), FUpdatePkU64Args(N, Data), SetCallReducerFlags); + FUpdatePkU64Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_u_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkU64(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkU64(const FReducerEventContext& Context, const UUpdatePkU64Reducer* Args) @@ -10352,7 +8726,9 @@ void URemoteReducers::UpdatePkU8(const uint8 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_pk_u8"), FUpdatePkU8Args(N, Data), SetCallReducerFlags); + FUpdatePkU8Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_u_8"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkU8(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkU8(const FReducerEventContext& Context, const UUpdatePkU8Reducer* Args) @@ -10396,7 +8772,9 @@ void URemoteReducers::UpdatePkUuid(const FSpacetimeDBUuid& U, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_pk_uuid"), FUpdatePkUuidArgs(U, Data), SetCallReducerFlags); + FUpdatePkUuidArgs ReducerArgs(U, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_pk_uuid"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePkUuid(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePkUuid(const FReducerEventContext& Context, const UUpdatePkUuidReducer* Args) @@ -10440,7 +8818,9 @@ void URemoteReducers::UpdateUniqueBool(const bool B, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_unique_bool"), FUpdateUniqueBoolArgs(B, Data), SetCallReducerFlags); + FUpdateUniqueBoolArgs ReducerArgs(B, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_unique_bool"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateUniqueBool(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateUniqueBool(const FReducerEventContext& Context, const UUpdateUniqueBoolReducer* Args) @@ -10484,7 +8864,9 @@ void URemoteReducers::UpdateUniqueConnectionId(const FSpacetimeDBConnectionId& A return; } - Conn->CallReducerTyped(TEXT("update_unique_connection_id"), FUpdateUniqueConnectionIdArgs(A, Data), SetCallReducerFlags); + FUpdateUniqueConnectionIdArgs ReducerArgs(A, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_unique_connection_id"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateUniqueConnectionId(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateUniqueConnectionId(const FReducerEventContext& Context, const UUpdateUniqueConnectionIdReducer* Args) @@ -10528,7 +8910,9 @@ void URemoteReducers::UpdateUniqueI128(const FSpacetimeDBInt128& N, const int32 return; } - Conn->CallReducerTyped(TEXT("update_unique_i128"), FUpdateUniqueI128Args(N, Data), SetCallReducerFlags); + FUpdateUniqueI128Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_unique_i_128"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateUniqueI128(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateUniqueI128(const FReducerEventContext& Context, const UUpdateUniqueI128Reducer* Args) @@ -10572,7 +8956,9 @@ void URemoteReducers::UpdateUniqueI16(const int16 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_unique_i16"), FUpdateUniqueI16Args(N, Data), SetCallReducerFlags); + FUpdateUniqueI16Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_unique_i_16"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateUniqueI16(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateUniqueI16(const FReducerEventContext& Context, const UUpdateUniqueI16Reducer* Args) @@ -10616,7 +9002,9 @@ void URemoteReducers::UpdateUniqueI256(const FSpacetimeDBInt256& N, const int32 return; } - Conn->CallReducerTyped(TEXT("update_unique_i256"), FUpdateUniqueI256Args(N, Data), SetCallReducerFlags); + FUpdateUniqueI256Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_unique_i_256"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateUniqueI256(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateUniqueI256(const FReducerEventContext& Context, const UUpdateUniqueI256Reducer* Args) @@ -10660,7 +9048,9 @@ void URemoteReducers::UpdateUniqueI32(const int32 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_unique_i32"), FUpdateUniqueI32Args(N, Data), SetCallReducerFlags); + FUpdateUniqueI32Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_unique_i_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateUniqueI32(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateUniqueI32(const FReducerEventContext& Context, const UUpdateUniqueI32Reducer* Args) @@ -10704,7 +9094,9 @@ void URemoteReducers::UpdateUniqueI64(const int64 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_unique_i64"), FUpdateUniqueI64Args(N, Data), SetCallReducerFlags); + FUpdateUniqueI64Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_unique_i_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateUniqueI64(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateUniqueI64(const FReducerEventContext& Context, const UUpdateUniqueI64Reducer* Args) @@ -10748,7 +9140,9 @@ void URemoteReducers::UpdateUniqueI8(const int8 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_unique_i8"), FUpdateUniqueI8Args(N, Data), SetCallReducerFlags); + FUpdateUniqueI8Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_unique_i_8"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateUniqueI8(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateUniqueI8(const FReducerEventContext& Context, const UUpdateUniqueI8Reducer* Args) @@ -10792,7 +9186,9 @@ void URemoteReducers::UpdateUniqueIdentity(const FSpacetimeDBIdentity& I, const return; } - Conn->CallReducerTyped(TEXT("update_unique_identity"), FUpdateUniqueIdentityArgs(I, Data), SetCallReducerFlags); + FUpdateUniqueIdentityArgs ReducerArgs(I, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_unique_identity"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateUniqueIdentity(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateUniqueIdentity(const FReducerEventContext& Context, const UUpdateUniqueIdentityReducer* Args) @@ -10836,7 +9232,9 @@ void URemoteReducers::UpdateUniqueString(const FString& S, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_unique_string"), FUpdateUniqueStringArgs(S, Data), SetCallReducerFlags); + FUpdateUniqueStringArgs ReducerArgs(S, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_unique_string"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateUniqueString(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateUniqueString(const FReducerEventContext& Context, const UUpdateUniqueStringReducer* Args) @@ -10880,7 +9278,9 @@ void URemoteReducers::UpdateUniqueU128(const FSpacetimeDBUInt128& N, const int32 return; } - Conn->CallReducerTyped(TEXT("update_unique_u128"), FUpdateUniqueU128Args(N, Data), SetCallReducerFlags); + FUpdateUniqueU128Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_unique_u_128"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateUniqueU128(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateUniqueU128(const FReducerEventContext& Context, const UUpdateUniqueU128Reducer* Args) @@ -10924,7 +9324,9 @@ void URemoteReducers::UpdateUniqueU16(const uint16 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_unique_u16"), FUpdateUniqueU16Args(N, Data), SetCallReducerFlags); + FUpdateUniqueU16Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_unique_u_16"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateUniqueU16(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateUniqueU16(const FReducerEventContext& Context, const UUpdateUniqueU16Reducer* Args) @@ -10968,7 +9370,9 @@ void URemoteReducers::UpdateUniqueU256(const FSpacetimeDBUInt256& N, const int32 return; } - Conn->CallReducerTyped(TEXT("update_unique_u256"), FUpdateUniqueU256Args(N, Data), SetCallReducerFlags); + FUpdateUniqueU256Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_unique_u_256"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateUniqueU256(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateUniqueU256(const FReducerEventContext& Context, const UUpdateUniqueU256Reducer* Args) @@ -11012,7 +9416,9 @@ void URemoteReducers::UpdateUniqueU32(const uint32 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_unique_u32"), FUpdateUniqueU32Args(N, Data), SetCallReducerFlags); + FUpdateUniqueU32Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_unique_u_32"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateUniqueU32(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateUniqueU32(const FReducerEventContext& Context, const UUpdateUniqueU32Reducer* Args) @@ -11056,7 +9462,9 @@ void URemoteReducers::UpdateUniqueU64(const uint64 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_unique_u64"), FUpdateUniqueU64Args(N, Data), SetCallReducerFlags); + FUpdateUniqueU64Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_unique_u_64"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateUniqueU64(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateUniqueU64(const FReducerEventContext& Context, const UUpdateUniqueU64Reducer* Args) @@ -11100,7 +9508,9 @@ void URemoteReducers::UpdateUniqueU8(const uint8 N, const int32 Data) return; } - Conn->CallReducerTyped(TEXT("update_unique_u8"), FUpdateUniqueU8Args(N, Data), SetCallReducerFlags); + FUpdateUniqueU8Args ReducerArgs(N, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_unique_u_8"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateUniqueU8(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateUniqueU8(const FReducerEventContext& Context, const UUpdateUniqueU8Reducer* Args) @@ -11144,7 +9554,9 @@ void URemoteReducers::UpdateUniqueUuid(const FSpacetimeDBUuid& U, const int32 Da return; } - Conn->CallReducerTyped(TEXT("update_unique_uuid"), FUpdateUniqueUuidArgs(U, Data), SetCallReducerFlags); + FUpdateUniqueUuidArgs ReducerArgs(U, Data); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_unique_uuid"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdateUniqueUuid(ReducerArgs)); } } bool URemoteReducers::InvokeUpdateUniqueUuid(const FReducerEventContext& Context, const UUpdateUniqueUuidReducer* Args) @@ -11215,11 +9627,45 @@ void UDbConnection::OnUnhandledProcedureErrorHandler(const FProcedureEventContex } } +void UDbConnection::RegisterPendingTypedReducer(uint32 RequestId, FReducer Reducer) +{ + Reducer.RequestId = RequestId; + PendingTypedReducers.Add(RequestId, MoveTemp(Reducer)); +} + +bool UDbConnection::TryGetPendingTypedReducer(uint32 RequestId, FReducer& OutReducer) const +{ + if (const FReducer* Found = PendingTypedReducers.Find(RequestId)) + { + OutReducer = *Found; + return true; + } + return false; +} + +bool UDbConnection::TryTakePendingTypedReducer(uint32 RequestId, FReducer& OutReducer) +{ + if (FReducer* Found = PendingTypedReducers.Find(RequestId)) + { + OutReducer = *Found; + PendingTypedReducers.Remove(RequestId); + return true; + } + return false; +} + void UDbConnection::ReducerEvent(const FReducerEvent& Event) { if (!Reducers) { return; } - FReducer DecodedReducer = DecodeReducer(Event); + FReducer DecodedReducer; + if (!TryTakePendingTypedReducer(Event.RequestId, DecodedReducer)) + { + const FString ErrorMessage = FString::Printf(TEXT("Reducer result for unknown request_id %u"), Event.RequestId); + UE_LOG(LogTemp, Error, TEXT("%s"), *ErrorMessage); + ReducerEventFailed(Event, ErrorMessage); + return; + } FTestClientReducerEvent ReducerEvent; ReducerEvent.CallerConnectionId = Event.CallerConnectionId; @@ -11231,10 +9677,10 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) FReducerEventContext Context(this, ReducerEvent); - // Use hardcoded string matching for reducer dispatching - const FString& ReducerName = Event.ReducerCall.ReducerName; + // Dispatch by typed reducer metadata + const FString& ReducerName = ReducerEvent.Reducer.ReducerName; - if (ReducerName == TEXT("delete_from_btree_u32")) + if (ReducerName == TEXT("delete_from_btree_u_32")) { FDeleteFromBtreeU32Args Args = ReducerEvent.Reducer.GetAsDeleteFromBtreeU32(); Reducers->InvokeDeleteFromBtreeU32WithArgs(Context, Args); @@ -11258,37 +9704,37 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeDeletePkConnectionIdWithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_pk_i128")) + if (ReducerName == TEXT("delete_pk_i_128")) { FDeletePkI128Args Args = ReducerEvent.Reducer.GetAsDeletePkI128(); Reducers->InvokeDeletePkI128WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_pk_i16")) + if (ReducerName == TEXT("delete_pk_i_16")) { FDeletePkI16Args Args = ReducerEvent.Reducer.GetAsDeletePkI16(); Reducers->InvokeDeletePkI16WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_pk_i256")) + if (ReducerName == TEXT("delete_pk_i_256")) { FDeletePkI256Args Args = ReducerEvent.Reducer.GetAsDeletePkI256(); Reducers->InvokeDeletePkI256WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_pk_i32")) + if (ReducerName == TEXT("delete_pk_i_32")) { FDeletePkI32Args Args = ReducerEvent.Reducer.GetAsDeletePkI32(); Reducers->InvokeDeletePkI32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_pk_i64")) + if (ReducerName == TEXT("delete_pk_i_64")) { FDeletePkI64Args Args = ReducerEvent.Reducer.GetAsDeletePkI64(); Reducers->InvokeDeletePkI64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_pk_i8")) + if (ReducerName == TEXT("delete_pk_i_8")) { FDeletePkI8Args Args = ReducerEvent.Reducer.GetAsDeletePkI8(); Reducers->InvokeDeletePkI8WithArgs(Context, Args); @@ -11306,49 +9752,49 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeDeletePkStringWithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_pk_u128")) + if (ReducerName == TEXT("delete_pk_u_128")) { FDeletePkU128Args Args = ReducerEvent.Reducer.GetAsDeletePkU128(); Reducers->InvokeDeletePkU128WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_pk_u16")) + if (ReducerName == TEXT("delete_pk_u_16")) { FDeletePkU16Args Args = ReducerEvent.Reducer.GetAsDeletePkU16(); Reducers->InvokeDeletePkU16WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_pk_u256")) + if (ReducerName == TEXT("delete_pk_u_256")) { FDeletePkU256Args Args = ReducerEvent.Reducer.GetAsDeletePkU256(); Reducers->InvokeDeletePkU256WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_pk_u32")) + if (ReducerName == TEXT("delete_pk_u_32")) { FDeletePkU32Args Args = ReducerEvent.Reducer.GetAsDeletePkU32(); Reducers->InvokeDeletePkU32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_pk_u32_insert_pk_u32_two")) + if (ReducerName == TEXT("delete_pk_u_32_insert_pk_u_32_two")) { FDeletePkU32InsertPkU32TwoArgs Args = ReducerEvent.Reducer.GetAsDeletePkU32InsertPkU32Two(); Reducers->InvokeDeletePkU32InsertPkU32TwoWithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_pk_u32_two")) + if (ReducerName == TEXT("delete_pk_u_32_two")) { FDeletePkU32TwoArgs Args = ReducerEvent.Reducer.GetAsDeletePkU32Two(); Reducers->InvokeDeletePkU32TwoWithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_pk_u64")) + if (ReducerName == TEXT("delete_pk_u_64")) { FDeletePkU64Args Args = ReducerEvent.Reducer.GetAsDeletePkU64(); Reducers->InvokeDeletePkU64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_pk_u8")) + if (ReducerName == TEXT("delete_pk_u_8")) { FDeletePkU8Args Args = ReducerEvent.Reducer.GetAsDeletePkU8(); Reducers->InvokeDeletePkU8WithArgs(Context, Args); @@ -11372,37 +9818,37 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeDeleteUniqueConnectionIdWithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_unique_i128")) + if (ReducerName == TEXT("delete_unique_i_128")) { FDeleteUniqueI128Args Args = ReducerEvent.Reducer.GetAsDeleteUniqueI128(); Reducers->InvokeDeleteUniqueI128WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_unique_i16")) + if (ReducerName == TEXT("delete_unique_i_16")) { FDeleteUniqueI16Args Args = ReducerEvent.Reducer.GetAsDeleteUniqueI16(); Reducers->InvokeDeleteUniqueI16WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_unique_i256")) + if (ReducerName == TEXT("delete_unique_i_256")) { FDeleteUniqueI256Args Args = ReducerEvent.Reducer.GetAsDeleteUniqueI256(); Reducers->InvokeDeleteUniqueI256WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_unique_i32")) + if (ReducerName == TEXT("delete_unique_i_32")) { FDeleteUniqueI32Args Args = ReducerEvent.Reducer.GetAsDeleteUniqueI32(); Reducers->InvokeDeleteUniqueI32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_unique_i64")) + if (ReducerName == TEXT("delete_unique_i_64")) { FDeleteUniqueI64Args Args = ReducerEvent.Reducer.GetAsDeleteUniqueI64(); Reducers->InvokeDeleteUniqueI64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_unique_i8")) + if (ReducerName == TEXT("delete_unique_i_8")) { FDeleteUniqueI8Args Args = ReducerEvent.Reducer.GetAsDeleteUniqueI8(); Reducers->InvokeDeleteUniqueI8WithArgs(Context, Args); @@ -11420,37 +9866,37 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeDeleteUniqueStringWithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_unique_u128")) + if (ReducerName == TEXT("delete_unique_u_128")) { FDeleteUniqueU128Args Args = ReducerEvent.Reducer.GetAsDeleteUniqueU128(); Reducers->InvokeDeleteUniqueU128WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_unique_u16")) + if (ReducerName == TEXT("delete_unique_u_16")) { FDeleteUniqueU16Args Args = ReducerEvent.Reducer.GetAsDeleteUniqueU16(); Reducers->InvokeDeleteUniqueU16WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_unique_u256")) + if (ReducerName == TEXT("delete_unique_u_256")) { FDeleteUniqueU256Args Args = ReducerEvent.Reducer.GetAsDeleteUniqueU256(); Reducers->InvokeDeleteUniqueU256WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_unique_u32")) + if (ReducerName == TEXT("delete_unique_u_32")) { FDeleteUniqueU32Args Args = ReducerEvent.Reducer.GetAsDeleteUniqueU32(); Reducers->InvokeDeleteUniqueU32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_unique_u64")) + if (ReducerName == TEXT("delete_unique_u_64")) { FDeleteUniqueU64Args Args = ReducerEvent.Reducer.GetAsDeleteUniqueU64(); Reducers->InvokeDeleteUniqueU64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("delete_unique_u8")) + if (ReducerName == TEXT("delete_unique_u_8")) { FDeleteUniqueU8Args Args = ReducerEvent.Reducer.GetAsDeleteUniqueU8(); Reducers->InvokeDeleteUniqueU8WithArgs(Context, Args); @@ -11468,13 +9914,13 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeInsertCallTimestampWithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_call_uuid_v4")) + if (ReducerName == TEXT("insert_call_uuid_v_4")) { FInsertCallUuidV4Args Args = ReducerEvent.Reducer.GetAsInsertCallUuidV4(); Reducers->InvokeInsertCallUuidV4WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_call_uuid_v7")) + if (ReducerName == TEXT("insert_call_uuid_v_7")) { FInsertCallUuidV7Args Args = ReducerEvent.Reducer.GetAsInsertCallUuidV7(); Reducers->InvokeInsertCallUuidV7WithArgs(Context, Args); @@ -11528,7 +9974,7 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeInsertCallerVecIdentityWithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_into_btree_u32")) + if (ReducerName == TEXT("insert_into_btree_u_32")) { FInsertIntoBtreeU32Args Args = ReducerEvent.Reducer.GetAsInsertIntoBtreeU32(); Reducers->InvokeInsertIntoBtreeU32WithArgs(Context, Args); @@ -11540,7 +9986,7 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeInsertIntoIndexedSimpleEnumWithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_into_pk_btree_u32")) + if (ReducerName == TEXT("insert_into_pk_btree_u_32")) { FInsertIntoPkBtreeU32Args Args = ReducerEvent.Reducer.GetAsInsertIntoPkBtreeU32(); Reducers->InvokeInsertIntoPkBtreeU32WithArgs(Context, Args); @@ -11588,49 +10034,49 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeInsertOneEveryVecStructWithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_one_f32")) + if (ReducerName == TEXT("insert_one_f_32")) { FInsertOneF32Args Args = ReducerEvent.Reducer.GetAsInsertOneF32(); Reducers->InvokeInsertOneF32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_one_f64")) + if (ReducerName == TEXT("insert_one_f_64")) { FInsertOneF64Args Args = ReducerEvent.Reducer.GetAsInsertOneF64(); Reducers->InvokeInsertOneF64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_one_i128")) + if (ReducerName == TEXT("insert_one_i_128")) { FInsertOneI128Args Args = ReducerEvent.Reducer.GetAsInsertOneI128(); Reducers->InvokeInsertOneI128WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_one_i16")) + if (ReducerName == TEXT("insert_one_i_16")) { FInsertOneI16Args Args = ReducerEvent.Reducer.GetAsInsertOneI16(); Reducers->InvokeInsertOneI16WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_one_i256")) + if (ReducerName == TEXT("insert_one_i_256")) { FInsertOneI256Args Args = ReducerEvent.Reducer.GetAsInsertOneI256(); Reducers->InvokeInsertOneI256WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_one_i32")) + if (ReducerName == TEXT("insert_one_i_32")) { FInsertOneI32Args Args = ReducerEvent.Reducer.GetAsInsertOneI32(); Reducers->InvokeInsertOneI32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_one_i64")) + if (ReducerName == TEXT("insert_one_i_64")) { FInsertOneI64Args Args = ReducerEvent.Reducer.GetAsInsertOneI64(); Reducers->InvokeInsertOneI64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_one_i8")) + if (ReducerName == TEXT("insert_one_i_8")) { FInsertOneI8Args Args = ReducerEvent.Reducer.GetAsInsertOneI8(); Reducers->InvokeInsertOneI8WithArgs(Context, Args); @@ -11660,37 +10106,37 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeInsertOneTimestampWithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_one_u128")) + if (ReducerName == TEXT("insert_one_u_128")) { FInsertOneU128Args Args = ReducerEvent.Reducer.GetAsInsertOneU128(); Reducers->InvokeInsertOneU128WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_one_u16")) + if (ReducerName == TEXT("insert_one_u_16")) { FInsertOneU16Args Args = ReducerEvent.Reducer.GetAsInsertOneU16(); Reducers->InvokeInsertOneU16WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_one_u256")) + if (ReducerName == TEXT("insert_one_u_256")) { FInsertOneU256Args Args = ReducerEvent.Reducer.GetAsInsertOneU256(); Reducers->InvokeInsertOneU256WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_one_u32")) + if (ReducerName == TEXT("insert_one_u_32")) { FInsertOneU32Args Args = ReducerEvent.Reducer.GetAsInsertOneU32(); Reducers->InvokeInsertOneU32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_one_u64")) + if (ReducerName == TEXT("insert_one_u_64")) { FInsertOneU64Args Args = ReducerEvent.Reducer.GetAsInsertOneU64(); Reducers->InvokeInsertOneU64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_one_u8")) + if (ReducerName == TEXT("insert_one_u_8")) { FInsertOneU8Args Args = ReducerEvent.Reducer.GetAsInsertOneU8(); Reducers->InvokeInsertOneU8WithArgs(Context, Args); @@ -11714,7 +10160,7 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeInsertOptionEveryPrimitiveStructWithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_option_i32")) + if (ReducerName == TEXT("insert_option_i_32")) { FInsertOptionI32Args Args = ReducerEvent.Reducer.GetAsInsertOptionI32(); Reducers->InvokeInsertOptionI32WithArgs(Context, Args); @@ -11744,7 +10190,7 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeInsertOptionUuidWithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_option_vec_option_i32")) + if (ReducerName == TEXT("insert_option_vec_option_i_32")) { FInsertOptionVecOptionI32Args Args = ReducerEvent.Reducer.GetAsInsertOptionVecOptionI32(); Reducers->InvokeInsertOptionVecOptionI32WithArgs(Context, Args); @@ -11762,37 +10208,37 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeInsertPkConnectionIdWithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_pk_i128")) + if (ReducerName == TEXT("insert_pk_i_128")) { FInsertPkI128Args Args = ReducerEvent.Reducer.GetAsInsertPkI128(); Reducers->InvokeInsertPkI128WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_pk_i16")) + if (ReducerName == TEXT("insert_pk_i_16")) { FInsertPkI16Args Args = ReducerEvent.Reducer.GetAsInsertPkI16(); Reducers->InvokeInsertPkI16WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_pk_i256")) + if (ReducerName == TEXT("insert_pk_i_256")) { FInsertPkI256Args Args = ReducerEvent.Reducer.GetAsInsertPkI256(); Reducers->InvokeInsertPkI256WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_pk_i32")) + if (ReducerName == TEXT("insert_pk_i_32")) { FInsertPkI32Args Args = ReducerEvent.Reducer.GetAsInsertPkI32(); Reducers->InvokeInsertPkI32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_pk_i64")) + if (ReducerName == TEXT("insert_pk_i_64")) { FInsertPkI64Args Args = ReducerEvent.Reducer.GetAsInsertPkI64(); Reducers->InvokeInsertPkI64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_pk_i8")) + if (ReducerName == TEXT("insert_pk_i_8")) { FInsertPkI8Args Args = ReducerEvent.Reducer.GetAsInsertPkI8(); Reducers->InvokeInsertPkI8WithArgs(Context, Args); @@ -11816,43 +10262,43 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeInsertPkStringWithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_pk_u128")) + if (ReducerName == TEXT("insert_pk_u_128")) { FInsertPkU128Args Args = ReducerEvent.Reducer.GetAsInsertPkU128(); Reducers->InvokeInsertPkU128WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_pk_u16")) + if (ReducerName == TEXT("insert_pk_u_16")) { FInsertPkU16Args Args = ReducerEvent.Reducer.GetAsInsertPkU16(); Reducers->InvokeInsertPkU16WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_pk_u256")) + if (ReducerName == TEXT("insert_pk_u_256")) { FInsertPkU256Args Args = ReducerEvent.Reducer.GetAsInsertPkU256(); Reducers->InvokeInsertPkU256WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_pk_u32")) + if (ReducerName == TEXT("insert_pk_u_32")) { FInsertPkU32Args Args = ReducerEvent.Reducer.GetAsInsertPkU32(); Reducers->InvokeInsertPkU32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_pk_u32_two")) + if (ReducerName == TEXT("insert_pk_u_32_two")) { FInsertPkU32TwoArgs Args = ReducerEvent.Reducer.GetAsInsertPkU32Two(); Reducers->InvokeInsertPkU32TwoWithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_pk_u64")) + if (ReducerName == TEXT("insert_pk_u_64")) { FInsertPkU64Args Args = ReducerEvent.Reducer.GetAsInsertPkU64(); Reducers->InvokeInsertPkU64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_pk_u8")) + if (ReducerName == TEXT("insert_pk_u_8")) { FInsertPkU8Args Args = ReducerEvent.Reducer.GetAsInsertPkU8(); Reducers->InvokeInsertPkU8WithArgs(Context, Args); @@ -11876,7 +10322,7 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeInsertResultEveryPrimitiveStructStringWithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_result_i32_string")) + if (ReducerName == TEXT("insert_result_i_32_string")) { FInsertResultI32StringArgs Args = ReducerEvent.Reducer.GetAsInsertResultI32String(); Reducers->InvokeInsertResultI32StringWithArgs(Context, Args); @@ -11888,19 +10334,19 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeInsertResultIdentityStringWithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_result_simple_enum_i32")) + if (ReducerName == TEXT("insert_result_simple_enum_i_32")) { FInsertResultSimpleEnumI32Args Args = ReducerEvent.Reducer.GetAsInsertResultSimpleEnumI32(); Reducers->InvokeInsertResultSimpleEnumI32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_result_string_i32")) + if (ReducerName == TEXT("insert_result_string_i_32")) { FInsertResultStringI32Args Args = ReducerEvent.Reducer.GetAsInsertResultStringI32(); Reducers->InvokeInsertResultStringI32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_result_vec_i32_string")) + if (ReducerName == TEXT("insert_result_vec_i_32_string")) { FInsertResultVecI32StringArgs Args = ReducerEvent.Reducer.GetAsInsertResultVecI32String(); Reducers->InvokeInsertResultVecI32StringWithArgs(Context, Args); @@ -11924,37 +10370,37 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeInsertUniqueConnectionIdWithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_unique_i128")) + if (ReducerName == TEXT("insert_unique_i_128")) { FInsertUniqueI128Args Args = ReducerEvent.Reducer.GetAsInsertUniqueI128(); Reducers->InvokeInsertUniqueI128WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_unique_i16")) + if (ReducerName == TEXT("insert_unique_i_16")) { FInsertUniqueI16Args Args = ReducerEvent.Reducer.GetAsInsertUniqueI16(); Reducers->InvokeInsertUniqueI16WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_unique_i256")) + if (ReducerName == TEXT("insert_unique_i_256")) { FInsertUniqueI256Args Args = ReducerEvent.Reducer.GetAsInsertUniqueI256(); Reducers->InvokeInsertUniqueI256WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_unique_i32")) + if (ReducerName == TEXT("insert_unique_i_32")) { FInsertUniqueI32Args Args = ReducerEvent.Reducer.GetAsInsertUniqueI32(); Reducers->InvokeInsertUniqueI32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_unique_i64")) + if (ReducerName == TEXT("insert_unique_i_64")) { FInsertUniqueI64Args Args = ReducerEvent.Reducer.GetAsInsertUniqueI64(); Reducers->InvokeInsertUniqueI64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_unique_i8")) + if (ReducerName == TEXT("insert_unique_i_8")) { FInsertUniqueI8Args Args = ReducerEvent.Reducer.GetAsInsertUniqueI8(); Reducers->InvokeInsertUniqueI8WithArgs(Context, Args); @@ -11972,43 +10418,43 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeInsertUniqueStringWithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_unique_u128")) + if (ReducerName == TEXT("insert_unique_u_128")) { FInsertUniqueU128Args Args = ReducerEvent.Reducer.GetAsInsertUniqueU128(); Reducers->InvokeInsertUniqueU128WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_unique_u16")) + if (ReducerName == TEXT("insert_unique_u_16")) { FInsertUniqueU16Args Args = ReducerEvent.Reducer.GetAsInsertUniqueU16(); Reducers->InvokeInsertUniqueU16WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_unique_u256")) + if (ReducerName == TEXT("insert_unique_u_256")) { FInsertUniqueU256Args Args = ReducerEvent.Reducer.GetAsInsertUniqueU256(); Reducers->InvokeInsertUniqueU256WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_unique_u32")) + if (ReducerName == TEXT("insert_unique_u_32")) { FInsertUniqueU32Args Args = ReducerEvent.Reducer.GetAsInsertUniqueU32(); Reducers->InvokeInsertUniqueU32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_unique_u32_update_pk_u32")) + if (ReducerName == TEXT("insert_unique_u_32_update_pk_u_32")) { FInsertUniqueU32UpdatePkU32Args Args = ReducerEvent.Reducer.GetAsInsertUniqueU32UpdatePkU32(); Reducers->InvokeInsertUniqueU32UpdatePkU32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_unique_u64")) + if (ReducerName == TEXT("insert_unique_u_64")) { FInsertUniqueU64Args Args = ReducerEvent.Reducer.GetAsInsertUniqueU64(); Reducers->InvokeInsertUniqueU64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_unique_u8")) + if (ReducerName == TEXT("insert_unique_u_8")) { FInsertUniqueU8Args Args = ReducerEvent.Reducer.GetAsInsertUniqueU8(); Reducers->InvokeInsertUniqueU8WithArgs(Context, Args); @@ -12062,49 +10508,49 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeInsertVecEveryVecStructWithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_vec_f32")) + if (ReducerName == TEXT("insert_vec_f_32")) { FInsertVecF32Args Args = ReducerEvent.Reducer.GetAsInsertVecF32(); Reducers->InvokeInsertVecF32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_vec_f64")) + if (ReducerName == TEXT("insert_vec_f_64")) { FInsertVecF64Args Args = ReducerEvent.Reducer.GetAsInsertVecF64(); Reducers->InvokeInsertVecF64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_vec_i128")) + if (ReducerName == TEXT("insert_vec_i_128")) { FInsertVecI128Args Args = ReducerEvent.Reducer.GetAsInsertVecI128(); Reducers->InvokeInsertVecI128WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_vec_i16")) + if (ReducerName == TEXT("insert_vec_i_16")) { FInsertVecI16Args Args = ReducerEvent.Reducer.GetAsInsertVecI16(); Reducers->InvokeInsertVecI16WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_vec_i256")) + if (ReducerName == TEXT("insert_vec_i_256")) { FInsertVecI256Args Args = ReducerEvent.Reducer.GetAsInsertVecI256(); Reducers->InvokeInsertVecI256WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_vec_i32")) + if (ReducerName == TEXT("insert_vec_i_32")) { FInsertVecI32Args Args = ReducerEvent.Reducer.GetAsInsertVecI32(); Reducers->InvokeInsertVecI32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_vec_i64")) + if (ReducerName == TEXT("insert_vec_i_64")) { FInsertVecI64Args Args = ReducerEvent.Reducer.GetAsInsertVecI64(); Reducers->InvokeInsertVecI64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_vec_i8")) + if (ReducerName == TEXT("insert_vec_i_8")) { FInsertVecI8Args Args = ReducerEvent.Reducer.GetAsInsertVecI8(); Reducers->InvokeInsertVecI8WithArgs(Context, Args); @@ -12134,37 +10580,37 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeInsertVecTimestampWithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_vec_u128")) + if (ReducerName == TEXT("insert_vec_u_128")) { FInsertVecU128Args Args = ReducerEvent.Reducer.GetAsInsertVecU128(); Reducers->InvokeInsertVecU128WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_vec_u16")) + if (ReducerName == TEXT("insert_vec_u_16")) { FInsertVecU16Args Args = ReducerEvent.Reducer.GetAsInsertVecU16(); Reducers->InvokeInsertVecU16WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_vec_u256")) + if (ReducerName == TEXT("insert_vec_u_256")) { FInsertVecU256Args Args = ReducerEvent.Reducer.GetAsInsertVecU256(); Reducers->InvokeInsertVecU256WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_vec_u32")) + if (ReducerName == TEXT("insert_vec_u_32")) { FInsertVecU32Args Args = ReducerEvent.Reducer.GetAsInsertVecU32(); Reducers->InvokeInsertVecU32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_vec_u64")) + if (ReducerName == TEXT("insert_vec_u_64")) { FInsertVecU64Args Args = ReducerEvent.Reducer.GetAsInsertVecU64(); Reducers->InvokeInsertVecU64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("insert_vec_u8")) + if (ReducerName == TEXT("insert_vec_u_8")) { FInsertVecU8Args Args = ReducerEvent.Reducer.GetAsInsertVecU8(); Reducers->InvokeInsertVecU8WithArgs(Context, Args); @@ -12212,37 +10658,37 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeUpdatePkConnectionIdWithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_pk_i128")) + if (ReducerName == TEXT("update_pk_i_128")) { FUpdatePkI128Args Args = ReducerEvent.Reducer.GetAsUpdatePkI128(); Reducers->InvokeUpdatePkI128WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_pk_i16")) + if (ReducerName == TEXT("update_pk_i_16")) { FUpdatePkI16Args Args = ReducerEvent.Reducer.GetAsUpdatePkI16(); Reducers->InvokeUpdatePkI16WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_pk_i256")) + if (ReducerName == TEXT("update_pk_i_256")) { FUpdatePkI256Args Args = ReducerEvent.Reducer.GetAsUpdatePkI256(); Reducers->InvokeUpdatePkI256WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_pk_i32")) + if (ReducerName == TEXT("update_pk_i_32")) { FUpdatePkI32Args Args = ReducerEvent.Reducer.GetAsUpdatePkI32(); Reducers->InvokeUpdatePkI32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_pk_i64")) + if (ReducerName == TEXT("update_pk_i_64")) { FUpdatePkI64Args Args = ReducerEvent.Reducer.GetAsUpdatePkI64(); Reducers->InvokeUpdatePkI64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_pk_i8")) + if (ReducerName == TEXT("update_pk_i_8")) { FUpdatePkI8Args Args = ReducerEvent.Reducer.GetAsUpdatePkI8(); Reducers->InvokeUpdatePkI8WithArgs(Context, Args); @@ -12266,43 +10712,43 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeUpdatePkStringWithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_pk_u128")) + if (ReducerName == TEXT("update_pk_u_128")) { FUpdatePkU128Args Args = ReducerEvent.Reducer.GetAsUpdatePkU128(); Reducers->InvokeUpdatePkU128WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_pk_u16")) + if (ReducerName == TEXT("update_pk_u_16")) { FUpdatePkU16Args Args = ReducerEvent.Reducer.GetAsUpdatePkU16(); Reducers->InvokeUpdatePkU16WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_pk_u256")) + if (ReducerName == TEXT("update_pk_u_256")) { FUpdatePkU256Args Args = ReducerEvent.Reducer.GetAsUpdatePkU256(); Reducers->InvokeUpdatePkU256WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_pk_u32")) + if (ReducerName == TEXT("update_pk_u_32")) { FUpdatePkU32Args Args = ReducerEvent.Reducer.GetAsUpdatePkU32(); Reducers->InvokeUpdatePkU32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_pk_u32_two")) + if (ReducerName == TEXT("update_pk_u_32_two")) { FUpdatePkU32TwoArgs Args = ReducerEvent.Reducer.GetAsUpdatePkU32Two(); Reducers->InvokeUpdatePkU32TwoWithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_pk_u64")) + if (ReducerName == TEXT("update_pk_u_64")) { FUpdatePkU64Args Args = ReducerEvent.Reducer.GetAsUpdatePkU64(); Reducers->InvokeUpdatePkU64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_pk_u8")) + if (ReducerName == TEXT("update_pk_u_8")) { FUpdatePkU8Args Args = ReducerEvent.Reducer.GetAsUpdatePkU8(); Reducers->InvokeUpdatePkU8WithArgs(Context, Args); @@ -12326,37 +10772,37 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeUpdateUniqueConnectionIdWithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_unique_i128")) + if (ReducerName == TEXT("update_unique_i_128")) { FUpdateUniqueI128Args Args = ReducerEvent.Reducer.GetAsUpdateUniqueI128(); Reducers->InvokeUpdateUniqueI128WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_unique_i16")) + if (ReducerName == TEXT("update_unique_i_16")) { FUpdateUniqueI16Args Args = ReducerEvent.Reducer.GetAsUpdateUniqueI16(); Reducers->InvokeUpdateUniqueI16WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_unique_i256")) + if (ReducerName == TEXT("update_unique_i_256")) { FUpdateUniqueI256Args Args = ReducerEvent.Reducer.GetAsUpdateUniqueI256(); Reducers->InvokeUpdateUniqueI256WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_unique_i32")) + if (ReducerName == TEXT("update_unique_i_32")) { FUpdateUniqueI32Args Args = ReducerEvent.Reducer.GetAsUpdateUniqueI32(); Reducers->InvokeUpdateUniqueI32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_unique_i64")) + if (ReducerName == TEXT("update_unique_i_64")) { FUpdateUniqueI64Args Args = ReducerEvent.Reducer.GetAsUpdateUniqueI64(); Reducers->InvokeUpdateUniqueI64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_unique_i8")) + if (ReducerName == TEXT("update_unique_i_8")) { FUpdateUniqueI8Args Args = ReducerEvent.Reducer.GetAsUpdateUniqueI8(); Reducers->InvokeUpdateUniqueI8WithArgs(Context, Args); @@ -12374,37 +10820,37 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) Reducers->InvokeUpdateUniqueStringWithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_unique_u128")) + if (ReducerName == TEXT("update_unique_u_128")) { FUpdateUniqueU128Args Args = ReducerEvent.Reducer.GetAsUpdateUniqueU128(); Reducers->InvokeUpdateUniqueU128WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_unique_u16")) + if (ReducerName == TEXT("update_unique_u_16")) { FUpdateUniqueU16Args Args = ReducerEvent.Reducer.GetAsUpdateUniqueU16(); Reducers->InvokeUpdateUniqueU16WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_unique_u256")) + if (ReducerName == TEXT("update_unique_u_256")) { FUpdateUniqueU256Args Args = ReducerEvent.Reducer.GetAsUpdateUniqueU256(); Reducers->InvokeUpdateUniqueU256WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_unique_u32")) + if (ReducerName == TEXT("update_unique_u_32")) { FUpdateUniqueU32Args Args = ReducerEvent.Reducer.GetAsUpdateUniqueU32(); Reducers->InvokeUpdateUniqueU32WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_unique_u64")) + if (ReducerName == TEXT("update_unique_u_64")) { FUpdateUniqueU64Args Args = ReducerEvent.Reducer.GetAsUpdateUniqueU64(); Reducers->InvokeUpdateUniqueU64WithArgs(Context, Args); return; } - if (ReducerName == TEXT("update_unique_u8")) + if (ReducerName == TEXT("update_unique_u_8")) { FUpdateUniqueU8Args Args = ReducerEvent.Reducer.GetAsUpdateUniqueU8(); Reducers->InvokeUpdateUniqueU8WithArgs(Context, Args); @@ -12608,7 +11054,13 @@ void UDbConnection::DbUpdate(const FDatabaseUpdateType& Update, const FSpacetime case ESpacetimeDBEventTag::Reducer: { FReducerEvent ReducerEvent = Event.GetAsReducer(); - FReducer Reducer = DecodeReducer(ReducerEvent); + FReducer Reducer; + if (!TryGetPendingTypedReducer(ReducerEvent.RequestId, Reducer)) + { + UE_LOG(LogTemp, Warning, TEXT("Missing typed reducer for request_id %u while building table-update event context; using UnknownTransaction event"), ReducerEvent.RequestId); + BaseEvent = FTestClientEvent::UnknownTransaction(FSpacetimeDBUnit()); + break; + } BaseEvent = FTestClientEvent::Reducer(Reducer); break; } @@ -12625,6 +11077,10 @@ void UDbConnection::DbUpdate(const FDatabaseUpdateType& Update, const FSpacetime BaseEvent = FTestClientEvent::Disconnected(Event.GetAsDisconnected()); break; + case ESpacetimeDBEventTag::Transaction: + BaseEvent = FTestClientEvent::Transaction(Event.GetAsTransaction()); + break; + case ESpacetimeDBEventTag::SubscribeError: BaseEvent = FTestClientEvent::SubscribeError(Event.GetAsSubscribeError()); break; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Private/Tests/CommonTestFunctions.cpp b/sdks/unreal/tests/TestClient/Source/TestClient/Private/Tests/CommonTestFunctions.cpp index b7805effb9a..a7b5faea2fb 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Private/Tests/CommonTestFunctions.cpp +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Private/Tests/CommonTestFunctions.cpp @@ -161,6 +161,7 @@ void SubscribeAllThen(UDbConnection* Conn, }; TestHelper->OnSubscriptionError = [](FErrorContext Ctx) { + UE_LOG(LogTemp, Error, TEXT("Subscription errored: %s"), *Ctx.Error); checkf(false, TEXT("Subscription errored: %s"), *Ctx.Error); }; @@ -190,6 +191,7 @@ void SubscribeTheseThen(UDbConnection* Conn, }; TestHelper->OnSubscriptionError = [](FErrorContext Ctx) { + UE_LOG(LogTemp, Error, TEXT("Subscription errored: %s"), *Ctx.Error); checkf(false, TEXT("Subscription errored: %s"), *Ctx.Error); }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalEveryPrimitiveStruct.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalEveryPrimitiveStruct.g.h index e012ce243d3..b7d5b704dce 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalEveryPrimitiveStruct.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalEveryPrimitiveStruct.g.h @@ -16,7 +16,7 @@ struct TESTCLIENT_API FTestClientOptionalEveryPrimitiveStruct bool bHasValue = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "bHasValue")) - FEveryPrimitiveStructType Value; + FEveryPrimitiveStructType Value = {}; FTestClientOptionalEveryPrimitiveStruct() = default; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalIdentity.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalIdentity.g.h index aba5ea23570..c619be5a59d 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalIdentity.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalIdentity.g.h @@ -16,7 +16,7 @@ struct TESTCLIENT_API FTestClientOptionalIdentity bool bHasValue = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "bHasValue")) - FSpacetimeDBIdentity Value; + FSpacetimeDBIdentity Value = {}; FTestClientOptionalIdentity() = default; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalInt32.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalInt32.g.h index 3fcc5bfdda0..174837ff6c2 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalInt32.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalInt32.g.h @@ -15,7 +15,7 @@ struct TESTCLIENT_API FTestClientOptionalInt32 bool bHasValue = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "bHasValue")) - int32 Value; + int32 Value = {}; FTestClientOptionalInt32() = default; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalSimpleEnum.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalSimpleEnum.g.h index 4889acee798..58fa60d6c70 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalSimpleEnum.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalSimpleEnum.g.h @@ -16,7 +16,7 @@ struct TESTCLIENT_API FTestClientOptionalSimpleEnum bool bHasValue = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "bHasValue")) - ESimpleEnumType Value; + ESimpleEnumType Value = {}; FTestClientOptionalSimpleEnum() = default; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalString.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalString.g.h index 39116b13c1f..410b852dcc0 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalString.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalString.g.h @@ -15,7 +15,7 @@ struct TESTCLIENT_API FTestClientOptionalString bool bHasValue = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "bHasValue")) - FString Value; + FString Value = {}; FTestClientOptionalString() = default; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalUuid.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalUuid.g.h index 64136bc683b..91a88e0fa19 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalUuid.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalUuid.g.h @@ -16,7 +16,7 @@ struct TESTCLIENT_API FTestClientOptionalUuid bool bHasValue = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "bHasValue")) - FSpacetimeDBUuid Value; + FSpacetimeDBUuid Value = {}; FTestClientOptionalUuid() = default; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalVecOptionalInt32.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalVecOptionalInt32.g.h index 5b896723bc1..f3a56a3481e 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalVecOptionalInt32.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Optionals/TestClientOptionalVecOptionalInt32.g.h @@ -15,7 +15,7 @@ struct TESTCLIENT_API FTestClientOptionalVecOptionalInt32 bool bHasValue = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "bHasValue")) - TArray Value; + TArray Value = {}; FTestClientOptionalVecOptionalInt32() = default; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultEveryPrimitiveStructString.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultEveryPrimitiveStructString.g.h index b70751e72ea..12d3ea7b444 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultEveryPrimitiveStructString.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultEveryPrimitiveStructString.g.h @@ -16,10 +16,10 @@ struct TESTCLIENT_API FTestClientResultEveryPrimitiveStructString bool bIsOk = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "bIsOk")) - FEveryPrimitiveStructType OkValue; + FEveryPrimitiveStructType OkValue = {}; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "!bIsOk")) - FString ErrValue; + FString ErrValue = {}; FTestClientResultEveryPrimitiveStructString() = default; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultIdentityString.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultIdentityString.g.h index d4fef91a60d..1b2d9768158 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultIdentityString.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultIdentityString.g.h @@ -16,10 +16,10 @@ struct TESTCLIENT_API FTestClientResultIdentityString bool bIsOk = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "bIsOk")) - FSpacetimeDBIdentity OkValue; + FSpacetimeDBIdentity OkValue = {}; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "!bIsOk")) - FString ErrValue; + FString ErrValue = {}; FTestClientResultIdentityString() = default; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultInt32String.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultInt32String.g.h index b8fc02c91e8..7e30c546452 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultInt32String.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultInt32String.g.h @@ -15,10 +15,10 @@ struct TESTCLIENT_API FTestClientResultInt32String bool bIsOk = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "bIsOk")) - int32 OkValue; + int32 OkValue = {}; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "!bIsOk")) - FString ErrValue; + FString ErrValue = {}; FTestClientResultInt32String() = default; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultSimpleEnumInt32.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultSimpleEnumInt32.g.h index 1f3a9fff848..52ecf52e3a8 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultSimpleEnumInt32.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultSimpleEnumInt32.g.h @@ -16,10 +16,10 @@ struct TESTCLIENT_API FTestClientResultSimpleEnumInt32 bool bIsOk = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "bIsOk")) - ESimpleEnumType OkValue; + ESimpleEnumType OkValue = {}; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "!bIsOk")) - int32 ErrValue; + int32 ErrValue = {}; FTestClientResultSimpleEnumInt32() = default; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultStringInt32.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultStringInt32.g.h index b1df79a3245..382f37d16d4 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultStringInt32.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultStringInt32.g.h @@ -15,10 +15,10 @@ struct TESTCLIENT_API FTestClientResultStringInt32 bool bIsOk = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "bIsOk")) - FString OkValue; + FString OkValue = {}; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "!bIsOk")) - int32 ErrValue; + int32 ErrValue = {}; FTestClientResultStringInt32() = default; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultVecInt32String.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultVecInt32String.g.h index 92cc0108bd6..48707d44f45 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultVecInt32String.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Results/TestClientResultVecInt32String.g.h @@ -15,10 +15,10 @@ struct TESTCLIENT_API FTestClientResultVecInt32String bool bIsOk = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "bIsOk")) - TArray OkValue; + TArray OkValue = {}; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpacetimeDB", meta = (EditCondition = "!bIsOk")) - FString ErrValue; + FString ErrValue = {}; FTestClientResultVecInt32String() = default; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/SpacetimeDBClient.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/SpacetimeDBClient.g.h index 29874d776ae..653735df451 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/SpacetimeDBClient.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/SpacetimeDBClient.g.h @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.12.0 (commit 11e258c2f8c9de8f67098f65e3f6a9db32026768). +// This was generated using spacetimedb cli version 2.0.1 (commit 6f8639a69dac2047da00b1fc8550c94ea2505892). #pragma once #include "CoreMinimal.h" @@ -9,7 +9,6 @@ #include "Connection/Callback.h" #include "Connection/DbConnectionBase.h" #include "Connection/DbConnectionBuilder.h" -#include "Connection/SetReducerFlags.h" #include "Connection/Subscription.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "ModuleBindings/Optionals/TestClientOptionalEveryPrimitiveStruct.g.h" @@ -376,7 +375,7 @@ struct TESTCLIENT_API FContextBase { GENERATED_BODY() - FContextBase() : Db(nullptr), Reducers(nullptr), SetReducerFlags(nullptr), Procedures(nullptr), Conn(nullptr) {}; + FContextBase() : Db(nullptr), Reducers(nullptr), Procedures(nullptr), Conn(nullptr) {}; FContextBase(UDbConnection* InConn); UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") @@ -385,9 +384,6 @@ struct TESTCLIENT_API FContextBase UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") URemoteReducers* Reducers; - UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") - USetReducerFlags* SetReducerFlags; - UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") URemoteProcedures* Procedures; @@ -415,9 +411,6 @@ class TESTCLIENT_API UContextBaseBpLib : public UBlueprintFunctionLibrary UFUNCTION(BlueprintPure, Category="SpacetimeDB") static URemoteReducers* GetReducers(const FContextBase& Ctx) { return Ctx.Reducers; } - UFUNCTION(BlueprintPure, Category="SpacetimeDB") - static USetReducerFlags* GetSetReducerFlags(const FContextBase& Ctx) { return Ctx.SetReducerFlags; } - static URemoteProcedures* GetProcedures(const FContextBase& Ctx) { return Ctx.Procedures; } UFUNCTION(BlueprintPure, Category="SpacetimeDB") @@ -648,7 +641,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeleteFromBtreeU32; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_from_btree_u32"); + Out.ReducerName = TEXT("delete_from_btree_u_32"); return Out; } @@ -712,7 +705,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeletePkI128; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_pk_i128"); + Out.ReducerName = TEXT("delete_pk_i_128"); return Out; } @@ -728,7 +721,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeletePkI16; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_pk_i16"); + Out.ReducerName = TEXT("delete_pk_i_16"); return Out; } @@ -744,7 +737,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeletePkI256; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_pk_i256"); + Out.ReducerName = TEXT("delete_pk_i_256"); return Out; } @@ -760,7 +753,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeletePkI32; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_pk_i32"); + Out.ReducerName = TEXT("delete_pk_i_32"); return Out; } @@ -776,7 +769,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeletePkI64; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_pk_i64"); + Out.ReducerName = TEXT("delete_pk_i_64"); return Out; } @@ -792,7 +785,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeletePkI8; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_pk_i8"); + Out.ReducerName = TEXT("delete_pk_i_8"); return Out; } @@ -840,7 +833,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeletePkU128; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_pk_u128"); + Out.ReducerName = TEXT("delete_pk_u_128"); return Out; } @@ -856,7 +849,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeletePkU16; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_pk_u16"); + Out.ReducerName = TEXT("delete_pk_u_16"); return Out; } @@ -872,7 +865,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeletePkU256; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_pk_u256"); + Out.ReducerName = TEXT("delete_pk_u_256"); return Out; } @@ -888,7 +881,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeletePkU32; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_pk_u32"); + Out.ReducerName = TEXT("delete_pk_u_32"); return Out; } @@ -904,7 +897,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeletePkU32InsertPkU32Two; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_pk_u32_insert_pk_u32_two"); + Out.ReducerName = TEXT("delete_pk_u_32_insert_pk_u_32_two"); return Out; } @@ -920,7 +913,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeletePkU32Two; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_pk_u32_two"); + Out.ReducerName = TEXT("delete_pk_u_32_two"); return Out; } @@ -936,7 +929,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeletePkU64; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_pk_u64"); + Out.ReducerName = TEXT("delete_pk_u_64"); return Out; } @@ -952,7 +945,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeletePkU8; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_pk_u8"); + Out.ReducerName = TEXT("delete_pk_u_8"); return Out; } @@ -1016,7 +1009,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeleteUniqueI128; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_unique_i128"); + Out.ReducerName = TEXT("delete_unique_i_128"); return Out; } @@ -1032,7 +1025,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeleteUniqueI16; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_unique_i16"); + Out.ReducerName = TEXT("delete_unique_i_16"); return Out; } @@ -1048,7 +1041,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeleteUniqueI256; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_unique_i256"); + Out.ReducerName = TEXT("delete_unique_i_256"); return Out; } @@ -1064,7 +1057,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeleteUniqueI32; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_unique_i32"); + Out.ReducerName = TEXT("delete_unique_i_32"); return Out; } @@ -1080,7 +1073,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeleteUniqueI64; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_unique_i64"); + Out.ReducerName = TEXT("delete_unique_i_64"); return Out; } @@ -1096,7 +1089,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeleteUniqueI8; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_unique_i8"); + Out.ReducerName = TEXT("delete_unique_i_8"); return Out; } @@ -1144,7 +1137,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeleteUniqueU128; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_unique_u128"); + Out.ReducerName = TEXT("delete_unique_u_128"); return Out; } @@ -1160,7 +1153,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeleteUniqueU16; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_unique_u16"); + Out.ReducerName = TEXT("delete_unique_u_16"); return Out; } @@ -1176,7 +1169,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeleteUniqueU256; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_unique_u256"); + Out.ReducerName = TEXT("delete_unique_u_256"); return Out; } @@ -1192,7 +1185,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeleteUniqueU32; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_unique_u32"); + Out.ReducerName = TEXT("delete_unique_u_32"); return Out; } @@ -1208,7 +1201,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeleteUniqueU64; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_unique_u64"); + Out.ReducerName = TEXT("delete_unique_u_64"); return Out; } @@ -1224,7 +1217,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::DeleteUniqueU8; Out.Data.Set(Value); - Out.ReducerName = TEXT("delete_unique_u8"); + Out.ReducerName = TEXT("delete_unique_u_8"); return Out; } @@ -1272,7 +1265,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertCallUuidV4; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_call_uuid_v4"); + Out.ReducerName = TEXT("insert_call_uuid_v_4"); return Out; } @@ -1288,7 +1281,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertCallUuidV7; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_call_uuid_v7"); + Out.ReducerName = TEXT("insert_call_uuid_v_7"); return Out; } @@ -1432,7 +1425,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertIntoBtreeU32; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_into_btree_u32"); + Out.ReducerName = TEXT("insert_into_btree_u_32"); return Out; } @@ -1464,7 +1457,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertIntoPkBtreeU32; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_into_pk_btree_u32"); + Out.ReducerName = TEXT("insert_into_pk_btree_u_32"); return Out; } @@ -1592,7 +1585,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertOneF32; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_one_f32"); + Out.ReducerName = TEXT("insert_one_f_32"); return Out; } @@ -1608,7 +1601,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertOneF64; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_one_f64"); + Out.ReducerName = TEXT("insert_one_f_64"); return Out; } @@ -1624,7 +1617,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertOneI128; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_one_i128"); + Out.ReducerName = TEXT("insert_one_i_128"); return Out; } @@ -1640,7 +1633,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertOneI16; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_one_i16"); + Out.ReducerName = TEXT("insert_one_i_16"); return Out; } @@ -1656,7 +1649,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertOneI256; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_one_i256"); + Out.ReducerName = TEXT("insert_one_i_256"); return Out; } @@ -1672,7 +1665,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertOneI32; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_one_i32"); + Out.ReducerName = TEXT("insert_one_i_32"); return Out; } @@ -1688,7 +1681,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertOneI64; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_one_i64"); + Out.ReducerName = TEXT("insert_one_i_64"); return Out; } @@ -1704,7 +1697,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertOneI8; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_one_i8"); + Out.ReducerName = TEXT("insert_one_i_8"); return Out; } @@ -1784,7 +1777,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertOneU128; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_one_u128"); + Out.ReducerName = TEXT("insert_one_u_128"); return Out; } @@ -1800,7 +1793,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertOneU16; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_one_u16"); + Out.ReducerName = TEXT("insert_one_u_16"); return Out; } @@ -1816,7 +1809,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertOneU256; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_one_u256"); + Out.ReducerName = TEXT("insert_one_u_256"); return Out; } @@ -1832,7 +1825,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertOneU32; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_one_u32"); + Out.ReducerName = TEXT("insert_one_u_32"); return Out; } @@ -1848,7 +1841,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertOneU64; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_one_u64"); + Out.ReducerName = TEXT("insert_one_u_64"); return Out; } @@ -1864,7 +1857,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertOneU8; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_one_u8"); + Out.ReducerName = TEXT("insert_one_u_8"); return Out; } @@ -1928,7 +1921,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertOptionI32; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_option_i32"); + Out.ReducerName = TEXT("insert_option_i_32"); return Out; } @@ -2008,7 +2001,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertOptionVecOptionI32; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_option_vec_option_i32"); + Out.ReducerName = TEXT("insert_option_vec_option_i_32"); return Out; } @@ -2056,7 +2049,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertPkI128; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_pk_i128"); + Out.ReducerName = TEXT("insert_pk_i_128"); return Out; } @@ -2072,7 +2065,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertPkI16; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_pk_i16"); + Out.ReducerName = TEXT("insert_pk_i_16"); return Out; } @@ -2088,7 +2081,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertPkI256; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_pk_i256"); + Out.ReducerName = TEXT("insert_pk_i_256"); return Out; } @@ -2104,7 +2097,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertPkI32; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_pk_i32"); + Out.ReducerName = TEXT("insert_pk_i_32"); return Out; } @@ -2120,7 +2113,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertPkI64; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_pk_i64"); + Out.ReducerName = TEXT("insert_pk_i_64"); return Out; } @@ -2136,7 +2129,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertPkI8; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_pk_i8"); + Out.ReducerName = TEXT("insert_pk_i_8"); return Out; } @@ -2200,7 +2193,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertPkU128; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_pk_u128"); + Out.ReducerName = TEXT("insert_pk_u_128"); return Out; } @@ -2216,7 +2209,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertPkU16; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_pk_u16"); + Out.ReducerName = TEXT("insert_pk_u_16"); return Out; } @@ -2232,7 +2225,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertPkU256; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_pk_u256"); + Out.ReducerName = TEXT("insert_pk_u_256"); return Out; } @@ -2248,7 +2241,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertPkU32; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_pk_u32"); + Out.ReducerName = TEXT("insert_pk_u_32"); return Out; } @@ -2264,7 +2257,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertPkU32Two; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_pk_u32_two"); + Out.ReducerName = TEXT("insert_pk_u_32_two"); return Out; } @@ -2280,7 +2273,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertPkU64; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_pk_u64"); + Out.ReducerName = TEXT("insert_pk_u_64"); return Out; } @@ -2296,7 +2289,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertPkU8; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_pk_u8"); + Out.ReducerName = TEXT("insert_pk_u_8"); return Out; } @@ -2360,7 +2353,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertResultI32String; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_result_i32_string"); + Out.ReducerName = TEXT("insert_result_i_32_string"); return Out; } @@ -2392,7 +2385,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertResultSimpleEnumI32; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_result_simple_enum_i32"); + Out.ReducerName = TEXT("insert_result_simple_enum_i_32"); return Out; } @@ -2408,7 +2401,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertResultStringI32; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_result_string_i32"); + Out.ReducerName = TEXT("insert_result_string_i_32"); return Out; } @@ -2424,7 +2417,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertResultVecI32String; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_result_vec_i32_string"); + Out.ReducerName = TEXT("insert_result_vec_i_32_string"); return Out; } @@ -2488,7 +2481,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertUniqueI128; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_unique_i128"); + Out.ReducerName = TEXT("insert_unique_i_128"); return Out; } @@ -2504,7 +2497,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertUniqueI16; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_unique_i16"); + Out.ReducerName = TEXT("insert_unique_i_16"); return Out; } @@ -2520,7 +2513,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertUniqueI256; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_unique_i256"); + Out.ReducerName = TEXT("insert_unique_i_256"); return Out; } @@ -2536,7 +2529,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertUniqueI32; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_unique_i32"); + Out.ReducerName = TEXT("insert_unique_i_32"); return Out; } @@ -2552,7 +2545,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertUniqueI64; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_unique_i64"); + Out.ReducerName = TEXT("insert_unique_i_64"); return Out; } @@ -2568,7 +2561,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertUniqueI8; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_unique_i8"); + Out.ReducerName = TEXT("insert_unique_i_8"); return Out; } @@ -2616,7 +2609,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertUniqueU128; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_unique_u128"); + Out.ReducerName = TEXT("insert_unique_u_128"); return Out; } @@ -2632,7 +2625,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertUniqueU16; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_unique_u16"); + Out.ReducerName = TEXT("insert_unique_u_16"); return Out; } @@ -2648,7 +2641,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertUniqueU256; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_unique_u256"); + Out.ReducerName = TEXT("insert_unique_u_256"); return Out; } @@ -2664,7 +2657,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertUniqueU32; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_unique_u32"); + Out.ReducerName = TEXT("insert_unique_u_32"); return Out; } @@ -2680,7 +2673,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertUniqueU32UpdatePkU32; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_unique_u32_update_pk_u32"); + Out.ReducerName = TEXT("insert_unique_u_32_update_pk_u_32"); return Out; } @@ -2696,7 +2689,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertUniqueU64; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_unique_u64"); + Out.ReducerName = TEXT("insert_unique_u_64"); return Out; } @@ -2712,7 +2705,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertUniqueU8; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_unique_u8"); + Out.ReducerName = TEXT("insert_unique_u_8"); return Out; } @@ -2856,7 +2849,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertVecF32; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_vec_f32"); + Out.ReducerName = TEXT("insert_vec_f_32"); return Out; } @@ -2872,7 +2865,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertVecF64; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_vec_f64"); + Out.ReducerName = TEXT("insert_vec_f_64"); return Out; } @@ -2888,7 +2881,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertVecI128; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_vec_i128"); + Out.ReducerName = TEXT("insert_vec_i_128"); return Out; } @@ -2904,7 +2897,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertVecI16; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_vec_i16"); + Out.ReducerName = TEXT("insert_vec_i_16"); return Out; } @@ -2920,7 +2913,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertVecI256; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_vec_i256"); + Out.ReducerName = TEXT("insert_vec_i_256"); return Out; } @@ -2936,7 +2929,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertVecI32; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_vec_i32"); + Out.ReducerName = TEXT("insert_vec_i_32"); return Out; } @@ -2952,7 +2945,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertVecI64; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_vec_i64"); + Out.ReducerName = TEXT("insert_vec_i_64"); return Out; } @@ -2968,7 +2961,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertVecI8; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_vec_i8"); + Out.ReducerName = TEXT("insert_vec_i_8"); return Out; } @@ -3048,7 +3041,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertVecU128; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_vec_u128"); + Out.ReducerName = TEXT("insert_vec_u_128"); return Out; } @@ -3064,7 +3057,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertVecU16; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_vec_u16"); + Out.ReducerName = TEXT("insert_vec_u_16"); return Out; } @@ -3080,7 +3073,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertVecU256; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_vec_u256"); + Out.ReducerName = TEXT("insert_vec_u_256"); return Out; } @@ -3096,7 +3089,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertVecU32; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_vec_u32"); + Out.ReducerName = TEXT("insert_vec_u_32"); return Out; } @@ -3112,7 +3105,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertVecU64; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_vec_u64"); + Out.ReducerName = TEXT("insert_vec_u_64"); return Out; } @@ -3128,7 +3121,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::InsertVecU8; Out.Data.Set(Value); - Out.ReducerName = TEXT("insert_vec_u8"); + Out.ReducerName = TEXT("insert_vec_u_8"); return Out; } @@ -3256,7 +3249,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdatePkI128; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_pk_i128"); + Out.ReducerName = TEXT("update_pk_i_128"); return Out; } @@ -3272,7 +3265,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdatePkI16; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_pk_i16"); + Out.ReducerName = TEXT("update_pk_i_16"); return Out; } @@ -3288,7 +3281,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdatePkI256; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_pk_i256"); + Out.ReducerName = TEXT("update_pk_i_256"); return Out; } @@ -3304,7 +3297,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdatePkI32; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_pk_i32"); + Out.ReducerName = TEXT("update_pk_i_32"); return Out; } @@ -3320,7 +3313,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdatePkI64; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_pk_i64"); + Out.ReducerName = TEXT("update_pk_i_64"); return Out; } @@ -3336,7 +3329,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdatePkI8; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_pk_i8"); + Out.ReducerName = TEXT("update_pk_i_8"); return Out; } @@ -3400,7 +3393,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdatePkU128; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_pk_u128"); + Out.ReducerName = TEXT("update_pk_u_128"); return Out; } @@ -3416,7 +3409,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdatePkU16; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_pk_u16"); + Out.ReducerName = TEXT("update_pk_u_16"); return Out; } @@ -3432,7 +3425,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdatePkU256; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_pk_u256"); + Out.ReducerName = TEXT("update_pk_u_256"); return Out; } @@ -3448,7 +3441,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdatePkU32; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_pk_u32"); + Out.ReducerName = TEXT("update_pk_u_32"); return Out; } @@ -3464,7 +3457,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdatePkU32Two; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_pk_u32_two"); + Out.ReducerName = TEXT("update_pk_u_32_two"); return Out; } @@ -3480,7 +3473,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdatePkU64; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_pk_u64"); + Out.ReducerName = TEXT("update_pk_u_64"); return Out; } @@ -3496,7 +3489,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdatePkU8; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_pk_u8"); + Out.ReducerName = TEXT("update_pk_u_8"); return Out; } @@ -3560,7 +3553,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdateUniqueI128; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_unique_i128"); + Out.ReducerName = TEXT("update_unique_i_128"); return Out; } @@ -3576,7 +3569,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdateUniqueI16; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_unique_i16"); + Out.ReducerName = TEXT("update_unique_i_16"); return Out; } @@ -3592,7 +3585,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdateUniqueI256; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_unique_i256"); + Out.ReducerName = TEXT("update_unique_i_256"); return Out; } @@ -3608,7 +3601,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdateUniqueI32; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_unique_i32"); + Out.ReducerName = TEXT("update_unique_i_32"); return Out; } @@ -3624,7 +3617,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdateUniqueI64; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_unique_i64"); + Out.ReducerName = TEXT("update_unique_i_64"); return Out; } @@ -3640,7 +3633,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdateUniqueI8; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_unique_i8"); + Out.ReducerName = TEXT("update_unique_i_8"); return Out; } @@ -3688,7 +3681,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdateUniqueU128; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_unique_u128"); + Out.ReducerName = TEXT("update_unique_u_128"); return Out; } @@ -3704,7 +3697,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdateUniqueU16; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_unique_u16"); + Out.ReducerName = TEXT("update_unique_u_16"); return Out; } @@ -3720,7 +3713,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdateUniqueU256; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_unique_u256"); + Out.ReducerName = TEXT("update_unique_u_256"); return Out; } @@ -3736,7 +3729,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdateUniqueU32; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_unique_u32"); + Out.ReducerName = TEXT("update_unique_u_32"); return Out; } @@ -3752,7 +3745,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdateUniqueU64; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_unique_u64"); + Out.ReducerName = TEXT("update_unique_u_64"); return Out; } @@ -3768,7 +3761,7 @@ struct TESTCLIENT_API FReducer FReducer Out; Out.Tag = EReducerTag::UpdateUniqueU8; Out.Data.Set(Value); - Out.ReducerName = TEXT("update_unique_u8"); + Out.ReducerName = TEXT("update_unique_u_8"); return Out; } @@ -6896,6 +6889,14 @@ struct TESTCLIENT_API FTestClientEvent return Obj; } + static FTestClientEvent Transaction(const FSpacetimeDBUnit& Value) + { + FTestClientEvent Obj; + Obj.Tag = ESpacetimeDBEventTag::Transaction; + Obj.MessageData.Set(Value); + return Obj; + } + static FTestClientEvent SubscribeError(const FString& Value) { FTestClientEvent Obj; @@ -6940,6 +6941,13 @@ struct TESTCLIENT_API FTestClientEvent return MessageData.Get(); } + FORCEINLINE bool IsTransaction() const { return Tag == ESpacetimeDBEventTag::Transaction; } + FORCEINLINE FSpacetimeDBUnit GetAsTransaction() const + { + ensureMsgf(IsTransaction(), TEXT("MessageData does not hold Transaction!")); + return MessageData.Get(); + } + FORCEINLINE bool IsSubscribeError() const { return Tag == ESpacetimeDBEventTag::SubscribeError; } FORCEINLINE FString GetAsSubscribeError() const { @@ -6963,6 +6971,7 @@ struct TESTCLIENT_API FTestClientEvent case ESpacetimeDBEventTag::SubscribeApplied: return GetAsSubscribeApplied() == Other.GetAsSubscribeApplied(); case ESpacetimeDBEventTag::UnsubscribeApplied: return GetAsUnsubscribeApplied() == Other.GetAsUnsubscribeApplied(); case ESpacetimeDBEventTag::Disconnected: return GetAsDisconnected() == Other.GetAsDisconnected(); + case ESpacetimeDBEventTag::Transaction: return GetAsTransaction() == Other.GetAsTransaction(); case ESpacetimeDBEventTag::SubscribeError: return GetAsSubscribeError() == Other.GetAsSubscribeError(); case ESpacetimeDBEventTag::UnknownTransaction: return GetAsUnknownTransaction() == Other.GetAsUnknownTransaction(); default: return false; @@ -7005,6 +7014,12 @@ class TESTCLIENT_API UTestClientEventBpLib : public UBlueprintFunctionLibrary return FTestClientEvent::Disconnected(InValue); } + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|TestClientEvent") + static FTestClientEvent Transaction(const FSpacetimeDBUnit& InValue) + { + return FTestClientEvent::Transaction(InValue); + } + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|TestClientEvent") static FTestClientEvent SubscribeError(const FString& InValue) { @@ -7029,6 +7044,9 @@ class TESTCLIENT_API UTestClientEventBpLib : public UBlueprintFunctionLibrary UFUNCTION(BlueprintPure, Category = "SpacetimeDB|TestClientEvent") static bool IsDisconnected(const FTestClientEvent& Event) { return Event.IsDisconnected(); } + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|TestClientEvent") + static bool IsTransaction(const FTestClientEvent& Event) { return Event.IsTransaction(); } + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|TestClientEvent") static bool IsSubscribeError(const FTestClientEvent& Event) { return Event.IsSubscribeError(); } @@ -7059,6 +7077,12 @@ class TESTCLIENT_API UTestClientEventBpLib : public UBlueprintFunctionLibrary return Event.GetAsDisconnected(); } + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|TestClientEvent") + static FSpacetimeDBUnit GetAsTransaction(const FTestClientEvent& Event) + { + return Event.GetAsTransaction(); + } + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|TestClientEvent") static FString GetAsSubscribeError(const FTestClientEvent& Event) { @@ -7141,409 +7165,6 @@ DECLARE_DYNAMIC_DELEGATE_OneParam( FOnSubscriptionError, FErrorContext, Context); -UCLASS(BlueprintType) -class TESTCLIENT_API USetReducerFlags : public USetReducerFlagsBase -{ - GENERATED_BODY() - -public: - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteFromBtreeU32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteLargeTable(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkBool(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkConnectionId(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkI128(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkI16(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkI256(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkI32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkI64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkI8(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkIdentity(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkString(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkU128(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkU16(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkU256(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkU32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkU32InsertPkU32Two(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkU32Two(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkU64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkU8(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeletePkUuid(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteUniqueBool(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteUniqueConnectionId(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteUniqueI128(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteUniqueI16(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteUniqueI256(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteUniqueI32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteUniqueI64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteUniqueI8(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteUniqueIdentity(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteUniqueString(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteUniqueU128(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteUniqueU16(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteUniqueU256(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteUniqueU32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteUniqueU64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteUniqueU8(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void DeleteUniqueUuid(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertCallTimestamp(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertCallUuidV4(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertCallUuidV7(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertCallerOneConnectionId(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertCallerOneIdentity(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertCallerPkConnectionId(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertCallerPkIdentity(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertCallerUniqueConnectionId(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertCallerUniqueIdentity(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertCallerVecConnectionId(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertCallerVecIdentity(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertIntoBtreeU32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertIntoIndexedSimpleEnum(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertIntoPkBtreeU32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertLargeTable(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneBool(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneByteStruct(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneConnectionId(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneEnumWithPayload(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneEveryPrimitiveStruct(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneEveryVecStruct(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneF32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneF64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneI128(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneI16(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneI256(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneI32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneI64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneI8(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneIdentity(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneSimpleEnum(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneString(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneTimestamp(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneU128(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneU16(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneU256(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneU32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneU64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneU8(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneUnitStruct(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOneUuid(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOptionEveryPrimitiveStruct(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOptionI32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOptionIdentity(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOptionSimpleEnum(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOptionString(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOptionUuid(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertOptionVecOptionI32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkBool(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkConnectionId(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkI128(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkI16(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkI256(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkI32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkI64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkI8(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkIdentity(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkSimpleEnum(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkString(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkU128(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkU16(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkU256(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkU32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkU32Two(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkU64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkU8(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPkUuid(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertPrimitivesAsStrings(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertResultEveryPrimitiveStructString(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertResultI32String(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertResultIdentityString(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertResultSimpleEnumI32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertResultStringI32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertResultVecI32String(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertTableHoldsTable(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueBool(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueConnectionId(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueI128(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueI16(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueI256(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueI32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueI64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueI8(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueIdentity(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueString(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueU128(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueU16(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueU256(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueU32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueU32UpdatePkU32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueU64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueU8(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUniqueUuid(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertUser(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecBool(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecByteStruct(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecConnectionId(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecEnumWithPayload(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecEveryPrimitiveStruct(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecEveryVecStruct(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecF32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecF64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecI128(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecI16(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecI256(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecI32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecI64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecI8(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecIdentity(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecSimpleEnum(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecString(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecTimestamp(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecU128(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecU16(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecU256(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecU32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecU64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecU8(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecUnitStruct(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void InsertVecUuid(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void NoOpSucceeds(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void SortedUuidsInsert(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateIndexedSimpleEnum(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkBool(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkConnectionId(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkI128(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkI16(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkI256(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkI32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkI64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkI8(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkIdentity(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkSimpleEnum(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkString(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkU128(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkU16(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkU256(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkU32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkU32Two(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkU64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkU8(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePkUuid(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateUniqueBool(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateUniqueConnectionId(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateUniqueI128(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateUniqueI16(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateUniqueI256(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateUniqueI32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateUniqueI64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateUniqueI8(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateUniqueIdentity(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateUniqueString(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateUniqueU128(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateUniqueU16(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateUniqueU256(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateUniqueU32(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateUniqueU64(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateUniqueU8(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdateUniqueUuid(ECallReducerFlags Flag); - -}; - // RemoteTables class UCLASS(BlueprintType) class TESTCLIENT_API URemoteTables : public UObject @@ -10722,9 +10343,6 @@ class TESTCLIENT_API URemoteReducers : public UObject UPROPERTY() class UDbConnection* Conn; - - UPROPERTY() - USetReducerFlags* SetCallReducerFlags; }; // RemoteProcedures class @@ -10859,9 +10477,6 @@ class TESTCLIENT_API UDbConnection : public UDbConnectionBase UPROPERTY(BlueprintReadOnly, Category="SpacetimeDB") URemoteReducers* Reducers; - UPROPERTY(BlueprintReadOnly, Category="SpacetimeDB") - USetReducerFlags* SetReducerFlags; - UPROPERTY(BlueprintReadOnly, Category="SpacetimeDB") URemoteProcedures* Procedures; @@ -10913,5 +10528,15 @@ class TESTCLIENT_API UDbConnection : public UDbConnectionBase virtual void ReducerEventFailed(const FReducerEvent& Event, const FString ErrorMessage) override; // Override the procedure event failed handler virtual void ProcedureEventFailed(const FProcedureEvent& Event, const FString ErrorMessage) override; + + friend class URemoteReducers; + + // Internal reducer correlation helpers (request_id -> typed reducer) + void RegisterPendingTypedReducer(uint32 RequestId, FReducer Reducer); + bool TryGetPendingTypedReducer(uint32 RequestId, FReducer& OutReducer) const; + bool TryTakePendingTypedReducer(uint32 RequestId, FReducer& OutReducer); + +private: + TMap PendingTypedReducers; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/BtreeU32Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/BtreeU32Table.g.h index 067e94c0618..a335ae737f4 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/BtreeU32Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/BtreeU32Table.g.h @@ -57,7 +57,7 @@ class TESTCLIENT_API UBtreeU32Table : public URemoteTable void PostInitialize(); - /** Update function for btree_u32 table*/ + /** Update function for btree_u_32 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -95,7 +95,7 @@ class TESTCLIENT_API UBtreeU32Table : public URemoteTable FOnBtreeU32Delete OnDelete; private: - const FString TableName = TEXT("btree_u32"); + const FString TableName = TEXT("btree_u_32"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneF32Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneF32Table.g.h index 789c5dafdc6..356a0a49cb1 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneF32Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneF32Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UOneF32Table : public URemoteTable public: void PostInitialize(); - /** Update function for one_f32 table*/ + /** Update function for one_f_32 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UOneF32Table : public URemoteTable FOnOneF32Delete OnDelete; private: - const FString TableName = TEXT("one_f32"); + const FString TableName = TEXT("one_f_32"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneF64Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneF64Table.g.h index 3dfb09c8b20..fdc739700cf 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneF64Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneF64Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UOneF64Table : public URemoteTable public: void PostInitialize(); - /** Update function for one_f64 table*/ + /** Update function for one_f_64 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UOneF64Table : public URemoteTable FOnOneF64Delete OnDelete; private: - const FString TableName = TEXT("one_f64"); + const FString TableName = TEXT("one_f_64"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI128Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI128Table.g.h index dc370d4929f..8d434832c4e 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI128Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI128Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UOneI128Table : public URemoteTable public: void PostInitialize(); - /** Update function for one_i128 table*/ + /** Update function for one_i_128 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UOneI128Table : public URemoteTable FOnOneI128Delete OnDelete; private: - const FString TableName = TEXT("one_i128"); + const FString TableName = TEXT("one_i_128"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI16Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI16Table.g.h index 0f26c456dbf..d3a334476b0 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI16Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI16Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UOneI16Table : public URemoteTable public: void PostInitialize(); - /** Update function for one_i16 table*/ + /** Update function for one_i_16 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UOneI16Table : public URemoteTable FOnOneI16Delete OnDelete; private: - const FString TableName = TEXT("one_i16"); + const FString TableName = TEXT("one_i_16"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI256Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI256Table.g.h index aee4aedfb92..b66a8445eb1 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI256Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI256Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UOneI256Table : public URemoteTable public: void PostInitialize(); - /** Update function for one_i256 table*/ + /** Update function for one_i_256 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UOneI256Table : public URemoteTable FOnOneI256Delete OnDelete; private: - const FString TableName = TEXT("one_i256"); + const FString TableName = TEXT("one_i_256"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI32Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI32Table.g.h index ed497686cd7..ca36ef53a53 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI32Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI32Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UOneI32Table : public URemoteTable public: void PostInitialize(); - /** Update function for one_i32 table*/ + /** Update function for one_i_32 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UOneI32Table : public URemoteTable FOnOneI32Delete OnDelete; private: - const FString TableName = TEXT("one_i32"); + const FString TableName = TEXT("one_i_32"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI64Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI64Table.g.h index dfb550e5662..6430333d295 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI64Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI64Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UOneI64Table : public URemoteTable public: void PostInitialize(); - /** Update function for one_i64 table*/ + /** Update function for one_i_64 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UOneI64Table : public URemoteTable FOnOneI64Delete OnDelete; private: - const FString TableName = TEXT("one_i64"); + const FString TableName = TEXT("one_i_64"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI8Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI8Table.g.h index f41b8bed6d5..aa035b2c9f1 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI8Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneI8Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UOneI8Table : public URemoteTable public: void PostInitialize(); - /** Update function for one_i8 table*/ + /** Update function for one_i_8 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UOneI8Table : public URemoteTable FOnOneI8Delete OnDelete; private: - const FString TableName = TEXT("one_i8"); + const FString TableName = TEXT("one_i_8"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU128Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU128Table.g.h index 0ccaa72f21f..d3c4ec8db55 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU128Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU128Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UOneU128Table : public URemoteTable public: void PostInitialize(); - /** Update function for one_u128 table*/ + /** Update function for one_u_128 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UOneU128Table : public URemoteTable FOnOneU128Delete OnDelete; private: - const FString TableName = TEXT("one_u128"); + const FString TableName = TEXT("one_u_128"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU16Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU16Table.g.h index 4501b0e7d59..0039e4b851c 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU16Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU16Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UOneU16Table : public URemoteTable public: void PostInitialize(); - /** Update function for one_u16 table*/ + /** Update function for one_u_16 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UOneU16Table : public URemoteTable FOnOneU16Delete OnDelete; private: - const FString TableName = TEXT("one_u16"); + const FString TableName = TEXT("one_u_16"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU256Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU256Table.g.h index ad10a3b4727..35ba0eebb24 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU256Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU256Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UOneU256Table : public URemoteTable public: void PostInitialize(); - /** Update function for one_u256 table*/ + /** Update function for one_u_256 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UOneU256Table : public URemoteTable FOnOneU256Delete OnDelete; private: - const FString TableName = TEXT("one_u256"); + const FString TableName = TEXT("one_u_256"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU32Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU32Table.g.h index cbdecbcd491..b6c6c5ee232 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU32Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU32Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UOneU32Table : public URemoteTable public: void PostInitialize(); - /** Update function for one_u32 table*/ + /** Update function for one_u_32 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UOneU32Table : public URemoteTable FOnOneU32Delete OnDelete; private: - const FString TableName = TEXT("one_u32"); + const FString TableName = TEXT("one_u_32"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU64Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU64Table.g.h index 14ce8017a71..adea19b3bf0 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU64Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU64Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UOneU64Table : public URemoteTable public: void PostInitialize(); - /** Update function for one_u64 table*/ + /** Update function for one_u_64 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UOneU64Table : public URemoteTable FOnOneU64Delete OnDelete; private: - const FString TableName = TEXT("one_u64"); + const FString TableName = TEXT("one_u_64"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU8Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU8Table.g.h index 128f8eb24cb..26062a9d79d 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU8Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OneU8Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UOneU8Table : public URemoteTable public: void PostInitialize(); - /** Update function for one_u8 table*/ + /** Update function for one_u_8 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UOneU8Table : public URemoteTable FOnOneU8Delete OnDelete; private: - const FString TableName = TEXT("one_u8"); + const FString TableName = TEXT("one_u_8"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OptionI32Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OptionI32Table.g.h index d404a836656..8807f71b633 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OptionI32Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OptionI32Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UOptionI32Table : public URemoteTable public: void PostInitialize(); - /** Update function for option_i32 table*/ + /** Update function for option_i_32 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UOptionI32Table : public URemoteTable FOnOptionI32Delete OnDelete; private: - const FString TableName = TEXT("option_i32"); + const FString TableName = TEXT("option_i_32"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OptionVecOptionI32Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OptionVecOptionI32Table.g.h index be51577a72d..c36d54cc025 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OptionVecOptionI32Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/OptionVecOptionI32Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UOptionVecOptionI32Table : public URemoteTable public: void PostInitialize(); - /** Update function for option_vec_option_i32 table*/ + /** Update function for option_vec_option_i_32 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UOptionVecOptionI32Table : public URemoteTable FOnOptionVecOptionI32Delete OnDelete; private: - const FString TableName = TEXT("option_vec_option_i32"); + const FString TableName = TEXT("option_vec_option_i_32"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI128Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI128Table.g.h index 0e1135a0b79..54351d3758a 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI128Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI128Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UPkI128Table : public URemoteTable void PostInitialize(); - /** Update function for pk_i128 table*/ + /** Update function for pk_i_128 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UPkI128Table : public URemoteTable FOnPkI128Delete OnDelete; private: - const FString TableName = TEXT("pk_i128"); + const FString TableName = TEXT("pk_i_128"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI16Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI16Table.g.h index 11c67eb11e2..b4bc0a01602 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI16Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI16Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UPkI16Table : public URemoteTable void PostInitialize(); - /** Update function for pk_i16 table*/ + /** Update function for pk_i_16 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UPkI16Table : public URemoteTable FOnPkI16Delete OnDelete; private: - const FString TableName = TEXT("pk_i16"); + const FString TableName = TEXT("pk_i_16"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI256Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI256Table.g.h index 54ac7cd2f4d..95c55e80bc3 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI256Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI256Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UPkI256Table : public URemoteTable void PostInitialize(); - /** Update function for pk_i256 table*/ + /** Update function for pk_i_256 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UPkI256Table : public URemoteTable FOnPkI256Delete OnDelete; private: - const FString TableName = TEXT("pk_i256"); + const FString TableName = TEXT("pk_i_256"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI32Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI32Table.g.h index 6bfc39baee2..805711689ef 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI32Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI32Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UPkI32Table : public URemoteTable void PostInitialize(); - /** Update function for pk_i32 table*/ + /** Update function for pk_i_32 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UPkI32Table : public URemoteTable FOnPkI32Delete OnDelete; private: - const FString TableName = TEXT("pk_i32"); + const FString TableName = TEXT("pk_i_32"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI64Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI64Table.g.h index c7fb8ceff7e..40e89be35b0 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI64Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI64Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UPkI64Table : public URemoteTable void PostInitialize(); - /** Update function for pk_i64 table*/ + /** Update function for pk_i_64 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UPkI64Table : public URemoteTable FOnPkI64Delete OnDelete; private: - const FString TableName = TEXT("pk_i64"); + const FString TableName = TEXT("pk_i_64"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI8Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI8Table.g.h index f33af5b4e60..8a03f4a049b 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI8Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkI8Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UPkI8Table : public URemoteTable void PostInitialize(); - /** Update function for pk_i8 table*/ + /** Update function for pk_i_8 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UPkI8Table : public URemoteTable FOnPkI8Delete OnDelete; private: - const FString TableName = TEXT("pk_i8"); + const FString TableName = TEXT("pk_i_8"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU128Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU128Table.g.h index 898f2e0f36b..069815b49d6 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU128Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU128Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UPkU128Table : public URemoteTable void PostInitialize(); - /** Update function for pk_u128 table*/ + /** Update function for pk_u_128 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UPkU128Table : public URemoteTable FOnPkU128Delete OnDelete; private: - const FString TableName = TEXT("pk_u128"); + const FString TableName = TEXT("pk_u_128"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU16Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU16Table.g.h index bf84e9c983a..2ddeb4be777 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU16Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU16Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UPkU16Table : public URemoteTable void PostInitialize(); - /** Update function for pk_u16 table*/ + /** Update function for pk_u_16 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UPkU16Table : public URemoteTable FOnPkU16Delete OnDelete; private: - const FString TableName = TEXT("pk_u16"); + const FString TableName = TEXT("pk_u_16"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU256Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU256Table.g.h index 08c20ff62c8..b1d09deed13 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU256Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU256Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UPkU256Table : public URemoteTable void PostInitialize(); - /** Update function for pk_u256 table*/ + /** Update function for pk_u_256 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UPkU256Table : public URemoteTable FOnPkU256Delete OnDelete; private: - const FString TableName = TEXT("pk_u256"); + const FString TableName = TEXT("pk_u_256"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU32Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU32Table.g.h index a789c124636..d982facd05e 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU32Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU32Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UPkU32Table : public URemoteTable void PostInitialize(); - /** Update function for pk_u32 table*/ + /** Update function for pk_u_32 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UPkU32Table : public URemoteTable FOnPkU32Delete OnDelete; private: - const FString TableName = TEXT("pk_u32"); + const FString TableName = TEXT("pk_u_32"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU32TwoTable.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU32TwoTable.g.h index c339273c53f..c15593a2475 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU32TwoTable.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU32TwoTable.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UPkU32TwoTable : public URemoteTable void PostInitialize(); - /** Update function for pk_u32_two table*/ + /** Update function for pk_u_32_two table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UPkU32TwoTable : public URemoteTable FOnPkU32TwoDelete OnDelete; private: - const FString TableName = TEXT("pk_u32_two"); + const FString TableName = TEXT("pk_u_32_two"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU64Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU64Table.g.h index 03b049c5649..d45897bb3ac 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU64Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU64Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UPkU64Table : public URemoteTable void PostInitialize(); - /** Update function for pk_u64 table*/ + /** Update function for pk_u_64 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UPkU64Table : public URemoteTable FOnPkU64Delete OnDelete; private: - const FString TableName = TEXT("pk_u64"); + const FString TableName = TEXT("pk_u_64"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU8Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU8Table.g.h index be15b181216..d5dc231c9a2 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU8Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/PkU8Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UPkU8Table : public URemoteTable void PostInitialize(); - /** Update function for pk_u8 table*/ + /** Update function for pk_u_8 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UPkU8Table : public URemoteTable FOnPkU8Delete OnDelete; private: - const FString TableName = TEXT("pk_u8"); + const FString TableName = TEXT("pk_u_8"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/ResultI32StringTable.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/ResultI32StringTable.g.h index 89b91d58575..6db46f146eb 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/ResultI32StringTable.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/ResultI32StringTable.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UResultI32StringTable : public URemoteTable public: void PostInitialize(); - /** Update function for result_i32_string table*/ + /** Update function for result_i_32_string table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UResultI32StringTable : public URemoteTable FOnResultI32StringDelete OnDelete; private: - const FString TableName = TEXT("result_i32_string"); + const FString TableName = TEXT("result_i_32_string"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/ResultSimpleEnumI32Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/ResultSimpleEnumI32Table.g.h index 793cdb36fc6..4b96a95de3b 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/ResultSimpleEnumI32Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/ResultSimpleEnumI32Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UResultSimpleEnumI32Table : public URemoteTable public: void PostInitialize(); - /** Update function for result_simple_enum_i32 table*/ + /** Update function for result_simple_enum_i_32 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UResultSimpleEnumI32Table : public URemoteTable FOnResultSimpleEnumI32Delete OnDelete; private: - const FString TableName = TEXT("result_simple_enum_i32"); + const FString TableName = TEXT("result_simple_enum_i_32"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/ResultStringI32Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/ResultStringI32Table.g.h index f1b5903f9e0..513f34fa5b9 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/ResultStringI32Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/ResultStringI32Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UResultStringI32Table : public URemoteTable public: void PostInitialize(); - /** Update function for result_string_i32 table*/ + /** Update function for result_string_i_32 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UResultStringI32Table : public URemoteTable FOnResultStringI32Delete OnDelete; private: - const FString TableName = TEXT("result_string_i32"); + const FString TableName = TEXT("result_string_i_32"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/ResultVecI32StringTable.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/ResultVecI32StringTable.g.h index cfe2096b6ab..9bb989777c0 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/ResultVecI32StringTable.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/ResultVecI32StringTable.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UResultVecI32StringTable : public URemoteTable public: void PostInitialize(); - /** Update function for result_vec_i32_string table*/ + /** Update function for result_vec_i_32_string table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UResultVecI32StringTable : public URemoteTable FOnResultVecI32StringDelete OnDelete; private: - const FString TableName = TEXT("result_vec_i32_string"); + const FString TableName = TEXT("result_vec_i_32_string"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI128Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI128Table.g.h index 478c18396c4..69e8fa44459 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI128Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI128Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UUniqueI128Table : public URemoteTable void PostInitialize(); - /** Update function for unique_i128 table*/ + /** Update function for unique_i_128 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UUniqueI128Table : public URemoteTable FOnUniqueI128Delete OnDelete; private: - const FString TableName = TEXT("unique_i128"); + const FString TableName = TEXT("unique_i_128"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI16Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI16Table.g.h index 19eed2f3e1f..089fd8288ed 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI16Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI16Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UUniqueI16Table : public URemoteTable void PostInitialize(); - /** Update function for unique_i16 table*/ + /** Update function for unique_i_16 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UUniqueI16Table : public URemoteTable FOnUniqueI16Delete OnDelete; private: - const FString TableName = TEXT("unique_i16"); + const FString TableName = TEXT("unique_i_16"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI256Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI256Table.g.h index cd361f925f7..bade2cef4d8 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI256Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI256Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UUniqueI256Table : public URemoteTable void PostInitialize(); - /** Update function for unique_i256 table*/ + /** Update function for unique_i_256 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UUniqueI256Table : public URemoteTable FOnUniqueI256Delete OnDelete; private: - const FString TableName = TEXT("unique_i256"); + const FString TableName = TEXT("unique_i_256"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI32Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI32Table.g.h index aada4f1ff3e..6422e86d25a 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI32Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI32Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UUniqueI32Table : public URemoteTable void PostInitialize(); - /** Update function for unique_i32 table*/ + /** Update function for unique_i_32 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UUniqueI32Table : public URemoteTable FOnUniqueI32Delete OnDelete; private: - const FString TableName = TEXT("unique_i32"); + const FString TableName = TEXT("unique_i_32"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI64Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI64Table.g.h index 764acab9cc8..b59d8424587 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI64Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI64Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UUniqueI64Table : public URemoteTable void PostInitialize(); - /** Update function for unique_i64 table*/ + /** Update function for unique_i_64 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UUniqueI64Table : public URemoteTable FOnUniqueI64Delete OnDelete; private: - const FString TableName = TEXT("unique_i64"); + const FString TableName = TEXT("unique_i_64"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI8Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI8Table.g.h index aa7727c19d5..9a062ac349a 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI8Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueI8Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UUniqueI8Table : public URemoteTable void PostInitialize(); - /** Update function for unique_i8 table*/ + /** Update function for unique_i_8 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UUniqueI8Table : public URemoteTable FOnUniqueI8Delete OnDelete; private: - const FString TableName = TEXT("unique_i8"); + const FString TableName = TEXT("unique_i_8"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU128Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU128Table.g.h index 2677d84d330..94d3264339d 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU128Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU128Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UUniqueU128Table : public URemoteTable void PostInitialize(); - /** Update function for unique_u128 table*/ + /** Update function for unique_u_128 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UUniqueU128Table : public URemoteTable FOnUniqueU128Delete OnDelete; private: - const FString TableName = TEXT("unique_u128"); + const FString TableName = TEXT("unique_u_128"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU16Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU16Table.g.h index aea33985c3d..aff7315996c 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU16Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU16Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UUniqueU16Table : public URemoteTable void PostInitialize(); - /** Update function for unique_u16 table*/ + /** Update function for unique_u_16 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UUniqueU16Table : public URemoteTable FOnUniqueU16Delete OnDelete; private: - const FString TableName = TEXT("unique_u16"); + const FString TableName = TEXT("unique_u_16"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU256Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU256Table.g.h index 21ddf618b21..c194b4419a7 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU256Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU256Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UUniqueU256Table : public URemoteTable void PostInitialize(); - /** Update function for unique_u256 table*/ + /** Update function for unique_u_256 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UUniqueU256Table : public URemoteTable FOnUniqueU256Delete OnDelete; private: - const FString TableName = TEXT("unique_u256"); + const FString TableName = TEXT("unique_u_256"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU32Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU32Table.g.h index c79c59b8e88..7cd143b611d 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU32Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU32Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UUniqueU32Table : public URemoteTable void PostInitialize(); - /** Update function for unique_u32 table*/ + /** Update function for unique_u_32 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UUniqueU32Table : public URemoteTable FOnUniqueU32Delete OnDelete; private: - const FString TableName = TEXT("unique_u32"); + const FString TableName = TEXT("unique_u_32"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU64Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU64Table.g.h index 3d022c15183..80cbcaebaa1 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU64Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU64Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UUniqueU64Table : public URemoteTable void PostInitialize(); - /** Update function for unique_u64 table*/ + /** Update function for unique_u_64 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UUniqueU64Table : public URemoteTable FOnUniqueU64Delete OnDelete; private: - const FString TableName = TEXT("unique_u64"); + const FString TableName = TEXT("unique_u_64"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU8Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU8Table.g.h index e07ea119744..5e38895c5d2 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU8Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/UniqueU8Table.g.h @@ -60,7 +60,7 @@ class TESTCLIENT_API UUniqueU8Table : public URemoteTable void PostInitialize(); - /** Update function for unique_u8 table*/ + /** Update function for unique_u_8 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -98,7 +98,7 @@ class TESTCLIENT_API UUniqueU8Table : public URemoteTable FOnUniqueU8Delete OnDelete; private: - const FString TableName = TEXT("unique_u8"); + const FString TableName = TEXT("unique_u_8"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecF32Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecF32Table.g.h index fa09dc1ffa5..345cece0c99 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecF32Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecF32Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UVecF32Table : public URemoteTable public: void PostInitialize(); - /** Update function for vec_f32 table*/ + /** Update function for vec_f_32 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UVecF32Table : public URemoteTable FOnVecF32Delete OnDelete; private: - const FString TableName = TEXT("vec_f32"); + const FString TableName = TEXT("vec_f_32"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecF64Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecF64Table.g.h index 8eb0e28d7fd..4e0b736f6a7 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecF64Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecF64Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UVecF64Table : public URemoteTable public: void PostInitialize(); - /** Update function for vec_f64 table*/ + /** Update function for vec_f_64 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UVecF64Table : public URemoteTable FOnVecF64Delete OnDelete; private: - const FString TableName = TEXT("vec_f64"); + const FString TableName = TEXT("vec_f_64"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI128Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI128Table.g.h index 95485adaee0..882ed6b4883 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI128Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI128Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UVecI128Table : public URemoteTable public: void PostInitialize(); - /** Update function for vec_i128 table*/ + /** Update function for vec_i_128 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UVecI128Table : public URemoteTable FOnVecI128Delete OnDelete; private: - const FString TableName = TEXT("vec_i128"); + const FString TableName = TEXT("vec_i_128"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI16Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI16Table.g.h index a793d1d42c1..5d50b9b67d0 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI16Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI16Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UVecI16Table : public URemoteTable public: void PostInitialize(); - /** Update function for vec_i16 table*/ + /** Update function for vec_i_16 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UVecI16Table : public URemoteTable FOnVecI16Delete OnDelete; private: - const FString TableName = TEXT("vec_i16"); + const FString TableName = TEXT("vec_i_16"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI256Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI256Table.g.h index d61ef4e5ad5..2bf83deb384 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI256Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI256Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UVecI256Table : public URemoteTable public: void PostInitialize(); - /** Update function for vec_i256 table*/ + /** Update function for vec_i_256 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UVecI256Table : public URemoteTable FOnVecI256Delete OnDelete; private: - const FString TableName = TEXT("vec_i256"); + const FString TableName = TEXT("vec_i_256"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI32Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI32Table.g.h index 7953feef881..2962afe1264 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI32Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI32Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UVecI32Table : public URemoteTable public: void PostInitialize(); - /** Update function for vec_i32 table*/ + /** Update function for vec_i_32 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UVecI32Table : public URemoteTable FOnVecI32Delete OnDelete; private: - const FString TableName = TEXT("vec_i32"); + const FString TableName = TEXT("vec_i_32"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI64Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI64Table.g.h index 4493a09f494..d9f2401a3d5 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI64Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI64Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UVecI64Table : public URemoteTable public: void PostInitialize(); - /** Update function for vec_i64 table*/ + /** Update function for vec_i_64 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UVecI64Table : public URemoteTable FOnVecI64Delete OnDelete; private: - const FString TableName = TEXT("vec_i64"); + const FString TableName = TEXT("vec_i_64"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI8Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI8Table.g.h index ea0d271ffe6..afb4c47813c 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI8Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecI8Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UVecI8Table : public URemoteTable public: void PostInitialize(); - /** Update function for vec_i8 table*/ + /** Update function for vec_i_8 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UVecI8Table : public URemoteTable FOnVecI8Delete OnDelete; private: - const FString TableName = TEXT("vec_i8"); + const FString TableName = TEXT("vec_i_8"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU128Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU128Table.g.h index 6ffec05f26e..6229d875c28 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU128Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU128Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UVecU128Table : public URemoteTable public: void PostInitialize(); - /** Update function for vec_u128 table*/ + /** Update function for vec_u_128 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UVecU128Table : public URemoteTable FOnVecU128Delete OnDelete; private: - const FString TableName = TEXT("vec_u128"); + const FString TableName = TEXT("vec_u_128"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU16Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU16Table.g.h index c30d06a29b8..193a9682aa4 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU16Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU16Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UVecU16Table : public URemoteTable public: void PostInitialize(); - /** Update function for vec_u16 table*/ + /** Update function for vec_u_16 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UVecU16Table : public URemoteTable FOnVecU16Delete OnDelete; private: - const FString TableName = TEXT("vec_u16"); + const FString TableName = TEXT("vec_u_16"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU256Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU256Table.g.h index 03939aceba1..873c966635e 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU256Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU256Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UVecU256Table : public URemoteTable public: void PostInitialize(); - /** Update function for vec_u256 table*/ + /** Update function for vec_u_256 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UVecU256Table : public URemoteTable FOnVecU256Delete OnDelete; private: - const FString TableName = TEXT("vec_u256"); + const FString TableName = TEXT("vec_u_256"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU32Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU32Table.g.h index eac904322e1..075385b23f2 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU32Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU32Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UVecU32Table : public URemoteTable public: void PostInitialize(); - /** Update function for vec_u32 table*/ + /** Update function for vec_u_32 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UVecU32Table : public URemoteTable FOnVecU32Delete OnDelete; private: - const FString TableName = TEXT("vec_u32"); + const FString TableName = TEXT("vec_u_32"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU64Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU64Table.g.h index c52cae6bb4d..6156442ba3b 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU64Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU64Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UVecU64Table : public URemoteTable public: void PostInitialize(); - /** Update function for vec_u64 table*/ + /** Update function for vec_u_64 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UVecU64Table : public URemoteTable FOnVecU64Delete OnDelete; private: - const FString TableName = TEXT("vec_u64"); + const FString TableName = TEXT("vec_u_64"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU8Table.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU8Table.g.h index d3602f7adce..21c48b3f05f 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU8Table.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Tables/VecU8Table.g.h @@ -20,7 +20,7 @@ class TESTCLIENT_API UVecU8Table : public URemoteTable public: void PostInitialize(); - /** Update function for vec_u8 table*/ + /** Update function for vec_u_8 table*/ FTableAppliedDiff Update(TArray> InsertsRef, TArray> DeletesRef); /** Number of subscribed rows currently in the cache */ @@ -58,7 +58,7 @@ class TESTCLIENT_API UVecU8Table : public URemoteTable FOnVecU8Delete OnDelete; private: - const FString TableName = TEXT("vec_u8"); + const FString TableName = TEXT("vec_u_8"); TSharedPtr> Data; }; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Types/EnumWithPayloadType.g.h b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Types/EnumWithPayloadType.g.h index 79eca6d6c3b..1c4ef086cf8 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Types/EnumWithPayloadType.g.h +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Public/ModuleBindings/Types/EnumWithPayloadType.g.h @@ -4,9 +4,9 @@ #pragma once #include "CoreMinimal.h" #include "BSATN/UESpacetimeDB.h" -#include "Types/Builtins.h" #include "ModuleBindings/Types/SimpleEnumType.g.h" #include "Kismet/BlueprintFunctionLibrary.h" +#include "Types/Builtins.h" #include "EnumWithPayloadType.g.generated.h" UENUM(BlueprintType) @@ -46,7 +46,7 @@ struct TESTCLIENT_API FEnumWithPayloadType public: FEnumWithPayloadType() = default; - TVariant, TArray, uint8, int16, TArray, FSpacetimeDBIdentity, FString, uint16, uint32, FSpacetimeDBUInt128, FSpacetimeDBInt128, FSpacetimeDBConnectionId, int8, TArray, double, int32, bool, FSpacetimeDBUInt256> MessageData; + TVariant, uint32, int16, uint8, FSpacetimeDBInt128, FString, int64, uint64, int32, double, FSpacetimeDBInt256, TArray, bool, int8, uint16, FSpacetimeDBUInt128, float, FSpacetimeDBUInt256, FSpacetimeDBConnectionId, TArray, TArray, FSpacetimeDBTimestamp> MessageData; UPROPERTY(BlueprintReadOnly) EEnumWithPayloadTag Tag = static_cast(0); diff --git a/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Private/ModuleBindings/SpacetimeDBClient.g.cpp b/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Private/ModuleBindings/SpacetimeDBClient.g.cpp index a6fb7dbf8f0..c08e7fea1dd 100644 --- a/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Private/ModuleBindings/SpacetimeDBClient.g.cpp +++ b/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Private/ModuleBindings/SpacetimeDBClient.g.cpp @@ -8,28 +8,12 @@ #include "ModuleBindings/Tables/PkUuidTable.g.h" #include "ModuleBindings/Tables/ProcInsertsIntoTable.g.h" -static FReducer DecodeReducer(const FReducerEvent& Event) -{ - const FString& ReducerName = Event.ReducerCall.ReducerName; - - if (ReducerName == TEXT("schedule_proc")) - { - FScheduleProcArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::ScheduleProc(Args); - } - - return FReducer(); -} - UDbConnection::UDbConnection(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { - SetReducerFlags = ObjectInitializer.CreateDefaultSubobject(this, TEXT("SetReducerFlags")); - Db = ObjectInitializer.CreateDefaultSubobject(this, TEXT("RemoteTables")); Db->Initialize(); Reducers = ObjectInitializer.CreateDefaultSubobject(this, TEXT("RemoteReducers")); - Reducers->SetCallReducerFlags = SetReducerFlags; Reducers->Conn = this; Procedures = ObjectInitializer.CreateDefaultSubobject(this, TEXT("RemoteProcedures")); @@ -44,7 +28,6 @@ FContextBase::FContextBase(UDbConnection* InConn) { Db = InConn->Db; Reducers = InConn->Reducers; - SetReducerFlags = InConn->SetReducerFlags; Procedures = InConn->Procedures; Conn = InConn; } @@ -85,11 +68,6 @@ void URemoteTables::Initialize() /**/ } -void USetReducerFlags::ScheduleProc(ECallReducerFlags Flag) -{ - FlagMap.Add("ScheduleProc", Flag); -} - void URemoteReducers::ScheduleProc() { if (!Conn) @@ -98,7 +76,9 @@ void URemoteReducers::ScheduleProc() return; } - Conn->CallReducerTyped(TEXT("schedule_proc"), FScheduleProcArgs(), SetCallReducerFlags); + FScheduleProcArgs ReducerArgs; + const uint32 RequestId = Conn->CallReducerTyped(TEXT("schedule_proc"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::ScheduleProc(ReducerArgs)); } } bool URemoteReducers::InvokeScheduleProc(const FReducerEventContext& Context, const UScheduleProcReducer* Args) @@ -459,11 +439,45 @@ void UDbConnection::OnUnhandledProcedureErrorHandler(const FProcedureEventContex } } +void UDbConnection::RegisterPendingTypedReducer(uint32 RequestId, FReducer Reducer) +{ + Reducer.RequestId = RequestId; + PendingTypedReducers.Add(RequestId, MoveTemp(Reducer)); +} + +bool UDbConnection::TryGetPendingTypedReducer(uint32 RequestId, FReducer& OutReducer) const +{ + if (const FReducer* Found = PendingTypedReducers.Find(RequestId)) + { + OutReducer = *Found; + return true; + } + return false; +} + +bool UDbConnection::TryTakePendingTypedReducer(uint32 RequestId, FReducer& OutReducer) +{ + if (FReducer* Found = PendingTypedReducers.Find(RequestId)) + { + OutReducer = *Found; + PendingTypedReducers.Remove(RequestId); + return true; + } + return false; +} + void UDbConnection::ReducerEvent(const FReducerEvent& Event) { if (!Reducers) { return; } - FReducer DecodedReducer = DecodeReducer(Event); + FReducer DecodedReducer; + if (!TryTakePendingTypedReducer(Event.RequestId, DecodedReducer)) + { + const FString ErrorMessage = FString::Printf(TEXT("Reducer result for unknown request_id %u"), Event.RequestId); + UE_LOG(LogTemp, Error, TEXT("%s"), *ErrorMessage); + ReducerEventFailed(Event, ErrorMessage); + return; + } FTestProcClientReducerEvent ReducerEvent; ReducerEvent.CallerConnectionId = Event.CallerConnectionId; @@ -475,8 +489,8 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) FReducerEventContext Context(this, ReducerEvent); - // Use hardcoded string matching for reducer dispatching - const FString& ReducerName = Event.ReducerCall.ReducerName; + // Dispatch by typed reducer metadata + const FString& ReducerName = ReducerEvent.Reducer.ReducerName; if (ReducerName == TEXT("schedule_proc")) { @@ -676,7 +690,13 @@ void UDbConnection::DbUpdate(const FDatabaseUpdateType& Update, const FSpacetime case ESpacetimeDBEventTag::Reducer: { FReducerEvent ReducerEvent = Event.GetAsReducer(); - FReducer Reducer = DecodeReducer(ReducerEvent); + FReducer Reducer; + if (!TryGetPendingTypedReducer(ReducerEvent.RequestId, Reducer)) + { + UE_LOG(LogTemp, Warning, TEXT("Missing typed reducer for request_id %u while building table-update event context; using UnknownTransaction event"), ReducerEvent.RequestId); + BaseEvent = FTestProcClientEvent::UnknownTransaction(FSpacetimeDBUnit()); + break; + } BaseEvent = FTestProcClientEvent::Reducer(Reducer); break; } @@ -693,6 +713,10 @@ void UDbConnection::DbUpdate(const FDatabaseUpdateType& Update, const FSpacetime BaseEvent = FTestProcClientEvent::Disconnected(Event.GetAsDisconnected()); break; + case ESpacetimeDBEventTag::Transaction: + BaseEvent = FTestProcClientEvent::Transaction(Event.GetAsTransaction()); + break; + case ESpacetimeDBEventTag::SubscribeError: BaseEvent = FTestProcClientEvent::SubscribeError(Event.GetAsSubscribeError()); break; diff --git a/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Public/ModuleBindings/SpacetimeDBClient.g.h b/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Public/ModuleBindings/SpacetimeDBClient.g.h index ecfb5d2d4b3..3269ea4c120 100644 --- a/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Public/ModuleBindings/SpacetimeDBClient.g.h +++ b/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Public/ModuleBindings/SpacetimeDBClient.g.h @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.12.0 (commit 11e258c2f8c9de8f67098f65e3f6a9db32026768). +// This was generated using spacetimedb cli version 2.0.1 (commit 6f8639a69dac2047da00b1fc8550c94ea2505892). #pragma once #include "CoreMinimal.h" @@ -9,7 +9,6 @@ #include "Connection/Callback.h" #include "Connection/DbConnectionBase.h" #include "Connection/DbConnectionBuilder.h" -#include "Connection/SetReducerFlags.h" #include "Connection/Subscription.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "ModuleBindings/Procedures/InsertWithTxCommit.g.h" @@ -66,7 +65,7 @@ struct TESTPROCCLIENT_API FContextBase { GENERATED_BODY() - FContextBase() : Db(nullptr), Reducers(nullptr), SetReducerFlags(nullptr), Procedures(nullptr), Conn(nullptr) {}; + FContextBase() : Db(nullptr), Reducers(nullptr), Procedures(nullptr), Conn(nullptr) {}; FContextBase(UDbConnection* InConn); UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") @@ -75,9 +74,6 @@ struct TESTPROCCLIENT_API FContextBase UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") URemoteReducers* Reducers; - UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") - USetReducerFlags* SetReducerFlags; - UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") URemoteProcedures* Procedures; @@ -105,9 +101,6 @@ class TESTPROCCLIENT_API UContextBaseBpLib : public UBlueprintFunctionLibrary UFUNCTION(BlueprintPure, Category="SpacetimeDB") static URemoteReducers* GetReducers(const FContextBase& Ctx) { return Ctx.Reducers; } - UFUNCTION(BlueprintPure, Category="SpacetimeDB") - static USetReducerFlags* GetSetReducerFlags(const FContextBase& Ctx) { return Ctx.SetReducerFlags; } - static URemoteProcedures* GetProcedures(const FContextBase& Ctx) { return Ctx.Procedures; } UFUNCTION(BlueprintPure, Category="SpacetimeDB") @@ -674,6 +667,14 @@ struct TESTPROCCLIENT_API FTestProcClientEvent return Obj; } + static FTestProcClientEvent Transaction(const FSpacetimeDBUnit& Value) + { + FTestProcClientEvent Obj; + Obj.Tag = ESpacetimeDBEventTag::Transaction; + Obj.MessageData.Set(Value); + return Obj; + } + static FTestProcClientEvent SubscribeError(const FString& Value) { FTestProcClientEvent Obj; @@ -718,6 +719,13 @@ struct TESTPROCCLIENT_API FTestProcClientEvent return MessageData.Get(); } + FORCEINLINE bool IsTransaction() const { return Tag == ESpacetimeDBEventTag::Transaction; } + FORCEINLINE FSpacetimeDBUnit GetAsTransaction() const + { + ensureMsgf(IsTransaction(), TEXT("MessageData does not hold Transaction!")); + return MessageData.Get(); + } + FORCEINLINE bool IsSubscribeError() const { return Tag == ESpacetimeDBEventTag::SubscribeError; } FORCEINLINE FString GetAsSubscribeError() const { @@ -741,6 +749,7 @@ struct TESTPROCCLIENT_API FTestProcClientEvent case ESpacetimeDBEventTag::SubscribeApplied: return GetAsSubscribeApplied() == Other.GetAsSubscribeApplied(); case ESpacetimeDBEventTag::UnsubscribeApplied: return GetAsUnsubscribeApplied() == Other.GetAsUnsubscribeApplied(); case ESpacetimeDBEventTag::Disconnected: return GetAsDisconnected() == Other.GetAsDisconnected(); + case ESpacetimeDBEventTag::Transaction: return GetAsTransaction() == Other.GetAsTransaction(); case ESpacetimeDBEventTag::SubscribeError: return GetAsSubscribeError() == Other.GetAsSubscribeError(); case ESpacetimeDBEventTag::UnknownTransaction: return GetAsUnknownTransaction() == Other.GetAsUnknownTransaction(); default: return false; @@ -783,6 +792,12 @@ class TESTPROCCLIENT_API UTestProcClientEventBpLib : public UBlueprintFunctionLi return FTestProcClientEvent::Disconnected(InValue); } + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|TestProcClientEvent") + static FTestProcClientEvent Transaction(const FSpacetimeDBUnit& InValue) + { + return FTestProcClientEvent::Transaction(InValue); + } + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|TestProcClientEvent") static FTestProcClientEvent SubscribeError(const FString& InValue) { @@ -807,6 +822,9 @@ class TESTPROCCLIENT_API UTestProcClientEventBpLib : public UBlueprintFunctionLi UFUNCTION(BlueprintPure, Category = "SpacetimeDB|TestProcClientEvent") static bool IsDisconnected(const FTestProcClientEvent& Event) { return Event.IsDisconnected(); } + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|TestProcClientEvent") + static bool IsTransaction(const FTestProcClientEvent& Event) { return Event.IsTransaction(); } + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|TestProcClientEvent") static bool IsSubscribeError(const FTestProcClientEvent& Event) { return Event.IsSubscribeError(); } @@ -837,6 +855,12 @@ class TESTPROCCLIENT_API UTestProcClientEventBpLib : public UBlueprintFunctionLi return Event.GetAsDisconnected(); } + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|TestProcClientEvent") + static FSpacetimeDBUnit GetAsTransaction(const FTestProcClientEvent& Event) + { + return Event.GetAsTransaction(); + } + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|TestProcClientEvent") static FString GetAsSubscribeError(const FTestProcClientEvent& Event) { @@ -919,17 +943,6 @@ DECLARE_DYNAMIC_DELEGATE_OneParam( FOnSubscriptionError, FErrorContext, Context); -UCLASS(BlueprintType) -class TESTPROCCLIENT_API USetReducerFlags : public USetReducerFlagsBase -{ - GENERATED_BODY() - -public: - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void ScheduleProc(ECallReducerFlags Flag); - -}; - // RemoteTables class UCLASS(BlueprintType) class TESTPROCCLIENT_API URemoteTables : public UObject @@ -981,9 +994,6 @@ class TESTPROCCLIENT_API URemoteReducers : public UObject UPROPERTY() class UDbConnection* Conn; - - UPROPERTY() - USetReducerFlags* SetCallReducerFlags; }; DECLARE_DYNAMIC_DELEGATE_ThreeParams(FOnInsertWithTxCommitComplete, @@ -1209,9 +1219,6 @@ class TESTPROCCLIENT_API UDbConnection : public UDbConnectionBase UPROPERTY(BlueprintReadOnly, Category="SpacetimeDB") URemoteReducers* Reducers; - UPROPERTY(BlueprintReadOnly, Category="SpacetimeDB") - USetReducerFlags* SetReducerFlags; - UPROPERTY(BlueprintReadOnly, Category="SpacetimeDB") URemoteProcedures* Procedures; @@ -1263,5 +1270,15 @@ class TESTPROCCLIENT_API UDbConnection : public UDbConnectionBase virtual void ReducerEventFailed(const FReducerEvent& Event, const FString ErrorMessage) override; // Override the procedure event failed handler virtual void ProcedureEventFailed(const FProcedureEvent& Event, const FString ErrorMessage) override; + + friend class URemoteReducers; + + // Internal reducer correlation helpers (request_id -> typed reducer) + void RegisterPendingTypedReducer(uint32 RequestId, FReducer Reducer); + bool TryGetPendingTypedReducer(uint32 RequestId, FReducer& OutReducer) const; + bool TryTakePendingTypedReducer(uint32 RequestId, FReducer& OutReducer); + +private: + TMap PendingTypedReducers; }; diff --git a/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Public/ModuleBindings/Types/ReturnEnumType.g.h b/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Public/ModuleBindings/Types/ReturnEnumType.g.h index 14b4b797c33..a0235284c48 100644 --- a/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Public/ModuleBindings/Types/ReturnEnumType.g.h +++ b/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Public/ModuleBindings/Types/ReturnEnumType.g.h @@ -22,7 +22,7 @@ struct TESTPROCCLIENT_API FReturnEnumType public: FReturnEnumType() = default; - TVariant MessageData; + TVariant MessageData; UPROPERTY(BlueprintReadOnly) EReturnEnumTag Tag = static_cast(0); From f824ab0f2b9121e9f6f1b7967b9df5b999c2a928 Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Thu, 26 Feb 2026 15:52:05 -0800 Subject: [PATCH 05/15] Add multi-module support --- Cargo.lock | 1 + crates/cli/src/subcommands/generate.rs | 10 + crates/codegen/Cargo.toml | 1 + crates/codegen/src/unrealcpp.rs | 1009 +++++++++++++++--------- 4 files changed, 637 insertions(+), 384 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a01d6991c9a..633788cc825 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7767,6 +7767,7 @@ dependencies = [ "insta", "itertools 0.12.1", "regex", + "serde_json", "spacetimedb-data-structures", "spacetimedb-lib 2.0.2", "spacetimedb-primitives 2.0.2", diff --git a/crates/cli/src/subcommands/generate.rs b/crates/cli/src/subcommands/generate.rs index 0e7c896d34c..f65e49e8b57 100644 --- a/crates/cli/src/subcommands/generate.rs +++ b/crates/cli/src/subcommands/generate.rs @@ -48,6 +48,7 @@ fn build_generate_config_schema(command: &clap::Command) -> Result clap::Command { .alias("module-name") .help("The module name that should be used for DLL export macros (required for lang unrealcpp)") ) + .arg( + Arg::new("module_prefix") + .long("module-prefix") + .help("The module prefix to use for generated types (only used with --lang unrealcpp)") + ) .arg( Arg::new("lang") .long("lang") @@ -285,6 +291,7 @@ pub struct GenerateRunConfig { pub lang: Language, pub namespace: String, pub module_name: Option, + pub module_prefix: Option, pub build_options: String, pub out_dir: PathBuf, pub include_private: bool, @@ -313,6 +320,7 @@ fn prepare_generate_run_configs<'a>( .get_one::("namespace")? .unwrap_or_else(|| "SpacetimeDB.Types".to_string()); let module_name = command_config.get_one::("unreal_module_name")?; + let module_prefix = command_config.get_one::("module_prefix")?; let build_options = command_config .get_one::("build_options")? .unwrap_or_else(String::new); @@ -371,6 +379,7 @@ fn prepare_generate_run_configs<'a>( lang, namespace, module_name, + module_prefix, build_options, out_dir, include_private, @@ -512,6 +521,7 @@ pub async fn run_prepared_generate_configs( unreal_cpp_lang = UnrealCpp { module_name: run.module_name.as_ref().unwrap(), uproject_dir: &run.out_dir, + module_prefix: run.module_prefix.as_deref().unwrap_or(""), }; &unreal_cpp_lang as &dyn Lang } diff --git a/crates/codegen/Cargo.toml b/crates/codegen/Cargo.toml index 54e0f589669..9d362a09ade 100644 --- a/crates/codegen/Cargo.toml +++ b/crates/codegen/Cargo.toml @@ -15,6 +15,7 @@ spacetimedb-schema.workspace = true anyhow.workspace = true convert_case.workspace = true itertools.workspace = true +serde_json.workspace = true [dev-dependencies] fs-err.workspace = true diff --git a/crates/codegen/src/unrealcpp.rs b/crates/codegen/src/unrealcpp.rs index ce233d995e7..403bf351300 100644 --- a/crates/codegen/src/unrealcpp.rs +++ b/crates/codegen/src/unrealcpp.rs @@ -23,6 +23,7 @@ use std::path::Path; pub struct UnrealCpp<'opts> { pub module_name: &'opts str, pub uproject_dir: &'opts Path, + pub module_prefix: &'opts str, } // --------------------------------------------------------------------------- @@ -37,8 +38,9 @@ impl UnrealCpp<'_> { impl Lang for UnrealCpp<'_> { fn generate_table_file_from_schema(&self, module: &ModuleDef, table: &TableDef, schema: TableSchema) -> OutputFile { - let struct_name = type_ref_name(module, table.product_type_ref); - let table_pascal = table.name.deref().to_case(Case::Pascal); + let module_prefix = self.module_prefix; + let struct_name = type_ref_name(self.module_prefix, module, table.product_type_ref); + let table_pascal = format!("{module_prefix}{}", table.name.deref().to_case(Case::Pascal)); let self_header = table_pascal.clone() + "Table"; let mut output = UnrealCppAutogen::new( @@ -76,7 +78,8 @@ impl Lang for UnrealCpp<'_> { if let Some(col) = columns.as_singleton() { let (f_name, f_ty) = &product_type.unwrap().elements[col.idx()]; let field_name = f_name.deref().to_case(Case::Pascal); - let field_type = cpp_ty_fmt_with_module(module, f_ty, self.module_name).to_string(); + let field_type = + cpp_ty_fmt_with_module(self.module_prefix, module, f_ty, self.module_name).to_string(); let index_name = accessor_name.deref().to_case(Case::Pascal); let index_class_name = format!("U{table_pascal}{index_name}UniqueIndex"); let key_type = field_type.clone(); @@ -173,7 +176,8 @@ impl Lang for UnrealCpp<'_> { .map(|col| { let (f_name, f_ty) = &product_type.unwrap().elements[col.idx()]; let field_name = f_name.deref().to_case(Case::Pascal); - let field_type = cpp_ty_fmt_with_module(module, f_ty, self.module_name).to_string(); + let field_type = + cpp_ty_fmt_with_module(self.module_prefix, module, f_ty, self.module_name).to_string(); let param_type = format!("const {field_type}&"); (field_name, field_type, param_type, f_ty, f_name.deref().to_string()) @@ -326,21 +330,21 @@ impl Lang for UnrealCpp<'_> { writeln!(output, " // Table Events"); writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams( "); writeln!(output, " FOn{table_pascal}Insert,"); - writeln!(output, " const FEventContext&, Context,"); + writeln!(output, " const F{module_prefix}EventContext&, Context,"); writeln!(output, " const {row_struct}&, NewRow);"); writeln!(output); if !table.is_event { writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams( "); writeln!(output, " FOn{table_pascal}Update,"); - writeln!(output, " const FEventContext&, Context,"); + writeln!(output, " const F{module_prefix}EventContext&, Context,"); writeln!(output, " const {row_struct}&, OldRow,"); writeln!(output, " const {row_struct}&, NewRow);"); writeln!(output); writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams( "); writeln!(output, " FOn{table_pascal}Delete,"); - writeln!(output, " const FEventContext&, Context,"); + writeln!(output, " const F{module_prefix}EventContext&, Context,"); writeln!(output, " const {row_struct}&, DeletedRow);"); writeln!(output); } @@ -379,7 +383,7 @@ impl Lang for UnrealCpp<'_> { filename: format!( "Source/{}/Public/ModuleBindings/Tables/{}Table.g.h", self.module_name, - table.name.deref().to_case(Case::Pascal) //type_ref_name(module, table.product_type_ref) + format!("{module_prefix}{}", table.name.deref().to_case(Case::Pascal)) ), code: output.into_inner(), } @@ -399,29 +403,40 @@ impl Lang for UnrealCpp<'_> { ); let code: String = match &module.typespace_for_generate()[typ.ty] { AlgebraicTypeDef::PlainEnum(plain_enum) => autogen_cpp_enum(name, plain_enum), - AlgebraicTypeDef::Product(product_type_def) => { - autogen_cpp_struct(module, name, product_type_def, &self.get_api_macro(), self.module_name) - } - AlgebraicTypeDef::Sum(sum_type_def) => { - autogen_cpp_sum(module, name, sum_type_def, &self.get_api_macro(), self.module_name) - } + AlgebraicTypeDef::Product(product_type_def) => autogen_cpp_struct( + self.module_prefix, + module, + name, + product_type_def, + &self.get_api_macro(), + self.module_name, + ), + AlgebraicTypeDef::Sum(sum_type_def) => autogen_cpp_sum( + self.module_prefix, + module, + name, + sum_type_def, + &self.get_api_macro(), + self.module_name, + ), }; vec![OutputFile { filename, code }] } fn generate_reducer_file(&self, module: &ModuleDef, reducer: &ReducerDef) -> OutputFile { + let module_prefix = self.module_prefix; let reducer_snake = reducer.name.deref(); let pascal = reducer_snake.to_case(Case::Pascal); // Collect includes for parameter types let mut includes = HashSet::::new(); for (_param_name, param_type) in &reducer.params_for_generate.elements { - collect_includes_for_type(module, param_type, &mut includes, self.module_name); + collect_includes_for_type(self.module_prefix, module, param_type, &mut includes, self.module_name); } - // Add ReducerBase.g.h for UReducerBase definition - includes.insert("ModuleBindings/ReducerBase.g.h".to_string()); + // Add {module_prefix}ReducerBase.g.h for U{module_prefix}ReducerBase definition + includes.insert(format!("ModuleBindings/{module_prefix}ReducerBase.g.h")); // Convert to sorted vector let mut include_vec: Vec = includes.into_iter().collect(); @@ -445,8 +460,8 @@ impl Lang for UnrealCpp<'_> { // Generate properties for each parameter for (param_name, param_type) in &reducer.params_for_generate.elements { let param_pascal = param_name.deref().to_case(Case::Pascal); - let type_str = cpp_ty_fmt_with_module(module, param_type, self.module_name).to_string(); - let init_str = cpp_ty_init_fmt_impl(module, param_type); + let type_str = cpp_ty_fmt_with_module(self.module_prefix, module, param_type, self.module_name).to_string(); + let init_str = cpp_ty_init_fmt_impl(self.module_prefix, module, param_type); let field_decl = format!("{type_str} {param_pascal}{init_str}"); // Check if the type is blueprintable @@ -477,7 +492,8 @@ impl Lang for UnrealCpp<'_> { } first = false; let param_pascal = param_name.deref().to_case(Case::Pascal); - let type_str = cpp_ty_fmt_with_module(module, param_type, self.module_name).to_string(); + let type_str = + cpp_ty_fmt_with_module(self.module_prefix, module, param_type, self.module_name).to_string(); write!(header, "const {type_str}& In{param_pascal}"); } @@ -563,7 +579,7 @@ impl Lang for UnrealCpp<'_> { writeln!(header, "UCLASS(BlueprintType)"); writeln!( header, - "class {} U{pascal}Reducer : public UReducerBase", + "class {} U{pascal}Reducer : public U{module_prefix}ReducerBase", self.get_api_macro() ); writeln!(header, "{{"); @@ -574,8 +590,8 @@ impl Lang for UnrealCpp<'_> { // Generate properties for each parameter (for dispatching) for (param_name, param_type) in &reducer.params_for_generate.elements { let param_pascal = param_name.deref().to_case(Case::Pascal); - let type_str = cpp_ty_fmt_with_module(module, param_type, self.module_name).to_string(); - let init_str = cpp_ty_init_fmt_impl(module, param_type); + let type_str = cpp_ty_fmt_with_module(self.module_prefix, module, param_type, self.module_name).to_string(); + let init_str = cpp_ty_init_fmt_impl(self.module_prefix, module, param_type); let field_decl = format!("{type_str} {param_pascal}{init_str}"); // Check if the type is blueprintable @@ -617,9 +633,10 @@ impl Lang for UnrealCpp<'_> { // Collect includes for parameter types let mut includes = HashSet::::new(); for (_param_name, param_type) in &procedure.params_for_generate.elements { - collect_includes_for_type(module, param_type, &mut includes, self.module_name); + collect_includes_for_type(self.module_prefix, module, param_type, &mut includes, self.module_name); } collect_includes_for_type( + self.module_prefix, module, &procedure.return_type_for_generate, &mut includes, @@ -648,8 +665,8 @@ impl Lang for UnrealCpp<'_> { // Generate properties for each parameter for (param_name, param_type) in &procedure.params_for_generate.elements { let param_pascal = param_name.deref().to_case(Case::Pascal); - let type_str = cpp_ty_fmt_with_module(module, param_type, self.module_name).to_string(); - let init_str = cpp_ty_init_fmt_impl(module, param_type); + let type_str = cpp_ty_fmt_with_module(self.module_prefix, module, param_type, self.module_name).to_string(); + let init_str = cpp_ty_init_fmt_impl(self.module_prefix, module, param_type); let field_decl = format!("{type_str} {param_pascal}{init_str}"); // Check if the type is blueprintable @@ -680,7 +697,8 @@ impl Lang for UnrealCpp<'_> { } first = false; let param_pascal = param_name.deref().to_case(Case::Pascal); - let type_str = cpp_ty_fmt_with_module(module, param_type, self.module_name).to_string(); + let type_str = + cpp_ty_fmt_with_module(self.module_prefix, module, param_type, self.module_name).to_string(); write!(header, "const {type_str}& In{param_pascal}"); } @@ -770,10 +788,11 @@ impl Lang for UnrealCpp<'_> { } fn generate_global_files(&self, module: &ModuleDef, options: &CodegenOptions) -> Vec { + let module_prefix = self.module_prefix; let mut files: Vec = vec![]; // First, collect and generate all optional types - let (optional_types, result_types) = collect_wrapper_types(module, options.visibility); + let (optional_types, result_types) = collect_wrapper_types(self.module_prefix, module, options.visibility); for optional_name in optional_types { let module_name = &self.module_name; let module_name_pascal = module_name.to_case(Case::Pascal); @@ -809,38 +828,51 @@ impl Lang for UnrealCpp<'_> { includes.insert("Connection/DbConnectionBuilder.h".to_string()); includes.insert("Connection/Subscription.h".to_string()); includes.insert("Connection/Callback.h".to_string()); - includes.insert("ModuleBindings/ReducerBase.g.h".to_string()); + includes.insert(format!("ModuleBindings/{module_prefix}ReducerBase.g.h")); includes.insert("Kismet/BlueprintFunctionLibrary.h".to_string()); // Include reducers for reducer in iter_reducers(module, options.visibility) { - let reducer_pascal = reducer.name.deref().to_case(Case::Pascal); + let reducer_pascal = format!("{module_prefix}{}", reducer.name.deref().to_case(Case::Pascal)); includes.insert(format!("ModuleBindings/Reducers/{reducer_pascal}.g.h")); } // Include procedures for procedure in iter_procedures(module, options.visibility) { - let procedure_pascal = procedure.name.deref().to_case(Case::Pascal); + let procedure_pascal = format!("{module_prefix}{}", procedure.name.deref().to_case(Case::Pascal)); includes.insert(format!("ModuleBindings/Procedures/{procedure_pascal}.g.h")); } // Collect includes for types used in delegates and contexts - // FSpacetimeDBIdentity is used in FOnConnectDelegate and context methods - collect_includes_for_type(module, &AlgebraicTypeUse::Identity, &mut includes, self.module_name); + // FSpacetimeDBIdentity is used in F{module_prefix}OnConnectDelegate and context methods + collect_includes_for_type( + self.module_prefix, + module, + &AlgebraicTypeUse::Identity, + &mut includes, + self.module_name, + ); // FSpacetimeDBConnectionId is used in context methods - collect_includes_for_type(module, &AlgebraicTypeUse::ConnectionId, &mut includes, self.module_name); + collect_includes_for_type( + self.module_prefix, + module, + &AlgebraicTypeUse::ConnectionId, + &mut includes, + self.module_name, + ); // Collect includes for all reducer parameter types for reducer in iter_reducers(module, options.visibility) { for (_param_name, param_type) in &reducer.params_for_generate.elements { - collect_includes_for_type(module, param_type, &mut includes, self.module_name); + collect_includes_for_type(self.module_prefix, module, param_type, &mut includes, self.module_name); } } // Collect includes for all procedure parameter types for procedure in iter_procedures(module, options.visibility) { for (_param_name, param_type) in &procedure.params_for_generate.elements { - collect_includes_for_type(module, param_type, &mut includes, self.module_name); + collect_includes_for_type(self.module_prefix, module, param_type, &mut includes, self.module_name); } collect_includes_for_type( + self.module_prefix, module, &procedure.return_type_for_generate, &mut includes, @@ -855,43 +887,56 @@ impl Lang for UnrealCpp<'_> { // Convert to string references let include_refs: Vec<&str> = include_vec.iter().map(|s| s.as_str()).collect(); - let mut client_h = UnrealCppAutogen::new(&include_refs, "SpacetimeDBClient", true); + let self_header = format!("{module_prefix}SpacetimeDBClient"); + let mut client_h = UnrealCppAutogen::new(&include_refs, &self_header, true); // Forward declarations writeln!(client_h, "// Forward declarations"); - writeln!(client_h, "class UDbConnection;"); - writeln!(client_h, "class URemoteTables;"); - writeln!(client_h, "class URemoteReducers;"); - writeln!(client_h, "class URemoteProcedures;"); - writeln!(client_h, "class USubscriptionBuilder;"); - writeln!(client_h, "class USubscriptionHandle;"); + writeln!(client_h, "class U{module_prefix}DbConnection;"); + writeln!(client_h, "class U{module_prefix}RemoteTables;"); + writeln!(client_h, "class U{module_prefix}RemoteReducers;"); + writeln!(client_h, "class U{module_prefix}RemoteProcedures;"); + writeln!(client_h, "class U{module_prefix}SubscriptionBuilder;"); + writeln!(client_h, "class U{module_prefix}SubscriptionHandle;"); writeln!(client_h); writeln!(client_h, "/** Forward declaration for tables */"); for (_, accessor_name, _) in iter_table_names_and_types(module, options.visibility) { - writeln!(client_h, "class U{}Table;", accessor_name.deref().to_case(Case::Pascal)); + writeln!( + client_h, + "class U{module_prefix}{}Table;", + accessor_name.deref().to_case(Case::Pascal) + ); } writeln!(client_h, "/***/"); writeln!(client_h); // Delegates first (as in manual) - generate_delegates(&mut client_h); + generate_delegates(&mut client_h, self.module_prefix); // Context structs generate_context_structs( &mut client_h, module, options.visibility, + self.module_prefix, &self.get_api_macro(), &self.module_name.to_case(Case::Pascal), ); // RemoteTables class - generate_remote_tables_class(&mut client_h, module, options.visibility, &self.get_api_macro()); + generate_remote_tables_class( + &mut client_h, + self.module_prefix, + module, + options.visibility, + &self.get_api_macro(), + ); // RemoteReducers class generate_remote_reducers_class( &mut client_h, + self.module_prefix, module, options.visibility, &self.get_api_macro(), @@ -901,6 +946,7 @@ impl Lang for UnrealCpp<'_> { // RemoteProcedures class generate_remote_procedures_class( &mut client_h, + self.module_prefix, module, options.visibility, &self.get_api_macro(), @@ -908,45 +954,52 @@ impl Lang for UnrealCpp<'_> { ); // SubscriptionBuilder class - generate_subscription_builder_class(&mut client_h, &self.get_api_macro()); + generate_subscription_builder_class(&mut client_h, self.module_prefix, &self.get_api_macro()); // SubscriptionHandle class - generate_subscription_handle_class(&mut client_h, &self.get_api_macro()); + generate_subscription_handle_class(&mut client_h, self.module_prefix, &self.get_api_macro()); // DbConnectionBuilder class - generate_db_connection_builder_class(&mut client_h, &self.get_api_macro()); + generate_db_connection_builder_class(&mut client_h, self.module_prefix, &self.get_api_macro()); // Main DbConnection class - generate_db_connection_class(&mut client_h, module, &self.get_api_macro()); + generate_db_connection_class(&mut client_h, self.module_prefix, module, &self.get_api_macro()); // Generate the separate ReducerBase file - let mut reducer_base_header = UnrealCppAutogen::new(&[], "ReducerBase", false); + let reducer_base_header_name = format!("{module_prefix}ReducerBase"); + let mut reducer_base_header = UnrealCppAutogen::new(&[], &reducer_base_header_name, false); - // Generate the UReducerBase class + // Generate the U{module_prefix}ReducerBase class writeln!(reducer_base_header, "// Abstract Reducer base class"); writeln!(reducer_base_header, "UCLASS(Abstract, BlueprintType)"); writeln!( reducer_base_header, - "class {} UReducerBase : public UObject", + "class {} U{module_prefix}ReducerBase : public UObject", self.get_api_macro() ); writeln!(reducer_base_header, "{{"); writeln!(reducer_base_header, " GENERATED_BODY()"); writeln!(reducer_base_header); writeln!(reducer_base_header, "public:"); - writeln!(reducer_base_header, " virtual ~UReducerBase() = default;"); + writeln!( + reducer_base_header, + " virtual ~U{module_prefix}ReducerBase() = default;" + ); writeln!(reducer_base_header, "}};"); writeln!(reducer_base_header); files.push(OutputFile { - filename: format!("Source/{}/Public/ModuleBindings/ReducerBase.g.h", self.module_name), + filename: format!( + "Source/{}/Public/ModuleBindings/{module_prefix}ReducerBase.g.h", + self.module_name + ), code: reducer_base_header.into_inner(), }); files.push(OutputFile { filename: format!( - "Source/{}/Public/ModuleBindings/SpacetimeDBClient.g.h", - self.module_name + "Source/{}/Public/ModuleBindings/{module_prefix}SpacetimeDBClient.g.h", + self.module_name, ), code: client_h.into_inner(), }); @@ -956,13 +1009,14 @@ impl Lang for UnrealCpp<'_> { .map(|(_, accessor_name, _)| { format!( "ModuleBindings/Tables/{}Table.g.h", - accessor_name.deref().to_case(Case::Pascal) //type_ref_name(module, product_type_ref) + format!("{module_prefix}{}", accessor_name.deref().to_case(Case::Pascal)) ) }) .collect(); let table_includes_str: Vec<&str> = table_includes.iter().map(|s| s.as_str()).collect(); - let mut cpp_includes = vec!["ModuleBindings/SpacetimeDBClient.g.h"]; + let spacetime_include = format!("ModuleBindings/{module_prefix}SpacetimeDBClient.g.h"); + let mut cpp_includes = vec![spacetime_include.as_str()]; // Add additional includes from manual reference cpp_includes.extend_from_slice(&["DBCache/WithBsatn.h", "BSATN/UEBSATNHelpers.h"]); @@ -971,11 +1025,17 @@ impl Lang for UnrealCpp<'_> { cpp_includes.extend(table_includes_str); let mut client_cpp = UnrealCppAutogen::new_cpp(&cpp_includes); - generate_client_implementation(&mut client_cpp, module, options.visibility, self.module_name); + generate_client_implementation( + &mut client_cpp, + module, + options.visibility, + self.module_prefix, + self.module_name, + ); files.push(OutputFile { filename: format!( - "Source/{}/Private/ModuleBindings/SpacetimeDBClient.g.cpp", - self.module_name + "Source/{}/Private/ModuleBindings/{module_prefix}SpacetimeDBClient.g.cpp", + self.module_name, ), code: client_cpp.into_inner(), }); @@ -985,11 +1045,11 @@ impl Lang for UnrealCpp<'_> { let schema = TableSchema::from_module_def(module, table, (), 0.into()) .validated() .expect("table schema should validate"); - let table_cpp_content = generate_table_cpp(module, table, self.module_name, &schema); + let table_cpp_content = generate_table_cpp(self.module_prefix, module, table, self.module_name, &schema); let table_cpp_filename = format!( "Source/{}/Private/ModuleBindings/Tables/{}Table.g.cpp", self.module_name, - table.name.deref().to_case(Case::Pascal) //type_ref_name(module, table.product_type_ref) + format!("{module_prefix}{}", table.name.deref().to_case(Case::Pascal)) ); files.push(OutputFile { filename: table_cpp_filename, @@ -1001,11 +1061,11 @@ impl Lang for UnrealCpp<'_> { let schema = TableSchema::from_view_def_for_codegen(module, view) .validated() .expect("Failed to generate table due to validation errors"); - let view_cpp_content = generate_table_cpp(module, &tbl, self.module_name, &schema); + let view_cpp_content = generate_table_cpp(self.module_prefix, module, &tbl, self.module_name, &schema); let view_cpp_filename = format!( "Source/{}/Private/ModuleBindings/Tables/{}Table.g.cpp", self.module_name, - view.name.deref().to_case(Case::Pascal) //type_ref_name(module, view.product_type_ref) + format!("{module_prefix}{}", view.name.deref().to_case(Case::Pascal)) ); files.push(OutputFile { filename: view_cpp_filename, @@ -1018,9 +1078,15 @@ impl Lang for UnrealCpp<'_> { } // Helper function to generate table .cpp implementation files -fn generate_table_cpp(module: &ModuleDef, table: &TableDef, module_name: &str, schema: &TableSchema) -> String { - let table_pascal = table.name.deref().to_case(Case::Pascal); - let struct_name = type_ref_name(module, table.product_type_ref); +fn generate_table_cpp( + module_prefix: &str, + module: &ModuleDef, + table: &TableDef, + module_name: &str, + schema: &TableSchema, +) -> String { + let table_pascal = format!("{module_prefix}{}", table.name.deref().to_case(Case::Pascal)); + let struct_name = type_ref_name(module_prefix, module, table.product_type_ref); let row_struct = format!("F{struct_name}Type"); // Include the table header and other necessary headers @@ -1052,7 +1118,7 @@ fn generate_table_cpp(module: &ModuleDef, table: &TableDef, module_name: &str, s if let Some(col) = columns.as_singleton() { let (f_name, f_ty) = &product_type.unwrap().elements[col.idx()]; let _field_name = f_name.deref().to_case(Case::Pascal); - let field_type = cpp_ty_fmt_with_module(module, f_ty, module_name).to_string(); + let field_type = cpp_ty_fmt_with_module(module_prefix, module, f_ty, module_name).to_string(); let index_name = accessor_name.deref().to_case(Case::Pascal); unique_indexes.push((index_name, field_type, f_name.deref().to_string())); } @@ -1067,7 +1133,7 @@ fn generate_table_cpp(module: &ModuleDef, table: &TableDef, module_name: &str, s .map(|col| { let (f_name, f_ty) = &product_type.unwrap().elements[col.idx()]; let field_name = f_name.deref().to_case(Case::Pascal); - let field_type = cpp_ty_fmt_with_module(module, f_ty, module_name).to_string(); + let field_type = cpp_ty_fmt_with_module(module_prefix, module, f_ty, module_name).to_string(); (field_name, field_type) }) .collect(); @@ -1176,7 +1242,7 @@ fn generate_table_cpp(module: &ModuleDef, table: &TableDef, module_name: &str, s if let Some(pk) = schema.pk() { let pk_field_name = pk.col_name.deref().to_case(Case::Pascal); let pk_type = &product_type.unwrap().elements[pk.col_pos.idx()].1; - let pk_type_str = cpp_ty_fmt_with_module(module, pk_type, module_name).to_string(); + let pk_type_str = cpp_ty_fmt_with_module(module_prefix, module, pk_type, module_name).to_string(); writeln!(output, " Diff.DeriveUpdatesByPrimaryKey<{pk_type_str}>("); writeln!(output, " [](const {row_struct}& Row) "); writeln!(output, " {{"); @@ -1221,7 +1287,7 @@ fn generate_table_cpp(module: &ModuleDef, table: &TableDef, module_name: &str, s // Helper functions for generating the consolidated SpacetimeDBClient file -fn generate_delegates(output: &mut UnrealCppAutogen) { +fn generate_delegates(output: &mut UnrealCppAutogen, module_prefix: &str) { writeln!( output, "// Delegates using the generated connection type. These wrap the base" @@ -1230,15 +1296,18 @@ fn generate_delegates(output: &mut UnrealCppAutogen) { output, "// delegates defined in the SDK so that projects can work directly with" ); - writeln!(output, "// UDbConnection without manual casting in user code."); + writeln!( + output, + "// U{module_prefix}DbConnection without manual casting in user code." + ); writeln!(output, "DECLARE_DYNAMIC_DELEGATE_ThreeParams("); - writeln!(output, "\tFOnConnectDelegate,"); + writeln!(output, "\tF{module_prefix}OnConnectDelegate,"); writeln!(output, "\tUDbConnection*, Connection,"); writeln!(output, "\tFSpacetimeDBIdentity, Identity,"); writeln!(output, "\tconst FString&, Token);"); writeln!(output); writeln!(output, "DECLARE_DYNAMIC_DELEGATE_TwoParams("); - writeln!(output, "\tFOnDisconnectDelegate,"); + writeln!(output, "\tF{module_prefix}OnDisconnectDelegate,"); writeln!(output, "\tUDbConnection*, Connection,"); writeln!(output, "\tconst FString&, Error);"); writeln!(output); @@ -1249,21 +1318,25 @@ fn generate_context_structs( output: &mut UnrealCppAutogen, module: &ModuleDef, visibility: CodegenVisibility, + module_prefix: &str, api_macro: &str, module_name: &str, ) { writeln!(output, "// Context classes for event handling"); writeln!(output); writeln!(output, "USTRUCT(BlueprintType)"); - writeln!(output, "struct {api_macro} FContextBase"); + writeln!(output, "struct {api_macro} F{module_prefix}ContextBase"); writeln!(output, "{{"); writeln!(output, "\tGENERATED_BODY()"); writeln!(output); writeln!( output, - "\tFContextBase() : Db(nullptr), Reducers(nullptr), Procedures(nullptr), Conn(nullptr) {{}};" + "\tF{module_prefix}ContextBase() : Db(nullptr), Reducers(nullptr), Procedures(nullptr), Conn(nullptr) {{}};" + ); + writeln!( + output, + "\tF{module_prefix}ContextBase(U{module_prefix}DbConnection* InConn);" ); - writeln!(output, "\tFContextBase(UDbConnection* InConn);"); writeln!(output); writeln!(output, "\tUPROPERTY(BlueprintReadOnly, Category = \"SpacetimeDB\")"); writeln!(output, "\tURemoteTables* Db;"); @@ -1290,11 +1363,11 @@ fn generate_context_structs( writeln!(output, "}};"); writeln!(output); - // BPLib for FContextBase - Needed to allow inheritance in Blueprint + // BPLib for F{module_prefix}ContextBase - Needed to allow inheritance in Blueprint writeln!(output, "UCLASS()"); writeln!( output, - "class {api_macro} UContextBaseBpLib : public UBlueprintFunctionLibrary" + "class {api_macro} U{module_prefix}ContextBaseBpLib : public UBlueprintFunctionLibrary" ); writeln!(output, "{{"); writeln!(output, "\tGENERATED_BODY()"); @@ -1304,31 +1377,31 @@ fn generate_context_structs( writeln!(output, "\tUFUNCTION(BlueprintPure, Category=\"SpacetimeDB\")"); writeln!( output, - "\tstatic URemoteTables* GetDb(const FContextBase& Ctx) {{ return Ctx.Db; }}" + "\tstatic U{module_prefix}RemoteTables* GetDb(const F{module_prefix}ContextBase& Ctx) {{ return Ctx.Db; }}" ); writeln!(output); writeln!(output, "\tUFUNCTION(BlueprintPure, Category=\"SpacetimeDB\")"); writeln!( output, - "\tstatic URemoteReducers* GetReducers(const FContextBase& Ctx) {{ return Ctx.Reducers; }}" + "\tstatic U{module_prefix}RemoteReducers* GetReducers(const F{module_prefix}ContextBase& Ctx) {{ return Ctx.Reducers; }}" ); writeln!(output); writeln!( output, - "\tstatic URemoteProcedures* GetProcedures(const FContextBase& Ctx) {{ return Ctx.Procedures; }}" + "\tstatic U{module_prefix}RemoteProcedures* GetProcedures(const F{module_prefix}ContextBase& Ctx) {{ return Ctx.Procedures; }}" ); writeln!(output); writeln!(output, "\tUFUNCTION(BlueprintPure, Category=\"SpacetimeDB\")"); writeln!( output, - "\tstatic bool IsActive(const FContextBase& Ctx) {{ return Ctx.IsActive(); }}" + "\tstatic bool IsActive(const F{module_prefix}ContextBase& Ctx) {{ return Ctx.IsActive(); }}" ); writeln!(output, "}};"); writeln!(output); - generate_reducer_bindings(output, module, visibility, api_macro, module_name); - generate_procedure_bindings(output, module, visibility, api_macro, module_name); + generate_reducer_bindings(output, module_prefix, module, visibility, api_macro, module_name); + generate_procedure_bindings(output, module_prefix, module, visibility, api_macro, module_name); // {}Event: union-like struct representing SpacetimeDB event messages writeln!(output, "/** Represents event with variant message data. */"); @@ -1342,7 +1415,10 @@ fn generate_context_structs( output, "\t/** Tagged union holding reducer call, unit events, or error string */" ); - writeln!(output, "\tTVariant MessageData;"); + writeln!( + output, + "\tTVariant MessageData;" + ); writeln!(output); writeln!(output, "\t/** Type tag indicating what this event represents */"); @@ -1355,11 +1431,14 @@ fn generate_context_structs( // === Static factory methods === writeln!(output, "\t/** === Static factory methods ===*/"); - writeln!(output, "\tstatic F{module_name}Event Reducer(const FReducer& Value)"); + writeln!( + output, + "\tstatic F{module_name}Event Reducer(const F{module_prefix}Reducer& Value)" + ); writeln!(output, "\t{{"); writeln!(output, "\t\tF{module_name}Event Obj;"); writeln!(output, "\t\tObj.Tag = ESpacetimeDBEventTag::Reducer;"); - writeln!(output, "\t\tObj.MessageData.Set(Value);"); + writeln!(output, "\t\tObj.MessageData.Set(Value);"); writeln!(output, "\t\treturn Obj;"); writeln!(output, "\t}}"); writeln!(output); @@ -1440,13 +1519,13 @@ fn generate_context_structs( output, "\tFORCEINLINE bool IsReducer() const {{ return Tag == ESpacetimeDBEventTag::Reducer; }}" ); - writeln!(output, "\tFORCEINLINE FReducer GetAsReducer() const"); + writeln!(output, "\tFORCEINLINE F{module_prefix}Reducer GetAsReducer() const"); writeln!(output, "\t{{"); writeln!( output, "\t\tensureMsgf(IsReducer(), TEXT(\"MessageData does not hold Reducer!\"));" ); - writeln!(output, "\t\treturn MessageData.Get();"); + writeln!(output, "\t\treturn MessageData.Get();"); writeln!(output, "\t}}"); writeln!(output); writeln!( @@ -1589,7 +1668,7 @@ fn generate_context_structs( ); writeln!( output, - " static F{module_name}Event Reducer(const FReducer& InValue)" + " static F{module_name}Event Reducer(const F{module_prefix}Reducer& InValue)" ); writeln!(output, " {{"); writeln!(output, " return F{module_name}Event::Reducer(InValue);"); @@ -1714,7 +1793,7 @@ fn generate_context_structs( ); writeln!( output, - " static FReducer GetAsReducer(const F{module_name}Event& Event)" + " static F{module_prefix}Reducer GetAsReducer(const F{module_name}Event& Event)" ); writeln!(output, " {{"); writeln!(output, " return Event.GetAsReducer();"); @@ -1802,17 +1881,20 @@ fn generate_context_structs( writeln!(output, "}};"); writeln!(output); - // FEventContext, FReducerEventContext, FErrorContext, FSubscriptionEventContext + // F{module_prefix}EventContext, F{module_prefix}ReducerEventContext, F{module_prefix}ErrorContext, F{module_prefix}SubscriptionEventContext writeln!(output); writeln!(output, "USTRUCT(BlueprintType)"); - writeln!(output, "struct {api_macro} FEventContext : public FContextBase"); + writeln!( + output, + "struct {api_macro} F{module_prefix}EventContext : public F{module_prefix}ContextBase" + ); writeln!(output, "{{"); writeln!(output, "\tGENERATED_BODY()"); writeln!(output); - writeln!(output, "\tFEventContext() = default;"); + writeln!(output, "\tF{module_prefix}EventContext() = default;"); writeln!( output, - "\tFEventContext(UDbConnection* InConn, const F{module_name}Event& InEvent) : FContextBase(InConn), Event(InEvent) {{}}" + "\tF{module_prefix}EventContext(U{module_prefix}DbConnection* InConn, const F{module_name}Event& InEvent) : F{module_prefix}ContextBase(InConn), Event(InEvent) {{}}" ); writeln!(output); writeln!(output, "\tUPROPERTY(BlueprintReadOnly, Category=\"SpacetimeDB\")"); @@ -1820,47 +1902,53 @@ fn generate_context_structs( writeln!(output, "}};"); writeln!(output); - // FReducerEventContext + // F{module_prefix}ReducerEventContext writeln!(output, "USTRUCT(BlueprintType)"); - writeln!(output, "struct {api_macro} FReducerEventContext : public FContextBase"); + writeln!( + output, + "struct {api_macro} F{module_prefix}ReducerEventContext : public F{module_prefix}ContextBase" + ); writeln!(output, "{{"); writeln!(output, "\tGENERATED_BODY()"); writeln!(output); - writeln!(output, "\tFReducerEventContext() = default;"); - writeln!(output, "\tFReducerEventContext(UDbConnection* InConn, F{module_name}ReducerEvent InEvent) : FContextBase(InConn), Event(InEvent) {{}}"); + writeln!(output, "\tF{module_prefix}ReducerEventContext() = default;"); + writeln!(output, "\tF{module_prefix}ReducerEventContext(U{module_prefix}DbConnection* InConn, F{module_name}ReducerEvent InEvent) : F{module_prefix}ContextBase(InConn), Event(InEvent) {{}}"); writeln!(output, "\t"); writeln!(output, "\tUPROPERTY(BlueprintReadOnly, Category=\"SpacetimeDB\") "); writeln!(output, "\tF{module_name}ReducerEvent Event;"); writeln!(output, "}};"); writeln!(output); - // FProcedureEventContext + // F{module_prefix}ProcedureEventContext writeln!(output, "USTRUCT(BlueprintType)"); writeln!( output, - "struct {api_macro} FProcedureEventContext : public FContextBase" + "struct {api_macro} F{module_prefix}ProcedureEventContext : public F{module_prefix}ContextBase" ); writeln!(output, "{{"); writeln!(output, "\tGENERATED_BODY()"); writeln!(output); - writeln!(output, "\tFProcedureEventContext() = default;"); - writeln!(output, "\tFProcedureEventContext(UDbConnection* InConn, F{module_name}ProcedureEvent InEvent) : FContextBase(InConn), Event(InEvent) {{}}"); + writeln!(output, "\tF{module_prefix}ProcedureEventContext() = default;"); + writeln!(output, "\tF{module_prefix}ProcedureEventContext(U{module_prefix}DbConnection* InConn, F{module_name}ProcedureEvent InEvent) : F{module_prefix}ContextBase(InConn), Event(InEvent) {{}}"); writeln!(output, "\t"); writeln!(output, "\tUPROPERTY(BlueprintReadOnly, Category=\"SpacetimeDB\") "); writeln!(output, "\tF{module_name}ProcedureEvent Event;"); writeln!(output, "}};"); writeln!(output); - // FErrorContext + // F{module_prefix}ErrorContext writeln!(output, "USTRUCT(BlueprintType)"); - writeln!(output, "struct {api_macro} FErrorContext : public FContextBase"); + writeln!( + output, + "struct {api_macro} F{module_prefix}ErrorContext : public F{module_prefix}ContextBase" + ); writeln!(output, "{{"); writeln!(output, "\tGENERATED_BODY()"); writeln!(output); - writeln!(output, "\tFErrorContext() = default;"); + writeln!(output, "\tF{module_prefix}ErrorContext() = default;"); writeln!( output, - "\tFErrorContext(UDbConnection* InConn, const FString& InError) : FContextBase(InConn), Error(InError) {{}}" + "\tF{module_prefix}ErrorContext(U{module_prefix}DbConnection* InConn, const FString& InError) : F{module_prefix}ContextBase(InConn), Error(InError) {{}}" ); writeln!(output); writeln!(output, "\tUPROPERTY(BlueprintReadOnly, Category=\"SpacetimeDB\")"); @@ -1869,35 +1957,36 @@ fn generate_context_structs( writeln!(output, "}};"); writeln!(output); - // FSubscriptionEventContext + // F{module_prefix}SubscriptionEventContext writeln!(output, "USTRUCT(BlueprintType)"); writeln!( output, - "struct {api_macro} FSubscriptionEventContext : public FContextBase" + "struct {api_macro} F{module_prefix}SubscriptionEventContext : public F{module_prefix}ContextBase" ); writeln!(output, "{{"); writeln!(output, "\tGENERATED_BODY()"); writeln!(output); - writeln!(output, "\tFSubscriptionEventContext() = default;"); + writeln!(output, "\tF{module_prefix}SubscriptionEventContext() = default;"); writeln!( output, - "\tFSubscriptionEventContext(UDbConnection* InConn) : FContextBase(InConn) {{}}" + "\tF{module_prefix}SubscriptionEventContext(U{module_prefix}DbConnection* InConn) : F{module_prefix}ContextBase(InConn) {{}}" ); writeln!(output); writeln!(output, "}};"); writeln!(output); writeln!(output, "DECLARE_DYNAMIC_DELEGATE_OneParam("); - writeln!(output, "\tFOnSubscriptionApplied,"); + writeln!(output, "\tF{module_prefix}OnSubscriptionApplied,"); writeln!(output, "\tFSubscriptionEventContext, Context);"); writeln!(output); writeln!(output, "DECLARE_DYNAMIC_DELEGATE_OneParam("); - writeln!(output, "\tFOnSubscriptionError,"); + writeln!(output, "\tF{module_prefix}OnSubscriptionError,"); writeln!(output, "\tFErrorContext, Context);"); writeln!(output); } fn generate_reducer_bindings( output: &mut UnrealCppAutogen, + module_prefix: &str, module: &ModuleDef, visibility: CodegenVisibility, api_macro: &str, @@ -1908,12 +1997,12 @@ fn generate_reducer_bindings( // Per-module typed Reducer tagged union + typed Event // --------------------------------------------------------------------- writeln!(output, "UENUM(BlueprintType, Category = \"SpacetimeDB\")"); - writeln!(output, "enum class EReducerTag : uint8"); + writeln!(output, "enum class E{module_prefix}ReducerTag : uint8"); writeln!(output, "{{"); { let mut first = true; for reducer in iter_reducers(module, visibility) { - let reducer_pascal = reducer.name.deref().to_case(Case::Pascal); + let reducer_pascal = format!("{module_prefix}{}", reducer.name.deref().to_case(Case::Pascal)); if !first { writeln!(output, ","); } else { @@ -1930,21 +2019,24 @@ fn generate_reducer_bindings( writeln!(output, "}};"); writeln!(output); - // FReducer: tagged union over reducer args, with optional metadata + // F{module_prefix}Reducer: tagged union over reducer args, with optional metadata writeln!(output, "USTRUCT(BlueprintType)"); - writeln!(output, "struct {api_macro} FReducer"); + writeln!(output, "struct {api_macro} F{module_prefix}Reducer"); writeln!(output, "{{"); writeln!(output, " GENERATED_BODY()"); writeln!(output); writeln!(output, "public:"); writeln!(output, " UPROPERTY(BlueprintReadOnly, Category = \"SpacetimeDB\")"); - writeln!(output, " EReducerTag Tag = static_cast(0);"); + writeln!( + output, + " E{module_prefix}ReducerTag Tag = static_cast(0);" + ); writeln!(output); write!(output, " TVariant<"); { let mut first = true; for reducer in iter_reducers(module, visibility) { - let reducer_pascal = reducer.name.deref().to_case(Case::Pascal); + let reducer_pascal = format!("{module_prefix}{}", reducer.name.deref().to_case(Case::Pascal)); if !first { write!(output, ", "); } else { @@ -1967,14 +2059,17 @@ fn generate_reducer_bindings( // Static constructors, Is*, GetAs* for reducer in iter_reducers(module, visibility) { - let reducer_pascal = reducer.name.deref().to_case(Case::Pascal); + let reducer_pascal = format!("{module_prefix}{}", reducer.name.deref().to_case(Case::Pascal)); writeln!( output, - " static FReducer {reducer_pascal}(const F{reducer_pascal}Args& Value)" + " static F{module_prefix}Reducer {reducer_pascal}(const F{reducer_pascal}Args& Value)" ); writeln!(output, " {{"); - writeln!(output, " FReducer Out;"); - writeln!(output, " Out.Tag = EReducerTag::{reducer_pascal};"); + writeln!(output, " F{module_prefix}Reducer Out;"); + writeln!( + output, + " Out.Tag = E{module_prefix}ReducerTag::{reducer_pascal};" + ); writeln!(output, " Out.Data.Set(Value);"); writeln!(output, " Out.ReducerName = TEXT(\"{}\");", reducer.name.deref()); writeln!(output, " return Out;"); @@ -1982,7 +2077,7 @@ fn generate_reducer_bindings( writeln!(output); writeln!( output, - " FORCEINLINE bool Is{reducer_pascal}() const {{ return Tag == EReducerTag::{reducer_pascal}; }}" + " FORCEINLINE bool Is{reducer_pascal}() const {{ return Tag == E{module_prefix}ReducerTag::{reducer_pascal}; }}" ); writeln!( output, @@ -1997,21 +2092,24 @@ fn generate_reducer_bindings( writeln!(output, " }}"); writeln!(output); } - writeln!(output, " FORCEINLINE bool operator==(const FReducer& Other) const"); + writeln!( + output, + " FORCEINLINE bool operator==(const F{module_prefix}Reducer& Other) const" + ); writeln!(output, " {{"); writeln!(output, " if (Tag != Other.Tag || ReducerId != Other.ReducerId || RequestId != Other.RequestId || ReducerName != Other.ReducerName) return false;"); writeln!(output, " switch (Tag)"); writeln!(output, " {{"); for reducer in iter_reducers(module, visibility) { - let reducer_pascal = reducer.name.deref().to_case(Case::Pascal); - writeln!(output, " case EReducerTag::{reducer_pascal}:"); + let reducer_pascal = format!("{module_prefix}{}", reducer.name.deref().to_case(Case::Pascal)); + writeln!(output, " case E{module_prefix}ReducerTag::{reducer_pascal}:"); writeln!( output, " return GetAs{reducer_pascal}() == Other.GetAs{reducer_pascal}();" ); } if reducer_count == 0 { - writeln!(output, " case EReducerTag::None:"); + writeln!(output, " case E{module_prefix}ReducerTag::None:"); writeln!(output, " return true;"); } @@ -2020,16 +2118,16 @@ fn generate_reducer_bindings( writeln!(output, " }}"); writeln!( output, - " FORCEINLINE bool operator!=(const FReducer& Other) const {{ return !(*this == Other); }}" + " FORCEINLINE bool operator!=(const F{module_prefix}Reducer& Other) const {{ return !(*this == Other); }}" ); writeln!(output, "}};"); writeln!(output); - // BPLib for FReducer + // BPLib for F{module_prefix}Reducer writeln!(output, "UCLASS()"); writeln!( output, - "class {api_macro} UReducerBpLib : public UBlueprintFunctionLibrary" + "class {api_macro} U{module_prefix}ReducerBpLib : public UBlueprintFunctionLibrary" ); writeln!(output, "{{"); writeln!(output, " GENERATED_BODY()"); @@ -2037,7 +2135,7 @@ fn generate_reducer_bindings( writeln!(output, "private:"); for reducer in iter_reducers(module, visibility) { - let reducer_pascal = reducer.name.deref().to_case(Case::Pascal); + let reducer_pascal = format!("{module_prefix}{}", reducer.name.deref().to_case(Case::Pascal)); // ---- Static constructors ---- writeln!(output); writeln!( @@ -2046,9 +2144,12 @@ fn generate_reducer_bindings( ); writeln!( output, - " static FReducer {reducer_pascal}(const F{reducer_pascal}Args& Value) {{" + " static F{module_prefix}Reducer {reducer_pascal}(const F{reducer_pascal}Args& Value) {{" + ); + writeln!( + output, + " return F{module_prefix}Reducer::{reducer_pascal}(Value);" ); - writeln!(output, " return FReducer::{reducer_pascal}(Value);"); writeln!(output, " }}"); writeln!(output); @@ -2059,7 +2160,7 @@ fn generate_reducer_bindings( ); writeln!( output, - " static bool Is{reducer_pascal}(const FReducer& Reducer) {{ return Reducer.Is{reducer_pascal}(); }}" + " static bool Is{reducer_pascal}(const F{module_prefix}Reducer& Reducer) {{ return Reducer.Is{reducer_pascal}(); }}" ); writeln!(output); @@ -2070,7 +2171,7 @@ fn generate_reducer_bindings( ); writeln!( output, - " static F{reducer_pascal}Args GetAs{reducer_pascal}(const FReducer& Reducer) {{" + " static F{reducer_pascal}Args GetAs{reducer_pascal}(const F{module_prefix}Reducer& Reducer) {{" ); writeln!(output, " return Reducer.GetAs{reducer_pascal}();"); writeln!(output, " }}"); @@ -2162,6 +2263,7 @@ fn generate_reducer_bindings( fn generate_procedure_bindings( output: &mut UnrealCppAutogen, + module_prefix: &str, module: &ModuleDef, visibility: CodegenVisibility, api_macro: &str, @@ -2173,12 +2275,12 @@ fn generate_procedure_bindings( // Per-module typed Procedure tagged union + typed Event // --------------------------------------------------------------------- writeln!(output, "UENUM(BlueprintType, Category = \"SpacetimeDB\")"); - writeln!(output, "enum class EProcedureTag : uint8"); + writeln!(output, "enum class E{module_prefix}ProcedureTag : uint8"); writeln!(output, "{{"); { let mut first = true; for procedure in iter_procedures(module, visibility) { - let procedure_pascal = procedure.name.deref().to_case(Case::Pascal); + let procedure_pascal = format!("{module_prefix}{}", procedure.name.deref().to_case(Case::Pascal)); if !first { writeln!(output, ","); } else { @@ -2191,21 +2293,24 @@ fn generate_procedure_bindings( writeln!(output, "}};"); writeln!(output); - // FProcedure: tagged union over procedure args, with optional metadata + // F{module_prefix}Procedure: tagged union over procedure args, with optional metadata writeln!(output, "USTRUCT(BlueprintType)"); - writeln!(output, "struct {api_macro} FProcedure"); + writeln!(output, "struct {api_macro} F{module_prefix}Procedure"); writeln!(output, "{{"); writeln!(output, " GENERATED_BODY()"); writeln!(output); writeln!(output, "public:"); writeln!(output, " UPROPERTY(BlueprintReadOnly, Category = \"SpacetimeDB\")"); - writeln!(output, " EProcedureTag Tag = static_cast(0);"); + writeln!( + output, + " E{module_prefix}ProcedureTag Tag = static_cast(0);" + ); writeln!(output); write!(output, " TVariant<"); { let mut first = true; for procedure in iter_procedures(module, visibility) { - let procedure_pascal = procedure.name.deref().to_case(Case::Pascal); + let procedure_pascal = format!("{module_prefix}{}", procedure.name.deref().to_case(Case::Pascal)); if !first { write!(output, ", "); } else { @@ -2225,14 +2330,17 @@ fn generate_procedure_bindings( // Static constructors, Is*, GetAs* for procedure in iter_procedures(module, visibility) { - let procedure_pascal = procedure.name.deref().to_case(Case::Pascal); + let procedure_pascal = format!("{module_prefix}{}", procedure.name.deref().to_case(Case::Pascal)); writeln!( output, - " static FProcedure {procedure_pascal}(const F{procedure_pascal}Args& Value)" + " static F{module_prefix}Procedure {procedure_pascal}(const F{procedure_pascal}Args& Value)" ); writeln!(output, " {{"); - writeln!(output, " FProcedure Out;"); - writeln!(output, " Out.Tag = EProcedureTag::{procedure_pascal};"); + writeln!(output, " F{module_prefix}Procedure Out;"); + writeln!( + output, + " Out.Tag = E{module_prefix}ProcedureTag::{procedure_pascal};" + ); writeln!(output, " Out.Data.Set(Value);"); writeln!( output, @@ -2244,7 +2352,7 @@ fn generate_procedure_bindings( writeln!(output); writeln!( output, - " FORCEINLINE bool Is{procedure_pascal}() const {{ return Tag == EProcedureTag::{procedure_pascal}; }}" + " FORCEINLINE bool Is{procedure_pascal}() const {{ return Tag == E{module_prefix}ProcedureTag::{procedure_pascal}; }}" ); writeln!( output, @@ -2259,14 +2367,17 @@ fn generate_procedure_bindings( writeln!(output, " }}"); writeln!(output); } - writeln!(output, " FORCEINLINE bool operator==(const FProcedure& Other) const"); + writeln!( + output, + " FORCEINLINE bool operator==(const F{module_prefix}Procedure& Other) const" + ); writeln!(output, " {{"); writeln!(output, " if (Tag != Other.Tag || ProcedureId != Other.ProcedureId || RequestId != Other.RequestId || ProcedureName != Other.ProcedureName) return false;"); writeln!(output, " switch (Tag)"); writeln!(output, " {{"); for procedure in iter_procedures(module, visibility) { - let procedure_pascal = procedure.name.deref().to_case(Case::Pascal); - writeln!(output, " case EProcedureTag::{procedure_pascal}:"); + let procedure_pascal = format!("{module_prefix}{}", procedure.name.deref().to_case(Case::Pascal)); + writeln!(output, " case E{module_prefix}ProcedureTag::{procedure_pascal}:"); writeln!( output, " return GetAs{procedure_pascal}() == Other.GetAs{procedure_pascal}();" @@ -2277,16 +2388,16 @@ fn generate_procedure_bindings( writeln!(output, " }}"); writeln!( output, - " FORCEINLINE bool operator!=(const FProcedure& Other) const {{ return !(*this == Other); }}" + " FORCEINLINE bool operator!=(const F{module_prefix}Procedure& Other) const {{ return !(*this == Other); }}" ); writeln!(output, "}};"); writeln!(output); - // BPLib for FProcedure + // BPLib for F{module_prefix}Procedure writeln!(output, "UCLASS()"); writeln!( output, - "class {api_macro} UProcedureBpLib : public UBlueprintFunctionLibrary" + "class {api_macro} U{module_prefix}ProcedureBpLib : public UBlueprintFunctionLibrary" ); writeln!(output, "{{"); writeln!(output, " GENERATED_BODY()"); @@ -2294,7 +2405,7 @@ fn generate_procedure_bindings( writeln!(output, "private:"); for procedure in iter_procedures(module, visibility) { - let procedure_pascal = procedure.name.deref().to_case(Case::Pascal); + let procedure_pascal = format!("{module_prefix}{}", procedure.name.deref().to_case(Case::Pascal)); // ---- Static constructors ---- writeln!(output); writeln!( @@ -2303,9 +2414,12 @@ fn generate_procedure_bindings( ); writeln!( output, - " static FProcedure {procedure_pascal}(const F{procedure_pascal}Args& Value) {{" + " static F{module_prefix}Procedure {procedure_pascal}(const F{procedure_pascal}Args& Value) {{" + ); + writeln!( + output, + " return F{module_prefix}Procedure::{procedure_pascal}(Value);" ); - writeln!(output, " return FProcedure::{procedure_pascal}(Value);"); writeln!(output, " }}"); writeln!(output); @@ -2316,7 +2430,7 @@ fn generate_procedure_bindings( ); writeln!( output, - " static bool Is{procedure_pascal}(const FProcedure& Procedure) {{ return Procedure.Is{procedure_pascal}(); }}" + " static bool Is{procedure_pascal}(const F{module_prefix}Procedure& Procedure) {{ return Procedure.Is{procedure_pascal}(); }}" ); writeln!(output); @@ -2327,7 +2441,7 @@ fn generate_procedure_bindings( ); writeln!( output, - " static F{procedure_pascal}Args GetAs{procedure_pascal}(const FProcedure& Procedure) {{" + " static F{procedure_pascal}Args GetAs{procedure_pascal}(const F{module_prefix}Procedure& Procedure) {{" ); writeln!(output, " return Procedure.GetAs{procedure_pascal}();"); writeln!(output, " }}"); @@ -2413,13 +2527,17 @@ fn generate_procedure_bindings( fn generate_remote_tables_class( output: &mut UnrealCppAutogen, + module_prefix: &str, module: &ModuleDef, visibility: CodegenVisibility, api_macro: &str, ) { writeln!(output, "// RemoteTables class"); writeln!(output, "UCLASS(BlueprintType)"); - writeln!(output, "class {api_macro} URemoteTables : public UObject"); + writeln!( + output, + "class {api_macro} U{module_prefix}RemoteTables : public UObject" + ); writeln!(output, "{{"); writeln!(output, " GENERATED_BODY()"); writeln!(output); @@ -2432,7 +2550,7 @@ fn generate_remote_tables_class( writeln!(output, " UPROPERTY(BlueprintReadOnly, Category=\"SpacetimeDB\")"); writeln!( output, - " U{}Table* {};", + " U{module_prefix}{}Table* {};", accessor_name.deref().to_case(Case::Pascal), accessor_name.deref().to_case(Case::Pascal) ); @@ -2445,6 +2563,7 @@ fn generate_remote_tables_class( fn generate_remote_reducers_class( output: &mut UnrealCppAutogen, + module_prefix: &str, module: &ModuleDef, visibility: CodegenVisibility, api_macro: &str, @@ -2452,7 +2571,10 @@ fn generate_remote_reducers_class( ) { writeln!(output, "// RemoteReducers class"); writeln!(output, "UCLASS(BlueprintType)"); - writeln!(output, "class {api_macro} URemoteReducers : public UObject"); + writeln!( + output, + "class {api_macro} U{module_prefix}RemoteReducers : public UObject" + ); writeln!(output, "{{"); writeln!(output, " GENERATED_BODY()"); writeln!(output); @@ -2461,7 +2583,7 @@ fn generate_remote_reducers_class( // Generate reducer events and call methods for reducer in iter_reducers(module, visibility) { - let reducer_pascal = reducer.name.deref().to_case(Case::Pascal); + let reducer_pascal = format!("{module_prefix}{}", reducer.name.deref().to_case(Case::Pascal)); // Generate delegate for reducer event let param_count = reducer.params_for_generate.elements.len() + 1; // +1 for context @@ -2474,19 +2596,19 @@ fn generate_remote_reducers_class( // For more than 9 params, use a struct to wrap the arguments writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams("); writeln!(output, " F{reducer_pascal}Handler,"); - writeln!(output, " const FReducerEventContext&, Context,"); + writeln!(output, " const F{module_prefix}ReducerEventContext&, Context,"); writeln!(output, " const F{reducer_pascal}Args&, Args"); writeln!(output, " );"); // For delegates using args struct, check the actual delegate parameters: - // 1. FReducerEventContext (always blueprintable) + // 1. F{module_prefix}ReducerEventContext (always blueprintable) // 2. F{Reducer}Args struct (always blueprintable as a USTRUCT) // So delegates with args struct are always blueprintable // But functions still need to check individual parameters for (_, param_type) in &reducer.params_for_generate.elements { if !is_type_blueprintable_for_delegates(module, param_type) { - let type_str = cpp_ty_fmt_with_module(module, param_type, module_name).to_string(); + let type_str = cpp_ty_fmt_with_module(module_prefix, module, param_type, module_name).to_string(); non_blueprintable_types_for_function.push(type_str); } } @@ -2507,12 +2629,13 @@ fn generate_remote_reducers_class( write!( output, - " {delegate_macro}(\n F{reducer_pascal}Handler,\n const FReducerEventContext&, Context" + " {delegate_macro}(\n F{reducer_pascal}Handler,\n const F{module_prefix}ReducerEventContext&, Context" ); for (param_name, param_type) in &reducer.params_for_generate.elements { // Use Blueprint-compatible types for delegates - let type_str = cpp_ty_fmt_blueprint_compatible(module, param_type, module_name).to_string(); + let type_str = + cpp_ty_fmt_blueprint_compatible(module_prefix, module, param_type, module_name).to_string(); // Collect non-blueprintable types for both delegate and function if !is_type_blueprintable_for_delegates(module, param_type) { @@ -2577,9 +2700,9 @@ fn generate_remote_reducers_class( // For UFUNCTION parameters, use Blueprint-compatible types let type_str = if non_blueprintable_types_for_function.is_empty() { - cpp_ty_fmt_blueprint_compatible(module, param_type, module_name).to_string() + cpp_ty_fmt_blueprint_compatible(module_prefix, module, param_type, module_name).to_string() } else { - cpp_ty_fmt_with_module(module, param_type, module_name).to_string() + cpp_ty_fmt_with_module(module_prefix, module, param_type, module_name).to_string() }; if should_pass_by_value_in_delegate(module, param_type) { @@ -2606,14 +2729,14 @@ fn generate_remote_reducers_class( // Generate invoke method (UObject version - kept for backwards compatibility) write!( output, - " bool Invoke{reducer_pascal}(const FReducerEventContext& Context, const U{reducer_pascal}Reducer* Args);" + " bool Invoke{reducer_pascal}(const F{module_prefix}ReducerEventContext& Context, const U{reducer_pascal}Reducer* Args);" ); writeln!(output); // Generate invoke method (FArgs version - zero allocation, used internally) write!( output, - " bool Invoke{reducer_pascal}WithArgs(const FReducerEventContext& Context, const F{reducer_pascal}Args& Args);" + " bool Invoke{reducer_pascal}WithArgs(const F{module_prefix}ReducerEventContext& Context, const F{reducer_pascal}Args& Args);" ); writeln!(output); writeln!(output); @@ -2621,7 +2744,7 @@ fn generate_remote_reducers_class( // Internal error handling writeln!(output, " // Internal error handling"); - writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FInternalOnUnhandledReducerError, const FReducerEventContext&, Context, const FString&, Error);"); + writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FInternalOnUnhandledReducerError, const F{module_prefix}ReducerEventContext&, Context, const FString&, Error);"); writeln!( output, " FInternalOnUnhandledReducerError InternalOnUnhandledReducerError;" @@ -2630,29 +2753,30 @@ fn generate_remote_reducers_class( writeln!(output, "private:"); writeln!(output); - writeln!(output, " friend UDbConnection;"); + writeln!(output, " friend U{module_prefix}DbConnection;"); writeln!(output); writeln!(output, " UPROPERTY()"); - writeln!(output, " class UDbConnection* Conn;"); + writeln!(output, " class U{module_prefix}DbConnection* Conn;"); writeln!(output, "}};"); writeln!(output); } fn generate_remote_procedures_class( output: &mut UnrealCppAutogen, + module_prefix: &str, module: &ModuleDef, visibility: CodegenVisibility, api_macro: &str, module_name: &str, ) { for procedure in iter_procedures(module, visibility) { - let procedure_pascal = procedure.name.deref().to_case(Case::Pascal); + let procedure_pascal = format!("{module_prefix}{}", procedure.name.deref().to_case(Case::Pascal)); let blueprintable_type_for_return = is_type_blueprintable_for_delegates(module, &procedure.return_type_for_generate); // In generate_remote_procedures_class, before the existing event delegate generation: let return_type_str = - cpp_ty_fmt_with_module(module, &procedure.return_type_for_generate, module_name).to_string(); + cpp_ty_fmt_with_module(module_prefix, module, &procedure.return_type_for_generate, module_name).to_string(); let return_type_ref = if return_type_str.starts_with('F') && return_type_str != "FSpacetimeDBUnit" { format!("const {}&", return_type_str) } else { @@ -2665,7 +2789,7 @@ fn generate_remote_procedures_class( "// NOTE: Procedure {procedure_pascal} has non-Blueprint-compatible return type: {return_type_str}" ); writeln!(output, "DECLARE_DELEGATE_ThreeParams(FOn{procedure_pascal}Complete,"); - writeln!(output, " const FProcedureEventContext&, /*Context*/"); + writeln!(output, " const F{module_prefix}ProcedureEventContext&, /*Context*/"); writeln!(output, " {return_type_ref}, /*Result,*/"); writeln!(output, " bool /*bSuccess*/);"); writeln!(output); @@ -2674,7 +2798,7 @@ fn generate_remote_procedures_class( output, "DECLARE_DYNAMIC_DELEGATE_ThreeParams(FOn{procedure_pascal}Complete," ); - writeln!(output, " const FProcedureEventContext&, Context,"); + writeln!(output, " const F{module_prefix}ProcedureEventContext&, Context,"); writeln!(output, " {}, Result,", return_type_ref); writeln!(output, " bool, bSuccess);"); writeln!(output); @@ -2683,7 +2807,10 @@ fn generate_remote_procedures_class( writeln!(output, "// RemoteProcedures class"); writeln!(output, "UCLASS(BlueprintType)"); - writeln!(output, "class {api_macro} URemoteProcedures : public UObject"); + writeln!( + output, + "class {api_macro} U{module_prefix}RemoteProcedures : public UObject" + ); writeln!(output, "{{"); writeln!(output, " GENERATED_BODY()"); writeln!(output); @@ -2692,13 +2819,13 @@ fn generate_remote_procedures_class( // Generate procedure events and call methods for procedure in iter_procedures(module, visibility) { - let procedure_pascal = procedure.name.deref().to_case(Case::Pascal); + let procedure_pascal = format!("{module_prefix}{}", procedure.name.deref().to_case(Case::Pascal)); let mut non_blueprintable_types_for_function = Vec::new(); for (_, param_type) in &procedure.params_for_generate.elements { if !is_type_blueprintable_for_delegates(module, param_type) { - let type_str = cpp_ty_fmt_with_module(module, param_type, module_name).to_string(); + let type_str = cpp_ty_fmt_with_module(module_prefix, module, param_type, module_name).to_string(); non_blueprintable_types_for_function.push(type_str); } } @@ -2729,9 +2856,9 @@ fn generate_remote_procedures_class( // For UFUNCTION parameters, use Blueprint-compatible types let type_str = if non_blueprintable_types_for_function.is_empty() { - cpp_ty_fmt_blueprint_compatible(module, param_type, module_name).to_string() + cpp_ty_fmt_blueprint_compatible(module_prefix, module, param_type, module_name).to_string() } else { - cpp_ty_fmt_with_module(module, param_type, module_name).to_string() + cpp_ty_fmt_with_module(module_prefix, module, param_type, module_name).to_string() }; if should_pass_by_value_in_delegate(module, param_type) { @@ -2763,7 +2890,7 @@ fn generate_remote_procedures_class( // Internal error handling writeln!(output, " // Internal error handling"); - writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FInternalOnUnhandledProcedureError, const FProcedureEventContext&, Context, const FString&, Error);"); + writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FInternalOnUnhandledProcedureError, const F{module_prefix}ProcedureEventContext&, Context, const FString&, Error);"); writeln!( output, " FInternalOnUnhandledProcedureError InternalOnUnhandledProcedureError;" @@ -2772,20 +2899,20 @@ fn generate_remote_procedures_class( writeln!(output, "private:"); writeln!(output); - writeln!(output, " friend UDbConnection;"); + writeln!(output, " friend U{module_prefix}DbConnection;"); writeln!(output); writeln!(output, " UPROPERTY()"); - writeln!(output, " class UDbConnection* Conn;"); + writeln!(output, " class U{module_prefix}DbConnection* Conn;"); writeln!(output, "}};"); writeln!(output); } -fn generate_subscription_builder_class(output: &mut UnrealCppAutogen, api_macro: &str) { +fn generate_subscription_builder_class(output: &mut UnrealCppAutogen, module_prefix: &str, api_macro: &str) { writeln!(output, "// SubscriptionBuilder class"); writeln!(output, "UCLASS(BlueprintType)"); writeln!( output, - "class {api_macro} USubscriptionBuilder : public USubscriptionBuilderBase" + "class {api_macro} U{module_prefix}SubscriptionBuilder : public USubscriptionBuilderBase" ); writeln!(output, "{{"); writeln!(output, " GENERATED_BODY()"); @@ -2795,19 +2922,19 @@ fn generate_subscription_builder_class(output: &mut UnrealCppAutogen, api_macro: writeln!(output, " UFUNCTION(BlueprintCallable, Category = \"SpacetimeDB\")"); writeln!( output, - " USubscriptionBuilder* OnApplied(FOnSubscriptionApplied Callback);" + " U{module_prefix}SubscriptionBuilder* OnApplied(F{module_prefix}OnSubscriptionApplied Callback);" ); writeln!(output); writeln!(output, " UFUNCTION(BlueprintCallable, Category = \"SpacetimeDB\")"); writeln!( output, - " USubscriptionBuilder* OnError(FOnSubscriptionError Callback);" + " U{module_prefix}SubscriptionBuilder* OnError(F{module_prefix}OnSubscriptionError Callback);" ); writeln!(output); writeln!(output, " UFUNCTION(BlueprintCallable, Category=\"SpacetimeDB\")"); writeln!( output, - " USubscriptionHandle* Subscribe(const TArray& SQL);" + " U{module_prefix}SubscriptionHandle* Subscribe(const TArray& SQL);" ); writeln!(output); writeln!( @@ -2815,54 +2942,66 @@ fn generate_subscription_builder_class(output: &mut UnrealCppAutogen, api_macro: " /** Convenience for subscribing to all rows from all tables */" ); writeln!(output, " UFUNCTION(BlueprintCallable, Category = \"SpacetimeDB\")"); - writeln!(output, " USubscriptionHandle* SubscribeToAllTables();"); + writeln!( + output, + " U{module_prefix}SubscriptionHandle* SubscribeToAllTables();" + ); writeln!(output); writeln!(output); - writeln!(output, " friend class UDbConnection;"); + writeln!(output, " friend class U{module_prefix}DbConnection;"); writeln!(output, " friend class UDbConnectionBase;"); writeln!(output); writeln!(output, "protected:"); writeln!(output, " UPROPERTY()"); - writeln!(output, " class UDbConnection* Conn;"); + writeln!(output, " class U{module_prefix}DbConnection* Conn;"); writeln!(output); writeln!( output, " // Delegates stored so Subscribe() can bind forwarding callbacks" ); - writeln!(output, " FOnSubscriptionApplied OnAppliedDelegateInternal;"); - writeln!(output, " FOnSubscriptionError OnErrorDelegateInternal;"); + writeln!( + output, + " F{module_prefix}OnSubscriptionApplied OnAppliedDelegateInternal;" + ); + writeln!( + output, + " F{module_prefix}OnSubscriptionError OnErrorDelegateInternal;" + ); writeln!(output, "}};"); writeln!(output); } -fn generate_subscription_handle_class(output: &mut UnrealCppAutogen, api_macro: &str) { +fn generate_subscription_handle_class(output: &mut UnrealCppAutogen, module_prefix: &str, api_macro: &str) { writeln!(output, "// SubscriptionHandle class"); writeln!(output, "UCLASS(BlueprintType)"); writeln!( output, - "class {api_macro} USubscriptionHandle : public USubscriptionHandleBase" + "class {api_macro} U{module_prefix}SubscriptionHandle : public USubscriptionHandleBase" ); writeln!(output, "{{"); writeln!(output, " GENERATED_BODY()"); writeln!(output); writeln!(output, "public:"); writeln!(output); - writeln!(output, " USubscriptionHandle() {{}};"); + writeln!(output, " U{module_prefix}SubscriptionHandle() {{}};"); writeln!(output); - writeln!(output, " explicit USubscriptionHandle(UDbConnection* InConn);"); + writeln!( + output, + " explicit U{module_prefix}SubscriptionHandle(U{module_prefix}DbConnection* InConn);" + ); writeln!(output); - writeln!(output, " friend class USubscriptionBuilder;"); + writeln!(output, " friend class U{module_prefix}SubscriptionBuilder;"); writeln!(output); writeln!(output, "private:"); writeln!(output, " UPROPERTY()"); - writeln!(output, " class UDbConnection* Conn;"); + writeln!(output, " class U{module_prefix}DbConnection* Conn;"); writeln!(output); writeln!( output, " // Delegates that expose subscription events with connection aware contexts" ); - writeln!(output, " FOnSubscriptionApplied OnAppliedDelegate;"); - writeln!(output, " FOnSubscriptionError OnErrorDelegate;"); + writeln!(output, " F{module_prefix}OnSubscriptionApplied OnAppliedDelegate;"); + writeln!(output, " F{module_prefix}OnSubscriptionError OnErrorDelegate;"); writeln!(output); writeln!(output, " UFUNCTION()"); writeln!( @@ -2876,50 +3015,56 @@ fn generate_subscription_handle_class(output: &mut UnrealCppAutogen, api_macro: writeln!(output); } -fn generate_db_connection_builder_class(output: &mut UnrealCppAutogen, api_macro: &str) { +fn generate_db_connection_builder_class(output: &mut UnrealCppAutogen, module_prefix: &str, api_macro: &str) { writeln!(output, "/*"); writeln!(output, " @Note: Child class of UDbConnectionBuilderBase."); writeln!(output, "*/"); writeln!(output, "UCLASS(BlueprintType)"); writeln!( output, - "class {api_macro} UDbConnectionBuilder : public UDbConnectionBuilderBase" + "class {api_macro} U{module_prefix}DbConnectionBuilder : public UDbConnectionBuilderBase" ); writeln!(output, "{{"); writeln!(output, " GENERATED_BODY()"); writeln!(output, "public:"); writeln!(output); writeln!(output, " UFUNCTION(BlueprintCallable, Category = \"SpacetimeDB\")"); - writeln!(output, " UDbConnectionBuilder* WithUri(const FString& InUri);"); + writeln!( + output, + " U{module_prefix}DbConnectionBuilder* WithUri(const FString& InUri);" + ); writeln!(output, " UFUNCTION(BlueprintCallable, Category = \"SpacetimeDB\")"); writeln!( output, - " UDbConnectionBuilder* WithDatabaseName(const FString& InName);" + " U{module_prefix}DbConnectionBuilder* WithDatabaseName(const FString& InName);" ); writeln!(output, " UFUNCTION(BlueprintCallable, Category = \"SpacetimeDB\")"); - writeln!(output, " UDbConnectionBuilder* WithToken(const FString& InToken);"); + writeln!( + output, + " U{module_prefix}DbConnectionBuilder* WithToken(const FString& InToken);" + ); writeln!(output, " UFUNCTION(BlueprintCallable, Category = \"SpacetimeDB\")"); writeln!( output, - " UDbConnectionBuilder* WithCompression(const ESpacetimeDBCompression& InCompression);" + " U{module_prefix}DbConnectionBuilder* WithCompression(const ESpacetimeDBCompression& InCompression);" ); writeln!(output, " UFUNCTION(BlueprintCallable, Category = \"SpacetimeDB\")"); writeln!( output, - " UDbConnectionBuilder* OnConnect(FOnConnectDelegate Callback);" + " U{module_prefix}DbConnectionBuilder* OnConnect(F{module_prefix}OnConnectDelegate Callback);" ); writeln!(output, " UFUNCTION(BlueprintCallable, Category = \"SpacetimeDB\")"); writeln!( output, - " UDbConnectionBuilder* OnConnectError(FOnConnectErrorDelegate Callback);" + " U{module_prefix}DbConnectionBuilder* OnConnectError(FOnConnectErrorDelegate Callback);" ); writeln!(output, " UFUNCTION(BlueprintCallable, Category = \"SpacetimeDB\")"); writeln!( output, - " UDbConnectionBuilder* OnDisconnect(FOnDisconnectDelegate Callback);" + " U{module_prefix}DbConnectionBuilder* OnDisconnect(F{module_prefix}OnDisconnectDelegate Callback);" ); writeln!(output, " UFUNCTION(BlueprintCallable, Category = \"SpacetimeDB\")"); - writeln!(output, " UDbConnection* Build();"); + writeln!(output, " U{module_prefix}DbConnection* Build();"); writeln!(output); writeln!(output, "private:"); writeln!(output); @@ -2927,59 +3072,76 @@ fn generate_db_connection_builder_class(output: &mut UnrealCppAutogen, api_macro output, " // Stored delegates which will be forwarded when the connection events occur." ); - writeln!(output, " FOnConnectDelegate OnConnectDelegateInternal;"); - writeln!(output, " FOnDisconnectDelegate OnDisconnectDelegateInternal;"); + writeln!( + output, + " F{module_prefix}OnConnectDelegate OnConnectDelegateInternal;" + ); + writeln!( + output, + " F{module_prefix}OnDisconnectDelegate OnDisconnectDelegateInternal;" + ); writeln!(output, "}};"); writeln!(output); } -fn generate_db_connection_class(output: &mut UnrealCppAutogen, _module: &ModuleDef, api_macro: &str) { +fn generate_db_connection_class( + output: &mut UnrealCppAutogen, + module_prefix: &str, + _module: &ModuleDef, + api_macro: &str, +) { writeln!(output, "// Main DbConnection class"); writeln!(output, "UCLASS(BlueprintType)"); - writeln!(output, "class {api_macro} UDbConnection : public UDbConnectionBase"); + writeln!( + output, + "class {api_macro} U{module_prefix}DbConnection : public UDbConnectionBase" + ); writeln!(output, "{{"); writeln!(output, " GENERATED_BODY()"); writeln!(output); writeln!(output, "public:"); writeln!( output, - " explicit UDbConnection(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());" + " explicit U{module_prefix}DbConnection(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());" ); writeln!(output); writeln!(output); writeln!(output, " UPROPERTY(BlueprintReadOnly, Category=\"SpacetimeDB\")"); - writeln!(output, " URemoteTables* Db;"); + writeln!(output, " U{module_prefix}RemoteTables* Db;"); writeln!(output); writeln!(output, " UPROPERTY(BlueprintReadOnly, Category=\"SpacetimeDB\")"); - writeln!(output, " URemoteReducers* Reducers;"); + writeln!(output, " U{module_prefix}RemoteReducers* Reducers;"); writeln!(output); writeln!(output, " UPROPERTY(BlueprintReadOnly, Category=\"SpacetimeDB\")"); - writeln!(output, " URemoteProcedures* Procedures;"); + writeln!(output, " U{module_prefix}RemoteProcedures* Procedures;"); writeln!(output); writeln!( output, " // Delegates that allow users to bind with the concrete connection type." ); - writeln!(output, " FOnConnectDelegate OnConnectDelegate;"); - writeln!(output, " FOnDisconnectDelegate OnDisconnectDelegate;"); + writeln!(output, " F{module_prefix}OnConnectDelegate OnConnectDelegate;"); + writeln!(output, " F{module_prefix}OnDisconnectDelegate OnDisconnectDelegate;"); writeln!(output); writeln!(output, " UFUNCTION(BlueprintCallable, Category=\"SpacetimeDB\")"); - writeln!(output, " USubscriptionBuilder* SubscriptionBuilder();"); + writeln!( + output, + " U{module_prefix}SubscriptionBuilder* SubscriptionBuilder();" + ); writeln!(output); writeln!(output, " /** Static entry point for constructing a connection. */"); writeln!( output, " UFUNCTION(BlueprintCallable, Category = \"SpacetimeDB\", DisplayName = \"SpacetimeDB Builder\")" ); - writeln!(output, " static UDbConnectionBuilder* Builder();"); + writeln!(output, " static U{module_prefix}DbConnectionBuilder* Builder();"); writeln!(output); writeln!(output, " // Error handling"); - writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnUnhandledReducerError, const FReducerEventContext&, Context, const FString&, Error);"); + writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnUnhandledReducerError, const F{module_prefix}ReducerEventContext&, Context, const FString&, Error);"); writeln!(output, " UPROPERTY(BlueprintAssignable, Category=\"SpacetimeDB\")"); writeln!(output, " FOnUnhandledReducerError OnUnhandledReducerError;"); writeln!(output); writeln!(output, " // Error handling"); - writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnUnhandledProcedureError, const FProcedureEventContext&, Context, const FString&, Error);"); + writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnUnhandledProcedureError, const F{module_prefix}ProcedureEventContext&, Context, const FString&, Error);"); writeln!(output, " UPROPERTY(BlueprintAssignable, Category=\"SpacetimeDB\")"); writeln!(output, " FOnUnhandledProcedureError OnUnhandledProcedureError;"); writeln!(output); @@ -3000,13 +3162,13 @@ fn generate_db_connection_class(output: &mut UnrealCppAutogen, _module: &ModuleD writeln!(output, " UFUNCTION()"); writeln!( output, - " void OnUnhandledReducerErrorHandler(const FReducerEventContext& Context, const FString& Error);" + " void OnUnhandledReducerErrorHandler(const F{module_prefix}ReducerEventContext& Context, const FString& Error);" ); writeln!(output); writeln!(output, " UFUNCTION()"); writeln!( output, - " void OnUnhandledProcedureErrorHandler(const FProcedureEventContext& Context, const FString& Error);" + " void OnUnhandledProcedureErrorHandler(const F{module_prefix}ProcedureEventContext& Context, const FString& Error);" ); writeln!(output); writeln!( @@ -3038,7 +3200,7 @@ fn generate_db_connection_class(output: &mut UnrealCppAutogen, _module: &ModuleD " virtual void ProcedureEventFailed(const FProcedureEvent& Event, const FString ErrorMessage) override;" ); writeln!(output); - writeln!(output, " friend class URemoteReducers;"); + writeln!(output, " friend class U{module_prefix}RemoteReducers;"); writeln!(output); writeln!( output, @@ -3046,19 +3208,22 @@ fn generate_db_connection_class(output: &mut UnrealCppAutogen, _module: &ModuleD ); writeln!( output, - " void RegisterPendingTypedReducer(uint32 RequestId, FReducer Reducer);" + " void RegisterPendingTypedReducer(uint32 RequestId, F{module_prefix}Reducer Reducer);" ); writeln!( output, - " bool TryGetPendingTypedReducer(uint32 RequestId, FReducer& OutReducer) const;" + " bool TryGetPendingTypedReducer(uint32 RequestId, F{module_prefix}Reducer& OutReducer) const;" ); writeln!( output, - " bool TryTakePendingTypedReducer(uint32 RequestId, FReducer& OutReducer);" + " bool TryTakePendingTypedReducer(uint32 RequestId, F{module_prefix}Reducer& OutReducer);" ); writeln!(output); writeln!(output, "private:"); - writeln!(output, " TMap PendingTypedReducers;"); + writeln!( + output, + " TMap PendingTypedReducers;" + ); writeln!(output, "}};"); writeln!(output); } @@ -3067,39 +3232,40 @@ fn generate_client_implementation( output: &mut UnrealCppAutogen, module: &ModuleDef, visibility: CodegenVisibility, + module_prefix: &str, module_name: &str, ) { - // UDbConnection constructor + // U{module_prefix}DbConnection constructor writeln!( output, - "UDbConnection::UDbConnection(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)" + "U{module_prefix}DbConnection::U{module_prefix}DbConnection(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)" ); writeln!(output, "{{"); writeln!( output, - "\tDb = ObjectInitializer.CreateDefaultSubobject(this, TEXT(\"RemoteTables\"));" + "\tDb = ObjectInitializer.CreateDefaultSubobject(this, TEXT(\"RemoteTables\"));" ); writeln!(output, "\tDb->Initialize();"); writeln!(output, "\t"); writeln!( output, - "\tReducers = ObjectInitializer.CreateDefaultSubobject(this, TEXT(\"RemoteReducers\"));" + "\tReducers = ObjectInitializer.CreateDefaultSubobject(this, TEXT(\"RemoteReducers\"));" ); writeln!(output, "\tReducers->Conn = this;"); writeln!(output); writeln!( output, - "\tProcedures = ObjectInitializer.CreateDefaultSubobject(this, TEXT(\"RemoteProcedures\"));" + "\tProcedures = ObjectInitializer.CreateDefaultSubobject(this, TEXT(\"RemoteProcedures\"));" ); writeln!(output, "\tProcedures->Conn = this;"); writeln!(output); for (name, accessor_name, product_type_ref) in iter_table_names_and_types(module, visibility) { - let struct_name = type_ref_name(module, product_type_ref); + let struct_name = type_ref_name(module_prefix, module, product_type_ref); let accessor = accessor_name.deref(); writeln!( output, - "\tRegisterTable(TEXT(\"{}\"), Db->{});", + "\tRegisterTable(TEXT(\"{}\"), Db->{});", struct_name, accessor.to_case(Case::Pascal), name.deref(), @@ -3109,8 +3275,11 @@ fn generate_client_implementation( writeln!(output, "}}"); writeln!(output); - // FContextBase constructor - writeln!(output, "FContextBase::FContextBase(UDbConnection* InConn)"); + // F{module_prefix}ContextBase constructor + writeln!( + output, + "F{module_prefix}ContextBase::F{module_prefix}ContextBase(U{module_prefix}DbConnection* InConn)" + ); writeln!(output, "{{"); writeln!(output, "\tDb = InConn->Db;"); writeln!(output, "\tReducers = InConn->Reducers;"); @@ -3118,41 +3287,47 @@ fn generate_client_implementation( writeln!(output, "\tConn = InConn;"); writeln!(output, "}}"); - // FContextBase methods - writeln!(output, "bool FContextBase::IsActive() const"); + // F{module_prefix}ContextBase methods + writeln!(output, "bool F{module_prefix}ContextBase::IsActive() const"); writeln!(output, "{{"); writeln!(output, "\treturn Conn->IsActive();"); writeln!(output, "}}"); - writeln!(output, "void FContextBase::Disconnect()"); + writeln!(output, "void F{module_prefix}ContextBase::Disconnect()"); writeln!(output, "{{"); writeln!(output, "\tConn->Disconnect();"); writeln!(output, "}}"); - writeln!(output, "USubscriptionBuilder* FContextBase::SubscriptionBuilder()"); + writeln!( + output, + "U{module_prefix}SubscriptionBuilder* F{module_prefix}ContextBase::SubscriptionBuilder()" + ); writeln!(output, "{{"); writeln!(output, "\treturn Conn->SubscriptionBuilder();"); writeln!(output, "}}"); writeln!( output, - "bool FContextBase::TryGetIdentity(FSpacetimeDBIdentity& OutIdentity) const" + "bool F{module_prefix}ContextBase::TryGetIdentity(FSpacetimeDBIdentity& OutIdentity) const" ); writeln!(output, "{{"); writeln!(output, "\treturn Conn->TryGetIdentity(OutIdentity);"); writeln!(output, "}}"); - writeln!(output, "FSpacetimeDBConnectionId FContextBase::GetConnectionId() const"); + writeln!( + output, + "FSpacetimeDBConnectionId F{module_prefix}ContextBase::GetConnectionId() const" + ); writeln!(output, "{{"); writeln!(output, "\treturn Conn->GetConnectionId();"); writeln!(output, "}}"); writeln!(output); - // URemoteTables Initialize method - writeln!(output, "void URemoteTables::Initialize()"); + // U{module_prefix}RemoteTables Initialize method + writeln!(output, "void U{module_prefix}RemoteTables::Initialize()"); writeln!(output, "{{"); writeln!(output); writeln!(output, "\t/** Creating tables */"); for (_, accessor_name, _) in iter_table_names_and_types(module, visibility) { writeln!( output, - "\t{} = NewObject(this);", + "\t{} = NewObject(this);", accessor_name.deref().to_case(Case::Pascal), accessor_name.deref().to_case(Case::Pascal) ); @@ -3171,11 +3346,11 @@ fn generate_client_implementation( writeln!(output, "}}"); writeln!(output); - generate_remote_reducer_calls(output, module, visibility, module_name); - generate_remote_procedure_calls(output, module, visibility, module_name); + generate_remote_reducer_calls(output, module, visibility, module_prefix, module_name); + generate_remote_procedure_calls(output, module, visibility, module_prefix, module_name); // Hook up error handling - writeln!(output, "void UDbConnection::PostInitProperties()"); + writeln!(output, "void U{module_prefix}DbConnection::PostInitProperties()"); writeln!(output, "{{"); writeln!(output, " Super::PostInitProperties();"); writeln!(output, " "); @@ -3185,7 +3360,7 @@ fn generate_client_implementation( ); writeln!(output, " if (Reducers)"); writeln!(output, " {{"); - writeln!(output, " Reducers->InternalOnUnhandledReducerError.AddDynamic(this, &UDbConnection::OnUnhandledReducerErrorHandler);"); + writeln!(output, " Reducers->InternalOnUnhandledReducerError.AddDynamic(this, &U{module_prefix}DbConnection::OnUnhandledReducerErrorHandler);"); writeln!(output, " }}"); writeln!(output); writeln!( @@ -3194,7 +3369,7 @@ fn generate_client_implementation( ); writeln!(output, " if (Procedures)"); writeln!(output, " {{"); - writeln!(output, " Procedures->InternalOnUnhandledProcedureError.AddDynamic(this, &UDbConnection::OnUnhandledProcedureErrorHandler);"); + writeln!(output, " Procedures->InternalOnUnhandledProcedureError.AddDynamic(this, &U{module_prefix}DbConnection::OnUnhandledProcedureErrorHandler);"); writeln!(output, " }}"); writeln!(output, "}}"); writeln!(output); @@ -3203,7 +3378,7 @@ fn generate_client_implementation( writeln!(output, "UFUNCTION()"); writeln!( output, - "void UDbConnection::OnUnhandledReducerErrorHandler(const FReducerEventContext& Context, const FString& Error)" + "void U{module_prefix}DbConnection::OnUnhandledReducerErrorHandler(const F{module_prefix}ReducerEventContext& Context, const FString& Error)" ); writeln!(output, "{{"); writeln!(output, " if (OnUnhandledReducerError.IsBound())"); @@ -3217,7 +3392,7 @@ fn generate_client_implementation( writeln!(output, "UFUNCTION()"); writeln!( output, - "void UDbConnection::OnUnhandledProcedureErrorHandler(const FProcedureEventContext& Context, const FString& Error)" + "void U{module_prefix}DbConnection::OnUnhandledProcedureErrorHandler(const F{module_prefix}ProcedureEventContext& Context, const FString& Error)" ); writeln!(output, "{{"); writeln!(output, " if (OnUnhandledProcedureError.IsBound())"); @@ -3229,7 +3404,7 @@ fn generate_client_implementation( writeln!( output, - "void UDbConnection::RegisterPendingTypedReducer(uint32 RequestId, FReducer Reducer)" + "void U{module_prefix}DbConnection::RegisterPendingTypedReducer(uint32 RequestId, F{module_prefix}Reducer Reducer)" ); writeln!(output, "{{"); writeln!(output, " Reducer.RequestId = RequestId;"); @@ -3238,12 +3413,12 @@ fn generate_client_implementation( writeln!(output); writeln!( output, - "bool UDbConnection::TryGetPendingTypedReducer(uint32 RequestId, FReducer& OutReducer) const" + "bool U{module_prefix}DbConnection::TryGetPendingTypedReducer(uint32 RequestId, F{module_prefix}Reducer& OutReducer) const" ); writeln!(output, "{{"); writeln!( output, - " if (const FReducer* Found = PendingTypedReducers.Find(RequestId))" + " if (const F{module_prefix}Reducer* Found = PendingTypedReducers.Find(RequestId))" ); writeln!(output, " {{"); writeln!(output, " OutReducer = *Found;"); @@ -3254,12 +3429,12 @@ fn generate_client_implementation( writeln!(output); writeln!( output, - "bool UDbConnection::TryTakePendingTypedReducer(uint32 RequestId, FReducer& OutReducer)" + "bool U{module_prefix}DbConnection::TryTakePendingTypedReducer(uint32 RequestId, F{module_prefix}Reducer& OutReducer)" ); writeln!(output, "{{"); writeln!( output, - " if (FReducer* Found = PendingTypedReducers.Find(RequestId))" + " if (F{module_prefix}Reducer* Found = PendingTypedReducers.Find(RequestId))" ); writeln!(output, " {{"); writeln!(output, " OutReducer = *Found;"); @@ -3271,12 +3446,15 @@ fn generate_client_implementation( writeln!(output); // ReducerEvent method implementation - writeln!(output, "void UDbConnection::ReducerEvent(const FReducerEvent& Event)"); + writeln!( + output, + "void U{module_prefix}DbConnection::ReducerEvent(const FReducerEvent& Event)" + ); writeln!(output, "{{"); writeln!(output, " if (!Reducers) {{ return; }}"); writeln!(output); - writeln!(output, " FReducer DecodedReducer;"); + writeln!(output, " F{module_prefix}Reducer DecodedReducer;"); writeln!( output, " if (!TryTakePendingTypedReducer(Event.RequestId, DecodedReducer))" @@ -3306,7 +3484,10 @@ fn generate_client_implementation( writeln!(output, " ReducerEvent.Reducer = DecodedReducer;"); writeln!(output); - writeln!(output, " FReducerEventContext Context(this, ReducerEvent);"); + writeln!( + output, + " F{module_prefix}ReducerEventContext Context(this, ReducerEvent);" + ); writeln!(output); writeln!(output, " // Dispatch by typed reducer metadata"); writeln!( @@ -3317,7 +3498,7 @@ fn generate_client_implementation( for reducer in iter_reducers(module, visibility) { let reducer_name = reducer.name.deref(); - let reducer_pascal = reducer.name.deref().to_case(Case::Pascal); + let reducer_pascal = format!("{module_prefix}{}", reducer.name.deref().to_case(Case::Pascal)); writeln!(output, " if (ReducerName == TEXT(\"{reducer_name}\"))"); writeln!(output, " {{"); writeln!( @@ -3345,7 +3526,7 @@ fn generate_client_implementation( // ReducerEventFailed method implementation writeln!( output, - "void UDbConnection::ReducerEventFailed(const FReducerEvent& Event, const FString ErrorMessage)" + "void U{module_prefix}DbConnection::ReducerEventFailed(const FReducerEvent& Event, const FString ErrorMessage)" ); writeln!(output, "{{"); writeln!(output, " if (!Reducers) {{ return; }}"); @@ -3363,7 +3544,10 @@ fn generate_client_implementation( writeln!(output, " ReducerEvent.Timestamp = Event.Timestamp;"); writeln!(output); - writeln!(output, " FReducerEventContext Context(this, ReducerEvent);"); + writeln!( + output, + " F{module_prefix}ReducerEventContext Context(this, ReducerEvent);" + ); writeln!(output); writeln!(output, " if (Reducers->InternalOnUnhandledReducerError.IsBound())"); writeln!(output, " {{"); @@ -3378,7 +3562,7 @@ fn generate_client_implementation( // ProcedureEventFailed method implementation writeln!( output, - "void UDbConnection::ProcedureEventFailed(const FProcedureEvent& Event, const FString ErrorMessage)" + "void U{module_prefix}DbConnection::ProcedureEventFailed(const FProcedureEvent& Event, const FString ErrorMessage)" ); writeln!(output, "{{"); writeln!(output, " if (!Procedures) {{ return; }}"); @@ -3393,7 +3577,10 @@ fn generate_client_implementation( writeln!(output, " ProcedureEvent.Timestamp = Event.Timestamp;"); writeln!(output); - writeln!(output, " FProcedureEventContext Context(this, ProcedureEvent);"); + writeln!( + output, + " F{module_prefix}ProcedureEventContext Context(this, ProcedureEvent);" + ); writeln!(output); writeln!( output, @@ -3409,23 +3596,29 @@ fn generate_client_implementation( writeln!(output); // Additional methods from manual reference - writeln!(output, "UDbConnectionBuilder* UDbConnection::Builder()"); + writeln!( + output, + "U{module_prefix}DbConnectionBuilder* U{module_prefix}DbConnection::Builder()" + ); writeln!(output, "{{"); - writeln!(output, "\treturn NewObject();"); + writeln!(output, "\treturn NewObject();"); writeln!(output, "}}"); writeln!(output, "// Added for creating subscriptions"); - writeln!(output, "USubscriptionBuilder* UDbConnection::SubscriptionBuilder()"); + writeln!( + output, + "U{module_prefix}SubscriptionBuilder* U{module_prefix}DbConnection::SubscriptionBuilder()" + ); writeln!(output, "{{"); writeln!( output, - "\tUSubscriptionBuilder* Builder = NewObject(this);" + "\tU{module_prefix}SubscriptionBuilder* Builder = NewObject(this);" ); writeln!(output, "\tBuilder->Conn = this;"); writeln!(output, "\treturn Builder;"); writeln!(output, "}}"); writeln!( output, - "USubscriptionBuilder* USubscriptionBuilder::OnApplied(FOnSubscriptionApplied Callback)" + "U{module_prefix}SubscriptionBuilder* U{module_prefix}SubscriptionBuilder::OnApplied(F{module_prefix}OnSubscriptionApplied Callback)" ); writeln!(output, "{{"); writeln!(output, "\tOnAppliedDelegateInternal = Callback;"); @@ -3433,7 +3626,7 @@ fn generate_client_implementation( writeln!(output, "}}"); writeln!( output, - "USubscriptionBuilder* USubscriptionBuilder::OnError(FOnSubscriptionError Callback)" + "U{module_prefix}SubscriptionBuilder* U{module_prefix}SubscriptionBuilder::OnError(F{module_prefix}OnSubscriptionError Callback)" ); writeln!(output, "{{"); writeln!(output, "\tOnErrorDelegateInternal = Callback;"); @@ -3441,12 +3634,12 @@ fn generate_client_implementation( writeln!(output, "}}"); writeln!( output, - "USubscriptionHandle* USubscriptionBuilder::Subscribe(const TArray& SQL)" + "U{module_prefix}SubscriptionHandle* U{module_prefix}SubscriptionBuilder::Subscribe(const TArray& SQL)" ); writeln!(output, "{{"); writeln!( output, - "\tUSubscriptionHandle* Handle = NewObject();" + "\tU{module_prefix}SubscriptionHandle* Handle = NewObject();" ); writeln!(output); writeln!(output, "\t// Store user callbacks on the handle"); @@ -3475,7 +3668,7 @@ fn generate_client_implementation( writeln!(output, "}}"); writeln!( output, - "USubscriptionHandle* USubscriptionBuilder::SubscribeToAllTables()" + "U{module_prefix}SubscriptionHandle* U{module_prefix}SubscriptionBuilder::SubscribeToAllTables()" ); writeln!(output, "{{"); writeln!(output, "\treturn Subscribe({{ \"SELECT * FROM * \" }});"); @@ -3483,7 +3676,7 @@ fn generate_client_implementation( writeln!(output); writeln!( output, - "USubscriptionHandle::USubscriptionHandle(UDbConnection* InConn)" + "U{module_prefix}SubscriptionHandle::U{module_prefix}SubscriptionHandle(U{module_prefix}DbConnection* InConn)" ); writeln!(output, "{{"); writeln!(output, "\tConn = InConn;"); @@ -3491,7 +3684,7 @@ fn generate_client_implementation( writeln!(output); writeln!( output, - "void USubscriptionHandle::ForwardOnApplied(const FSubscriptionEventContextBase& BaseCtx)" + "void U{module_prefix}SubscriptionHandle::ForwardOnApplied(const FSubscriptionEventContextBase& BaseCtx)" ); writeln!(output, "{{"); writeln!(output, "\tif (OnAppliedDelegate.IsBound())"); @@ -3503,7 +3696,7 @@ fn generate_client_implementation( writeln!(output); writeln!( output, - "void USubscriptionHandle::ForwardOnError(const FErrorContextBase& BaseCtx)" + "void U{module_prefix}SubscriptionHandle::ForwardOnError(const FErrorContextBase& BaseCtx)" ); writeln!(output, "{{"); writeln!(output, "\tif (OnErrorDelegate.IsBound())"); @@ -3517,41 +3710,47 @@ fn generate_client_implementation( writeln!(output, "// Cast from parent to child class"); writeln!( output, - "UDbConnectionBuilder* UDbConnectionBuilder::WithUri(const FString& InUri)" + "U{module_prefix}DbConnectionBuilder* U{module_prefix}DbConnectionBuilder::WithUri(const FString& InUri)" ); writeln!(output, "{{"); - writeln!(output, "\treturn Cast(WithUriBase(InUri));"); + writeln!( + output, + "\treturn Cast(WithUriBase(InUri));" + ); writeln!(output, "}}"); writeln!( output, - "UDbConnectionBuilder* UDbConnectionBuilder::WithDatabaseName(const FString& InName)" + "U{module_prefix}DbConnectionBuilder* U{module_prefix}DbConnectionBuilder::WithDatabaseName(const FString& InName)" ); writeln!(output, "{{"); writeln!( output, - "\treturn Cast(WithDatabaseNameBase(InName));" + "\treturn Cast(WithDatabaseNameBase(InName));" ); writeln!(output, "}}"); writeln!( output, - "UDbConnectionBuilder* UDbConnectionBuilder::WithToken(const FString& InToken)" + "U{module_prefix}DbConnectionBuilder* U{module_prefix}DbConnectionBuilder::WithToken(const FString& InToken)" ); writeln!(output, "{{"); - writeln!(output, "\treturn Cast(WithTokenBase(InToken));"); + writeln!( + output, + "\treturn Cast(WithTokenBase(InToken));" + ); writeln!(output, "}}"); writeln!( output, - "UDbConnectionBuilder* UDbConnectionBuilder::WithCompression(const ESpacetimeDBCompression& InCompression)" + "U{module_prefix}DbConnectionBuilder* U{module_prefix}DbConnectionBuilder::WithCompression(const ESpacetimeDBCompression& InCompression)" ); writeln!(output, "{{"); writeln!( output, - "\treturn Cast(WithCompressionBase(InCompression));" + "\treturn Cast(WithCompressionBase(InCompression));" ); writeln!(output, "}}"); writeln!( output, - "UDbConnectionBuilder* UDbConnectionBuilder::OnConnect(FOnConnectDelegate Callback)" + "U{module_prefix}DbConnectionBuilder* U{module_prefix}DbConnectionBuilder::OnConnect(F{module_prefix}OnConnectDelegate Callback)" ); writeln!(output, "{{"); writeln!(output, "\tOnConnectDelegateInternal = Callback;"); @@ -3559,25 +3758,31 @@ fn generate_client_implementation( writeln!(output, "}}"); writeln!( output, - "UDbConnectionBuilder* UDbConnectionBuilder::OnConnectError(FOnConnectErrorDelegate Callback)" + "U{module_prefix}DbConnectionBuilder* U{module_prefix}DbConnectionBuilder::OnConnectError(FOnConnectErrorDelegate Callback)" ); writeln!(output, "{{"); writeln!( output, - "\treturn Cast(OnConnectErrorBase(Callback));" + "\treturn Cast(OnConnectErrorBase(Callback));" ); writeln!(output, "}}"); writeln!( output, - "UDbConnectionBuilder* UDbConnectionBuilder::OnDisconnect(FOnDisconnectDelegate Callback)" + "U{module_prefix}DbConnectionBuilder* U{module_prefix}DbConnectionBuilder::OnDisconnect(F{module_prefix}OnDisconnectDelegate Callback)" ); writeln!(output, "{{"); writeln!(output, "\tOnDisconnectDelegateInternal = Callback;"); writeln!(output, "\treturn this;"); writeln!(output, "}}"); - writeln!(output, "UDbConnection* UDbConnectionBuilder::Build()"); + writeln!( + output, + "U{module_prefix}DbConnection* U{module_prefix}DbConnectionBuilder::Build()" + ); writeln!(output, "{{"); - writeln!(output, "\tUDbConnection* Connection = NewObject();"); + writeln!( + output, + "\tU{module_prefix}DbConnection* Connection = NewObject();" + ); writeln!(output); writeln!(output, "\t// Store delegates on the connection for later use"); writeln!(output, "\tConnection->OnConnectDelegate = OnConnectDelegateInternal;"); @@ -3603,9 +3808,12 @@ fn generate_client_implementation( writeln!(output, "\tConnection->SetOnDisconnectDelegate(BaseDisconnect);"); writeln!(output, "\tOnDisconnectBase(BaseDisconnect);"); writeln!(output); - writeln!(output, "\treturn Cast(BuildConnection(Connection));"); + writeln!( + output, + "\treturn Cast(BuildConnection(Connection));" + ); writeln!(output, "}}"); - writeln!(output, "void UDbConnection::ForwardOnConnect(UDbConnectionBase* BaseConnection, FSpacetimeDBIdentity InIdentity, const FString& InToken)"); + writeln!(output, "void U{module_prefix}DbConnection::ForwardOnConnect(UDbConnectionBase* BaseConnection, FSpacetimeDBIdentity InIdentity, const FString& InToken)"); writeln!(output, "{{"); writeln!(output, "\tif (OnConnectDelegate.IsBound())"); writeln!(output, "\t{{"); @@ -3614,7 +3822,7 @@ fn generate_client_implementation( writeln!(output, "}}"); writeln!( output, - "void UDbConnection::ForwardOnDisconnect(UDbConnectionBase* BaseConnection, const FString& Error)" + "void U{module_prefix}DbConnection::ForwardOnDisconnect(UDbConnectionBase* BaseConnection, const FString& Error)" ); writeln!(output, "{{"); writeln!(output, "\tif (OnDisconnectDelegate.IsBound())"); @@ -3627,7 +3835,7 @@ fn generate_client_implementation( writeln!( output, - "void UDbConnection::DbUpdate(const FDatabaseUpdateType& Update, const FSpacetimeDBEvent& Event)" + "void U{module_prefix}DbConnection::DbUpdate(const FDatabaseUpdateType& Update, const FSpacetimeDBEvent& Event)" ); writeln!(output, "{{"); @@ -3644,7 +3852,7 @@ fn generate_client_implementation( writeln!(output, " case ESpacetimeDBEventTag::Reducer:"); writeln!(output, " {{"); writeln!(output, " FReducerEvent ReducerEvent = Event.GetAsReducer();"); - writeln!(output, " FReducer Reducer;"); + writeln!(output, " F{module_prefix}Reducer Reducer;"); writeln!( output, " if (!TryGetPendingTypedReducer(ReducerEvent.RequestId, Reducer))" @@ -3723,7 +3931,7 @@ fn generate_client_implementation( writeln!(output); // Wrap in EventContext - writeln!(output, " FEventContext Context(this, BaseEvent);"); + writeln!(output, " F{module_prefix}EventContext Context(this, BaseEvent);"); writeln!( output, " // Populate typed reducer args for convenience in table handlers" @@ -3740,15 +3948,16 @@ fn generate_remote_reducer_calls( output: &mut UnrealCppAutogen, module: &ModuleDef, visibility: CodegenVisibility, + module_prefix: &str, module_name: &str, ) { // Reducer implementations for reducer in iter_reducers(module, visibility) { - let reducer_pascal = reducer.name.deref().to_case(Case::Pascal); + let reducer_pascal = format!("{module_prefix}{}", reducer.name.deref().to_case(Case::Pascal)); let reducer_snake = reducer.name.deref(); // Call method implementation - write!(output, "void URemoteReducers::{reducer_pascal}("); + write!(output, "void U{module_prefix}RemoteReducers::{reducer_pascal}("); let mut first = true; for (param_name, param_type) in &reducer.params_for_generate.elements { if !first { @@ -3756,9 +3965,9 @@ fn generate_remote_reducer_calls( } first = false; // Use Blueprint-compatible types (same as UFUNCTION and delegates) - let type_str = cpp_ty_fmt_blueprint_compatible(module, param_type, module_name).to_string(); + let type_str = cpp_ty_fmt_blueprint_compatible(module_prefix, module, param_type, module_name).to_string(); if should_pass_by_value_in_delegate(module, param_type) { - // Primitives use const by-value in URemoteReducers methods (same as UFUNCTION) + // Primitives use const by-value in U{module_prefix}RemoteReducers methods (same as UFUNCTION) write!( output, "const {} {}", @@ -3795,7 +4004,7 @@ fn generate_remote_reducer_calls( ); writeln!( output, - "\tif (RequestId != 0) {{ Conn->RegisterPendingTypedReducer(RequestId, FReducer::{reducer_pascal}(ReducerArgs)); }}" + "\tif (RequestId != 0) {{ Conn->RegisterPendingTypedReducer(RequestId, F{module_prefix}Reducer::{reducer_pascal}(ReducerArgs)); }}" ); } else { write!(output, "\tF{reducer_pascal}Args ReducerArgs("); @@ -3815,7 +4024,7 @@ fn generate_remote_reducer_calls( ); writeln!( output, - "\tif (RequestId != 0) {{ Conn->RegisterPendingTypedReducer(RequestId, FReducer::{reducer_pascal}(ReducerArgs)); }}" + "\tif (RequestId != 0) {{ Conn->RegisterPendingTypedReducer(RequestId, F{module_prefix}Reducer::{reducer_pascal}(ReducerArgs)); }}" ); } writeln!(output, "}}"); @@ -3824,7 +4033,7 @@ fn generate_remote_reducer_calls( // Invoke method implementation write!( output, - "bool URemoteReducers::Invoke{reducer_pascal}(const FReducerEventContext& Context, const U{reducer_pascal}Reducer* Args)" + "bool U{module_prefix}RemoteReducers::Invoke{reducer_pascal}(const F{module_prefix}ReducerEventContext& Context, const U{reducer_pascal}Reducer* Args)" ); writeln!(output); writeln!(output, "{{"); @@ -3876,7 +4085,7 @@ fn generate_remote_reducer_calls( // InvokeWithArgs method implementation (zero allocation version) write!( output, - "bool URemoteReducers::Invoke{reducer_pascal}WithArgs(const FReducerEventContext& Context, const F{reducer_pascal}Args& Args)" + "bool U{module_prefix}RemoteReducers::Invoke{reducer_pascal}WithArgs(const F{module_prefix}ReducerEventContext& Context, const F{reducer_pascal}Args& Args)" ); writeln!(output); writeln!(output, "{{"); @@ -3917,15 +4126,16 @@ fn generate_remote_procedure_calls( output: &mut UnrealCppAutogen, module: &ModuleDef, visibility: CodegenVisibility, + module_prefix: &str, module_name: &str, ) { // Procedure implementations for procedure in iter_procedures(module, visibility) { - let procedure_pascal = procedure.name.deref().to_case(Case::Pascal); + let procedure_pascal = format!("{module_prefix}{}", procedure.name.deref().to_case(Case::Pascal)); let procedure_snake = procedure.name.deref(); // Call method implementation - write!(output, "void URemoteProcedures::{procedure_pascal}("); + write!(output, "void U{module_prefix}RemoteProcedures::{procedure_pascal}("); let mut first = true; for (param_name, param_type) in &procedure.params_for_generate.elements { if !first { @@ -3933,9 +4143,9 @@ fn generate_remote_procedure_calls( } first = false; // Use Blueprint-compatible types (same as UFUNCTION and delegates) - let type_str = cpp_ty_fmt_blueprint_compatible(module, param_type, module_name).to_string(); + let type_str = cpp_ty_fmt_blueprint_compatible(module_prefix, module, param_type, module_name).to_string(); if should_pass_by_value_in_delegate(module, param_type) { - // Primitives use const by-value in URemoteProcedures methods (same as UFUNCTION) + // Primitives use const by-value in U{module_prefix}RemoteProcedures methods (same as UFUNCTION) write!( output, "const {} {}", @@ -3969,7 +4179,7 @@ fn generate_remote_procedure_calls( // Get the actual return type for this procedure let return_type_str = - cpp_ty_fmt_with_module(module, &procedure.return_type_for_generate, module_name).to_string(); + cpp_ty_fmt_with_module(module_prefix, module, &procedure.return_type_for_generate, module_name).to_string(); writeln!(output, " FOnProcedureCompleteDelegate Wrapper;"); writeln!(output, " Wrapper.BindLambda("); @@ -3991,7 +4201,7 @@ fn generate_remote_procedure_calls( writeln!(output, " F{module_name}ProcedureEvent ProcedureEvent = F{module_name}ProcedureEvent(Event.GetAsProcedure());"); writeln!( output, - " FProcedureEventContext Context = FProcedureEventContext(Conn, ProcedureEvent);" + " F{module_prefix}ProcedureEventContext Context = F{module_prefix}ProcedureEventContext(Conn, ProcedureEvent);" ); writeln!(output, " // Fire the user's typed delegate"); writeln!( @@ -4084,6 +4294,7 @@ impl UnrealCppAutogen { // Unified helper function to collect special wrapper types (optionals and results) fn collect_wrapper_types( + module_prefix: &str, module: &ModuleDef, visibility: CodegenVisibility, ) -> (HashSet, HashSet<(String, String)>) { @@ -4092,6 +4303,7 @@ fn collect_wrapper_types( // Helper function to recursively collect from a type fn collect_from_type( + module_prefix: &str, module: &ModuleDef, ty: &AlgebraicTypeUse, optional_types: &mut HashSet, @@ -4100,34 +4312,34 @@ fn collect_wrapper_types( match ty { AlgebraicTypeUse::Option(inner) => { // Generate the optional type name - let optional_name = get_optional_type_name(module, inner); + let optional_name = get_optional_type_name(module_prefix, module, inner); optional_types.insert(optional_name); // Recursively collect from inner type - collect_from_type(module, inner, optional_types, result_types); + collect_from_type(module_prefix, module, inner, optional_types, result_types); } AlgebraicTypeUse::Result { ok_ty, err_ty } => { // Generate the result type name components - let ok_name = get_type_name_for_result(module, ok_ty); - let err_name = get_type_name_for_result(module, err_ty); + let ok_name = get_type_name_for_result(module_prefix, module, ok_ty); + let err_name = get_type_name_for_result(module_prefix, module, err_ty); result_types.insert((ok_name, err_name)); // Recursively collect from both inner types - collect_from_type(module, ok_ty, optional_types, result_types); - collect_from_type(module, err_ty, optional_types, result_types); + collect_from_type(module_prefix, module, ok_ty, optional_types, result_types); + collect_from_type(module_prefix, module, err_ty, optional_types, result_types); } AlgebraicTypeUse::Array(elem) => { - collect_from_type(module, elem, optional_types, result_types); + collect_from_type(module_prefix, module, elem, optional_types, result_types); } AlgebraicTypeUse::Ref(r) => { // Check if the referenced type contains optionals or results match &module.typespace_for_generate()[*r] { AlgebraicTypeDef::Product(product) => { for (_, field_ty) in &product.elements { - collect_from_type(module, field_ty, optional_types, result_types); + collect_from_type(module_prefix, module, field_ty, optional_types, result_types); } } AlgebraicTypeDef::Sum(sum) => { for (_, variant_ty) in &sum.variants { - collect_from_type(module, variant_ty, optional_types, result_types); + collect_from_type(module_prefix, module, variant_ty, optional_types, result_types); } } _ => {} @@ -4141,7 +4353,7 @@ fn collect_wrapper_types( for (_, _, product_type_ref) in iter_table_names_and_types(module, visibility) { let product_type = module.typespace_for_generate()[product_type_ref].as_product().unwrap(); for (_, field_ty) in &product_type.elements { - collect_from_type(module, field_ty, &mut optional_types, &mut result_types); + collect_from_type(module_prefix, module, field_ty, &mut optional_types, &mut result_types); } } @@ -4150,12 +4362,18 @@ fn collect_wrapper_types( match &module.typespace_for_generate()[typ.ty] { AlgebraicTypeDef::Product(product) => { for (_, field_ty) in &product.elements { - collect_from_type(module, field_ty, &mut optional_types, &mut result_types); + collect_from_type(module_prefix, module, field_ty, &mut optional_types, &mut result_types); } } AlgebraicTypeDef::Sum(sum) => { for (_, variant_ty) in &sum.variants { - collect_from_type(module, variant_ty, &mut optional_types, &mut result_types); + collect_from_type( + module_prefix, + module, + variant_ty, + &mut optional_types, + &mut result_types, + ); } } _ => {} @@ -4165,16 +4383,17 @@ fn collect_wrapper_types( // Collect from reducer parameters for reducer in iter_reducers(module, visibility) { for (_, param_ty) in &reducer.params_for_generate.elements { - collect_from_type(module, param_ty, &mut optional_types, &mut result_types); + collect_from_type(module_prefix, module, param_ty, &mut optional_types, &mut result_types); } } // Collect from procedure parameters and return types for procedure in iter_procedures(module, visibility) { for (_, param_ty) in &procedure.params_for_generate.elements { - collect_from_type(module, param_ty, &mut optional_types, &mut result_types); + collect_from_type(module_prefix, module, param_ty, &mut optional_types, &mut result_types); } collect_from_type( + module_prefix, module, &procedure.return_type_for_generate, &mut optional_types, @@ -4240,7 +4459,7 @@ fn get_cpp_type_for_array_element(elem_type_str: &str, module: &ModuleDef, modul } // Helper function to get array element type name for optional array types -fn get_array_element_type_name(module: &ModuleDef, elem: &AlgebraicTypeUse) -> String { +fn get_array_element_type_name(module_prefix: &str, module: &ModuleDef, elem: &AlgebraicTypeUse) -> String { match elem { AlgebraicTypeUse::Primitive(p) => match p { PrimitiveType::Bool => "Bool".to_string(), @@ -4266,21 +4485,21 @@ fn get_array_element_type_name(module: &ModuleDef, elem: &AlgebraicTypeUse) -> S AlgebraicTypeUse::TimeDuration => "TimeDuration".to_string(), AlgebraicTypeUse::Uuid => "Uuid".to_string(), AlgebraicTypeUse::ScheduleAt => "ScheduleAt".to_string(), - AlgebraicTypeUse::Ref(r) => type_ref_name(module, *r), + AlgebraicTypeUse::Ref(r) => type_ref_name(module_prefix, module, *r), AlgebraicTypeUse::Option(nested_inner) => { // Handle optional elements in arrays like Vec> - get_optional_type_name(module, nested_inner) + get_optional_type_name(module_prefix, module, nested_inner) } AlgebraicTypeUse::Result { ok_ty, err_ty } => { // Handle result elements in arrays like Vec> - get_result_type_name(module, ok_ty, err_ty) + get_result_type_name(module_prefix, module, ok_ty, err_ty) } _ => "Unknown".to_string(), } } // Get the name for an optional type (e.g., "OptionalString", "OptionalInt32") -fn get_optional_type_name(module: &ModuleDef, inner: &AlgebraicTypeUse) -> String { +fn get_optional_type_name(module_prefix: &str, module: &ModuleDef, inner: &AlgebraicTypeUse) -> String { match inner { AlgebraicTypeUse::Primitive(p) => match p { PrimitiveType::Bool => "OptionalBool".to_string(), @@ -4308,20 +4527,20 @@ fn get_optional_type_name(module: &ModuleDef, inner: &AlgebraicTypeUse) -> Strin AlgebraicTypeUse::ScheduleAt => "OptionalScheduleAt".to_string(), AlgebraicTypeUse::Array(elem) => { // Generate specific optional array types based on element type - let elem_name = get_array_element_type_name(module, elem); + let elem_name = get_array_element_type_name(module_prefix, module, elem); format!("OptionalVec{elem_name}") } AlgebraicTypeUse::Ref(r) => { - let type_name = type_ref_name(module, *r); + let type_name = type_ref_name(module_prefix, module, *r); format!("Optional{type_name}") } AlgebraicTypeUse::Option(nested_inner) => { // Handle nested optionals like Option> - let inner_optional_name = get_optional_type_name(module, nested_inner); + let inner_optional_name = get_optional_type_name(module_prefix, module, nested_inner); format!("Optional{inner_optional_name}") } AlgebraicTypeUse::Result { ok_ty, err_ty } => { - let result_name = get_result_type_name(module, ok_ty, err_ty); + let result_name = get_result_type_name(module_prefix, module, ok_ty, err_ty); format!("Optional{result_name}") } _ => "OptionalUnknown".to_string(), @@ -4592,14 +4811,19 @@ fn generate_optional_type(optional_name: &str, module: &ModuleDef, api_macro: &s } // Get the name for a result type (e.g., "ResultStringString", "ResultInt32String") -fn get_result_type_name(module: &ModuleDef, ok_ty: &AlgebraicTypeUse, err_ty: &AlgebraicTypeUse) -> String { - let ok_name = get_type_name_for_result(module, ok_ty); - let err_name = get_type_name_for_result(module, err_ty); +fn get_result_type_name( + module_prefix: &str, + module: &ModuleDef, + ok_ty: &AlgebraicTypeUse, + err_ty: &AlgebraicTypeUse, +) -> String { + let ok_name = get_type_name_for_result(module_prefix, module, ok_ty); + let err_name = get_type_name_for_result(module_prefix, module, err_ty); format!("Result{ok_name}{err_name}") } // Helper function to get the type name component for result types -fn get_type_name_for_result(module: &ModuleDef, ty: &AlgebraicTypeUse) -> String { +fn get_type_name_for_result(module_prefix: &str, module: &ModuleDef, ty: &AlgebraicTypeUse) -> String { match ty { AlgebraicTypeUse::Primitive(p) => match p { PrimitiveType::Bool => "Bool".to_string(), @@ -4628,18 +4852,18 @@ fn get_type_name_for_result(module: &ModuleDef, ty: &AlgebraicTypeUse) -> String AlgebraicTypeUse::Unit => "Unit".to_string(), AlgebraicTypeUse::Array(elem) => { // Generate specific array types based on element type - let elem_name = get_array_element_type_name(module, elem); + let elem_name = get_array_element_type_name(module_prefix, module, elem); format!("Vec{elem_name}") } - AlgebraicTypeUse::Ref(r) => type_ref_name(module, *r), + AlgebraicTypeUse::Ref(r) => type_ref_name(module_prefix, module, *r), AlgebraicTypeUse::Option(inner) => { // Handle optional types like Option - let inner_name = get_type_name_for_result(module, inner); + let inner_name = get_type_name_for_result(module_prefix, module, inner); format!("Optional{inner_name}") } AlgebraicTypeUse::Result { ok_ty, err_ty } => { // Handle nested results like Result, bool> - get_result_type_name(module, ok_ty, err_ty) + get_result_type_name(module_prefix, module, ok_ty, err_ty) } AlgebraicTypeUse::Never => "Never".to_string(), } @@ -4839,6 +5063,7 @@ fn generate_result_type( } fn autogen_cpp_struct( + module_prefix: &str, module: &ModuleDef, name: &str, // Changed to &str product_type: &ProductTypeDef, @@ -4848,7 +5073,7 @@ fn autogen_cpp_struct( let mut headers = HashSet::::new(); for (_, field_ty) in product_type { - collect_includes_for_type(module, field_ty, &mut headers, module_name); + collect_includes_for_type(module_prefix, module, field_ty, &mut headers, module_name); } // Convert to `Vec<&str>` so UnrealCppAutogen::new works @@ -4868,8 +5093,8 @@ fn autogen_cpp_struct( for (orig_name, ty) in product_type.into_iter() { let field_name = orig_name.deref().to_case(Case::Pascal); - let ty_str = cpp_ty_fmt_with_module(module, ty, module_name).to_string(); - let init_str = cpp_ty_init_fmt_impl(module, ty); + let ty_str = cpp_ty_fmt_with_module(module_prefix, module, ty, module_name).to_string(); + let init_str = cpp_ty_init_fmt_impl(module_prefix, module, ty); let field_decl = format!("{ty_str} {field_name}{init_str}"); // Check if the type is blueprintable @@ -5150,6 +5375,7 @@ fn autogen_cpp_enum(name: &str, enum_type: &PlainEnumTypeDef) -> String { } fn autogen_cpp_sum( + module_prefix: &str, module: &ModuleDef, name: &str, sum_type: &SumTypeDef, @@ -5163,7 +5389,7 @@ fn autogen_cpp_sum( /* ------------------------------------------------------------------ */ let mut includes = HashSet::::new(); for (_, alg_ty) in &sum_type.variants { - collect_includes_for_type(module, alg_ty, &mut includes, module_name); + collect_includes_for_type(module_prefix, module, alg_ty, &mut includes, module_name); } includes.insert("Kismet/BlueprintFunctionLibrary.h".to_string()); @@ -5187,7 +5413,7 @@ fn autogen_cpp_sum( let comma = if ix + 1 == sum_type.variants.len() { "" } else { "," }; writeln!(output, " {}{}", variant.to_case(Case::Pascal), comma); - let variant_cpp_type = cpp_ty_fmt_with_module(module, _variant_type, module_name).to_string(); + let variant_cpp_type = cpp_ty_fmt_with_module(module_prefix, module, _variant_type, module_name).to_string(); variant_type.insert(variant_cpp_type); } writeln!(output, "}};\n"); @@ -5223,7 +5449,7 @@ fn autogen_cpp_sum( /* 4a. Static factories per variant -------------------------------- */ for (variant_name, variant_type) in &sum_type.variants { let pas = variant_name.to_case(Case::Pascal); - let variant_cpp_type = cpp_ty_fmt_with_module(module, variant_type, module_name).to_string(); + let variant_cpp_type = cpp_ty_fmt_with_module(module_prefix, module, variant_type, module_name).to_string(); let param_type = format!("const {variant_cpp_type}& "); writeln!(output, " static F{name}Type {pas}({param_type}Value)\n {{"); @@ -5240,7 +5466,7 @@ fn autogen_cpp_sum( /* 4b. Get/Is helpers ---------------------------------------------- */ for (variant_name, variant_type) in &sum_type.variants { let pas = variant_name.to_case(Case::Pascal); - let variant_cpp_type = cpp_ty_fmt_with_module(module, variant_type, module_name).to_string(); + let variant_cpp_type = cpp_ty_fmt_with_module(module_prefix, module, variant_type, module_name).to_string(); // Is* writeln!( @@ -5360,7 +5586,7 @@ fn autogen_cpp_sum( let variant_count = sum_type.variants.len(); for (idx, (variant_name, variant_type)) in sum_type.variants.iter().enumerate() { let variant_pascal = variant_name.to_case(Case::Pascal); - let variant_cpp_type = cpp_ty_fmt_with_module(module, variant_type, module_name).to_string(); + let variant_cpp_type = cpp_ty_fmt_with_module(module_prefix, module, variant_type, module_name).to_string(); if idx < variant_count - 1 { writeln!(output, " {variant_pascal}, {variant_cpp_type},"); @@ -5384,7 +5610,7 @@ fn autogen_cpp_sum( for (variant_name, variant_type) in &sum_type.variants { let pas = variant_name.to_case(Case::Pascal); - let variant_cpp_type = cpp_ty_fmt_with_module(module, variant_type, module_name).to_string(); + let variant_cpp_type = cpp_ty_fmt_with_module(module_prefix, module, variant_type, module_name).to_string(); // ctor functions if is_blueprintable(module, variant_type) { @@ -5457,40 +5683,44 @@ impl IdentifierCasing for Identifier { } fn cpp_ty_fmt_with_module<'a>( + module_prefix: &'a str, module: &'a ModuleDef, ty: &'a AlgebraicTypeUse, module_name: &'a str, ) -> impl fmt::Display + 'a { - cpp_ty_fmt_impl(module, ty, module_name) + cpp_ty_fmt_impl(module_prefix, module, ty, module_name) } fn cpp_ty_fmt_blueprint_compatible<'a>( + module_prefix: &'a str, module: &'a ModuleDef, ty: &'a AlgebraicTypeUse, module_name: &'a str, ) -> impl fmt::Display + 'a { - cpp_ty_fmt_blueprint_impl(module, ty, module_name) + cpp_ty_fmt_blueprint_impl(module_prefix, module, ty, module_name) } fn cpp_ty_fmt_blueprint_impl<'a>( + module_prefix: &'a str, module: &'a ModuleDef, ty: &'a AlgebraicTypeUse, module_name: &'a str, ) -> impl fmt::Display + 'a { fmt_fn(move |f| match ty { AlgebraicTypeUse::Array(elem) => { - let elem_type = cpp_ty_fmt_with_module(module, elem, module_name).to_string(); + let elem_type = cpp_ty_fmt_with_module(module_prefix, module, elem, module_name).to_string(); write!(f, "TArray<{elem_type}>") } // For all other types, use the regular implementation _ => { - let display_obj = cpp_ty_fmt_with_module(module, ty, module_name); + let display_obj = cpp_ty_fmt_with_module(module_prefix, module, ty, module_name); write!(f, "{display_obj}") } }) } fn cpp_ty_fmt_impl<'a>( + module_prefix: &'a str, module: &'a ModuleDef, ty: &'a AlgebraicTypeUse, module_name: &'a str, @@ -5520,7 +5750,7 @@ fn cpp_ty_fmt_impl<'a>( } AlgebraicTypeUse::Array(elem) => { - let elem_type = cpp_ty_fmt_impl(module, elem, module_name).to_string(); + let elem_type = cpp_ty_fmt_impl(module_prefix, module, elem, module_name).to_string(); write!(f, "TArray<{elem_type}>") } @@ -5535,7 +5765,7 @@ fn cpp_ty_fmt_impl<'a>( // --------- references to user-defined types --------- AlgebraicTypeUse::Ref(r) => { - let scoped = type_ref_name(module, *r); // PascalCase + let scoped = type_ref_name(module_prefix, module, *r); // PascalCase match &module.typespace_for_generate()[*r] { AlgebraicTypeDef::PlainEnum(_) => write!(f, "E{scoped}Type"), // enum → EFooType AlgebraicTypeDef::Product(_) => write!(f, "F{scoped}Type"), // struct/record → FFooType @@ -5545,7 +5775,7 @@ fn cpp_ty_fmt_impl<'a>( // Options use the generated optional types AlgebraicTypeUse::Option(inner) => { - let optional_name = get_optional_type_name(module, inner); + let optional_name = get_optional_type_name(module_prefix, module, inner); if module_name.is_empty() { write!(f, "F{optional_name}") } else { @@ -5556,8 +5786,8 @@ fn cpp_ty_fmt_impl<'a>( // Result use the generated result types AlgebraicTypeUse::Result { ok_ty, err_ty } => { - let ok_name = get_type_name_for_result(module, ok_ty); - let err_name = get_type_name_for_result(module, err_ty); + let ok_name = get_type_name_for_result(module_prefix, module, ok_ty); + let err_name = get_type_name_for_result(module_prefix, module, err_ty); let module_name_pascal = module_name.to_case(Case::Pascal); write!(f, "F{module_name_pascal}Result{ok_name}{err_name}") @@ -5572,7 +5802,7 @@ fn cpp_ty_fmt_impl<'a>( // otherwise the engine logs "property not initialized properly" errors. // This includes primitives (bool defaults to true if not initialized to false), // and enum types (must be initialized to a valid enum value). -fn cpp_ty_init_fmt_impl(module: &ModuleDef, ty: &AlgebraicTypeUse) -> String { +fn cpp_ty_init_fmt_impl(module_prefix: &str, module: &ModuleDef, ty: &AlgebraicTypeUse) -> String { match ty { AlgebraicTypeUse::Primitive(p) => match p { PrimitiveType::Bool => " = false".to_string(), @@ -5606,7 +5836,7 @@ fn cpp_ty_init_fmt_impl(module: &ModuleDef, ty: &AlgebraicTypeUse) -> String { // Use the first variant as the default value. match &module.typespace_for_generate()[*r] { AlgebraicTypeDef::PlainEnum(plain_enum) => { - let type_name = type_ref_name(module, *r); + let type_name = type_ref_name(module_prefix, module, *r); if let Some(first_variant) = plain_enum.variants.first() { let variant_name = first_variant.deref().to_case(Case::Pascal); format!(" = E{type_name}Type::{variant_name}") @@ -5629,34 +5859,43 @@ fn cpp_ty_init_fmt_impl(module: &ModuleDef, ty: &AlgebraicTypeUse) -> String { // Given an `AlgebraicTypeUse`, add every referenced type’s generated // header name (`".g.h"`) into `out` (a `HashSet` avoids dups). -fn collect_includes_for_type(module: &ModuleDef, ty: &AlgebraicTypeUse, out: &mut HashSet, module_name: &str) { +fn collect_includes_for_type( + module_prefix: &str, + module: &ModuleDef, + ty: &AlgebraicTypeUse, + out: &mut HashSet, + module_name: &str, +) { use AlgebraicTypeUse::*; match ty { Ref(r) => { - let header = format!("ModuleBindings/Types/{}Type.g.h", type_ref_name(module, *r)); + let header = format!( + "ModuleBindings/Types/{}Type.g.h", + type_ref_name(module_prefix, module, *r) + ); out.insert(header); } Option(inner) => { // Add the optional type header - let optional_name = get_optional_type_name(module, inner); + let optional_name = get_optional_type_name(module_prefix, module, inner); let module_name_pascal = module_name.to_case(Case::Pascal); let header = format!("ModuleBindings/Optionals/{module_name_pascal}{optional_name}.g.h"); out.insert(header); // Also collect includes for the inner type - collect_includes_for_type(module, inner, out, module_name); + collect_includes_for_type(module_prefix, module, inner, out, module_name); } Result { ok_ty, err_ty } => { // Add the result type header - let result_name = get_result_type_name(module, ok_ty, err_ty); + let result_name = get_result_type_name(module_prefix, module, ok_ty, err_ty); let module_name_pascal = module_name.to_case(Case::Pascal); let header = format!("ModuleBindings/Results/{module_name_pascal}{result_name}.g.h"); out.insert(header); // Also collect includes for the ok and err types - collect_includes_for_type(module, ok_ty, out, module_name); - collect_includes_for_type(module, err_ty, out, module_name); + collect_includes_for_type(module_prefix, module, ok_ty, out, module_name); + collect_includes_for_type(module_prefix, module, err_ty, out, module_name); } Array(inner) => { - collect_includes_for_type(module, inner, out, module_name); + collect_includes_for_type(module_prefix, module, inner, out, module_name); } // Builtin types that require Builtins.h (also includes LargeIntegers.h) Identity | ConnectionId | Timestamp | TimeDuration | ScheduleAt | Uuid => { @@ -5687,11 +5926,13 @@ fn collect_includes_for_type(module: &ModuleDef, ty: &AlgebraicTypeUse, out: &mu } // UnrealCPP-specific type reference name function that preserves original case -fn type_ref_name(module: &ModuleDef, typeref: spacetimedb_lib::sats::AlgebraicTypeRef) -> String { +fn type_ref_name(module_prefix: &str, module: &ModuleDef, typeref: spacetimedb_lib::sats::AlgebraicTypeRef) -> String { let (name, _def) = module.type_def_from_ref(typeref).unwrap(); // Preserve original case instead of applying Pascal case conversion - name.name_segments() + let base_name = name + .name_segments() .last() .map(|id| id.deref().to_string()) - .unwrap_or_else(|| "Unnamed".to_string()) + .unwrap_or_else(|| "Unnamed".to_string()); + format!("{module_prefix}{base_name}") } From db20a128f53f23b2a53cdbfdb9930e7bad032424 Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Fri, 27 Feb 2026 16:07:51 -0800 Subject: [PATCH 06/15] Update Unreal Blackholio --- crates/codegen/src/UnrealCPP-README.md | 13 +- crates/codegen/src/unrealcpp.rs | 149 ++++++++++++++++++ .../Source/client_unreal/Private/Entity.cpp | 41 ++--- .../client_unreal/Private/GameManager.cpp | 14 ++ .../ModuleBindings/SpacetimeDBClient.g.cpp | 134 ++++++++-------- .../ModuleBindings/Tables/CircleTable.g.cpp | 18 +++ .../ModuleBindings/Tables/ConfigTable.g.cpp | 5 + .../Tables/ConsumeEntityEventTable.g.cpp | 7 +- .../ModuleBindings/Tables/EntityTable.g.cpp | 5 + .../ModuleBindings/Tables/FoodTable.g.cpp | 5 + .../ModuleBindings/Tables/PlayerTable.g.cpp | 10 ++ .../Source/client_unreal/Public/Entity.h | 2 +- .../Source/client_unreal/Public/GameManager.h | 2 + .../ModuleBindings/SpacetimeDBClient.g.h | 77 +++++---- .../ModuleBindings/Tables/CircleTable.g.h | 77 +++++++++ .../ModuleBindings/Tables/ConfigTable.g.h | 40 +++++ .../Tables/ConsumeEntityEventTable.g.h | 17 -- .../ModuleBindings/Tables/EntityTable.g.h | 40 +++++ .../ModuleBindings/Tables/FoodTable.g.h | 40 +++++ .../ModuleBindings/Tables/PlayerTable.g.h | 80 ++++++++++ 20 files changed, 625 insertions(+), 151 deletions(-) diff --git a/crates/codegen/src/UnrealCPP-README.md b/crates/codegen/src/UnrealCPP-README.md index 47520517b5f..121ba90f945 100644 --- a/crates/codegen/src/UnrealCPP-README.md +++ b/crates/codegen/src/UnrealCPP-README.md @@ -316,7 +316,7 @@ cargo run --bin spacetimedb-cli -- generate --lang unrealcpp --uproject-dir crat ### Parameters - `--lang unrealcpp`: Specifies the UnrealCPP code generator -- `--uproject-dir`: Directory containing Unreal's .uproject or .uplugin file +- `--uproject-dir`: Directory containing your Unreal project's `.uproject` file - `--module-path`: Path to your SpacetimeDB module source code - `--unreal-module-name`: **Required** - Name used for generated classes, API prefix and putting generated module bindings in the correct Module's Source @@ -331,6 +331,15 @@ The `--unreal-module-name` parameter is **mandatory** for UnrealCPP generation b **⚠️ IMPORTANT:** Without the module name, the generated code would not compile in Unreal Engine due to missing API macros and naming conflicts. +### Project Setup Behavior + +When generating into an Unreal project, the code generator also: + +1. Ensures the named module exists in the project's `Modules` array in the `.uproject` file. +2. Creates missing `Source//.Build.cs`, `Source//.cpp`, and `Source//.h` files. + +If the `.uproject` file is missing, unreadable, malformed, or has an invalid `Modules` field, generation fails immediately. + ## Implementation Details The Blueprint compatibility checking is implemented in the `is_blueprintable()` function, which recursively checks: @@ -344,4 +353,4 @@ All error messages follow a consistent format: - **Single type:** `"uint32 types are not Blueprint-compatible"` - **Multiple types:** `"uint32, uint64 types are not Blueprint-compatible"` -This makes it clear to developers exactly which types need to be changed for Blueprint compatibility. \ No newline at end of file +This makes it clear to developers exactly which types need to be changed for Blueprint compatibility. diff --git a/crates/codegen/src/unrealcpp.rs b/crates/codegen/src/unrealcpp.rs index 403bf351300..707b2721306 100644 --- a/crates/codegen/src/unrealcpp.rs +++ b/crates/codegen/src/unrealcpp.rs @@ -791,6 +791,34 @@ impl Lang for UnrealCpp<'_> { let module_prefix = self.module_prefix; let mut files: Vec = vec![]; + let source_dir = self.uproject_dir.join("Source").join(self.module_name); + let required_files = [ + ( + format!("{}.Build.cs", self.module_name), + generate_build_cs_content(self.module_name), + ), + ( + format!("{}.cpp", self.module_name), + generate_module_cpp_content(self.module_name), + ), + ( + format!("{}.h", self.module_name), + generate_module_h_content(self.module_name), + ), + ]; + + for (filename, content) in required_files { + let file_path = source_dir.join(&filename); + if !file_path.exists() { + files.push(OutputFile { + filename: format!("Source/{}/{}", self.module_name, filename), + code: content, + }); + } + } + + ensure_module_in_uproject(self.uproject_dir, self.module_name).unwrap_or_else(|err| panic!("{err}")); + // First, collect and generate all optional types let (optional_types, result_types) = collect_wrapper_types(self.module_prefix, module, options.visibility); for optional_name in optional_types { @@ -5936,3 +5964,124 @@ fn type_ref_name(module_prefix: &str, module: &ModuleDef, typeref: spacetimedb_l .unwrap_or_else(|| "Unnamed".to_string()); format!("{module_prefix}{base_name}") } + +fn ensure_module_in_uproject(uproject_dir: &Path, module_name: &str) -> Result<(), String> { + let uproject_file = std::fs::read_dir(uproject_dir) + .map_err(|e| format!("Failed to read Unreal project directory '{}': {e}", uproject_dir.display()))? + .filter_map(|entry| entry.ok()) + .find(|entry| { + entry + .path() + .extension() + .and_then(|ext| ext.to_str()) + .map(|ext| ext == "uproject") + .unwrap_or(false) + }) + .ok_or_else(|| { + format!( + "No .uproject file found in '{}'. Unreal code generation requires a project directory containing a .uproject file.", + uproject_dir.display() + ) + })?; + + let uproject_path = uproject_file.path(); + let content = std::fs::read_to_string(&uproject_path) + .map_err(|e| format!("Failed to read .uproject file '{}': {e}", uproject_path.display()))?; + + let mut json: serde_json::Value = serde_json::from_str(&content) + .map_err(|e| format!("Invalid JSON in .uproject file '{}': {e}", uproject_path.display()))?; + + if !json.is_object() { + return Err(format!( + "Invalid .uproject file '{}': top-level JSON must be an object.", + uproject_path.display() + )); + } + + let json_obj = json + .as_object_mut() + .expect("validated object .uproject JSON should have an object map"); + + if !json_obj.contains_key("Modules") { + json_obj.insert("Modules".to_string(), serde_json::Value::Array(vec![])); + } + + let modules = json_obj + .get_mut("Modules") + .and_then(|m| m.as_array_mut()) + .ok_or_else(|| { + format!( + "Invalid .uproject file '{}': 'Modules' must be an array.", + uproject_path.display() + ) + })?; + + let module_exists = modules.iter().any(|module| { + module + .get("Name") + .and_then(|name| name.as_str()) + .map(|name| name == module_name) + .unwrap_or(false) + }); + + if !module_exists { + modules.push(serde_json::json!({ + "Name": module_name, + "Type": "Runtime", + "LoadingPhase": "Default" + })); + + let formatted_json = serde_json::to_string_pretty(&json) + .map_err(|e| format!("Failed to serialize .uproject file '{}': {e}", uproject_path.display()))?; + + std::fs::write(&uproject_path, formatted_json) + .map_err(|e| format!("Failed to write .uproject file '{}': {e}", uproject_path.display()))?; + } + + Ok(()) +} + +fn generate_build_cs_content(module_name: &str) -> String { + format!( + r#"using UnrealBuildTool; + +public class {module_name} : ModuleRules +{{ + public {module_name}(ReadOnlyTargetRules Target) : base(Target) + {{ + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + + PublicDependencyModuleNames.AddRange(new string[] {{ + "Core", + "CoreUObject", + "Engine", + "SpacetimeDbSdk" + }}); + + PrivateDependencyModuleNames.AddRange(new string[] {{ + }}); + }} +}} +"#, + module_name = module_name + ) +} + +fn generate_module_cpp_content(module_name: &str) -> String { + format!( + r#"#include "{module_name}.h" +#include "Modules/ModuleManager.h" + +IMPLEMENT_PRIMARY_GAME_MODULE(FDefaultGameModuleImpl, {module_name}, "{module_name}"); +"#, + module_name = module_name + ) +} + +fn generate_module_h_content(_module_name: &str) -> String { + r#"#pragma once + +#include "CoreMinimal.h" +"# + .to_string() +} diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Private/Entity.cpp b/demo/Blackholio/client-unreal/Source/client_unreal/Private/Entity.cpp index 9d307293b52..e74c1321e7d 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Private/Entity.cpp +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Private/Entity.cpp @@ -49,6 +49,20 @@ void AEntity::ConsumeDespawn(float DeltaTime) } } +void AEntity::StartConsumeDespawn(AEntity* InConsumingEntity) +{ + if (!InConsumingEntity) + { + return; + } + + ConsumingEntity = InConsumingEntity; + bIsDespawning = true; + DespawnElapsed = 0.f; + ConsumeStartPosition = GetActorLocation(); + ConsumeStartScale = GetActorScale3D(); +} + void AEntity::Spawn(int32 InEntityId) { EntityId = InEntityId; @@ -72,39 +86,16 @@ void AEntity::OnEntityUpdated(const FEntityType& NewVal) void AEntity::OnDelete(const FEventContext& Context) { - if (ConsumeDelete(Context)) + if (bIsDespawning) return; Destroy(); } -bool AEntity::ConsumeDelete(const FEventContext& Context) -{ - if (!Context.Event.IsReducer()) - return false; - - const FReducer Reducer = Context.Event.GetAsReducer(); - - if (!Reducer.IsConsumeEntity()) - return false; - - const FConsumeEntityArgs Args = Reducer.GetAsConsumeEntity(); - const int32 ConsumerId = Args.Request.ConsumerEntityId; - ConsumingEntity = AGameManager::Instance->GetEntity(ConsumerId); - if (!ConsumingEntity) - return false; - - bIsDespawning = true; - DespawnElapsed = 0.f; - ConsumeStartPosition = GetActorLocation(); - ConsumeStartScale = GetActorScale3D(); - return true; -} - void AEntity::SetColor(const FLinearColor& Color) const { if (UPaperSpriteComponent* SpriteComponent = FindComponentByClass()) { SpriteComponent->SetSpriteColor(Color); } -} \ No newline at end of file +} diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Private/GameManager.cpp b/demo/Blackholio/client-unreal/Source/client_unreal/Private/GameManager.cpp index 4579401dadd..4ddab00c278 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Private/GameManager.cpp +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Private/GameManager.cpp @@ -7,6 +7,7 @@ #include "Connection/Credentials.h" #include "ModuleBindings/Tables/CircleTable.g.h" #include "ModuleBindings/Tables/ConfigTable.g.h" +#include "ModuleBindings/Tables/ConsumeEntityEventTable.g.h" #include "ModuleBindings/Tables/EntityTable.g.h" #include "ModuleBindings/Tables/FoodTable.g.h" #include "ModuleBindings/Tables/PlayerTable.g.h" @@ -103,6 +104,7 @@ void AGameManager::HandleConnect(UDbConnection* InConn, FSpacetimeDBIdentity Ide LocalIdentity = Identity; Conn->Db->Circle->OnInsert.AddDynamic(this, &AGameManager::OnCircleInsert); + Conn->Db->ConsumeEntityEvent->OnInsert.AddDynamic(this, &AGameManager::OnConsumeEntityEventInsert); Conn->Db->Entity->OnUpdate.AddDynamic(this, &AGameManager::OnEntityUpdate); Conn->Db->Entity->OnDelete.AddDynamic(this, &AGameManager::OnEntityDelete); Conn->Db->Food->OnInsert.AddDynamic(this, &AGameManager::OnFoodInsert); @@ -254,6 +256,18 @@ void AGameManager::OnFoodInsert(const FEventContext& Context, const FFoodType& N SpawnFood(NewRow); } +void AGameManager::OnConsumeEntityEventInsert(const FEventContext& Context, const FConsumeEntityEventType& NewRow) +{ + AEntity* ConsumedEntity = GetEntity(NewRow.ConsumedEntityId); + AEntity* ConsumerEntity = GetEntity(NewRow.ConsumerEntityId); + if (!ConsumedEntity || !ConsumerEntity) + { + return; + } + + ConsumedEntity->StartConsumeDespawn(ConsumerEntity); +} + void AGameManager::OnPlayerInsert(const FEventContext& Context, const FPlayerType& NewRow) { SpawnOrGetPlayer(NewRow); diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/SpacetimeDBClient.g.cpp b/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/SpacetimeDBClient.g.cpp index 8071a62f7fa..2a5c2f73f72 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/SpacetimeDBClient.g.cpp +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/SpacetimeDBClient.g.cpp @@ -11,52 +11,12 @@ #include "ModuleBindings/Tables/FoodTable.g.h" #include "ModuleBindings/Tables/PlayerTable.g.h" -static FReducer DecodeReducer(const FReducerEvent& Event) -{ - const FString& ReducerName = Event.ReducerCall.ReducerName; - - if (ReducerName == TEXT("enter_game")) - { - FEnterGameArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::EnterGame(Args); - } - - if (ReducerName == TEXT("player_split")) - { - FPlayerSplitArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::PlayerSplit(Args); - } - - if (ReducerName == TEXT("respawn")) - { - FRespawnArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::Respawn(Args); - } - - if (ReducerName == TEXT("suicide")) - { - FSuicideArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::Suicide(Args); - } - - if (ReducerName == TEXT("update_player_input")) - { - FUpdatePlayerInputArgs Args = UE::SpacetimeDB::Deserialize(Event.ReducerCall.Args); - return FReducer::UpdatePlayerInput(Args); - } - - return FReducer(); -} - UDbConnection::UDbConnection(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { - SetReducerFlags = ObjectInitializer.CreateDefaultSubobject(this, TEXT("SetReducerFlags")); - Db = ObjectInitializer.CreateDefaultSubobject(this, TEXT("RemoteTables")); Db->Initialize(); Reducers = ObjectInitializer.CreateDefaultSubobject(this, TEXT("RemoteReducers")); - Reducers->SetCallReducerFlags = SetReducerFlags; Reducers->Conn = this; Procedures = ObjectInitializer.CreateDefaultSubobject(this, TEXT("RemoteProcedures")); @@ -74,7 +34,6 @@ FContextBase::FContextBase(UDbConnection* InConn) { Db = InConn->Db; Reducers = InConn->Reducers; - SetReducerFlags = InConn->SetReducerFlags; Procedures = InConn->Procedures; Conn = InConn; } @@ -121,27 +80,6 @@ void URemoteTables::Initialize() /**/ } -void USetReducerFlags::EnterGame(ECallReducerFlags Flag) -{ - FlagMap.Add("EnterGame", Flag); -} -void USetReducerFlags::PlayerSplit(ECallReducerFlags Flag) -{ - FlagMap.Add("PlayerSplit", Flag); -} -void USetReducerFlags::Respawn(ECallReducerFlags Flag) -{ - FlagMap.Add("Respawn", Flag); -} -void USetReducerFlags::Suicide(ECallReducerFlags Flag) -{ - FlagMap.Add("Suicide", Flag); -} -void USetReducerFlags::UpdatePlayerInput(ECallReducerFlags Flag) -{ - FlagMap.Add("UpdatePlayerInput", Flag); -} - void URemoteReducers::EnterGame(const FString& Name) { if (!Conn) @@ -150,7 +88,9 @@ void URemoteReducers::EnterGame(const FString& Name) return; } - Conn->CallReducerTyped(TEXT("enter_game"), FEnterGameArgs(Name), SetCallReducerFlags); + FEnterGameArgs ReducerArgs(Name); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("enter_game"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::EnterGame(ReducerArgs)); } } bool URemoteReducers::InvokeEnterGame(const FReducerEventContext& Context, const UEnterGameReducer* Args) @@ -194,7 +134,9 @@ void URemoteReducers::PlayerSplit() return; } - Conn->CallReducerTyped(TEXT("player_split"), FPlayerSplitArgs(), SetCallReducerFlags); + FPlayerSplitArgs ReducerArgs; + const uint32 RequestId = Conn->CallReducerTyped(TEXT("player_split"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::PlayerSplit(ReducerArgs)); } } bool URemoteReducers::InvokePlayerSplit(const FReducerEventContext& Context, const UPlayerSplitReducer* Args) @@ -238,7 +180,9 @@ void URemoteReducers::Respawn() return; } - Conn->CallReducerTyped(TEXT("respawn"), FRespawnArgs(), SetCallReducerFlags); + FRespawnArgs ReducerArgs; + const uint32 RequestId = Conn->CallReducerTyped(TEXT("respawn"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::Respawn(ReducerArgs)); } } bool URemoteReducers::InvokeRespawn(const FReducerEventContext& Context, const URespawnReducer* Args) @@ -282,7 +226,9 @@ void URemoteReducers::Suicide() return; } - Conn->CallReducerTyped(TEXT("suicide"), FSuicideArgs(), SetCallReducerFlags); + FSuicideArgs ReducerArgs; + const uint32 RequestId = Conn->CallReducerTyped(TEXT("suicide"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::Suicide(ReducerArgs)); } } bool URemoteReducers::InvokeSuicide(const FReducerEventContext& Context, const USuicideReducer* Args) @@ -326,7 +272,9 @@ void URemoteReducers::UpdatePlayerInput(const FDbVector2Type& Direction) return; } - Conn->CallReducerTyped(TEXT("update_player_input"), FUpdatePlayerInputArgs(Direction), SetCallReducerFlags); + FUpdatePlayerInputArgs ReducerArgs(Direction); + const uint32 RequestId = Conn->CallReducerTyped(TEXT("update_player_input"), ReducerArgs); + if (RequestId != 0) { Conn->RegisterPendingTypedReducer(RequestId, FReducer::UpdatePlayerInput(ReducerArgs)); } } bool URemoteReducers::InvokeUpdatePlayerInput(const FReducerEventContext& Context, const UUpdatePlayerInputReducer* Args) @@ -397,11 +345,45 @@ void UDbConnection::OnUnhandledProcedureErrorHandler(const FProcedureEventContex } } +void UDbConnection::RegisterPendingTypedReducer(uint32 RequestId, FReducer Reducer) +{ + Reducer.RequestId = RequestId; + PendingTypedReducers.Add(RequestId, MoveTemp(Reducer)); +} + +bool UDbConnection::TryGetPendingTypedReducer(uint32 RequestId, FReducer& OutReducer) const +{ + if (const FReducer* Found = PendingTypedReducers.Find(RequestId)) + { + OutReducer = *Found; + return true; + } + return false; +} + +bool UDbConnection::TryTakePendingTypedReducer(uint32 RequestId, FReducer& OutReducer) +{ + if (FReducer* Found = PendingTypedReducers.Find(RequestId)) + { + OutReducer = *Found; + PendingTypedReducers.Remove(RequestId); + return true; + } + return false; +} + void UDbConnection::ReducerEvent(const FReducerEvent& Event) { if (!Reducers) { return; } - FReducer DecodedReducer = DecodeReducer(Event); + FReducer DecodedReducer; + if (!TryTakePendingTypedReducer(Event.RequestId, DecodedReducer)) + { + const FString ErrorMessage = FString::Printf(TEXT("Reducer result for unknown request_id %u"), Event.RequestId); + UE_LOG(LogTemp, Error, TEXT("%s"), *ErrorMessage); + ReducerEventFailed(Event, ErrorMessage); + return; + } FClientUnrealReducerEvent ReducerEvent; ReducerEvent.CallerConnectionId = Event.CallerConnectionId; @@ -413,8 +395,8 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) FReducerEventContext Context(this, ReducerEvent); - // Use hardcoded string matching for reducer dispatching - const FString& ReducerName = Event.ReducerCall.ReducerName; + // Dispatch by typed reducer metadata + const FString& ReducerName = ReducerEvent.Reducer.ReducerName; if (ReducerName == TEXT("enter_game")) { @@ -638,7 +620,13 @@ void UDbConnection::DbUpdate(const FDatabaseUpdateType& Update, const FSpacetime case ESpacetimeDBEventTag::Reducer: { FReducerEvent ReducerEvent = Event.GetAsReducer(); - FReducer Reducer = DecodeReducer(ReducerEvent); + FReducer Reducer; + if (!TryGetPendingTypedReducer(ReducerEvent.RequestId, Reducer)) + { + UE_LOG(LogTemp, Warning, TEXT("Missing typed reducer for request_id %u while building table-update event context; using UnknownTransaction event"), ReducerEvent.RequestId); + BaseEvent = FClientUnrealEvent::UnknownTransaction(FSpacetimeDBUnit()); + break; + } BaseEvent = FClientUnrealEvent::Reducer(Reducer); break; } @@ -655,6 +643,10 @@ void UDbConnection::DbUpdate(const FDatabaseUpdateType& Update, const FSpacetime BaseEvent = FClientUnrealEvent::Disconnected(Event.GetAsDisconnected()); break; + case ESpacetimeDBEventTag::Transaction: + BaseEvent = FClientUnrealEvent::Transaction(Event.GetAsTransaction()); + break; + case ESpacetimeDBEventTag::SubscribeError: BaseEvent = FClientUnrealEvent::SubscribeError(Event.GetAsSubscribeError()); break; diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/CircleTable.g.cpp b/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/CircleTable.g.cpp index 975329c06d0..198f20ae88f 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/CircleTable.g.cpp +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/CircleTable.g.cpp @@ -13,6 +13,24 @@ void UCircleTable::PostInitialize() Data = MakeShared>(); TSharedPtr> CircleTable = Data->GetOrAdd(TableName); + CircleTable->AddUniqueConstraint("entity_id", [](const FCircleType& Row) -> const int32& { + return Row.EntityId; }); + + EntityId = NewObject(this); + EntityId->SetCache(CircleTable); + + // Register a new multi-key B-Tree index named "player_id" on the CircleTable. + CircleTable->AddMultiKeyBTreeIndex>( + TEXT("player_id"), + [](const FCircleType& Row) + { + // This tuple is stored in the B-Tree index for fast composite key lookups. + return MakeTuple(Row.PlayerId); + } + ); + + PlayerId = NewObject(this); + PlayerId->SetCache(CircleTable); /***/ } diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/ConfigTable.g.cpp b/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/ConfigTable.g.cpp index 6f7a6d774ca..d6523596f27 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/ConfigTable.g.cpp +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/ConfigTable.g.cpp @@ -13,6 +13,11 @@ void UConfigTable::PostInitialize() Data = MakeShared>(); TSharedPtr> ConfigTable = Data->GetOrAdd(TableName); + ConfigTable->AddUniqueConstraint("id", [](const FConfigType& Row) -> const int32& { + return Row.Id; }); + + Id = NewObject(this); + Id->SetCache(ConfigTable); /***/ } diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/ConsumeEntityEventTable.g.cpp b/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/ConsumeEntityEventTable.g.cpp index 2ab6e4ef260..65a5cac52e0 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/ConsumeEntityEventTable.g.cpp +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/ConsumeEntityEventTable.g.cpp @@ -19,7 +19,12 @@ void UConsumeEntityEventTable::PostInitialize() FTableAppliedDiff UConsumeEntityEventTable::Update(TArray> InsertsRef, TArray> DeletesRef) { - FTableAppliedDiff Diff = BaseUpdate(InsertsRef, DeletesRef, Data, TableName); + // Event tables are callback-only: do not persist rows in the local cache. + FTableAppliedDiff Diff; + for (const FWithBsatn& Insert : InsertsRef) + { + Diff.Inserts.Add(Insert.Bsatn, Insert.Row); + } return Diff; } diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/EntityTable.g.cpp b/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/EntityTable.g.cpp index 15f46a924ff..33aa332bbf9 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/EntityTable.g.cpp +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/EntityTable.g.cpp @@ -13,6 +13,11 @@ void UEntityTable::PostInitialize() Data = MakeShared>(); TSharedPtr> EntityTable = Data->GetOrAdd(TableName); + EntityTable->AddUniqueConstraint("entity_id", [](const FEntityType& Row) -> const int32& { + return Row.EntityId; }); + + EntityId = NewObject(this); + EntityId->SetCache(EntityTable); /***/ } diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/FoodTable.g.cpp b/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/FoodTable.g.cpp index 12191581ea2..313969e8b47 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/FoodTable.g.cpp +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/FoodTable.g.cpp @@ -13,6 +13,11 @@ void UFoodTable::PostInitialize() Data = MakeShared>(); TSharedPtr> FoodTable = Data->GetOrAdd(TableName); + FoodTable->AddUniqueConstraint("entity_id", [](const FFoodType& Row) -> const int32& { + return Row.EntityId; }); + + EntityId = NewObject(this); + EntityId->SetCache(FoodTable); /***/ } diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/PlayerTable.g.cpp b/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/PlayerTable.g.cpp index 9c2a69f9bda..f8c52f4d4e6 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/PlayerTable.g.cpp +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Private/ModuleBindings/Tables/PlayerTable.g.cpp @@ -13,6 +13,16 @@ void UPlayerTable::PostInitialize() Data = MakeShared>(); TSharedPtr> PlayerTable = Data->GetOrAdd(TableName); + PlayerTable->AddUniqueConstraint("identity", [](const FPlayerType& Row) -> const FSpacetimeDBIdentity& { + return Row.Identity; }); + PlayerTable->AddUniqueConstraint("player_id", [](const FPlayerType& Row) -> const int32& { + return Row.PlayerId; }); + + Identity = NewObject(this); + Identity->SetCache(PlayerTable); + + PlayerId = NewObject(this); + PlayerId->SetCache(PlayerTable); /***/ } diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Public/Entity.h b/demo/Blackholio/client-unreal/Source/client_unreal/Public/Entity.h index 11016809f31..3a1c051f75a 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Public/Entity.h +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Public/Entity.h @@ -32,11 +32,11 @@ class CLIENT_UNREAL_API AEntity : public AActor int32 EntityId = 0; virtual void Tick(float DeltaTime) override; void ConsumeDespawn(float DeltaTime); + void StartConsumeDespawn(AEntity* InConsumingEntity); void Spawn(int32 InEntityId); virtual void OnEntityUpdated(const FEntityType& NewVal); virtual void OnDelete(const FEventContext& Context); - bool ConsumeDelete(const FEventContext& Context); void SetColor(const FLinearColor& Color) const; diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Public/GameManager.h b/demo/Blackholio/client-unreal/Source/client_unreal/Public/GameManager.h index 939319b3ce1..7adcfdc89fb 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Public/GameManager.h +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Public/GameManager.h @@ -122,5 +122,7 @@ class CLIENT_UNREAL_API AGameManager : public AActor void OnPlayerInsert(const FEventContext& Context, const FPlayerType& NewRow); UFUNCTION() void OnPlayerDelete(const FEventContext& Context, const FPlayerType& RemovedRow); + UFUNCTION() + void OnConsumeEntityEventInsert(const FEventContext& Context, const FConsumeEntityEventType& NewRow); /* Data Bindings */ }; diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/SpacetimeDBClient.g.h b/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/SpacetimeDBClient.g.h index decf7040e1a..6f33c10da54 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/SpacetimeDBClient.g.h +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/SpacetimeDBClient.g.h @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 2.0.0 (commit 6a6b5a6616f0578aa641bc0689691f953b13feb8). +// This was generated using spacetimedb cli version 2.0.1 (commit a953d3b65c4a925b3b3824c419eb53821db95e2f). #pragma once #include "CoreMinimal.h" @@ -9,7 +9,6 @@ #include "Connection/Callback.h" #include "Connection/DbConnectionBase.h" #include "Connection/DbConnectionBuilder.h" -#include "Connection/SetReducerFlags.h" #include "Connection/Subscription.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "ModuleBindings/ReducerBase.g.h" @@ -61,7 +60,7 @@ struct CLIENT_UNREAL_API FContextBase { GENERATED_BODY() - FContextBase() : Db(nullptr), Reducers(nullptr), SetReducerFlags(nullptr), Procedures(nullptr), Conn(nullptr) {}; + FContextBase() : Db(nullptr), Reducers(nullptr), Procedures(nullptr), Conn(nullptr) {}; FContextBase(UDbConnection* InConn); UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") @@ -70,9 +69,6 @@ struct CLIENT_UNREAL_API FContextBase UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") URemoteReducers* Reducers; - UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") - USetReducerFlags* SetReducerFlags; - UPROPERTY(BlueprintReadOnly, Category = "SpacetimeDB") URemoteProcedures* Procedures; @@ -100,9 +96,6 @@ class CLIENT_UNREAL_API UContextBaseBpLib : public UBlueprintFunctionLibrary UFUNCTION(BlueprintPure, Category="SpacetimeDB") static URemoteReducers* GetReducers(const FContextBase& Ctx) { return Ctx.Reducers; } - UFUNCTION(BlueprintPure, Category="SpacetimeDB") - static USetReducerFlags* GetSetReducerFlags(const FContextBase& Ctx) { return Ctx.SetReducerFlags; } - static URemoteProcedures* GetProcedures(const FContextBase& Ctx) { return Ctx.Procedures; } UFUNCTION(BlueprintPure, Category="SpacetimeDB") @@ -437,6 +430,14 @@ struct CLIENT_UNREAL_API FClientUnrealEvent return Obj; } + static FClientUnrealEvent Transaction(const FSpacetimeDBUnit& Value) + { + FClientUnrealEvent Obj; + Obj.Tag = ESpacetimeDBEventTag::Transaction; + Obj.MessageData.Set(Value); + return Obj; + } + static FClientUnrealEvent SubscribeError(const FString& Value) { FClientUnrealEvent Obj; @@ -481,6 +482,13 @@ struct CLIENT_UNREAL_API FClientUnrealEvent return MessageData.Get(); } + FORCEINLINE bool IsTransaction() const { return Tag == ESpacetimeDBEventTag::Transaction; } + FORCEINLINE FSpacetimeDBUnit GetAsTransaction() const + { + ensureMsgf(IsTransaction(), TEXT("MessageData does not hold Transaction!")); + return MessageData.Get(); + } + FORCEINLINE bool IsSubscribeError() const { return Tag == ESpacetimeDBEventTag::SubscribeError; } FORCEINLINE FString GetAsSubscribeError() const { @@ -504,6 +512,7 @@ struct CLIENT_UNREAL_API FClientUnrealEvent case ESpacetimeDBEventTag::SubscribeApplied: return GetAsSubscribeApplied() == Other.GetAsSubscribeApplied(); case ESpacetimeDBEventTag::UnsubscribeApplied: return GetAsUnsubscribeApplied() == Other.GetAsUnsubscribeApplied(); case ESpacetimeDBEventTag::Disconnected: return GetAsDisconnected() == Other.GetAsDisconnected(); + case ESpacetimeDBEventTag::Transaction: return GetAsTransaction() == Other.GetAsTransaction(); case ESpacetimeDBEventTag::SubscribeError: return GetAsSubscribeError() == Other.GetAsSubscribeError(); case ESpacetimeDBEventTag::UnknownTransaction: return GetAsUnknownTransaction() == Other.GetAsUnknownTransaction(); default: return false; @@ -546,6 +555,12 @@ class CLIENT_UNREAL_API UClientUnrealEventBpLib : public UBlueprintFunctionLibra return FClientUnrealEvent::Disconnected(InValue); } + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ClientUnrealEvent") + static FClientUnrealEvent Transaction(const FSpacetimeDBUnit& InValue) + { + return FClientUnrealEvent::Transaction(InValue); + } + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ClientUnrealEvent") static FClientUnrealEvent SubscribeError(const FString& InValue) { @@ -570,6 +585,9 @@ class CLIENT_UNREAL_API UClientUnrealEventBpLib : public UBlueprintFunctionLibra UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ClientUnrealEvent") static bool IsDisconnected(const FClientUnrealEvent& Event) { return Event.IsDisconnected(); } + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ClientUnrealEvent") + static bool IsTransaction(const FClientUnrealEvent& Event) { return Event.IsTransaction(); } + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ClientUnrealEvent") static bool IsSubscribeError(const FClientUnrealEvent& Event) { return Event.IsSubscribeError(); } @@ -600,6 +618,12 @@ class CLIENT_UNREAL_API UClientUnrealEventBpLib : public UBlueprintFunctionLibra return Event.GetAsDisconnected(); } + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ClientUnrealEvent") + static FSpacetimeDBUnit GetAsTransaction(const FClientUnrealEvent& Event) + { + return Event.GetAsTransaction(); + } + UFUNCTION(BlueprintPure, Category = "SpacetimeDB|ClientUnrealEvent") static FString GetAsSubscribeError(const FClientUnrealEvent& Event) { @@ -682,25 +706,6 @@ DECLARE_DYNAMIC_DELEGATE_OneParam( FOnSubscriptionError, FErrorContext, Context); -UCLASS(BlueprintType) -class CLIENT_UNREAL_API USetReducerFlags : public USetReducerFlagsBase -{ - GENERATED_BODY() - -public: - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void EnterGame(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void PlayerSplit(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void Respawn(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void Suicide(ECallReducerFlags Flag); - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void UpdatePlayerInput(ECallReducerFlags Flag); - -}; - // RemoteTables class UCLASS(BlueprintType) class CLIENT_UNREAL_API URemoteTables : public UObject @@ -815,9 +820,6 @@ class CLIENT_UNREAL_API URemoteReducers : public UObject UPROPERTY() class UDbConnection* Conn; - - UPROPERTY() - USetReducerFlags* SetCallReducerFlags; }; // RemoteProcedures class @@ -952,9 +954,6 @@ class CLIENT_UNREAL_API UDbConnection : public UDbConnectionBase UPROPERTY(BlueprintReadOnly, Category="SpacetimeDB") URemoteReducers* Reducers; - UPROPERTY(BlueprintReadOnly, Category="SpacetimeDB") - USetReducerFlags* SetReducerFlags; - UPROPERTY(BlueprintReadOnly, Category="SpacetimeDB") URemoteProcedures* Procedures; @@ -1006,5 +1005,15 @@ class CLIENT_UNREAL_API UDbConnection : public UDbConnectionBase virtual void ReducerEventFailed(const FReducerEvent& Event, const FString ErrorMessage) override; // Override the procedure event failed handler virtual void ProcedureEventFailed(const FProcedureEvent& Event, const FString ErrorMessage) override; + + friend class URemoteReducers; + + // Internal reducer correlation helpers (request_id -> typed reducer) + void RegisterPendingTypedReducer(uint32 RequestId, FReducer Reducer); + bool TryGetPendingTypedReducer(uint32 RequestId, FReducer& OutReducer) const; + bool TryTakePendingTypedReducer(uint32 RequestId, FReducer& OutReducer); + +private: + TMap PendingTypedReducers; }; diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/CircleTable.g.h b/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/CircleTable.g.h index 8f8b8cbea06..e92587259a2 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/CircleTable.g.h +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/CircleTable.g.h @@ -12,12 +12,89 @@ #include "DBCache/TableCache.h" #include "CircleTable.g.generated.h" +UCLASS(Blueprintable) +class CLIENT_UNREAL_API UCircleEntityIdUniqueIndex : public UObject +{ + GENERATED_BODY() + +private: + // Declare an instance of your templated helper. + // It's private because the UObject wrapper will expose its functionality. + FUniqueIndexHelper> EntityIdIndexHelper; + +public: + UCircleEntityIdUniqueIndex() + // Initialize the helper with the specific unique index name + : EntityIdIndexHelper("entity_id") { + } + + /** + * Finds a Circle by their unique entityid. + * @param Key The entityid to search for. + * @return The found FCircleType, or a default-constructed FCircleType if not found. + */ + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|CircleIndex") + FCircleType Find(int32 Key) + { + // Simply delegate the call to the internal helper + return EntityIdIndexHelper.FindUniqueIndex(Key); + } + + // A public setter to provide the cache to the helper after construction + // This is a common pattern when the cache might be created or provided by another system. + void SetCache(TSharedPtr> InCircleCache) + { + EntityIdIndexHelper.Cache = InCircleCache; + } +}; +/***/ + +UCLASS(Blueprintable) +class UCirclePlayerIdIndex : public UObject +{ + GENERATED_BODY() + +public: + TArray Filter(const int32& PlayerId) const + { + TArray OutResults; + + LocalCache->FindByMultiKeyBTreeIndex>( + OutResults, + TEXT("player_id"), + MakeTuple(PlayerId) + ); + + return OutResults; + } + + void SetCache(TSharedPtr> InCache) + { + LocalCache = InCache; + } + +private: + UFUNCTION(BlueprintCallable) + void FilterPlayerId(TArray& OutResults, const int32& PlayerId) + { + OutResults = Filter(PlayerId); + } + + TSharedPtr> LocalCache; +}; + UCLASS(BlueprintType) class CLIENT_UNREAL_API UCircleTable : public URemoteTable { GENERATED_BODY() public: + UPROPERTY(BlueprintReadOnly) + UCircleEntityIdUniqueIndex* EntityId; + + UPROPERTY(BlueprintReadOnly) + UCirclePlayerIdIndex* PlayerId; + void PostInitialize(); /** Update function for circle table*/ diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/ConfigTable.g.h b/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/ConfigTable.g.h index 93a6903f6a4..57d5532ba38 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/ConfigTable.g.h +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/ConfigTable.g.h @@ -12,12 +12,52 @@ #include "DBCache/TableCache.h" #include "ConfigTable.g.generated.h" +UCLASS(Blueprintable) +class CLIENT_UNREAL_API UConfigIdUniqueIndex : public UObject +{ + GENERATED_BODY() + +private: + // Declare an instance of your templated helper. + // It's private because the UObject wrapper will expose its functionality. + FUniqueIndexHelper> IdIndexHelper; + +public: + UConfigIdUniqueIndex() + // Initialize the helper with the specific unique index name + : IdIndexHelper("id") { + } + + /** + * Finds a Config by their unique id. + * @param Key The id to search for. + * @return The found FConfigType, or a default-constructed FConfigType if not found. + */ + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|ConfigIndex") + FConfigType Find(int32 Key) + { + // Simply delegate the call to the internal helper + return IdIndexHelper.FindUniqueIndex(Key); + } + + // A public setter to provide the cache to the helper after construction + // This is a common pattern when the cache might be created or provided by another system. + void SetCache(TSharedPtr> InConfigCache) + { + IdIndexHelper.Cache = InConfigCache; + } +}; +/***/ + UCLASS(BlueprintType) class CLIENT_UNREAL_API UConfigTable : public URemoteTable { GENERATED_BODY() public: + UPROPERTY(BlueprintReadOnly) + UConfigIdUniqueIndex* Id; + void PostInitialize(); /** Update function for config table*/ diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/ConsumeEntityEventTable.g.h b/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/ConsumeEntityEventTable.g.h index 210bedcaca8..82b2ff1b858 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/ConsumeEntityEventTable.g.h +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/ConsumeEntityEventTable.g.h @@ -37,26 +37,9 @@ class CLIENT_UNREAL_API UConsumeEntityEventTable : public URemoteTable const FEventContext&, Context, const FConsumeEntityEventType&, NewRow); - DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams( - FOnConsumeEntityEventUpdate, - const FEventContext&, Context, - const FConsumeEntityEventType&, OldRow, - const FConsumeEntityEventType&, NewRow); - - DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams( - FOnConsumeEntityEventDelete, - const FEventContext&, Context, - const FConsumeEntityEventType&, DeletedRow); - UPROPERTY(BlueprintAssignable, Category = "SpacetimeDB Events") FOnConsumeEntityEventInsert OnInsert; - UPROPERTY(BlueprintAssignable, Category = "SpacetimeDB Events") - FOnConsumeEntityEventUpdate OnUpdate; - - UPROPERTY(BlueprintAssignable, Category = "SpacetimeDB Events") - FOnConsumeEntityEventDelete OnDelete; - private: const FString TableName = TEXT("consume_entity_event"); diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/EntityTable.g.h b/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/EntityTable.g.h index 21c60473f17..ac3dd913121 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/EntityTable.g.h +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/EntityTable.g.h @@ -12,12 +12,52 @@ #include "DBCache/TableCache.h" #include "EntityTable.g.generated.h" +UCLASS(Blueprintable) +class CLIENT_UNREAL_API UEntityEntityIdUniqueIndex : public UObject +{ + GENERATED_BODY() + +private: + // Declare an instance of your templated helper. + // It's private because the UObject wrapper will expose its functionality. + FUniqueIndexHelper> EntityIdIndexHelper; + +public: + UEntityEntityIdUniqueIndex() + // Initialize the helper with the specific unique index name + : EntityIdIndexHelper("entity_id") { + } + + /** + * Finds a Entity by their unique entityid. + * @param Key The entityid to search for. + * @return The found FEntityType, or a default-constructed FEntityType if not found. + */ + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|EntityIndex") + FEntityType Find(int32 Key) + { + // Simply delegate the call to the internal helper + return EntityIdIndexHelper.FindUniqueIndex(Key); + } + + // A public setter to provide the cache to the helper after construction + // This is a common pattern when the cache might be created or provided by another system. + void SetCache(TSharedPtr> InEntityCache) + { + EntityIdIndexHelper.Cache = InEntityCache; + } +}; +/***/ + UCLASS(BlueprintType) class CLIENT_UNREAL_API UEntityTable : public URemoteTable { GENERATED_BODY() public: + UPROPERTY(BlueprintReadOnly) + UEntityEntityIdUniqueIndex* EntityId; + void PostInitialize(); /** Update function for entity table*/ diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/FoodTable.g.h b/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/FoodTable.g.h index 87ebfb95e9b..5f3e0013a82 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/FoodTable.g.h +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/FoodTable.g.h @@ -12,12 +12,52 @@ #include "DBCache/TableCache.h" #include "FoodTable.g.generated.h" +UCLASS(Blueprintable) +class CLIENT_UNREAL_API UFoodEntityIdUniqueIndex : public UObject +{ + GENERATED_BODY() + +private: + // Declare an instance of your templated helper. + // It's private because the UObject wrapper will expose its functionality. + FUniqueIndexHelper> EntityIdIndexHelper; + +public: + UFoodEntityIdUniqueIndex() + // Initialize the helper with the specific unique index name + : EntityIdIndexHelper("entity_id") { + } + + /** + * Finds a Food by their unique entityid. + * @param Key The entityid to search for. + * @return The found FFoodType, or a default-constructed FFoodType if not found. + */ + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|FoodIndex") + FFoodType Find(int32 Key) + { + // Simply delegate the call to the internal helper + return EntityIdIndexHelper.FindUniqueIndex(Key); + } + + // A public setter to provide the cache to the helper after construction + // This is a common pattern when the cache might be created or provided by another system. + void SetCache(TSharedPtr> InFoodCache) + { + EntityIdIndexHelper.Cache = InFoodCache; + } +}; +/***/ + UCLASS(BlueprintType) class CLIENT_UNREAL_API UFoodTable : public URemoteTable { GENERATED_BODY() public: + UPROPERTY(BlueprintReadOnly) + UFoodEntityIdUniqueIndex* EntityId; + void PostInitialize(); /** Update function for food table*/ diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/PlayerTable.g.h b/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/PlayerTable.g.h index af4f729e441..fd13ef2a07a 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/PlayerTable.g.h +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/Tables/PlayerTable.g.h @@ -12,12 +12,92 @@ #include "DBCache/TableCache.h" #include "PlayerTable.g.generated.h" +UCLASS(Blueprintable) +class CLIENT_UNREAL_API UPlayerIdentityUniqueIndex : public UObject +{ + GENERATED_BODY() + +private: + // Declare an instance of your templated helper. + // It's private because the UObject wrapper will expose its functionality. + FUniqueIndexHelper> IdentityIndexHelper; + +public: + UPlayerIdentityUniqueIndex() + // Initialize the helper with the specific unique index name + : IdentityIndexHelper("identity") { + } + + /** + * Finds a Player by their unique identity. + * @param Key The identity to search for. + * @return The found FPlayerType, or a default-constructed FPlayerType if not found. + */ + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|PlayerIndex") + FPlayerType Find(FSpacetimeDBIdentity Key) + { + // Simply delegate the call to the internal helper + return IdentityIndexHelper.FindUniqueIndex(Key); + } + + // A public setter to provide the cache to the helper after construction + // This is a common pattern when the cache might be created or provided by another system. + void SetCache(TSharedPtr> InPlayerCache) + { + IdentityIndexHelper.Cache = InPlayerCache; + } +}; +/***/ + +UCLASS(Blueprintable) +class CLIENT_UNREAL_API UPlayerPlayerIdUniqueIndex : public UObject +{ + GENERATED_BODY() + +private: + // Declare an instance of your templated helper. + // It's private because the UObject wrapper will expose its functionality. + FUniqueIndexHelper> PlayerIdIndexHelper; + +public: + UPlayerPlayerIdUniqueIndex() + // Initialize the helper with the specific unique index name + : PlayerIdIndexHelper("player_id") { + } + + /** + * Finds a Player by their unique playerid. + * @param Key The playerid to search for. + * @return The found FPlayerType, or a default-constructed FPlayerType if not found. + */ + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB|PlayerIndex") + FPlayerType Find(int32 Key) + { + // Simply delegate the call to the internal helper + return PlayerIdIndexHelper.FindUniqueIndex(Key); + } + + // A public setter to provide the cache to the helper after construction + // This is a common pattern when the cache might be created or provided by another system. + void SetCache(TSharedPtr> InPlayerCache) + { + PlayerIdIndexHelper.Cache = InPlayerCache; + } +}; +/***/ + UCLASS(BlueprintType) class CLIENT_UNREAL_API UPlayerTable : public URemoteTable { GENERATED_BODY() public: + UPROPERTY(BlueprintReadOnly) + UPlayerIdentityUniqueIndex* Identity; + + UPROPERTY(BlueprintReadOnly) + UPlayerPlayerIdUniqueIndex* PlayerId; + void PostInitialize(); /** Update function for player table*/ From e13523435aeaaa6623571d9bd17292de400d9bae Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Fri, 27 Feb 2026 16:58:59 -0800 Subject: [PATCH 07/15] Lint + CLI fixes --- crates/codegen/src/unrealcpp.rs | 8 ++++---- .../00100-cli-reference/00100-cli-reference.md | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/codegen/src/unrealcpp.rs b/crates/codegen/src/unrealcpp.rs index 707b2721306..d4d4e6abb3f 100644 --- a/crates/codegen/src/unrealcpp.rs +++ b/crates/codegen/src/unrealcpp.rs @@ -383,7 +383,7 @@ impl Lang for UnrealCpp<'_> { filename: format!( "Source/{}/Public/ModuleBindings/Tables/{}Table.g.h", self.module_name, - format!("{module_prefix}{}", table.name.deref().to_case(Case::Pascal)) + format_args!("{module_prefix}{}", table.name.deref().to_case(Case::Pascal)) ), code: output.into_inner(), } @@ -1037,7 +1037,7 @@ impl Lang for UnrealCpp<'_> { .map(|(_, accessor_name, _)| { format!( "ModuleBindings/Tables/{}Table.g.h", - format!("{module_prefix}{}", accessor_name.deref().to_case(Case::Pascal)) + format_args!("{module_prefix}{}", accessor_name.deref().to_case(Case::Pascal)) ) }) .collect(); @@ -1077,7 +1077,7 @@ impl Lang for UnrealCpp<'_> { let table_cpp_filename = format!( "Source/{}/Private/ModuleBindings/Tables/{}Table.g.cpp", self.module_name, - format!("{module_prefix}{}", table.name.deref().to_case(Case::Pascal)) + format_args!("{module_prefix}{}", table.name.deref().to_case(Case::Pascal)) ); files.push(OutputFile { filename: table_cpp_filename, @@ -1093,7 +1093,7 @@ impl Lang for UnrealCpp<'_> { let view_cpp_filename = format!( "Source/{}/Private/ModuleBindings/Tables/{}Table.g.cpp", self.module_name, - format!("{module_prefix}{}", view.name.deref().to_case(Case::Pascal)) + format_args!("{module_prefix}{}", view.name.deref().to_case(Case::Pascal)) ); files.push(OutputFile { filename: view_cpp_filename, diff --git a/docs/docs/00300-resources/00200-reference/00100-cli-reference/00100-cli-reference.md b/docs/docs/00300-resources/00200-reference/00100-cli-reference/00100-cli-reference.md index cde29f9e372..2f5f2295d17 100644 --- a/docs/docs/00300-resources/00200-reference/00100-cli-reference/00100-cli-reference.md +++ b/docs/docs/00300-resources/00200-reference/00100-cli-reference/00100-cli-reference.md @@ -316,6 +316,7 @@ Run `spacetime help generate` for more detailed information. Default value: `SpacetimeDB.Types` * `--unreal-module-name ` — The module name that should be used for DLL export macros (required for lang unrealcpp) +* `--module-prefix ` — The module prefix to use for generated types (only used with --lang unrealcpp) * `-l`, `--lang ` — The language to generate Possible values: `csharp`, `typescript`, `rust`, `unrealcpp` From 7b67fd0148ab49f1f33d26203450cada1e6bf9c8 Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Wed, 4 Mar 2026 09:49:20 -0800 Subject: [PATCH 08/15] Repairs after testing Blakcholio tutorial and multi-module heavy testing --- crates/codegen/src/unrealcpp.rs | 304 ++++++++++-------- .../ModuleBindings/SpacetimeDBClient.g.h | 6 +- .../00400-unreal-tutorial/00200-part-1.md | 2 +- .../00400-unreal-tutorial/00300-part-2.md | 19 +- .../00400-unreal-tutorial/00400-part-3.md | 2 +- .../00400-unreal-tutorial/00500-part-4.md | 2 +- .../00400-unreal-tutorial/index.md | 2 +- .../src/components/CppModuleVersionNotice.tsx | 9 +- .../part-2-03-blueprint-add-variables.png | Bin 16950 -> 17506 bytes .../part-2-05-blueprint-buildconnection-1.png | Bin 113486 -> 136159 bytes .../ModuleBindings/SpacetimeDBClient.g.h | 6 +- .../ModuleBindings/SpacetimeDBClient.g.h | 6 +- 12 files changed, 204 insertions(+), 154 deletions(-) diff --git a/crates/codegen/src/unrealcpp.rs b/crates/codegen/src/unrealcpp.rs index d4d4e6abb3f..a9e83433b65 100644 --- a/crates/codegen/src/unrealcpp.rs +++ b/crates/codegen/src/unrealcpp.rs @@ -1,7 +1,7 @@ //! Autogenerated Unreal‑C++ code‑gen backend for SpacetimeDB CLI use crate::code_indenter::CodeIndenter; use crate::util::{ - collect_case, fmt_fn, iter_table_names_and_types, iter_tables, print_auto_generated_file_comment, + fmt_fn, iter_table_names_and_types, iter_tables, print_auto_generated_file_comment, print_auto_generated_version_comment, CodegenVisibility, }; use crate::util::{iter_indexes, iter_procedures, iter_reducers}; @@ -329,21 +329,21 @@ impl Lang for UnrealCpp<'_> { // Generate table events in public section writeln!(output, " // Table Events"); writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams( "); - writeln!(output, " FOn{table_pascal}Insert,"); + writeln!(output, " F{module_prefix}On{table_pascal}Insert,"); writeln!(output, " const F{module_prefix}EventContext&, Context,"); writeln!(output, " const {row_struct}&, NewRow);"); writeln!(output); if !table.is_event { writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams( "); - writeln!(output, " FOn{table_pascal}Update,"); + writeln!(output, " F{module_prefix}On{table_pascal}Update,"); writeln!(output, " const F{module_prefix}EventContext&, Context,"); writeln!(output, " const {row_struct}&, OldRow,"); writeln!(output, " const {row_struct}&, NewRow);"); writeln!(output); writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams( "); - writeln!(output, " FOn{table_pascal}Delete,"); + writeln!(output, " F{module_prefix}On{table_pascal}Delete,"); writeln!(output, " const F{module_prefix}EventContext&, Context,"); writeln!(output, " const {row_struct}&, DeletedRow);"); writeln!(output); @@ -353,7 +353,7 @@ impl Lang for UnrealCpp<'_> { output, " UPROPERTY(BlueprintAssignable, Category = \"SpacetimeDB Events\")" ); - writeln!(output, " FOn{table_pascal}Insert OnInsert;"); + writeln!(output, " F{module_prefix}On{table_pascal}Insert OnInsert;"); writeln!(output); if !table.is_event { @@ -361,14 +361,14 @@ impl Lang for UnrealCpp<'_> { output, " UPROPERTY(BlueprintAssignable, Category = \"SpacetimeDB Events\")" ); - writeln!(output, " FOn{table_pascal}Update OnUpdate;"); + writeln!(output, " F{module_prefix}On{table_pascal}Update OnUpdate;"); writeln!(output); writeln!( output, " UPROPERTY(BlueprintAssignable, Category = \"SpacetimeDB Events\")" ); - writeln!(output, " FOn{table_pascal}Delete OnDelete;"); + writeln!(output, " F{module_prefix}On{table_pascal}Delete OnDelete;"); writeln!(output); } @@ -390,23 +390,17 @@ impl Lang for UnrealCpp<'_> { } fn generate_type_files(&self, module: &ModuleDef, typ: &TypeDef) -> Vec { - let name = typ - .accessor_name - .name_segments() - .last() - .map(|id| id.deref()) - .unwrap_or("Unnamed"); + let name = type_ref_name(self.module_prefix, module, typ.ty); let filename = format!( "Source/{}/Public/ModuleBindings/Types/{}Type.g.h", - self.module_name, - collect_case(Case::Pascal, typ.accessor_name.name_segments()) + self.module_name, &name ); let code: String = match &module.typespace_for_generate()[typ.ty] { - AlgebraicTypeDef::PlainEnum(plain_enum) => autogen_cpp_enum(name, plain_enum), + AlgebraicTypeDef::PlainEnum(plain_enum) => autogen_cpp_enum(&name, plain_enum), AlgebraicTypeDef::Product(product_type_def) => autogen_cpp_struct( self.module_prefix, module, - name, + &name, product_type_def, &self.get_api_macro(), self.module_name, @@ -414,7 +408,7 @@ impl Lang for UnrealCpp<'_> { AlgebraicTypeDef::Sum(sum_type_def) => autogen_cpp_sum( self.module_prefix, module, - name, + &name, sum_type_def, &self.get_api_macro(), self.module_name, @@ -426,8 +420,8 @@ impl Lang for UnrealCpp<'_> { fn generate_reducer_file(&self, module: &ModuleDef, reducer: &ReducerDef) -> OutputFile { let module_prefix = self.module_prefix; - let reducer_snake = reducer.name.deref(); - let pascal = reducer_snake.to_case(Case::Pascal); + let reducer_pascal = reducer.name.deref().to_case(Case::Pascal); + let pascal = format!("{module_prefix}{reducer_pascal}"); // Collect includes for parameter types let mut includes = HashSet::::new(); @@ -628,7 +622,8 @@ impl Lang for UnrealCpp<'_> { procedure: &spacetimedb_schema::def::ProcedureDef, ) -> OutputFile { let procedure_snake = procedure.name.deref(); - let pascal = procedure_snake.to_case(Case::Pascal); + let procedure_pascal = procedure_snake.to_case(Case::Pascal); + let pascal = format!("{}{}", self.module_prefix, procedure_pascal); // Collect includes for parameter types let mut includes = HashSet::::new(); @@ -827,7 +822,13 @@ impl Lang for UnrealCpp<'_> { let filename = format!("Source/{module_name}/Public/ModuleBindings/Optionals/{module_name_pascal}{optional_name}.g.h"); - let content = generate_optional_type(&optional_name, module, &self.get_api_macro(), self.module_name); + let content = generate_optional_type( + &optional_name, + self.module_prefix, + module, + &self.get_api_macro(), + self.module_name, + ); files.push(OutputFile { filename, code: content, @@ -841,7 +842,14 @@ impl Lang for UnrealCpp<'_> { "Source/{module_name}/Public/ModuleBindings/Results/{module_name_pascal}Result{ok_name}{error_name}.g.h" ); - let content = generate_result_type(&ok_name, &error_name, module, &self.get_api_macro(), self.module_name); + let content = generate_result_type( + self.module_prefix, + &ok_name, + &error_name, + module, + &self.get_api_macro(), + self.module_name, + ); files.push(OutputFile { filename, code: content, @@ -991,7 +999,13 @@ impl Lang for UnrealCpp<'_> { generate_db_connection_builder_class(&mut client_h, self.module_prefix, &self.get_api_macro()); // Main DbConnection class - generate_db_connection_class(&mut client_h, self.module_prefix, module, &self.get_api_macro()); + generate_db_connection_class( + &mut client_h, + self.module_prefix, + self.module_name, + module, + &self.get_api_macro(), + ); // Generate the separate ReducerBase file let reducer_base_header_name = format!("{module_prefix}ReducerBase"); @@ -1330,13 +1344,13 @@ fn generate_delegates(output: &mut UnrealCppAutogen, module_prefix: &str) { ); writeln!(output, "DECLARE_DYNAMIC_DELEGATE_ThreeParams("); writeln!(output, "\tF{module_prefix}OnConnectDelegate,"); - writeln!(output, "\tUDbConnection*, Connection,"); + writeln!(output, "\tU{module_prefix}DbConnection*, Connection,"); writeln!(output, "\tFSpacetimeDBIdentity, Identity,"); writeln!(output, "\tconst FString&, Token);"); writeln!(output); writeln!(output, "DECLARE_DYNAMIC_DELEGATE_TwoParams("); writeln!(output, "\tF{module_prefix}OnDisconnectDelegate,"); - writeln!(output, "\tUDbConnection*, Connection,"); + writeln!(output, "\tU{module_prefix}DbConnection*, Connection,"); writeln!(output, "\tconst FString&, Error);"); writeln!(output); writeln!(output); @@ -1367,13 +1381,13 @@ fn generate_context_structs( ); writeln!(output); writeln!(output, "\tUPROPERTY(BlueprintReadOnly, Category = \"SpacetimeDB\")"); - writeln!(output, "\tURemoteTables* Db;"); + writeln!(output, "\tU{module_prefix}RemoteTables* Db;"); writeln!(output); writeln!(output, "\tUPROPERTY(BlueprintReadOnly, Category = \"SpacetimeDB\")"); - writeln!(output, "\tURemoteReducers* Reducers;"); + writeln!(output, "\tU{module_prefix}RemoteReducers* Reducers;"); writeln!(output); writeln!(output, "\tUPROPERTY(BlueprintReadOnly, Category = \"SpacetimeDB\")"); - writeln!(output, "\tURemoteProcedures* Procedures;"); + writeln!(output, "\tU{module_prefix}RemoteProcedures* Procedures;"); writeln!(output); writeln!(output, "\tbool IsActive() const;"); writeln!(output, "\tvoid Disconnect();"); @@ -1382,11 +1396,11 @@ fn generate_context_structs( "\tbool TryGetIdentity(FSpacetimeDBIdentity& OutIdentity) const;" ); writeln!(output, "\tFSpacetimeDBConnectionId GetConnectionId() const;"); - writeln!(output, "\tUSubscriptionBuilder* SubscriptionBuilder();"); + writeln!(output, "\tU{module_prefix}SubscriptionBuilder* SubscriptionBuilder();"); writeln!(output); writeln!(output, "protected:"); writeln!(output, "\tUPROPERTY()"); - writeln!(output, "\tUDbConnection* Conn;"); + writeln!(output, "\tU{module_prefix}DbConnection* Conn;"); writeln!(output); writeln!(output, "}};"); writeln!(output); @@ -1430,7 +1444,6 @@ fn generate_context_structs( generate_reducer_bindings(output, module_prefix, module, visibility, api_macro, module_name); generate_procedure_bindings(output, module_prefix, module, visibility, api_macro, module_name); - // {}Event: union-like struct representing SpacetimeDB event messages writeln!(output, "/** Represents event with variant message data. */"); writeln!(output, "USTRUCT(BlueprintType)"); @@ -2004,11 +2017,11 @@ fn generate_context_structs( writeln!(output); writeln!(output, "DECLARE_DYNAMIC_DELEGATE_OneParam("); writeln!(output, "\tF{module_prefix}OnSubscriptionApplied,"); - writeln!(output, "\tFSubscriptionEventContext, Context);"); + writeln!(output, "\tF{module_prefix}SubscriptionEventContext, Context);"); writeln!(output); writeln!(output, "DECLARE_DYNAMIC_DELEGATE_OneParam("); writeln!(output, "\tF{module_prefix}OnSubscriptionError,"); - writeln!(output, "\tFErrorContext, Context);"); + writeln!(output, "\tF{module_prefix}ErrorContext, Context);"); writeln!(output); } @@ -2030,13 +2043,13 @@ fn generate_reducer_bindings( { let mut first = true; for reducer in iter_reducers(module, visibility) { - let reducer_pascal = format!("{module_prefix}{}", reducer.name.deref().to_case(Case::Pascal)); + let reducer_name = reducer.name.deref().to_case(Case::Pascal); if !first { writeln!(output, ","); } else { first = false; } - write!(output, " {reducer_pascal}"); + write!(output, " {reducer_name}"); } writeln!(output); } @@ -2087,17 +2100,15 @@ fn generate_reducer_bindings( // Static constructors, Is*, GetAs* for reducer in iter_reducers(module, visibility) { - let reducer_pascal = format!("{module_prefix}{}", reducer.name.deref().to_case(Case::Pascal)); + let reducer_name = reducer.name.deref().to_case(Case::Pascal); + let reducer_pascal = format!("{module_prefix}{reducer_name}"); writeln!( output, - " static F{module_prefix}Reducer {reducer_pascal}(const F{reducer_pascal}Args& Value)" + " static F{module_prefix}Reducer {reducer_name}(const F{reducer_pascal}Args& Value)" ); writeln!(output, " {{"); writeln!(output, " F{module_prefix}Reducer Out;"); - writeln!( - output, - " Out.Tag = E{module_prefix}ReducerTag::{reducer_pascal};" - ); + writeln!(output, " Out.Tag = E{module_prefix}ReducerTag::{reducer_name};"); writeln!(output, " Out.Data.Set(Value);"); writeln!(output, " Out.ReducerName = TEXT(\"{}\");", reducer.name.deref()); writeln!(output, " return Out;"); @@ -2105,16 +2116,16 @@ fn generate_reducer_bindings( writeln!(output); writeln!( output, - " FORCEINLINE bool Is{reducer_pascal}() const {{ return Tag == E{module_prefix}ReducerTag::{reducer_pascal}; }}" + " FORCEINLINE bool Is{reducer_name}() const {{ return Tag == E{module_prefix}ReducerTag::{reducer_name}; }}" ); writeln!( output, - " FORCEINLINE F{reducer_pascal}Args GetAs{reducer_pascal}() const" + " FORCEINLINE F{reducer_pascal}Args GetAs{reducer_name}() const" ); writeln!(output, " {{"); writeln!( output, - " ensureMsgf(Is{reducer_pascal}(), TEXT(\"Reducer does not hold {reducer_pascal}!\"));" + " ensureMsgf(Is{reducer_name}(), TEXT(\"Reducer does not hold {reducer_name}!\"));" ); writeln!(output, " return Data.Get();"); writeln!(output, " }}"); @@ -2129,11 +2140,11 @@ fn generate_reducer_bindings( writeln!(output, " switch (Tag)"); writeln!(output, " {{"); for reducer in iter_reducers(module, visibility) { - let reducer_pascal = format!("{module_prefix}{}", reducer.name.deref().to_case(Case::Pascal)); - writeln!(output, " case E{module_prefix}ReducerTag::{reducer_pascal}:"); + let reducer_name = reducer.name.deref().to_case(Case::Pascal); + writeln!(output, " case E{module_prefix}ReducerTag::{reducer_name}:"); writeln!( output, - " return GetAs{reducer_pascal}() == Other.GetAs{reducer_pascal}();" + " return GetAs{reducer_name}() == Other.GetAs{reducer_name}();" ); } if reducer_count == 0 { @@ -2163,7 +2174,8 @@ fn generate_reducer_bindings( writeln!(output, "private:"); for reducer in iter_reducers(module, visibility) { - let reducer_pascal = format!("{module_prefix}{}", reducer.name.deref().to_case(Case::Pascal)); + let reducer_name = reducer.name.deref().to_case(Case::Pascal); + let reducer_pascal = format!("{module_prefix}{reducer_name}"); // ---- Static constructors ---- writeln!(output); writeln!( @@ -2172,12 +2184,9 @@ fn generate_reducer_bindings( ); writeln!( output, - " static F{module_prefix}Reducer {reducer_pascal}(const F{reducer_pascal}Args& Value) {{" - ); - writeln!( - output, - " return F{module_prefix}Reducer::{reducer_pascal}(Value);" + " static F{module_prefix}Reducer {reducer_name}(const F{reducer_pascal}Args& Value) {{" ); + writeln!(output, " return F{module_prefix}Reducer::{reducer_name}(Value);"); writeln!(output, " }}"); writeln!(output); @@ -2188,7 +2197,7 @@ fn generate_reducer_bindings( ); writeln!( output, - " static bool Is{reducer_pascal}(const F{module_prefix}Reducer& Reducer) {{ return Reducer.Is{reducer_pascal}(); }}" + " static bool Is{reducer_name}(const F{module_prefix}Reducer& Reducer) {{ return Reducer.Is{reducer_name}(); }}" ); writeln!(output); @@ -2199,9 +2208,9 @@ fn generate_reducer_bindings( ); writeln!( output, - " static F{reducer_pascal}Args GetAs{reducer_pascal}(const F{module_prefix}Reducer& Reducer) {{" + " static F{reducer_pascal}Args GetAs{reducer_name}(const F{module_prefix}Reducer& Reducer) {{" ); - writeln!(output, " return Reducer.GetAs{reducer_pascal}();"); + writeln!(output, " return Reducer.GetAs{reducer_name}();"); writeln!(output, " }}"); } @@ -2261,7 +2270,7 @@ fn generate_reducer_bindings( output, "\tUPROPERTY(EditAnywhere, BlueprintReadWrite, Category=\"SpacetimeDB\")" ); - writeln!(output, "\tFReducer Reducer;"); + writeln!(output, "\tF{module_prefix}Reducer Reducer;"); writeln!(output); writeln!( @@ -2308,13 +2317,13 @@ fn generate_procedure_bindings( { let mut first = true; for procedure in iter_procedures(module, visibility) { - let procedure_pascal = format!("{module_prefix}{}", procedure.name.deref().to_case(Case::Pascal)); + let procedure_name = procedure.name.deref().to_case(Case::Pascal); if !first { writeln!(output, ","); } else { first = false; } - write!(output, " {procedure_pascal}"); + write!(output, " {procedure_name}"); } writeln!(output); } @@ -2358,16 +2367,17 @@ fn generate_procedure_bindings( // Static constructors, Is*, GetAs* for procedure in iter_procedures(module, visibility) { - let procedure_pascal = format!("{module_prefix}{}", procedure.name.deref().to_case(Case::Pascal)); + let procedure_name = procedure.name.deref().to_case(Case::Pascal); + let procedure_pascal = format!("{module_prefix}{procedure_name}"); writeln!( output, - " static F{module_prefix}Procedure {procedure_pascal}(const F{procedure_pascal}Args& Value)" + " static F{module_prefix}Procedure {procedure_name}(const F{procedure_pascal}Args& Value)" ); writeln!(output, " {{"); writeln!(output, " F{module_prefix}Procedure Out;"); writeln!( output, - " Out.Tag = E{module_prefix}ProcedureTag::{procedure_pascal};" + " Out.Tag = E{module_prefix}ProcedureTag::{procedure_name};" ); writeln!(output, " Out.Data.Set(Value);"); writeln!( @@ -2379,17 +2389,17 @@ fn generate_procedure_bindings( writeln!(output, " }}"); writeln!(output); writeln!( - output, - " FORCEINLINE bool Is{procedure_pascal}() const {{ return Tag == E{module_prefix}ProcedureTag::{procedure_pascal}; }}" - ); + output, + " FORCEINLINE bool Is{procedure_name}() const {{ return Tag == E{module_prefix}ProcedureTag::{procedure_name}; }}" + ); writeln!( output, - " FORCEINLINE F{procedure_pascal}Args GetAs{procedure_pascal}() const" + " FORCEINLINE F{procedure_pascal}Args GetAs{procedure_name}() const" ); writeln!(output, " {{"); writeln!( output, - " ensureMsgf(Is{procedure_pascal}(), TEXT(\"Procedure does not hold {procedure_pascal}!\"));" + " ensureMsgf(Is{procedure_name}(), TEXT(\"Procedure does not hold {procedure_name}!\"));" ); writeln!(output, " return Data.Get();"); writeln!(output, " }}"); @@ -2404,11 +2414,11 @@ fn generate_procedure_bindings( writeln!(output, " switch (Tag)"); writeln!(output, " {{"); for procedure in iter_procedures(module, visibility) { - let procedure_pascal = format!("{module_prefix}{}", procedure.name.deref().to_case(Case::Pascal)); - writeln!(output, " case E{module_prefix}ProcedureTag::{procedure_pascal}:"); + let procedure_name = procedure.name.deref().to_case(Case::Pascal); + writeln!(output, " case E{module_prefix}ProcedureTag::{procedure_name}:"); writeln!( output, - " return GetAs{procedure_pascal}() == Other.GetAs{procedure_pascal}();" + " return GetAs{procedure_name}() == Other.GetAs{procedure_name}();" ); } writeln!(output, " default: return false;"); @@ -2433,7 +2443,8 @@ fn generate_procedure_bindings( writeln!(output, "private:"); for procedure in iter_procedures(module, visibility) { - let procedure_pascal = format!("{module_prefix}{}", procedure.name.deref().to_case(Case::Pascal)); + let procedure_name = procedure.name.deref().to_case(Case::Pascal); + let procedure_pascal = format!("{module_prefix}{procedure_name}"); // ---- Static constructors ---- writeln!(output); writeln!( @@ -2442,11 +2453,11 @@ fn generate_procedure_bindings( ); writeln!( output, - " static F{module_prefix}Procedure {procedure_pascal}(const F{procedure_pascal}Args& Value) {{" + " static F{module_prefix}Procedure {procedure_name}(const F{procedure_pascal}Args& Value) {{" ); writeln!( output, - " return F{module_prefix}Procedure::{procedure_pascal}(Value);" + " return F{module_prefix}Procedure::{procedure_name}(Value);" ); writeln!(output, " }}"); writeln!(output); @@ -2458,7 +2469,7 @@ fn generate_procedure_bindings( ); writeln!( output, - " static bool Is{procedure_pascal}(const F{module_prefix}Procedure& Procedure) {{ return Procedure.Is{procedure_pascal}(); }}" + " static bool Is{procedure_name}(const F{module_prefix}Procedure& Procedure) {{ return Procedure.Is{procedure_name}(); }}" ); writeln!(output); @@ -2469,9 +2480,9 @@ fn generate_procedure_bindings( ); writeln!( output, - " static F{procedure_pascal}Args GetAs{procedure_pascal}(const F{module_prefix}Procedure& Procedure) {{" + " static F{procedure_pascal}Args GetAs{procedure_name}(const F{module_prefix}Procedure& Procedure) {{" ); - writeln!(output, " return Procedure.GetAs{procedure_pascal}();"); + writeln!(output, " return Procedure.GetAs{procedure_name}();"); writeln!(output, " }}"); } @@ -2611,7 +2622,8 @@ fn generate_remote_reducers_class( // Generate reducer events and call methods for reducer in iter_reducers(module, visibility) { - let reducer_pascal = format!("{module_prefix}{}", reducer.name.deref().to_case(Case::Pascal)); + let reducer_name = reducer.name.deref().to_case(Case::Pascal); + let reducer_pascal = format!("{module_prefix}{reducer_name}"); // Generate delegate for reducer event let param_count = reducer.params_for_generate.elements.len() + 1; // +1 for context @@ -2701,21 +2713,21 @@ fn generate_remote_reducers_class( " // NOTE: Not exposed to Blueprint because {types_str} types are not Blueprint-compatible" ); } - writeln!(output, " F{reducer_pascal}Handler On{reducer_pascal};"); + writeln!(output, " F{reducer_pascal}Handler On{reducer_name};"); writeln!(output); // Generate call method if non_blueprintable_types_for_function.is_empty() { write!( output, - " UFUNCTION(BlueprintCallable, Category=\"SpacetimeDB\")\n void {reducer_pascal}(" + " UFUNCTION(BlueprintCallable, Category=\"SpacetimeDB\")\n void {reducer_name}(" ); } else { // Generate specific message about which types are not Blueprint-compatible let types_str = non_blueprintable_types_for_function.join(", "); write!( output, - " // NOTE: Not exposed to Blueprint because {types_str} types are not Blueprint-compatible\n void {reducer_pascal}(" + " // NOTE: Not exposed to Blueprint because {types_str} types are not Blueprint-compatible\n void {reducer_name}(" ); } @@ -2757,14 +2769,14 @@ fn generate_remote_reducers_class( // Generate invoke method (UObject version - kept for backwards compatibility) write!( output, - " bool Invoke{reducer_pascal}(const F{module_prefix}ReducerEventContext& Context, const U{reducer_pascal}Reducer* Args);" + " bool Invoke{reducer_name}(const F{module_prefix}ReducerEventContext& Context, const U{reducer_pascal}Reducer* Args);" ); writeln!(output); // Generate invoke method (FArgs version - zero allocation, used internally) write!( output, - " bool Invoke{reducer_pascal}WithArgs(const F{module_prefix}ReducerEventContext& Context, const F{reducer_pascal}Args& Args);" + " bool Invoke{reducer_name}WithArgs(const F{module_prefix}ReducerEventContext& Context, const F{reducer_pascal}Args& Args);" ); writeln!(output); writeln!(output); @@ -2772,10 +2784,10 @@ fn generate_remote_reducers_class( // Internal error handling writeln!(output, " // Internal error handling"); - writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FInternalOnUnhandledReducerError, const F{module_prefix}ReducerEventContext&, Context, const FString&, Error);"); + writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(F{module_prefix}InternalOnUnhandledReducerError, const F{module_prefix}ReducerEventContext&, Context, const FString&, Error);"); writeln!( output, - " FInternalOnUnhandledReducerError InternalOnUnhandledReducerError;" + " F{module_prefix}InternalOnUnhandledReducerError InternalOnUnhandledReducerError;" ); writeln!(output); @@ -2798,7 +2810,7 @@ fn generate_remote_procedures_class( module_name: &str, ) { for procedure in iter_procedures(module, visibility) { - let procedure_pascal = format!("{module_prefix}{}", procedure.name.deref().to_case(Case::Pascal)); + let procedure_name = procedure.name.deref().to_case(Case::Pascal); let blueprintable_type_for_return = is_type_blueprintable_for_delegates(module, &procedure.return_type_for_generate); @@ -2814,9 +2826,12 @@ fn generate_remote_procedures_class( if !blueprintable_type_for_return { writeln!( output, - "// NOTE: Procedure {procedure_pascal} has non-Blueprint-compatible return type: {return_type_str}" + "// NOTE: Procedure {procedure_name} has non-Blueprint-compatible return type: {return_type_str}" + ); + writeln!( + output, + "DECLARE_DELEGATE_ThreeParams(F{module_prefix}On{procedure_name}Complete," ); - writeln!(output, "DECLARE_DELEGATE_ThreeParams(FOn{procedure_pascal}Complete,"); writeln!(output, " const F{module_prefix}ProcedureEventContext&, /*Context*/"); writeln!(output, " {return_type_ref}, /*Result,*/"); writeln!(output, " bool /*bSuccess*/);"); @@ -2824,7 +2839,7 @@ fn generate_remote_procedures_class( } else { writeln!( output, - "DECLARE_DYNAMIC_DELEGATE_ThreeParams(FOn{procedure_pascal}Complete," + "DECLARE_DYNAMIC_DELEGATE_ThreeParams(F{module_prefix}On{procedure_name}Complete," ); writeln!(output, " const F{module_prefix}ProcedureEventContext&, Context,"); writeln!(output, " {}, Result,", return_type_ref); @@ -2847,7 +2862,7 @@ fn generate_remote_procedures_class( // Generate procedure events and call methods for procedure in iter_procedures(module, visibility) { - let procedure_pascal = format!("{module_prefix}{}", procedure.name.deref().to_case(Case::Pascal)); + let procedure_name = procedure.name.deref().to_case(Case::Pascal); let mut non_blueprintable_types_for_function = Vec::new(); @@ -2864,14 +2879,14 @@ fn generate_remote_procedures_class( if non_blueprintable_types_for_function.is_empty() && blueprintable_type_for_return { write!( output, - " UFUNCTION(BlueprintCallable, Category=\"SpacetimeDB\")\n void {procedure_pascal}(" + " UFUNCTION(BlueprintCallable, Category=\"SpacetimeDB\")\n void {procedure_name}(" ); } else { // Generate specific message about which types are not Blueprint-compatible let types_str = non_blueprintable_types_for_function.join(", "); write!( output, - " // NOTE: Not exposed to Blueprint because return type or {types_str} types are not Blueprint-compatible\n void {procedure_pascal}(" + " // NOTE: Not exposed to Blueprint because return type or {types_str} types are not Blueprint-compatible\n void {procedure_name}(" ); } @@ -2910,7 +2925,7 @@ fn generate_remote_procedures_class( if !first { write!(output, ", "); } - writeln!(output, "FOn{}Complete Callback);", procedure_pascal); + writeln!(output, "F{module_prefix}On{}Complete Callback);", procedure_name); writeln!(output); writeln!(output); @@ -3115,6 +3130,7 @@ fn generate_db_connection_builder_class(output: &mut UnrealCppAutogen, module_pr fn generate_db_connection_class( output: &mut UnrealCppAutogen, module_prefix: &str, + module_name: &str, _module: &ModuleDef, api_macro: &str, ) { @@ -3159,19 +3175,25 @@ fn generate_db_connection_class( writeln!(output, " /** Static entry point for constructing a connection. */"); writeln!( output, - " UFUNCTION(BlueprintCallable, Category = \"SpacetimeDB\", DisplayName = \"SpacetimeDB Builder\")" + " UFUNCTION(BlueprintCallable, Category = \"SpacetimeDB\", DisplayName = \"SpacetimeDB {module_name} Builder\")" ); writeln!(output, " static U{module_prefix}DbConnectionBuilder* Builder();"); writeln!(output); writeln!(output, " // Error handling"); - writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnUnhandledReducerError, const F{module_prefix}ReducerEventContext&, Context, const FString&, Error);"); + writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(F{module_prefix}OnUnhandledReducerError, const F{module_prefix}ReducerEventContext&, Context, const FString&, Error);"); writeln!(output, " UPROPERTY(BlueprintAssignable, Category=\"SpacetimeDB\")"); - writeln!(output, " FOnUnhandledReducerError OnUnhandledReducerError;"); + writeln!( + output, + " F{module_prefix}OnUnhandledReducerError OnUnhandledReducerError;" + ); writeln!(output); writeln!(output, " // Error handling"); - writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnUnhandledProcedureError, const F{module_prefix}ProcedureEventContext&, Context, const FString&, Error);"); + writeln!(output, " DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(F{module_prefix}OnUnhandledProcedureError, const F{module_prefix}ProcedureEventContext&, Context, const FString&, Error);"); writeln!(output, " UPROPERTY(BlueprintAssignable, Category=\"SpacetimeDB\")"); - writeln!(output, " FOnUnhandledProcedureError OnUnhandledProcedureError;"); + writeln!( + output, + " F{module_prefix}OnUnhandledProcedureError OnUnhandledProcedureError;" + ); writeln!(output); writeln!(output); writeln!(output, "protected:"); @@ -3228,6 +3250,8 @@ fn generate_db_connection_class( " virtual void ProcedureEventFailed(const FProcedureEvent& Event, const FString ErrorMessage) override;" ); writeln!(output); + writeln!(output, " friend class U{module_prefix}SubscriptionBuilder;"); + writeln!(output, " friend class U{module_prefix}DbConnectionBuilder;"); writeln!(output, " friend class U{module_prefix}RemoteReducers;"); writeln!(output); writeln!( @@ -3526,19 +3550,20 @@ fn generate_client_implementation( for reducer in iter_reducers(module, visibility) { let reducer_name = reducer.name.deref(); - let reducer_pascal = format!("{module_prefix}{}", reducer.name.deref().to_case(Case::Pascal)); + let reducer_method = reducer_name.to_case(Case::Pascal); + let reducer_pascal = format!("{module_prefix}{reducer_method}"); writeln!(output, " if (ReducerName == TEXT(\"{reducer_name}\"))"); writeln!(output, " {{"); writeln!( output, - " F{reducer_pascal}Args Args = ReducerEvent.Reducer.GetAs{reducer_pascal}();" + " F{reducer_pascal}Args Args = ReducerEvent.Reducer.GetAs{reducer_method}();" ); // FIX: Pass FArgs directly to InvokeWithArgs instead of creating UReducer UObject. // UObject creation/destruction cannot keep up at 30Hz tick rate, causing memory leak. // Stack-allocated FArgs struct has zero allocation overhead. writeln!( output, - " Reducers->Invoke{reducer_pascal}WithArgs(Context, Args);" + " Reducers->Invoke{reducer_method}WithArgs(Context, Args);" ); writeln!(output, " return;"); writeln!(output, " }}"); @@ -3717,7 +3742,7 @@ fn generate_client_implementation( writeln!(output, "{{"); writeln!(output, "\tif (OnAppliedDelegate.IsBound())"); writeln!(output, "\t{{"); - writeln!(output, "\t\tFSubscriptionEventContext Ctx(Conn);"); + writeln!(output, "\t\tF{module_prefix}SubscriptionEventContext Ctx(Conn);"); writeln!(output, "\t\tOnAppliedDelegate.Execute(Ctx);"); writeln!(output, "\t}}"); writeln!(output, "}}"); @@ -3729,7 +3754,7 @@ fn generate_client_implementation( writeln!(output, "{{"); writeln!(output, "\tif (OnErrorDelegate.IsBound())"); writeln!(output, "\t{{"); - writeln!(output, "\t\tFErrorContext Ctx(Conn, BaseCtx.Error);"); + writeln!(output, "\t\tF{module_prefix}ErrorContext Ctx(Conn, BaseCtx.Error);"); writeln!(output, "\t\tOnErrorDelegate.Execute(Ctx);"); writeln!(output, "\t}}"); writeln!(output, "}}"); @@ -3981,11 +4006,12 @@ fn generate_remote_reducer_calls( ) { // Reducer implementations for reducer in iter_reducers(module, visibility) { - let reducer_pascal = format!("{module_prefix}{}", reducer.name.deref().to_case(Case::Pascal)); + let reducer_name = reducer.name.deref().to_case(Case::Pascal); + let reducer_pascal = format!("{module_prefix}{reducer_name}"); let reducer_snake = reducer.name.deref(); // Call method implementation - write!(output, "void U{module_prefix}RemoteReducers::{reducer_pascal}("); + write!(output, "void U{module_prefix}RemoteReducers::{reducer_name}("); let mut first = true; for (param_name, param_type) in &reducer.params_for_generate.elements { if !first { @@ -4032,7 +4058,7 @@ fn generate_remote_reducer_calls( ); writeln!( output, - "\tif (RequestId != 0) {{ Conn->RegisterPendingTypedReducer(RequestId, F{module_prefix}Reducer::{reducer_pascal}(ReducerArgs)); }}" + "\tif (RequestId != 0) {{ Conn->RegisterPendingTypedReducer(RequestId, F{module_prefix}Reducer::{reducer_name}(ReducerArgs)); }}" ); } else { write!(output, "\tF{reducer_pascal}Args ReducerArgs("); @@ -4052,7 +4078,7 @@ fn generate_remote_reducer_calls( ); writeln!( output, - "\tif (RequestId != 0) {{ Conn->RegisterPendingTypedReducer(RequestId, F{module_prefix}Reducer::{reducer_pascal}(ReducerArgs)); }}" + "\tif (RequestId != 0) {{ Conn->RegisterPendingTypedReducer(RequestId, F{module_prefix}Reducer::{reducer_name}(ReducerArgs)); }}" ); } writeln!(output, "}}"); @@ -4061,11 +4087,11 @@ fn generate_remote_reducer_calls( // Invoke method implementation write!( output, - "bool U{module_prefix}RemoteReducers::Invoke{reducer_pascal}(const F{module_prefix}ReducerEventContext& Context, const U{reducer_pascal}Reducer* Args)" + "bool U{module_prefix}RemoteReducers::Invoke{reducer_name}(const F{module_prefix}ReducerEventContext& Context, const U{reducer_pascal}Reducer* Args)" ); writeln!(output); writeln!(output, "{{"); - writeln!(output, " if (!On{reducer_pascal}.IsBound())"); + writeln!(output, " if (!On{reducer_name}.IsBound())"); writeln!(output, " {{"); writeln!(output, " // Handle unhandled reducer error"); writeln!(output, " if (InternalOnUnhandledReducerError.IsBound())"); @@ -4077,7 +4103,7 @@ fn generate_remote_reducer_calls( writeln!(output, " // For now, just broadcast any error"); writeln!( output, - " InternalOnUnhandledReducerError.Broadcast(Context, TEXT(\"No handler registered for {reducer_pascal}\"));" + " InternalOnUnhandledReducerError.Broadcast(Context, TEXT(\"No handler registered for {reducer_name}\"));" ); writeln!(output, " }}"); writeln!(output, " return false;"); @@ -4095,10 +4121,10 @@ fn generate_remote_reducer_calls( let param_pascal = param_name.deref().to_case(Case::Pascal); writeln!(output, " ArgsStruct.{param_pascal} = Args->{param_pascal};"); } - writeln!(output, " On{reducer_pascal}.Broadcast(Context, ArgsStruct);"); + writeln!(output, " On{reducer_name}.Broadcast(Context, ArgsStruct);"); } else { // Use individual parameters - write!(output, " On{reducer_pascal}.Broadcast(Context"); + write!(output, " On{reducer_name}.Broadcast(Context"); for (param_name, _) in &reducer.params_for_generate.elements { let param_pascal = param_name.deref().to_case(Case::Pascal); write!(output, ", Args->{param_pascal}"); @@ -4113,17 +4139,17 @@ fn generate_remote_reducer_calls( // InvokeWithArgs method implementation (zero allocation version) write!( output, - "bool U{module_prefix}RemoteReducers::Invoke{reducer_pascal}WithArgs(const F{module_prefix}ReducerEventContext& Context, const F{reducer_pascal}Args& Args)" + "bool U{module_prefix}RemoteReducers::Invoke{reducer_name}WithArgs(const F{module_prefix}ReducerEventContext& Context, const F{reducer_pascal}Args& Args)" ); writeln!(output); writeln!(output, "{{"); - writeln!(output, " if (!On{reducer_pascal}.IsBound())"); + writeln!(output, " if (!On{reducer_name}.IsBound())"); writeln!(output, " {{"); writeln!(output, " if (InternalOnUnhandledReducerError.IsBound())"); writeln!(output, " {{"); writeln!( output, - " InternalOnUnhandledReducerError.Broadcast(Context, TEXT(\"No handler registered for {reducer_pascal}\"));" + " InternalOnUnhandledReducerError.Broadcast(Context, TEXT(\"No handler registered for {reducer_name}\"));" ); writeln!(output, " }}"); writeln!(output, " return false;"); @@ -4133,10 +4159,10 @@ fn generate_remote_reducer_calls( // Check if we're using args struct (more than 9 params including context) if use_args_struct { // Pass args struct directly - writeln!(output, " On{reducer_pascal}.Broadcast(Context, Args);"); + writeln!(output, " On{reducer_name}.Broadcast(Context, Args);"); } else { // Use individual parameters from Args struct - write!(output, " On{reducer_pascal}.Broadcast(Context"); + write!(output, " On{reducer_name}.Broadcast(Context"); for (param_name, _) in &reducer.params_for_generate.elements { let param_pascal = param_name.deref().to_case(Case::Pascal); write!(output, ", Args.{param_pascal}"); @@ -4159,11 +4185,12 @@ fn generate_remote_procedure_calls( ) { // Procedure implementations for procedure in iter_procedures(module, visibility) { - let procedure_pascal = format!("{module_prefix}{}", procedure.name.deref().to_case(Case::Pascal)); + let procedure_name = procedure.name.deref().to_case(Case::Pascal); + let procedure_pascal = format!("{module_prefix}{procedure_name}"); let procedure_snake = procedure.name.deref(); // Call method implementation - write!(output, "void U{module_prefix}RemoteProcedures::{procedure_pascal}("); + write!(output, "void U{module_prefix}RemoteProcedures::{procedure_name}("); let mut first = true; for (param_name, param_type) in &procedure.params_for_generate.elements { if !first { @@ -4193,7 +4220,7 @@ fn generate_remote_procedure_calls( if !first { write!(output, ", "); } - writeln!(output, "FOn{}Complete Callback)", procedure_pascal); + writeln!(output, "F{module_prefix}On{}Complete Callback)", procedure_name); writeln!(output, "{{"); writeln!(output, " if (!Conn)"); writeln!(output, " {{"); @@ -4433,7 +4460,12 @@ fn collect_wrapper_types( } // Helper function to get C++ type for array elements in optional arrays -fn get_cpp_type_for_array_element(elem_type_str: &str, module: &ModuleDef, module_name: &str) -> String { +fn get_cpp_type_for_array_element( + module_prefix: &str, + elem_type_str: &str, + module: &ModuleDef, + module_name: &str, +) -> String { match elem_type_str { "Bool" => "bool".to_string(), "I8" | "Int8" => "int8".to_string(), @@ -4470,7 +4502,8 @@ fn get_cpp_type_for_array_element(elem_type_str: &str, module: &ModuleDef, modul .last() .map(|id| id.deref().to_string()) .unwrap_or_else(|| "Unnamed".to_string()); - type_name == elem_type_str + let prefixed_type_name = format!("{module_prefix}{type_name}"); + prefixed_type_name == elem_type_str && matches!( module.typespace_for_generate()[type_def.ty], AlgebraicTypeDef::PlainEnum(_) @@ -4576,7 +4609,12 @@ fn get_optional_type_name(module_prefix: &str, module: &ModuleDef, inner: &Algeb } // Helper function to determine C++ type from type name string for result types -fn determine_cpp_type_for_result(type_name: &str, module: &ModuleDef, module_name: &str) -> String { +fn determine_cpp_type_for_result( + module_prefix: &str, + type_name: &str, + module: &ModuleDef, + module_name: &str, +) -> String { match type_name { "Bool" => "bool".to_string(), "Int8" => "int8".to_string(), @@ -4615,7 +4653,7 @@ fn determine_cpp_type_for_result(type_name: &str, module: &ModuleDef, module_nam _ if type_name.starts_with("Vec") => { // Handle array types like VecInt32 let elem_type_str = &type_name[3..]; // Remove "Vec" prefix - let cpp_elem_type = get_cpp_type_for_array_element(elem_type_str, module, module_name); + let cpp_elem_type = get_cpp_type_for_array_element(module_prefix, elem_type_str, module, module_name); format!("TArray<{cpp_elem_type}>") } _ if type_name.starts_with("Result") => { @@ -4632,7 +4670,8 @@ fn determine_cpp_type_for_result(type_name: &str, module: &ModuleDef, module_nam .last() .map(|id| id.deref().to_string()) .unwrap_or_else(|| "Unnamed".to_string()); - type_name_from_def == type_name + let prefixed_type_name = format!("{module_prefix}{type_name_from_def}"); + prefixed_type_name == type_name && matches!( module.typespace_for_generate()[type_def.ty], AlgebraicTypeDef::PlainEnum(_) @@ -4722,12 +4761,18 @@ fn add_includes_for_type_name(type_name: &str, includes: &mut Vec, modul } // Generate the content for an optional type file -fn generate_optional_type(optional_name: &str, module: &ModuleDef, api_macro: &str, module_name: &str) -> String { +fn generate_optional_type( + optional_name: &str, + module_prefix: &str, + module: &ModuleDef, + api_macro: &str, + module_name: &str, +) -> String { // Extract the inner type from the optional name let inner_type_str = optional_name.strip_prefix("Optional").unwrap_or(optional_name); // Determine the C++ type for the inner value - let cpp_inner_type = determine_cpp_type_for_result(inner_type_str, module, module_name); + let cpp_inner_type = determine_cpp_type_for_result(module_prefix, inner_type_str, module, module_name); // Determine if we need extra includes let mut extra_includes = vec![]; @@ -4899,6 +4944,7 @@ fn get_type_name_for_result(module_prefix: &str, module: &ModuleDef, ty: &Algebr // Generate the content for a result type file fn generate_result_type( + module_prefix: &str, ok_type_name: &str, err_type_name: &str, module: &ModuleDef, @@ -4906,10 +4952,10 @@ fn generate_result_type( module_name: &str, ) -> String { // Determine the C++ type for the ok value - let cpp_ok_type = determine_cpp_type_for_result(ok_type_name, module, module_name); + let cpp_ok_type = determine_cpp_type_for_result(module_prefix, ok_type_name, module, module_name); // Determine the C++ type for the err value - let cpp_err_type = determine_cpp_type_for_result(err_type_name, module, module_name); + let cpp_err_type = determine_cpp_type_for_result(module_prefix, err_type_name, module, module_name); // Determine if we need extra includes let mut extra_includes = vec![]; diff --git a/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/SpacetimeDBClient.g.h b/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/SpacetimeDBClient.g.h index 6f33c10da54..891bde00912 100644 --- a/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/SpacetimeDBClient.g.h +++ b/demo/Blackholio/client-unreal/Source/client_unreal/Public/ModuleBindings/SpacetimeDBClient.g.h @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 2.0.1 (commit a953d3b65c4a925b3b3824c419eb53821db95e2f). +// This was generated using spacetimedb cli version 2.0.3 (commit b6045fcc908d2846f8fb26570c2f300f5d685996). #pragma once #include "CoreMinimal.h" @@ -965,7 +965,7 @@ class CLIENT_UNREAL_API UDbConnection : public UDbConnectionBase USubscriptionBuilder* SubscriptionBuilder(); /** Static entry point for constructing a connection. */ - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB", DisplayName = "SpacetimeDB Builder") + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB", DisplayName = "SpacetimeDB client_unreal Builder") static UDbConnectionBuilder* Builder(); // Error handling @@ -1006,6 +1006,8 @@ class CLIENT_UNREAL_API UDbConnection : public UDbConnectionBase // Override the procedure event failed handler virtual void ProcedureEventFailed(const FProcedureEvent& Event, const FString ErrorMessage) override; + friend class USubscriptionBuilder; + friend class UDbConnectionBuilder; friend class URemoteReducers; // Internal reducer correlation helpers (request_id -> typed reducer) diff --git a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00200-part-1.md b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00200-part-1.md index 3f99a1ea25f..f23f9d5659a 100644 --- a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00200-part-1.md +++ b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00200-part-1.md @@ -79,7 +79,7 @@ The `GameManager` class will be where we will put the high level initialization > **Note:** In a production Unreal project, you would typically implement this logic in a Subsystem. For simplicity, this tutorial uses a singleton actor. -1. Open the `client_unreal` project to launch the Unreal Editor. +1. Open the `blackholio` project to launch the Unreal Editor. 2. **Create a GameManager Blueprint** - In the **Content Drawer**, click **Add**, then select **Blueprint -> Blueprint Class**. - Click **Actor**. diff --git a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00300-part-2.md b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00300-part-2.md index 050dcd204d9..efff8f629e8 100644 --- a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00300-part-2.md +++ b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00300-part-2.md @@ -14,7 +14,7 @@ This progressive tutorial is continued from [part 1](./00200-part-1.md). ## Project Structure -Now that we have our client project setup we can configure the module directory. Regardless of what language you choose, your module will always go into a `spacetimedb` directory within your client directory like this: +Now that we have our client project setup we can configure the module directory. Regardless of what language you choose, your module will always go into a `blackholio` directory within your client directory like this: ``` blackholio/ # Unreal project root @@ -26,7 +26,8 @@ blackholio/ # Unreal project root ├── Plugins/ │ └── SpacetimeDbSdk/ # This is where the SpacetimeDB Unreal SDK lives ├── ... rest of Unreal files -└── spacetimedb/ # This is where the server module lives +└── blackholio/ # This is where the server module lives +│ └── spacetimedb/ ``` ## Create a Server Module @@ -524,7 +525,7 @@ Created new database with name: blackholio, identity: c200d2c69b4524292b91822afa Next, use the `spacetime` command to call our newly defined `Debug` reducer: ```sh -spacetime call --server local blackholio Debug +spacetime call --server local blackholio debug ``` @@ -649,7 +650,7 @@ Let's generate our types for our module. In the `blackholio/spacetimedb` directo ```sh -spacetime generate --lang unrealcpp --uproject-dir ../../blackholio --module-path ./ --unreal-module-name blackholio +spacetime generate --lang unrealcpp --uproject-dir ../.. --module-path ./ --unreal-module-name blackholio ``` This will generate a set of files in the `blackholio/Source/blackholio/Private/ModuleBindings` and `blackholio/Source/blackholio/Public/ModuleBindings` directories which contain the code generated types and reducer functions that are defined in your module, but usable on the client. @@ -658,6 +659,10 @@ This will generate a set of files in the `blackholio/Source/blackholio/Private/M `--uproject-dir` is straightforward as the path to the .uproject file. `--unreal-module-name` is the name of the Unreal module which in most projects is the name of the project, in this case `blackholio`. ::: +:::warning +After generating external code with `spacetime generate` highly recommended you restart the Unreal Editor, it can also help to run the `Generate project files` against the `.uproject` file. +::: + ``` ├── Reducers ├── Tables @@ -729,7 +734,7 @@ public: UPROPERTY(EditAnywhere, Category="BH|Connection") FString ServerUri = TEXT("127.0.0.1:3000"); UPROPERTY(EditAnywhere, Category="BH|Connection") - FString ModuleName = TEXT("blackholio"); + FString DatabaseName = TEXT("blackholio"); UPROPERTY(EditAnywhere, Category="BH|Connection") FString TokenFilePath = TEXT(".spacetime_blackholio"); @@ -805,7 +810,7 @@ void AGameManager::BeginPlay() UDbConnectionBuilder* Builder = UDbConnection::Builder() ->WithUri(ServerUri) - ->WithDatabaseName(ModuleName) + ->WithDatabaseName(DatabaseName) ->OnConnect(ConnectDelegate) ->OnDisconnect(DisconnectDelegate) ->OnConnectError(ConnectErrorDelegate); @@ -910,7 +915,7 @@ Next, open and update `BP_GameManager` to add the following **Variables**: - Check **Instance Editable** - Change **Category** to `Connection` - Change **Default Value** to `127.0.0.1:3000` -2. Add `ModuleName` +2. Add `DatabaseName` - Change **Variable Type** to **String** - Check **Instance Editable** - Change **Category** to `Connection` diff --git a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00400-part-3.md b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00400-part-3.md index 022aad81b48..baf1a9b24c1 100644 --- a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00400-part-3.md +++ b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00400-part-3.md @@ -2400,7 +2400,7 @@ Update **Event BeginPlay** as follows: At this point, you may need to regenerate your bindings the following command from the `blackholio/spacetimedb` directory. ```sh -spacetime generate --lang unrealcpp --uproject-dir .. --unreal-module-name blackholio +spacetime generate --lang unrealcpp --uproject-dir ../.. --module-path ./ --unreal-module-name blackholio ``` diff --git a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00500-part-4.md b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00500-part-4.md index 05ae0d41a81..5cc3955d686 100644 --- a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00500-part-4.md +++ b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00500-part-4.md @@ -526,7 +526,7 @@ spacetime publish --server local blackholio --delete-data Regenerate your server bindings with: ```sh -spacetime generate --lang unrealcpp --uproject-dir .. --unreal-module-name blackholio +spacetime generate --lang unrealcpp --uproject-dir ../.. --module-path ./ --unreal-module-name blackholio ``` ### Moving on the Client diff --git a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/index.md b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/index.md index befddefd5f4..b2e91caf6ac 100644 --- a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/index.md +++ b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/index.md @@ -30,7 +30,7 @@ Please file an issue [here](https://github.com/clockworklabs/SpacetimeDB/issues) ## Blackhol.io Tutorial - Basic Multiplayer -First you'll get started with the core client/server setup. For part 2, you'll be able to choose between **Rust** or **C#** for your server module language: +First you'll get started with the core client/server setup. For part 2, you'll be able to choose between **Rust**, **C#**, or **C++** for your server module language: - [Part 1 - Setup](./00200-part-1.md) - [Part 2 - Connecting to SpacetimeDB](./00300-part-2.md) diff --git a/docs/src/components/CppModuleVersionNotice.tsx b/docs/src/components/CppModuleVersionNotice.tsx index c656e50b43b..a314ac67a2c 100644 --- a/docs/src/components/CppModuleVersionNotice.tsx +++ b/docs/src/components/CppModuleVersionNotice.tsx @@ -1,14 +1,7 @@ import React from "react"; -import Admonition from "@theme/Admonition"; export function CppModuleVersionNotice(): JSX.Element { return ( - -

- C++ support is currently in beta and subject to change. SpacetimeDB C++ 2.0 is - coming soon, but C++ server modules are currently pinned to v1.12.0. If you are - following the C++ tab in this guide, use the v1.12.0 release track for now. -

-
+ <> ); } diff --git a/docs/static/images/unreal/part-2-03-blueprint-add-variables.png b/docs/static/images/unreal/part-2-03-blueprint-add-variables.png index 6e1da2e76ec05103e88bc4643e96fc8aea0724dc..96aa19bebeaf472b74b73df0f6fdb5d5621e115d 100644 GIT binary patch literal 17506 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 literal 16950 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 diff --git a/docs/static/images/unreal/part-2-05-blueprint-buildconnection-1.png b/docs/static/images/unreal/part-2-05-blueprint-buildconnection-1.png index d74f410b29caf48f1693b9fc8050d2551b9b030e..aa640ae3fd358cccd2102ee69c1632071db6676f 100644 GIT binary patch literal 136159 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%0D}%= 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

P zt}0?{g6vqjV06Rmb=5qrXr3ZwZ}DENK3YE0(kjE35;CrN5Yqpbvk+DQ$Z)!Y@jOjC+7<<=EE~nZ4SeJUj(~l%H>%2nQ zUU^k(>i;M3@}aKbGn(!(D-zvVA?%gsFXP%g4o`Bbb z3p96qAva3&H{pz!*Nh-BT=|i|j}5!(nLYmGQ{}%dzk1v?G{Y-x{EDVh|6))459~Fa z?jW!9<9#*MP^}WMA4;cPRfxT*VXky8eLE3l!>ls>PjwVimXBV&MPuW;ZaWyM_+^l- zwPE=0U(*L|u<+H1F~VuPkQ~x%`%$hl-wwjgmCp;h;-lT*yGwr(JkmYrcIr2#^mmn3 z(}8V>72w>4xvY6L;HiegR5E2jh4z z(QeQ|b~=Zl{aSTxp~ge|UcF~QcV18IIGffApzbJcWyQORwDR^EvZ~HVoD|X&S@eR^ zZcCTNuRoRC`{LdnOx#KvF3XFl`dYIozZK7KA?`G(-{XnU^Dk&6rSqd27D&LnG9C=h z`C=X^YznKrbwJap8SAmY<*g;$XP-js)k@6m;PA)cKYVLyRWlu=S=!Vvle}v$pVQ5g z&g8SzYr%rsOIwcnwkocg!bLYSk!e-fLtDEmzDSF&Jk)=l)0jTQk$m4>{cj`i#BpbU zLNWX~Wf_8MMahpk61m!y@UK=$TNE$t+0>HVh1W(P{BFjW!-brIKeJ8y^FQ$(|f~uC`^wN#e4$4i5`OO3_)_LPHjvs5%M!cy2-~r&& zPrpWSg?N(pH07)=Fnr~)j@J0IoY3#CO5~p6#{(b`h>9aNIdCJuD{_JN^rhbSRzh~+ z6N;g%Q`!PHp;%UbYxqu)V)DP6nEJgKm&sVWK7GM1Za>Jk5>%4u`vgn##TO;xu6KFJ zJOwUP7VsDDlt`$Kv;XoOmCVfE9*#-F^AQ;u*ZdvzVt4X-R?Hl!Iu}0a4_;>UW!Ty9 zW!Q9dT}9SA7E?~0Qf;p{=|*@5ax*Y^gkAhlk_~lYhFwB>k+=3JG{2}Q4g?R2nif7! z7g?XjykJrWcU~^DTeXX;6IQ24`xk>L*`5))$YYKaWPJ9vh5jw$-Sb>43NmS>Q<~`C zP%D_zewk3aBB>8)8vE9(h8i#3M_h|j7uG`B1t2X6$U~g1fKgW;LjlCHUDCm-ihKB;?@5U%v z=SM(^it4%b`G_GcjSAiGG(u!OYQ$Se63Ww|&)$|jCAnG#o(3ZW<$o~Yxl z+1TTb#aN({P?IpPcqVFFfD&*TrQer2TFU{8W8BP+R)*d*y=z7txWO;QAs|Q5IG<|e~uc%OVq)?p)B-J?#31$!1*JP@zTEnC+dziq-0nzv}*+#2wPt#mab9*p>WlR41e{mZvlk3zqQ1NwA>JU)*$IMi<=l)+E~sG8W>e&@01_|b2+K@$zsK>$A!Nq@)38Q-Eh>LkNvA! zSy^Bw1V_nU(8V%!svb{$s2iIP_R77oNH2M5NB~B*X5jWU7fw1l7B6WQ~ z`kMAgyp$7JcLp!oKOYQK6lqn{!e%fRlm6tj;fMO|r-5E;KO!$BbYoSnW?K0q-}~~? zCMI29-|JiVSqk*WQ$ujrT>oVW+H&(+KaRlO19h+PHNkOz9>-=+Ahx2I#-0iTz;`Uy+3A4N@g zt^LH_DX(A#DUs8~UC}Jy^IovD_xAS`F%t%%nciW>2}d7s3X=lB2@@_%^bX~-o?mrx z1Z0_hM4mnbt#y`Lmnkx?wkHI3-r=lZwr@dEBLg3Uobp{8R9w9E6Bh(>7?w$LHTfLk zmK6>TWn{l9(aPNI!LRHZ_{=l-hJzr&B!6eBeC5aE?*c>GFejo4XobY4; zp{z%4HF$0(^SJD{EVct1&4@X4K1s)J2e;qKM0T$P46O$5>aERJCZX23B95`xX4DDc z4sxhx8C7VDl|v6qL@@8??=PeuHG!9?UAF0SHo#Rb%FZ;3F0RLidir_A&k5X zMD?T_tZl}B5hG*!7f0yw;6^Kh|HT22hh{6iwp~cPg0>(wK&HO*T!^ychzc~Y?F)4l zUGH1aB|_cpKATGf!V3CkPc0a1LiX{1l!MB=v6BO>Q4uY0QNCzb^f6|a4b-gwSoGtw zSG%ult5%&~e)=-7B5X}WfDXDEd(a+uNwcC5dLO5Y(ps2&8XtD3r&3|8&1-_ZpJ1+! z4`Tayfx0M05k(*}4gRH`c4{v;*i#g~z~;ZK0a4IT6kX`tsuMqOIMc;{Mpo@pupmW( zKhM#?h>anmOIW{YzEP;%>gv0U>KvpUJ?`3meyJ0-FBRh1*Hqu(#|9LDC$^o@l0v9( z( z^%mH-x79>}@#&|5Lod%ORh*3lnP!w=2!B**E~wO(k-%aqwP; zM?dENC0({X6Y`oYPWMhWaDi>-Z13Y|qSEiJtQ#i8jm;X=WGF)$29^IHaRWDED@u|i zGhDlDIfK9RXMp1urnEtRqykOvY}A3Jx;38XA(tv-4t8=m%n7XScyLl}Ug2L)<4X3K zAFC@DbU@OckMy3q<4%IC0~u6JsNQ8?PtCISOx@`N`zGQHZ_rFb3Wx};OkP?Nox6Zf zRF9C1GMuE6p#eVViya0WhZ*0W!expyD(W6gUWL2r4|99F*T__eUc6ZU$WK}J{R69` zJ2dplJn%oejWI?%s*VeJew#K!&v-5o5VD6of%9GK$9bn_$M`m!XBg}yx)wY21_DJ zbO4vnBP3ONrmQxr--_>`YeKZP1r;f=yixBAG{BXa(Q}NG3CZpB^4DCrGU`tGT^7ox z97^z0%<3$p=iWa-7Uf+2t}%8PpaSvUy;#qNh{-N zcaP&RX2SvLk?AL$)@z#|Xc@z+QiwU#-0|T!C^dqz?_;lmXrzVoUK_wAgf-l_Y7~j; zGxX~C{>Ccba0Z(`VUea08fS!1eGBD&h^bE$kB|P5!7yluN|7I(z|2Zzm z4i(_quWS6(2C-U&=*eYrqU@L>nh}*F4Vn)?i14gst!py>k>JLpIlzhCedkTZu-P) z={XTYq(`Co?_R#AyH~!uZin;FQyNc`pMXXL?Fxni%---#TB9QgV_vWH&CndISF5DRnHo z5!{<+rHV9tVX4X|J^Lj!ZFHHEyuhz$62f-E!^46n?Qf=(m7UFz!4vgD`vUHzK?a%C z5);pib82Xs+SAA3WFFz>1TlA9OOR=dsBvhhb7=w}3$$x)-Utk4xey%gxI(-hzvdD$ zw4a%;GWQRpkw9kS#l_mA5*EdHD{1P4MqG#KdbaW<4~FYFI(#M}_;>^{IC#Jk3i*}g z5cZNh13k#YkvS&@X3!0E$?;QNY*poC! z`kIVvwzVXjxY%{eI(bw3%97HW9=q>;edHL9-%L z7PQH)|D~dlGT&B`SYMaz|AL}OBw(SkqSy00Nn`52Y+G!nh>ewdbno6Py9}UH^og`a za1;4HMlvfy!y=%sJU;advU~JrQa0LQ$Dj4l;Z}HlKHuK7n^cKnbjYB;ahrKp}1Gd7vVBJhn zMP%pBVQe66`%X8ZXxwBH{p*g{H?IsYJ=N;2s86ejO0YJ|euv@ERgAY6!glbE= zyS|F#uvcDiFnU0Az2`Qtr_mkgzQ|XvrxcL)37R~tCaT_8n9Tv%O@-L=hG5g_#17ddj;u7Z{y(t~Wwf&6px5vjC6~!lV57y4= z0chWex|!URdj%ymu6bfVNZP2cIHyEfy3*nf$e=+7x=_nN?Zhra`=HoDY%;jxHX4%Q zs32(4=hlyU%y0$Fvv1**)Bw z8$4!b+&qfniEh+WT+vQBj$X^ENA@VP9EL6X*Gli{1xP{6R7sP3jU_l+PW~KSfE}1g zUTBozowc>9Ev1-vp$ZR;hENerBMtGbIJg`yIApjg%=no@w-}@;wUAbPa`N>lZwxY&Trlpu}m}T7MM1kIbi_=I@wp)6Q;< zIX_Mt$lIdadBF|EAUSD(rBLRS5GT6Ejp=756cy1HMt%y=FqyF^BO6m=07T~xfav&a zF}W!p>}b^#Y^hOIlm8aOUezENaMeGhpy_(>_zXzfB`X08IX{?cY|i=bKADpFFBAcb zfl|^4epzkrjC>esv-T*{bUsN(Z-gabf^gY@?{Szi-pM=OAh&QgxxBxeelMQLYysuTLj)ehEjIuLkT9 zWLJX_>m1dYlKv!58_JOa&`aB~Evz82pM>gXJ%nJgpOl3kER0zCd#WzikPWxUVcSpu z;}hsZwGnPor$_oHeHjLW`q3Fgp4b}^cz#jM9H~SshAx8uN_imDAT*rF06peIE#n_f zC-dZ@#Lrnl8EXlK;}t6=PGI-b@jxP-;pG2>01d??E#*KuN@yf7sx*Tf#WGGL`;~O@ zHGsSC7lc+N|2x-Sxi|Cmb^nAAQTdza)`ypkUKZxV>z zE0;a34+qdE`1og%q(oWx-slFH9lrnHA&?4@NMTFDrUMO3xs8#qXyLVUd>#im)O&;9U`!pMAB_$sV}{YivWzCh$HOurL3O#kOBM1Hi%UgwMT z=CLMHdFYm#vb}hlrrXqYlf~5GSh)B=9RzMS>@CUUmQbxr`82+YGg8b`dU~2*I!1N@ z;)r3|#EI79DKG~nZ`8u18zu&dQ3lE<97VyqR7FZp%o2cZCvcnD(l!l%q}=l_^G>PJWuL zmL2x`e-<3^3B!sg`npg?Ty7YEKmg)oI!qN62|x@RSt$>e(_lxd(Z%Q?$ER1b90Xc} z_7>8Y?h8?TX$SB@cDY_54&KMRn#;LwTD?06qsXQy;XJ#+k);7KP53> z?Et5-?LnexZW2P>geWgh5$u^Q(CVpJ~N$^H6OQZKlxpV{j2g z{qA3e`o~F1g`5P`eZevP`*>E{7w@g`PLWVKA{QYQzoNzI!a%woUUc*1aq~Nj2V;!h z)=P$lQ2*Nx;Hgs@9%IlH>fUlXAjO*aNv{i#|GaRT|3&@5!0;N+|4jkMy1L0sG?k^M!3GfLoQB0C|-s#R1fVpaU1uhoiBRC8azr-QS2Hd%)4<1AH6nZ~zhjrZ{x#i~o{YM+}Gw zeM^eBMYKd*P7!0{5Bk?~4>_JOs0d}nxE^YY~sm2N#0F0G}Ve`VVdlzxKhQ~djK)R3LHw+fG~ z`aKZ=S%@E}r%eINJ*+tzp(;cJ13N}$nb1h0G;=(3hQQapl~E<&yelSUXxWtE z39735-`b77cJ>qzXk7-_-arhBA2YlRTqVN(5DO`JtJdg6*Eh@nTsj2`=7v3K_ouq*a zm}(H(Ooy{CP&!dRYh0rqvE-W#nb<}U&8;2>@Y<@Z;tcbd`#)Jcy}QUr8axMziZ8%mfp>(l%~F zJ6cZ1$?+fK&et{Lv0T04xNm^?-WATm7wOHuT^4`j7w)n!pI8l(QJaCZUj}+@Y^LlO z%{_~)){;ide&9SWI@Ahwx__xukGFAW!gQS9m&MI86&Xy_u|r^JW09bg?lq`^g^aiR zQio>~OxATW8RA;aKb>e zB*0HHPX@A%&d;{T51YT6luo65vW8~Ko(c>Gy=J?ZZ)v8TgtTA(q?Nt6k$Woh-+E^_ zi}(HwN1NzX8RS`v66HZ33W+Zg=6zq)RmFIjhj;uDY9V0}U0S!ZGWSYE_ee3x)uHo7lU!0PBoD?k(fhjgIB*-b!B zQ3_&Tv?J+k?$*%EBnj`2Olhbc)Bc=PS!pH7v29BNqfIy=UOBCc+h=t%OG#V|XhqqN znB|Y9n3#OD-`uVD#w-;;sB@UeB2N_MJ(*h#xgQSS(5}$4+GkU7a|EW+3xN5JnJnF4 z{jmY`ZDoA!^}T=WCg8nRlmhPo)roSY3lEqkwn#~&#VQ=D2V%tll&8A7ht%cqeCm-U zyv6^FfqDP45BBnB%alxA7+)}8jyeNPBB z;cOQqagRm*;Rx>hcY$QYFdYq=7yxy)B^U#hAq2)KF6mWTT8U5i%Cy|i`hLwtzjrzG z$sheH8FT%M59X`J32gZf>%&bRe151V>lZ+ueHq zjHYw%{v=sgGsco@-k0_h7;N1~5k@ zj0bFKTj1Z7`vCcd@mb#ry_o0>+1c6@4kw!P^u7{TArVb6F&cFtPt_SI)3+RQ^qx^&6e?2TRXV zZreWBQR%L~rfs&%1I|4#2BdZb5-_{e2=$fCf*!OQE_0M4Y_Z-$7mv&uUL7saSp7xgp;OuM zY(-1(nv?&l>+a%Mn{wbpB&eDUH$+R{ft1fC#)G$x$(C;JPObLZH)=h-9p$)FNkXPi z*9~qn~8RW$(xRY-BVRQ#iZY#r2uj{6GnQNDF~as=4NrsKUd7@ zPH{!NrFz4YKtWtA9RwJ4ngBoveBeaQdh@R?z`;Bx6VG;v<6DTW1!=HLI2*;^$Dkk} zhzGPTWN_^i+d~kgmJjm8;BY`m3|I9P#$AHR-OQ0z;=Ef&D=_Vzfq3hX*0xY?W{!>Z ze^d`R@tPm)HJAGTEUD#l7w8{ol5k0&fKQ4mc{#jVd1PWuEX2Z8EK#~A&ya}^c$1m} zGz~2g?E_w6i+v8sDsEn0eCS8{b#t3z6BCXACJ(?>1o2<%;8z=C&J?UWx+8-4;?}V3 zNUxJS>?OC6eYBT+_AP9w=|QF z)t&A#oR_)+AWtu_tr^H4G7nfDtx%B$HkrEg9%FvLRvxQWMWpzebuAp$S*G5`>x zTx>Ap~*O>?Bs}GV!TFzCq9JjNlQ+d(8mD8Nu&Yvjt4MND0X5_ z|Fk2~5LSgxq`Je;aZ;WqtNjkOM=5^PnGl9J62KrbH!QGx_qjwl#U7qUHw`m)nDic8=d)Sld z7SXu0+zr}SVH9}H1a+Rv@;hZ8rYPA*zRa7(sNJRSEX>Wp0H>1s-H<3JRoe7_3Q=yY zqRoy9U!|_ab(!Kmh3s2?3s}(pq`h;jRJo_K==&~;J1ofd!HpJe%QTDMaKnPr#DuF~ z;H|8awu0zG|FnuABN>t41PD(@W0=!W2)b5RQ>5#lzsO%AtLISEHP~s=Aa=<>L#`!V zPP(yZp))ZX{dREFiE8WZh(OWj(sy-|Lo_FxdV3ta@YnhXdOlyxm)-NnY_F5{=M`|c zs;@StziIUP0yYT#<+Ul;m09z(xDX2YWPNQ~lM+MDcmV{=4)%8Z-HIuV=X(d)lro zBb?WKe?$gJlOy>}^CLkV?CJ31s~-_CYhqdK=3D3-Vry%#*>hRVDd53T=(aA=yR4K| z-91b5g5T=@!`62|HPv+Osz?**C?F*?0Yy4WPozmNqEe(O2nbRHL28Id@6tPw4$?$= zM|zPOdhfkMC<#gK!T0^{|NZOUwXz@?P7ZTs_RKu{d1m(B`~2~phJpBQ=k$n`K@H^4 zJ$9O}fqXD*JT6ytci5KbboOe~)J^w*%^!~J_rkpV;*#Q1SrXOQ64f%w3u&0f?w%8; z9by-nWphW6=8JRNl$a^i6^uhN&xn z_grVz7a$1Acf2Tcjj{JkquJBUorZxE@KoaKJ`i>=cx9KpF7*Bjn5aOi+f2z_P!%~~HCBXQAqk`?!?#H62^raxMb0_tm9 zL%MHy)cEZX+_U@60PB0pq_4x-84yV~2ytqpea@^l)+Ea-qxcDT^NJ$pI#W-CP?(}MQ2f16?KJ`I>lL9|^j#>#@@oXQ9OgKNM_R(8w zkX@UoT`8v>vaQ_fbz%~L(c%g6eIhX4^pVbKMe{OBrgL3? zuVx;55uDq45|97(apLULa8?VdLp{bwCHeC7{*Rh6m9!78;$_buxsfypheM~gl zjzSo}6vO?*axWo((2EG^z4?MxNcrVOgh@Rr7#8Or4^ufAmhR+96~s38QPEJsbgAnisSoj>SeR2mCx7*x7j`o6TCeM`z*i6K>d^yMNZIJ z8h!J==Sfqxvqi4>45{4lh*Ws*YT|F*H)5|Z`J<0x*^0%AWdT?SMu|vFTG77x}H(Mwlsogenu=rZ+L@80&i2u8+*0M6AFp7^l z@I>ZISP}Ak388q7fV=v+o?57s#bO@25!8;Xh3+R(96Ij z7an~%a6jF7aZi2DGh4`QrJngBj55Myr(wO7uaTLl<(=VtQM@_Cr)WYmWPQ~+zI)WA z4Ge*NmiX@A`KH4>{OfYr>Cz2<0)HTEPYXf%h%Sl#;a924i0wnE$LgQb=r9`)83D#S z&dNk@A&+uX=?ZRfuGn@gy)&xi>8%c<;d&CqvFkar*^`%lu-H5%L6*dkUSjV))Da%dI8S^-2zdkCr7YvpB@d1<5mApou zW;fSvMH)X7bFlCvd$IiDy`9}%(E&ejY4&;MQ|!S?bUwg@r*Fq77*_cfNix%KJuE9; zB6mrNZc4GtIn|c{xg?q!xu&@e#E4eBMLW7BNYDRDnK@!)9quLK+S6FL8cPGnz1vua zZIvndslkHn?=0B2=zhM)qo@@=>D))bFd)MAgjnsb@MO7_L%3vrH*m831^Q8HMBSfX z#XpsK;yw3<8x5JenF0Q$a^3xj!F}q8&eS{nRjIIk3GxIF%MW#5*`&yD!+_O3?mIK&^3v)&8|38^w~4`CeW?cJBQ zpRM%^{&CC3?R0%JSW-4i6gyG4HS4@>`yw~YRn>JWGWYjR-bAU(HdW4cDdqaYSWzI| z#Mtw%Urbs(|Fn%Zig8+S7V}Lm#8pen0Sv5>KL2waO+pZDQH{!!y#lMql=7P-B)Nt9=OUwn)D(ku< zX~*xFQ@Qs)q`kF1k$8I%HS8P6sUEHzE%3{*-c+s9(lL2LgI+!*RR``gFYJaVvCkp# zmf%2Sr8W@=5Ye?jl$4xoLfJl_#<*JhrPxel~!Glw59OHdc#A$>(k~_+Tx6# zmB%ybT?aHD^79nDp^v;dO}WxL{8qy78Ik7v(5KCi+BZ6q$ z%Q0cwZZbsa!WX~PHY9~S9GF{uT3xVhs`?@g>WpTaF|JVY&O%g*D}9>*|DLN0%pvQj zgWXxtwTBJser&of*KXMVP8+uHalBxL(44`J3!Akmb81j&{y?n#_(blZ>1N&V8Uq(U z<>C)Zanif{!u``6*r8pUxpH8W|O&k?;2u-RuKG%7m zc_tp{d#<6OH|&yKE$I!Z*UOh4uX}MGK(X2Qc$elKMkHUd<;C5@aU<@bw3mNYwe<}h z?dK0pmD5*FMOidrp2M{~7-8!o|=t9Ye^8pvu#@*3@ttGa!Icwee$%=_lIxG(ebFAcD-GmAzau z+4b+B()1FNW!yPQXNqp1IPUg_zy!o{U~q#HhM|QO#Z#w@`-=Z|Q%}$wUhH(dSKHw@ zf-E2RGoQ*e!2S^6i?-d|ZmkYK-V$J{%_)6qD{^{I(CCq>V;r-Ur(0A<+@+P%JNC3k z>v%?C7|KI6LYrqkpYbQ=?90BCm@bykn}zKRJ8){sdnQSH@KT;$Ct_ z)lfNjXOx7y-$f)6l}z7y$<$kivcrRDr8~3jCbfW&CdPLt_((D>mW?g*i}fy6A31!A zD^cmSc+8Zf2ktc%>@XR>Z(O%pKirE^;j7g|4x8+nXLV=kesx>U7O|o~|L}XpJYzKq zfo$tFUtiCXEFsK1Ok62s)|(A9_p9%BvPvv2UlD-9nS=wVdTna#1rvAdzaVUx#@|^T z`LAU?)J!4@uehE(+xF9CiRxMHHTF+-JWXZVT})8f!00&M?krxL^&9D>j>JsK*NUZ5 z94&5?X0NuSvABr`Dnl#l>lwd!R%qe6JB`QIv9u3K)9sEi2l%qu>?(#mQ0<43cMh@3 zYqoO%=U@>Fu6K@2W}PifZW4u%TGYoJtjcQf>O}?)VI~Uy35|?jXMBf?>>cPK)0~e( z=B13sX60J7xNK}b|Iq2LBdDG{e#aiKiuXm#QOxCF+5SeiqdPb%xV#lja4g+8;5k%; z$GQINHhM-hab|ZsD!elyKLK2{99QQo=3C;}xUkv#@TG% zGTX;o&>s~dQmZb_$7%t#oTUJrQ^IqTp_=vvAYdE>q%={-3&Y-PK&#E`iy4`cnp&@q zJo}-l(pg+Av{@l1*)hShd7RWnZ-0GnrBZG@y)Y+^tXb^QAZg@G69m} z>W;cN2ryf3t5c1`Pdk#VKK>i%(uE55rHO1B2%nZpo(yv}PWz;F*;)w%H+Xski!VOd zCy$4{$BI0Wwl8i)WEk9i;3N_!F&M z5edlN2iv&>LNbo)=B+FiNy0!|lo{Fe;;+6(hFk@sYG zj{R3wo=wNuoyUzz4{eAV+UT()trqGWswHXdXLVjCKe_~AEJ$p1*Wt&`v{=mDiv)^V zus^|ml|c$I{gerv1I3aSDTGr4-h<*NS8RB}5^r=)_Wq8T?Jl#xhUZtAq!SA2`&RQG z7w6v`wq6}KxzX>Umu3Hp&P#Fcm~f*M(p9N(aN%=sfp>uKTA#JNY+#>sJx-J#FU0H# zSht45RS zM0?>&VO zUo-?HtRy6g!CSR_u3Xf@CuZVMacO%j8?Ui(O-jFbm(MNrq?0@5>sD4VO*5!|(%_Wh z0*!>UPk5~n+0aF&9hFW`b?mm7`6>9>tH2N6d5R&9RE)mHT*9&^=4s5k^WiX|CJVQk z72|n|TB)>Ik)I!oU&m3+9Ljr=_vqX84Oh6;QYk9AS@19{II|z7T%*+*!5DzE>bV1|8fN9$7`naR#L`IX4#MBrV zr*3yV#1I4=IMyHnc}kqf3z9oHGs%$TsSg+z+V!Pdm+ISaA0r8wF>VZJz53jdTyFin=f@1|0;C? zwj@84hv;6GJv&#_Hiw>nK8n~`rl^gAeUf~DQ!CCn=PJ9jy8#j1g4BBmV;vkQko0FR zh8&<6Od@2b*s7l+_zzxEGP}Hlr^)atb_;tN#btaDY`F~`O)%GAdSwR0G;wXYlu{{j z?7k2gTbXH?wd>{~eq*h1Qv{Xv$eK6VL0YHums=9TLxSP@#D}^W?T3r|4_8YzGK79~ z&d916Ytc8G$Z@JN(MEAera0YC&&lBg{5Dn>KA{@3Y*pKaE4acw ztX?&uPuIHa6_jqR6{Kl(+f zL-w4&OK{2j+i)EJ>o-=1pCX4df6Te2@t3Lh%7Np0S>yHjKGZfC64a=toLW3_WUPum zk#9Uwh>z91{K6W`FHNdB$-(rN-RpMjGGbtQa{U!cdr9ZpT_RH3}7cMA89O9N8`4jGMM6Tk0}{M6lTVncg` z!B&7XseZ7lwDhsK`B$d}eUL1ol6%VrcA3h+ughp1T2+oBtJfX%#OL;wHLNf08NVAI z`YyhDpT39ekuVT6H8s)oe!xm|JC^Rp>pnC_>%K}G51LtQ2r%e2R@fSmjcL$(xn)UB@T1<9= zXs=n(?!`VuOdz?cb`T${rl);1m`gU2c+v+iV}UB$TcW2c!#2A|>l^@W;_KCC%dfy) zFta0Amm4tGQthimAA32c12@f05*n;=GrRkbv5VCF%gf7og~g9<;keODQ#`mPj~(4) zAPB6$;f-q;3?@)VA^ii-Iw;(5TZ>>Z8VI%W>L!sY?7^e-vK9Rr0^cJD_$kMx&oi%I z#%`SYQ%$QU!hW}Lj+I7iG)Wz^b|&w;xNsh198D}+Y;uNt>2Ex`BaVpi*GqOnJ~Tz0 zHt9a!0EGWjzl^JgcnhRl*D4gidF-J~Ha2Od8?|VXntt)$_M4&&mOVB}$4GaA{4yp+ zpTEcUGz!pIn{eOi!||2rUM|a|kEZXC$ff^tBTVo|%_Gh9-0~Y9`}TwS+tIk<2E(Nt zm-0}Sv>;l0i{j1O`w=VJ*M&BNT*X~+Zp-EkYQNNQ_3jU8n1f$dxd;ozLW)Y(&Lik^ zyFX!ce@Z_XZ2YH@bqBF$Y`3IK>SoibV2#`&Fmn?_v}qM?He7a~Y2viq?r%X|17=*} zR&i5ZJqCEF(;pa;GLvoYa_qmBHGAs9E`;$)B6poF(s92qt$AYT*iM4^=8hs?@ufhq zer^F{cfzPaZ_hTSwYykt9!5-2`}FBKrAzs;ky|1FM^cy*fgF`{puvBtp%d0i9ca zlsU)|12lUx*6suD)q{Pe;Q9exO<|g-+)&wQty91BYaXLmo-&hIAX;(r{^}99N~-VX z-!FjopTu9?7;IUn;xU`eG6%Eyt;qMyw!X>8Eh1kaAeQf4Vx`&P&702@6xwwS9en>` zr-9=;L1(GiGAQN{+IzTXA%;W|uQ?^d4R?fPvhsOfT<>Ku!}2uG+QCbgi>_U)0BIgf zJt={}CjM`UYT`OYjh&46HyCeK5PrGJLKhQPSiSQF0gHD!%GS!0E;y_IYZ%q1;*}8A zn*fKny1L2-d3-yQ1*gx8Bk_|RJXsxRCGleFuEOqFdst+w9)!VdxViuK+4KyyjZ^6n zCqZsJcgFvoGyX<_QNz~sPC=++px1#u)qMvmIRwZDK(PaIRi@(t8qUJwv$>CP zkkMJ{{uI|wz6@VN^1cwUu|&PPNu#569Z}4}F!H$QgYoky2Yl!8*pjz*UY-XL;}vJT z^A7ov$1Ss9Y)1y1z%8xYI#bj|j*M)kZ3?Xa*%U^m>81)JjNm`g+-uYJ@^cI7a`CW= z+mZ$27|1JB;sK=6wpFB0Z@@)X7ROEp0x1@AtxGSPzcy%l1m61W*HaQ&L5y}&QV8@^ zH;B9Vqn1~)atF2Y_79WO8Mw}1?Ayqtw{m@!qfeCmtVA}al_A|Sl#|nTi0h}K!PdCD zv%~wTjEFZlZa2%M&$g;jr*b{Wy*X-=2w$Y!w&V{u$>~1L6zmTv`U77#jRN6{#Gk>Q2;H z2{LtbAO}PL0e8n>3dVr|-eU$){ac84xSBP{H!TS5rDoF3e!v(P;sZKhd_WW@_rT9~ z8cEO3bO3ohuivnT+Z-D3#ci&H(q3G0#Se^H&iFkF_g04s(#Vih9|r3zTfXfjvnB*2 zmVq}*((jgiXp8&V7WpCaX;!sgbd4qwOg!UW6#SywnzHJ>Q00B0F5?`aZZ#HQ1=o3? zfw_JA+o_~8T;w*p(~bR0hZi&r^|q$T3@k&@?@659CSsKMGmA+QsYb7!qc?ARgyWa8 z4DAps<5XXqRR%|mn&{f44JhA^j{2uf9tdv7Ly25*5!-UUV6|avW*}h0J{kfnP>kO0!XyVWi3%%TQTYUoqR9-i5ukT1Bml z*rX<1_Rt_Z70B*BBW0{j@A#PX)6M6IPKK0#8*k&GXALb;q|besz+W*UMYqN6DZs0F ztNFd7NEzjr5NlYWKTkULO;u1Tm+5I?B9U*1;L^Rq9^*i)FY9HRW<;q%5s2 zfB9<&)NNu!xna<6=+lT#u3pY*>`&s|9Ts{cRdGPZBjInW(>>cY`MF3~a{W4pg6?d>Y1Obz`lEQ7i7YxC8fo z&m#zF-h9<7;P5G`CLI`6((W3P7)`n&LwHJ{2$q^N-#qvXL3BQsu9WdXp+M^TcHi&c zzg1VSe^l8#F$nWxu>qTKSZVok-^v;-`YfwM$#ujXtU>_Zd^_2wYo z+JVY7H#g?1wuCLTfJTx3DA<>y>K?lt=zT5j341;`V>T!9pI-Zlp>G=1Gchq~b(B@g z!m@Lfm*Q649f#0xr`xxt$sSsb`;7Jm$_=9`fbN+rhb+HXH3zZf^aSkU9KW7|f{RhPMKz^p6o1-F}aUPb`j4vbFslfpi1fS~{DqBZ=dK!a+> z9D>9L%8%ifPB=uldfP)*;x37z+mAtsjiIbFuJ@L!B+N{2d?gPRq+|0rKeG03=4i-S z_0#lnZn#|PWwlT)A11t?UEdu4BRXoj5fKlV_&C=vXFlYQG1Cps-2n%sAMruRR9AF+ z^7p;J4cZ@hLm%`HgO7K4(O{Kn}EhxOvBq)@+@W0w<2B)%s&zuYtmo}i7`>}@5m}Xo_lC6f~dKHjcC%_J}lR| z(8EYZKmIT#pk$J!9Sj7-R@2bP7}WieKKDue)>C{11%)h|d)P_o`Xf&^jr4<+%i#S4 z3fY-w!TQgpkfF8Ddv#84v1wppv}w44^=cgN3nhkD8Oj@HzR|zS*m*clC`a*%9|dHQ z@ujet{DtpBLhv?WXkS0U6{ntIdCh#!C2(r*t32`p)DlU#qsbIp8Yx(4So7=cR-U=O zHz7ixyZ}dfn^X~jk0KB>jIR5hlaMj${LHaNor(8K4*Pkp#@1lHkd zl3b6*ET05$BY|0QS&U32o60{RVD>PC>>SR$`*+G5$i;#JK5zZKsA?J~(4oZ_AKCrx zjecCM1Pzcg@hI_8AH_DNA698M8;t#pMV(t6XGn#^x(~$;eW|Z!UrO%P;+@TWiiiUC z@DAvCXW9FkFw4fA6MpKA6%6qA=ZmEk=%_ac)7K~QC2v&N^|e+A)FL>nd!->}h37T> z<>&MwKdGh)@;37Ni<(po@Ws1J#59&TH`V>MoMWDk`hZQ8%7T0$T#-9KOXTZpM+{wP*>d&P%5X6r`D9Bq{Xxv5 zCrd{Kfrz)qQKuW4Qit+}m*ljHbMY-xaG_w8ny*-_R|%ZTtE8U;=o<6m$u7+PQV3rM zr6QxZZWC%$?5K;~VI@-Wt9G!g=JiqQI|FuZIZc*iQ)4Ge8Us;%{}I4hta9mzC0z=iJI zBB$JfM_@ZEZDUlj^_FQ%rws1PqR|=1pp)Z#TxUiYN)N*-ixFOg*-ZOeC6#tMM4>QC6!86NfMJ>++miAIsUmW`u@|X(iz^l{lwv z$Ra+!tBenx10x}{0h;%cXX4TZ$|9;9G%xVd(I!Z?dZs-B~uU`SfCcf%w~$5a2GOyPpSM}cNY|rAVglI`RoR?ZWmMl zk(_XLA^TLtQ>wGbR4*s;_9))M*lX!}=aCL7H11t1p&uw@#=&cs2`Tcdi>9NJ;LsTI0#k05LYx)cK;dp`> zwjM7Or6v5W`#PWV$ZtXr6o@6IORv;CuOj)(?YrMaO{e9;{KeTFWFH*Zk$o^eO+$XUPD7hFE5Pa_cGZh?zl=9#t*j!+4@Bvl~ z2z&>W3z5%*_xKR&Fbiv;H}(X#G7@ z1xdLJ8UeLzwOVWw3IDW}+0CY^#oP!iig=G>xmteoD`8qNq5|?{-q=6QE+p3W5kLvW z)fyB(3CV-_jt2C_saP!3;a60tY@Cum-8S2*E5s2B8lb*oDRe+j4DL~)(=WA!)HHcr z5y^AD(V7zU{9si3?^>(TgIdhd!$8}V$|9k{_E1`$7qE^HesBSiYgV~(gZIHvi~OZL zv&quf0ISzPLeSGGesDK^U2Q|LZdaL@~x7+tESHV*xp)WLg(Y!~;!cprbRe--Yildh@!!AJ8bRPF7~>SM zs{*&Vzu%dm5OS|4D9RT{yzKK1$KDTh_wXq7II~;vIO=*QglH_YO4^$UtDO)@ zLpHIUpREFdU~d2*!KMYtXnRptfou{W1$uY7#oL?=hy1j#San(OtAheS|}v zJzNQd-n54wQxnXyj5O(iBd(C+{DFliRX(e(_0EcM;}AG*X}$Wa(PQ+LdZ{hLswq9c z>u-{8eHJq3*9z!tY%7He5^{)DtacWZX&PqixwAhq62@ptoeautFzm>6^yEe5cwU-; z$Y=YjF6Vix(P?#~uUM4rUbSZ(r~CVGZI|tyWgO+=yA>c{Q>en95LDxm0{Ku z!HzYdrlnUINa``W_KNdQK`1o(mGTQdukH58sSkW8@>yJ+!Mp}~zy%i>Q?mh^vcieI z2Vl~1H+Bjq(m8+&jfhxI-S@QYywsH31qIlR|BFu$8?cs%rdQ~$ZJ#;0BS@@D_TuHb z(Y`yaJE8l~{P+f}-l6o%*8F9M=yIREmoQ6MU$DgLK&YT041=uRLg+rYKk~e4lol+f zW-*0D9E@SU%Vxm^h+HFvBs($v z4tp9aV$PRR?dwqArv$iNRf-_=_jwKhR2_zYVN6Bz`)2RFx-x zvB+_$RHSnpz8tH9Z-Uv<9THtg^O1iGKL0N(TvVjN{6DkN@;Z!@i|a7V-ZRte@A@fM zwY~lV7a=E!v^s`_0#UDaH+|l(nfT%kdo%ftj{$SUH$hL04^GdAq;kkMkEpD3nL_W5SVJFDTK*uGZuF!AG8!P0w^5u&^X+T4wT(0Q!t3Hd#tZ?YH4@M`A-Jh*I{5TA9r@YVc>^&kUAs?F&^9Q9wug6FSiF#>ooL5IYE7c+d!6ld-S z#-iTp$E_2#u=GRyAgsP`dgFLEKpO#X{UQ6!o(G`6PD$VYc1n71|!!M`lIKhrVaBK17k%7 zL!yJUb~Cy^*33W{z24^DswRxB=*F)@FPxwwlPfWw{L0~dI}Br#z|}yXY3}_yg=3a1 ztGA2m*v2&? ztIPS2EmR*4dhB3p)9|vReD!TKFulzKIqHKx$c@5pw7C$Yt^FCZw4J@&osAN7bCGHf z<&2ouV*mQ3X%9{Te-HNUc`wqV&v|6m7HREo;*rl!e|4$0Gy>C9fGq6$&o!qWeJ&&W z(_5prn@&$Xh(}i68VhaJ3h)C{S6ZJiTC}wU(v@e9ZdjAtI{W8N1%K}p4^Vq$ZezI2 z#;Kxz|J|vFGmo{TuT==pk7P|X>bGjSSADZ%pBXd93{dDkpq8!YiTj-i_6n@`9SGDi zNoTRM=2m@JlE!;}Cs1#cBP0(Z;MYeRvzFONY&^JHEa`(Riu$I6hSzHbzqd=c>CzdV znz6BJOJkMuo{ro8tBGQSys6u-8|7YWNcFSqu_J;NsL39QwFz0a?&|1Dfs@sx857%c~2^)zYbJ2qg{MUC=xv+{G4f}Tv{Q`H3 z8m}ld%6W2SIh}K$g39+DgQd?u!%=5HTdn! zdmf?%-^`Fg+_!F^a3IOXKv|KyFIl(8ODvCGGIlx$2nu=wYx#=%Ou&h}g}ZcPtRmaj z6z;PwRYMor-wPUNLV?rtH{p$22v=b%=0;V zNnfB_;%}~xkg%eW$2M=8@&^9U&Fy)vQfl6N_k`@EMI-|W=izUn3Sf5U4wpXFv!84@ zn+t(pHZ_0at=c|QI}4fGOR7%|to)vOofy=_A-#PBX0YEB0|G{l?a+fyTdx>7pZCt8F z4qC1bLvD7v-ITJ%kngmpBjX%2dDgWKiL`s%@%D|_X@Z%<)Pvj_cy@J%y%(Bc#svor z&Y+|eW+8%nzVi^2>?J6oU-x;pyjgX^vi|11`07{%f7*C4EvhQ7>eu`qsdGcixAD>r z9b1UG77B&?t-A={pmy6$$26x;LTP0KT_R*u@@s4FJDmJjX1QeUYrr(9qa#54&`ni` zj!nzFki!rY>yt%G6H zu}(q`CjjdNkhDOVP(vlm72|mf*%CIEScCy6AFypirhOIe`WNkd5uO28@A9yv8O0Qw z&1~(R20ZX`Zc&KMmkVOgyB9;>NedPS6zx#6^iRhM^;=oQO;oHlnnO&QI2K-bC5b^-Q*iCzCHd07Gd1(x-AY^@!27f(IuLL`yt0h=rv!e?Bd=Nt z@S2lPY0K6|KxA*xji7(k2j~zg{IB}30C}0QwVs4ij>Z6G@>kq6>S7JH(yW?7&;PXi z^jHDVTdvq?)MqrPgRW=wsPLw7n|sqSyvU%cqxNH}w|WFfWImMO-U)A|$@g&QXbW#z zFrOtEDXG!a&lJIz1+RdY9{pLIruTW_(G7lwg<1hTtopHt{vH3EdGVW8fD@PRFUTNt zMZ`=zW&q@0f$Zt&cJXU;{*?900W3jjhk@(o=VC&WYAd!bb($y5v5MLaA35q%y8h|c zh&QkfI_uGU08Vf4Qt{lQW{mxeY_j2Fr~!73@$WY?d6#crKU?|o&9(C|>o23(yfXy{ zNayUKfcLn?#(iJr1S538l_5N>-T8;vlH7%Tahfzy*pA-3Zj0kaU2FiH)wBGUvQHrB zzcLu16HYVQi}NzVc6!dXcj+6j0ZJN2Yz?AvxGYF#Y}_Y|<)zjO7~m|}r7SUjd{14q z#c9qeF!7dP)>FrZ+^~Gjzsd)w9b0;8ANDMB=)K6j|NP1!8T6*T`tS#0+U6&}@W4*% z!R|kL$d!b$f|3J>0zn`L;hFA6IrxF{UwZ(g7i<^m+oZN~=>FXr%#_+cG(DiAK%D=l znCAZ~E9_fx7OL!#Q%^bE^l37-MlXe|#laW%Zt(ZzApfaLV&_40;~<+7A^b8~#1+5htR4Z!;J zPUR(R>g1RSiS}2DoEqS=f)XNu75dwQ=a|saL5;n z(&*+$yWU?K`)sX`ctebmPOfv(gdq^J32exn)A|e2vpMFCLSNcQ_j=0#{Dx) z-tKDB`x%uD&Cl;6U&tygC4Si5f+ZSq{@VYt(zKK|l4V5R(Hl7D^ps)iYDxlT(@?>Y z9~A^3fG)QDFEt4Em)RV^$3=5qLF4X|DeNNhcnAmh+uHfQHhkL^3N#tzaL|7Vod7S9 zW7WaOm5*axy5yR^yyVJ*5(U=v!<<<%>bc#UJo_pq`}%>&S>ECh65s1Bemh26>xX6I z`zdm~`6k9&YXT=HC$9Z+z`&xSTx#A7Nf4xo|1W{^`4)L%5qsNgCHMS%gvS2}m&)4_ z8RUt)v27T;=Tr8aSB~<(`lK>Q$lzfRdiLLnLbb0{-9;p8SvF-2X~MvVdym{bL}IwM z4Pp@A5A}0f5+r{=E&OnAcx!jp&!}Qii!gloi}sY>mx;kmV1O~t74x1l>5x}z1+)~8 zl_b$_Tnl}csT}GVdMi5W{kl&Y{6t-{F+lyF!EHH>{lw(#VUW!+Rr4Kgi!M;U5>t~g z>sKH%HtM~bN-SnH>uo`^r-!4{M&lJU zTAuw;N1Wd2SP&xvIQ$o%27%_An=_{Kzuqd4Gi&|mp>j?wYkJy)s(T@2n5Da#e@Z(2 zS@M}f<0+vC?g_G4Zpi0!6~P(TVLO-W#W|G3re|n*F(m**wc;A zV9qk~7SAEnSj+wy>qpVo1=&RWS)Nk4OFharW>b;_)?>s^|G#<~;EMq?R|jEt@2U_W zOIlYXrAX5}52aYySdO7oU`MFCS2UQ1)fNM3-T}?bv4-)M-;LW37EI{~9`znoviCm$ zA`N#s$U#q$e5aW);(|0e>6rt^b3{ed~v0Y zt12brA&tB!ImW3`oIA?>%{?TG-FqU_DyDCC(mo#7@s)*^1!OQ^#$2=^)2A+ZKEv16v9u zK1BzxZUqIXylj}z$-(3QceZGqG9fg+p;T%NcXg@qs@$F51Cb44*&~6s`ypd4YVap$ zV8*!eB;zkNr*?p{&an?@MFgM%X5#VB76F*V=n9hncO-Q+mmiTqd3k+v-X3%N&>jy@ zNO;N@|ADB!D~$ap>dSR6x0-pB&dpecxX&AupQa;C8{SvFE+Xjtm9%%_rJ?^QdRzAx zh&xJN-W5bK{INjr6)k}ep;v|%OopbRiycLjy~le|-yA|e<1a&T;C-CHF-o#do84#r z&&CeGpq&A?{Ku<;d#Imcc5T^482+JV{3RwE@00BZ*(}etn+;e1-Oe4`BnMb`)A=F` zn!=%F-vvuSunRfIC0rHqzuq5a1-1*!TjBoYbF6+{6;iz@*&VM9gE`XVVa>zi!M6@_MHhz=a9f!{uiH{J|k0 z$;F3AFW(QwMM5Jyv1Nb}_>*XQ`fxsE3pw9P=g{WVpO&8ftyG+Su95Z^ z98oC|H*XiyQ?l)O{V8u8)v!7UG%_46wDjxwzz*Vt(xuWhIoh4XI4vd}2hf7s+{N3A_of7NOfvs8&I^r9eN_m!2 zEaG4=8IPHFo0x0+P#4Fj@PUUXo3Z#mOA_FJ2ols;0CM*HcHIJoi}(r}*l_9?5QXh~ zO9H6g=TIm^lxfiaKf6WDZhx*A3ZUx|Udp&qlYt#F^W*^71FN6HKVb2Qk)MA5Z`bPt z*kM-ZQ&Q7^4!XjG|30}qj@GQnfykh#t2HacX*mU#w>u(WH|j2YgZP-~9oBy z7fB%W*S84rwMeBJaL`>PY@jP$IgmGJH9eX1ZhY`lq+5ySnWM zrIe}gPOUE-2#zr2)-@8&eE7SHj#TK>X9&{UfQ;od&mG5S@S}LRoaC;c!w-HaH7EF- zB-H3wG}OzSp`-YM;p+2C6I9OTJ&^Q*7xtnL(%Ek-S^8;OBXo!9ckyoBPvEVMm;13( zQ3Tjg`(!=UgW1?=BqV43L);gXveHP_2uQr|yKy-#yh!q(iVN#s;Za*>x1-`}^D$dU71W_04asahR zbH@GdrNBUj8wVMmQ)7$h-2kFNZx9F^xr3TsqUL?#-A&jAmQR%Yoj5ZCn`; ziT9)^>J(xWJat#w<7EU?nsXk?-cf>*?f{>0g_>Mk+b8@=N=b zme_Sp#HY2a1lY?U+e8cW*LmNTyng@XdiycI;^t$JU)lWe@4`n)Q*+$&GeCjzX^;0P_4KI!(v5zco`mVl=# zgva5oEkS^Q=rZFLkTgqs;ro0RD;Cq=Bm@|N9?-oKs%=x10Gi=ODM1Ml$jHQH6#W?_h5N~e0^A``t&a_- zknSMlEU={{8&iP`QqqQ!Sj^x)LOc6mo|OM)G~PG93OM(bLV98jALE z0ab$Q?m)0Z5v86rXgsr48HS&mo9gF(av?s1Pr%o%iS1P{AD{`nA}rI~3203`1wZf4 z?8bg-qf}f7pWbWE$rWAP9`|BufHs`ZxikhKG$cvkmu*~!tNhT(-h%7T6crtgHSIeV z1DN)BkEagu)z7DJ=p=gvX7`Qsi5h5buK3C~xt}g)#@Cu<2$@!G>2m=$j<|Y{NdRMe0k6z_5AHNrCnm>B`SH{XD*JMSxj`FtpDBnY9cTitEKVb3S~AgxV}$0mnGILzH^3qM=Q zT5(>>utT4H+;_JH1!lDq1_AQd#bky*+?a zp;IR=|5%)TpO_BWhn{)3PFnG|n!~Ga72(mO(|zo>z&pr2C_jSFl*X!|ozT^?*JekDr4jT<^bR{!cOy08_ zB5oU3xoo#&(>HLJS+F&>@mm$anNyovj&#JwKUC=uq>cC$I%1-JTfp9Ago}CAj0ocJ zNOCa_v3SuLBedfZvPrBbUD#{sjbDx`qSJlY{(9k;(&4%q-HywT`yblh^kCvB1nXA4 zPv#(JpNt;_zHA&opx7nSO`?y4S##GMGMHd5!w*=8_-mK}y0Je^r@B}K=i_Uc@S2Lv zws^uJlge0su;V(5MsH4yxOLF}uAV{y%mEfSS#L3po8ZNL?m;orA@;21HWll(R@Yl- zTx(#}lfL34EEWp#s@vi>>Yf0xScwEf;q9U(MTg7~gz_exnq%{V@}6SH!dB^+8^AWa zrm$m-u;Y>zF;2P9m?E4TVlPfciWk2^=H4tYZIVQ8FuW!%ms7x!?Pkaf54i29Lr3(R zver(`;tve{zR{Eq(f#7xYC_FsexYyM1eW~FMD<9&;LFm#S}IPYiH zuGKSW)prn8vWfA+N5`P=uJ+B);uc)@?gvRE6U&$0HczgoMt&-#Wxj^ato>w3SnBIL zI--ot4H2q1p}SkH58V!V@@@V7`CN$+)xInE!$VvIf>ZtpidhhBY-vfsU_D6gpd?t>4>~& zuT!e{gPz&x%lqmZ{NQSGSp-^69X|B`jfFR3rZzk)YaAot{Igl;`y0oMKXCGGzYcM0 zj=e}Nu#F-`XJTKM_fX`7koH^;RU4`g(j@POu%PCeO}!c}#l*x-UxpjxEmWzIki5*J zf&M>;NaPj84ZGX4ttdzL-aSRnph%B%d&1WOJJyy#RGr&s&55ksZhBc4RJeq z+0B=$X~~?r7IoxzP;LobO169jWhG6afq4zwDSB7y>9;$^$saF29SwRfF%{VPY$2;| z`Lk#-QlJyh|Li9zBD-RjK52+QZ1ynQPBp2ok4Mtv!yC>l_$8rw&8~7ltwQnuQ%pGkYVpjx)7b%CNn?kXIv;6DV+-@H$-z4 z2$9Y1_|@v{>fUHN0dE)`zqi5VjC7Q*ENnVV(qD+Nzu_YKKzHE71u}?Xk-@I7z!vT( znArV?2#e!aas#YR%Jn|_wXX{nzeg+SP$X<-sq>P|UF7_{S~|vHgpt7QJ+U+V_D;cU zvgKrO$VI;K1QQ%Iu?_hk`1HJ&j=XyPx}}Xyo>FKp@%EJiq+YP9)!w-|qQB5@)~H|j znK`_)=iHR_c588ahr4S7?#5(HfJhx@vxo)w`SqN~*yAR1X@4VyRa_L8?bH$1){Yxf z!OyXi(~p`NdcqUe>ALsyF_X6)>-XbR>gRHe&YlPY0~`&%CxB)dIlBc%o_z+Q&jV6eapN3j^BN zbVSPY)UkV>fgDec1RD0v(*<(0PygQY=a3{AJ40Ju3nYGd)e^P?e*qL}E3*_L;V;g8 z-uk3O0qgPk@!0AWEpm4&v$1M*F(@UAVp}R?#hP|z{%QB-!P{T1w@g^w#h z$|1-1YVqW?Nck{dtMti|(Ou70yTB&~-|fqy=;9vLn<*|@wzC{oj|Vf+xjyI+-zV)& z_{C5*91+n$EW&q#o82%j)o%?%t*}(Qw(#xpREZy#uoBKwr7Adln99b}6U>JY6}K>A zM3QpVk})48{hQSKD52%Xjfub``g+!^dh3*onVb3}ThF{~_srl8KOU=wyDZ#&wp#p^ zQpo~3>x?4imtuD^8{-&MqgT27k7FeF`Km1U6`j$ztw+AiC|^emZ++k@7m~vK2gFz9 zyW(BX0F{6GJpFhCNpdK`5_+ugD~K@ug?mA7ia&GIS`yiQBj@oY_&JmZm3WwXeUU#N zf4q6gyoDWM$`xK$SK$DYFoC%{_Zh%)*MeRfPJUXGNnWK$JwXE-VD?k|(Eb|J+hQ#k zI=$I-zP;)k2G@=tu)&FoTGnYK5tw*#aYL00#veXj1=3iid0`BaHLP3~ZbATKh!Dy2 zH|ox#z)hn3B!8fB{&j$YY5>F=E1>DHqeiL4cY8CUg2QVv;gWdGi{1 zcHRhqlN!vq><~vz{#1RD#bUrV_nQaC^xU+HPQtul?y<$QZwnbQQ445BY(zb!Z3Oxl zR_k?C>8T&jGMEwUSV^4OT4Gzg0{BgV3LEhzj{L~P9u=NMUW=p2=K}5g@?2aC<=}*N zkoVYVNz{KoDmR7--Gpl&!gNz1oG#n;7<2_w{e>UMP1a9=zpi>fvOD894Sd(M#~|w8 z<`Z$dh@!pcrvm~#N1zz^hL{fjQ)Xd{{SS^SCw?-d@)m$641p)_?q(L#j!mV zaE|N|^?ZpvN=%6nuOp*EEGWU5*!!s+(1^yR`T85x!zIjNZ{sjOEM{F;`gWO3g;|XF zs9+;KDr}Wp8A4`Ke4(s$E0$AXQONH)hqe*W__s}m(w-4p0D^>u!vFUw87L-L*(7BV0lr9>woD>uHngmm06<8 z$Ry&VHu2iq4C!BIuAikB8Y#15*bMWx(sHI1Y6+mfS+kt~+*m&q&;L$&T1VKCh&=2I z$o5{xPe!|7s;xI>Tle?dRpW{YJtnxYLUdsDJ%YUdTr<2eghgd>9t9$~jf}l|x{H%; zryilPp8oUVmW|}l#vJujJh{k}7H1wi@wEM(X~lguV7MC?yXVr<+a$!Q;nu58=aV^D zCkEE*4YX?9@Ehn--F&xeBMv8}>OLw0yNy_cnh^vlK1`6EnfF|L{Pea-MqFc~x--&V zR-UhnqAU6QR#hx(@MUJjmcruEy_-DvWzU4`Y~L%UyFH&1&u6bisR>6+_GE+<>_ObH z-mM}pD*Z=KSaf2wsQ3Ij7<|xH^V&(#oO6-{mIP;k(}`3%4B_w74Ox*tX9O50z8uMh zJxzi*LKR`TQVk97v7fTnWS*OxkCr;BAg_Nxs`luBSm3?ZNj!-~C5$gdCm97VC2sDe zlimocLZWK)+(IzvWf#%S%@D=6%twdonQpEVm}O7|&ZEN?ls3cT%0`~4&u7^90>1Z6 z9>Hjfya{y;*fLjGozI{7CX(5bKDjMiHxqnudRtb%U7hX=ek%AXLtWjl|I7(KWT>B? zN-65RX$8z7!(CW)BTC;}wsP*!l^`$$K?~yk;%Utd4Wf_ns7P$3B*hd$PBzB`0|8o5 zL{DYj_%)b%<*MGkOToCUeyQ|!!-klaIUfLgq>m(P1>r6LyhYF{{D0~oDf}huQ~mAl_UNdjFHiHn9x13Zo5rE zJ8N$;aSitU(_3Q++a)1M>Y4iHPE)IKY>Oi8RYl0w3T9^&6KqH~;7;uOp@oXi&=6?x zaMfZ<2Ajl6NNWeKhTDy>k6Rwx%`7I__Pw}j72~s@Y)GJkfh5QM->M1ne-o%%2q!4T za1UxAiUmOwFW#VGjl_#`kBy6~Af1EEMw$@8P;YdUJqFr$!Bhm~92tW`hxNA*Rk0og zk)`LJ5n?xow?aKh(9-rn{8W`LMk_7B9%^ndIBSyd?fyx+eClw= zK*OVA1pR3)cl2r70bORAYzJcGz^Q7Mk1SE|TWFFXrkJ3Q}edNzz#GYxfkl6;h8vN6`NYtsd! z$=4@>6f0SxQ9D;94q6vVwtp3t5ZY60=k?DwKZ9F5n@7}fbRoBoNZ>a_O1DK!tVX*{ zY({%NHT}#CIB^5DVJ7i;e#>+dWn#Ml1+Yb1mg42P?v>SFan=EAovbZc`Zvm()Lujt9V&+&&gUZ_A)jqO(HoZW*bJI?ejz@OR1yTffx zbfNYK;89773x$xv>OenO`EBtmws>qQKJd8=G?VgfaUlmfqCJhAFNeZ+5H5?TQMj(k@hELK8}2-#mKn@8wfgbNN) zo1tMpJe4rIQ@ymJAzW=yO(LHt2Af${wmw>ZWOSyxgV9yp^NA8YWYOY@Iq59psrn6* zu_>PqYw^3dNZA}%x^lK;lBR^@q1Bbe@Cs4|Zi=8X*w)ro^5mP*Yj;iD$JBPxAveg= zxo>_GIhE42)DR7-ws5@W?%VtZmP4;Ebgjc*cb}F>>}5&P#sL7g)U*2zC^R}_h7?K! z5%l6`FA}GP_p;D86&KUNo(+UgCF&vx)#nns<($*k_mqZ+NU?BkIZnD%VY+~^YWks5 zXpQwsSE}E4h_GLg#*bN$OyAywX}qUu;-9AsTQ+ZGZn-w=*c`g^Hf6fN-h>xakOR$XT zxA>|zR}o9yF=?x(HW^?td;XG!aMnMd<)!7_D&O2mlyW&Zktq_s{)>vbWaZlX;?EyU zQhLmxjaEvodErV3sZ(@*FqB`sQ=@mr#`*Nc@xbCP$G^HcHrzV zFno8guxp_R(sm;?RX~p7WRUavGRib@*Cd5*)kNlG@h)P!Hx6FUw+J zx}GS0ufv&-E6@)(>Po~{&tf1vkm*Vz-c34PKhy1-=X&9|Sq~`voB$+3CK4p~<5Yh= zP~HgjTR%vtn>$mpWc7fcvqX1sh6s_6uOI(V+~2;HNh?jSx>KM(Q=WO?JZl~s*NU1Vh{V{@Q2 zw_qp;P>T^QZ;OaMF_TbdF`94C)`G#_&ZnW{>-AusNn|C)qYR4yWoU;41(h!=&e zx3%h~=?U8+h}Pu`g@d==Zg*!TH3^0*DP5xdTckRh`~I%m87FDHTGC;G?8HB~IQf>{|S6l{ZWACrOQGD&{1;$Mv z1O+wnOS7nV6==9M*fUVe!VgjTJB~Yuk4#v!b^BE7KWN-Zla5AX0bh9Dy-w5~+d$kU z-tV0?>XPlWjO^c~)PA3kVIfc-Wcpu!>0{@&I`u`2MG+yCGw(GFfckd=HO4<0Hcy;6GKt#`r8ccc>(+LPAATRW z0#7d4WjXnmp(;VG=DNlV(!Cp4U-*aa4mvC$UEYJ%hN`+I z@fJR82cdpg0#1>rGm4N{{rM1L*OLV3cu>k;ovu~_NHMs5Pa#b?2Am+WJZ#=~9og_I zom?kqQCp-PW(Lk45d!&afe%`l3||Pa5*>k@JHe$}+T@#P6#vKrV-hBLGUw^^mFX18 zYbacJ2w66zqoWu2(Y*Rcmk>2r`oMbVNMDx_m=!hU(JbXJ&a83n@*=U*VC%3?XX>cN zwUa8xhT@r5cx*+FM*|$HvowKMOg=uRXLALL?yxO}{$T@PXe6FE_6;X^)V!mF0Z!Wk9|K|Rk zhI@S7iq&g3IIoueA?kUt@~yVz!9wdaVMY*m5?C-O<1e3~r)ediny+tr`| z#FOLe(dUnzYWi%SJL))0rB-14Ol434PLp>U|0Y=f#j~=r@O$??uupj3XAmpQv`D=3KaV=1 zNoOIK#uFInz_PUA*zF(s`Rt}j;D!GqVgDQ_?YvrinxmYontXZ~R>9Xk(B1;Hk~R?8 zr5gF4S4=yIVXk{1=W^xylWz-KkEX+}qV`{C%BEPm!NY$kFoP(2U~p&D;=d1nLO10d zmE;NCbfM5J1JOW5#(}q4Nz2pG_7)8dYG-MlioR;@?eC}3h~#qaQ~!hI{^uJdpMO;r zvjV#YAmLbQooXAo*aEHBoGBzXQZ!|`tgI%t%v-)6e}1JQ>=K9Ppe70hRS+%y=Q8xc ze)abD<}NomRUYjsvr5bRBIcH*Yw?JimOEYb6<^Lvp-}2&bD_@oLaryZlT|LS@_6u# zquML_=@t{ke{_;%608~qV##Ve^WuF{ug)E_8_-RH7J|}JuY=p}9D9^uy^89}yBzzc zq1t!WmwD#Z<5TrMKJt4C-6ss$04JXU#l`h?vW51awK!u+Zx&4hdd5~eTN^FN79$S~901ClQ^g97_|L7O1$e#u zL@fI848cKu`~K=!CDXYU?&i6<)0+p%WuqVKjy^DY|0k=3e2Oy25Tq9hI=mgZiCv~i zw)5#(h`gM(^N+kLb%f=I9#}R%IQ)cN5NhGgIUX_w)C~Z3th{s1=(FrM9hZp32=}ga z`>(%GwbsjF_6Kj!gEUgdyoV^qQHzFFIbGJXizhd`^Prb_fn1Ki?idFeszcwXgmP53 zL}(p{Z~m&Xe!;$e`X7!5b^UB-tIX|Bcb5)0y2>>60uU9@wLBm;0I2Jm!TfKe$Bn4> zR|WyT_+R+zA4LYppUliyZ*T8D0iuk*(}Wh7CYr~jNW7ked;j9{Ji_iihS&|1h1SB> zyRDEm^`bEr(<#L-Go%6ihP9!kR!2NQ+!?d`+MDl=V#aMSn5In_L(g5_DMb2Sh;MN9DY_kEXU4QEqWoUN zJK^eGHX+rnm2>>w+LeDPJ^6o8dZkEtvh@Z4TL72&m(u%huNSgc$6~{c;T1qO$JYZ& ztJ0cq@%MhMDWKkDr>G=#>tAYSM^Vm%jBKKs={ceS&Srqc zcDxELb{}fMQ$$I_J(;(~I8Bo;xO^zse{?cxI=YV8|AXVex+J?D#OZSdk)1@TM!d~$ z9}~ds|G`xU_*?V`5O-sx{;hFoeqo2 zhP#8vYx+dW^G-g?4li%7&^XoSU^2G_;?wR|bfLno{wN-^JQpq6$o0JC(gA9Goy;6c zc80tGRvqf~7vW0{Meh2*Cq(L+%KN+}fj^;!L57&^&hlWteShm!piBE+MZEAhx?&V{ z{%@#1hx%!c()H`xjc)@IpE#^{P>S9@T-TuwFr^h3sKiVFdigJuaHOXuaf8X~K*A}^ zMDL1=0dGR(!(lyhS)eQPSA{#ZG58Oqb~Zm9*in!4|4`3^wA1P1%NyZ zl-qV2{C*zxf1*RrUKwJ@KRHR)=-n%<*J8@5B?&M{$vmF*9C2+ZWJu&E1HKD?*Ep@) zn+=-Z+eBTHwV2(`R3Pg6n;42{Z@S%ifqNFkyhuk&i<`sh&-OO6w63Yto?5weOy#b0 z+wR3I@VWJr5gi+vh5BYqc|v#LM|R4cp+6DG+46sBoI0V?CD8P=AektjgL_DIzLb$i ztk#n&_icE2n+G!qVySwOt5YS`m)(4Xwsn_011RxSF7FX`WM$BwjnIc4?^G8kQH{*h z0Qa8%h;5K({=Z`z+Hhb}L)hd(w-omHTmTMLNU&X=xqSCWS{6@{dVrmHrJZSjk)QkOhfs^Uqs)v+jk z*P_?iVkb66f1_0oOcpV^Ik z^{aLzmj5g2(ssN_bjPE2;cMu=8ACuUtUH@N#WG#gGavFKQ%8Vk&ml{95Cs|R)sV;z zfWozX%-*uZ7a>@)d6^p*8%awWRLo6XzIfw;b~OlAziDaNnA~lSn`76X9V@noK64}a z{isHtl)Cf}3#B zjhfI5b|smJ>z&`8B~`AJE;TTD{{r8K;QLuVn!koZU%-uZ&8(JLgySg5PByE$n#<&_ zCk?rjJ-(ZcahvBfv6*QKbGj8+5g>-_qW&k=JFO*1-^pIL}@yKwyco%h6eu&lH=B%g2pdE9H+%;rvw$2Xa$rR}+J zG{7aY!-%fNh+n`s73W{X}v#*Hm^l_VWl9+_zmXX3@RVD+cTmP@}J z>oAmwH`21Wyg!$%+BdNarJo}M`xQ;b?&ne>R&?B}_|Z{+L4Zu*~ z=xwaRaz}PT_vdN>mQDVm{g&L!hMW4TVYO>D4CHEi-F$zixrOBVVs?Dngx6&3x%BGk zFRqpmK|vI*{4n5nG7}WbG7StKteU}V$>OOGIA3P@lX;y&%N-}eN-gOY9v-X79+gXh zylSVdR?pdGLiQM9B)>E_4^JbA@;=r7a^eH{*dI8E3%%c3vk}hgj(2r!PeJd`_m*!= zdTwCc`XMiN^6f!h?d|gn={^mr|IVrt`*2(2&AYtYk;)(Rbhln!yxp@&tJ`|-(FC;S zM;or(H4{5no}f-Ul}?b`>?mlZF8gozWx7-RlW}<{+5W|AD&S(A^76H(AT(KGef$k| z*Ym(mVJGS4#*37?9P7^jdHTgLJlzaGkQ(AIVLp|8YQL9Gb*{*=?EaA|m#OfOjK{13 zD1!T+8Ey{^1@QTIG@5?4IWxH*e(_y(G1o=px~4xM7h1zF%L`_9^$=XX%bn%6R^K? zyl6<9m(KK{aHT2l^qA*jVxDNZB*7?u=Z&8BZ;=Yeut32ZvQnuO(WxEfd`BhXRmVao z#-i27B80}`!57UB*l`6a(?v$Bx3ZB}e+Xt^Kkm@#hGb=V$CWdmy3eOI*3)`X7;!{) z?rjolFj)~lc%8F)+=D@$uTH)DSX#Pkz1h8-z6Y~SfqY#yZ&hH?W*t%tG|5_$tLlhz za)-=oh`UqL7m4lQy`8Tm$oQ|7XFl|{;K=2O_&O~$?ul^$@jW>?!}lahsYI}5rj6I& z{L78RbX4%yX1|RUb5tyli4%TRqZ_v}_xxW2YE?>yYEhWO9bd?txs| zCF($$EH(P$+_bk(&<>>u%fAxNa4=ICFLO(>o4J}7C7{uJIgld6s#lO(hW8yA=+WG8qPammFKXc^l=y9W zt&2(UjFse|iRBNkP$62*C6mz*mU2mCNj^jHzH5Pi> z$RKqat4MCsEaBz`jWcI*MW*@(fQ=sRL%C%bUVbtnBSV0&q>pL><;G(Bt@(Dufi$R# z)O$7WX^_VH!5pUfGibeHrC;yoIyt>(_DHfx(N<*UU4R3Y-_IffeB8$`g_zzl4}MvB z#?)G}QO1ugd4!>4M4;)UUoWp5zXz?<+_rVX?%M|6Y1VeX2Pa-0!|4MyH$bjhTaPUQjfxgkfnw8f7_pITPhE#j)z{rE`%J?R_u_gtH7 z+ILvQAKobWX%RfXYt!Q;Q58{=fRCqn+>7cUtXGq`UV6}^-1Ug6j$sWJKaZxwR6T0W z6gXg4-F+V4C`Cja1zsIVT{}S|9=S0<-uCg%=cAyk)x;p#62@f_xwA5ijS|Ux(CZ{O z5qZSwx%D(_SJOr+Ov+eEz{!`8Qrt7pZO+-`$OV6kJfys=E_`OX}&-hUqIjwaRuP8Wd;p& z3^aA8QkoO2!MHbdVwI4mKOWT}Da8Har=Spbf|1end7~T9R)!av&T9h6^@z05y}y7u zba(*z7RHEm)n#yv!N^G@=5rH6F=z*=au4r0@cX<+JN!D|>ybU)#ca%%W zFH~h;>wG15edJ-RP0EEB{vnGVukTMGq047m@sp6M|1=TaP?oz!bw>Zv(&@UTSl1?P zk<3uy(C-Kq|3#_~AJ1UCoZE5r*0230KU?_r_)TTo_doa&%qQgi$!@0mKw0&54;JC) zw_&IH9yg;wQQR|+d#6KNsKZX(;CX!me}@VE;r2%Jb(*R3Def)>p^_x^J!Dsv;c)fonJAHrhG(4OB~P@8KJGV?B^qV*RYIK4V~$Tf@3!v)O*#Ae z`ts&iM?O<^B@e@cYrQvY$nnFLYNp%IBMRFG5wma-30`M+Lbv*-K7CxzeVpWHzE8hb zTe%LVe{p{Ox*y>$Ao=Zn$qzX&D*U*cPgTX57v3V&7&Y#^JW8@8pWO9*!oI?;;Rj;; zF5-mlgEClLiNxL4T{DScl%IZ)7CI*_?vD3|U}bqeE|45v84>!b+|4VWr5E1vuQqBN z?y@83e~u|O7UO=)aVp80E_X!zY?YGoMvqbrixEO(J~cnH@n`Oh(g%GfT}PY37~JtL z)u+I8N5&)m#57CYu1(+aGh)b7D(|*6h$JrI-hrHC+7p|=>6eM^)(`EuRMB%vHBUxO zHo|hJTHh-MX=g{WJ?67*J1rb@R)^;dhc?d{BlRd_17Xf2ZB9 zPD!T_BRWG^R3kIT3G8*#G?FkF;Ozd*57gj-8E$FcSgYI8liFdrQ z^73#6Hf)v>FL9L~JX3|nZjURUO&J%~Ot~A_Gjh^$@LYZ_oy2|FOq(+^Dai#>HS;TT zGUg8zfBaliLj&wQaX+^Pg(bef{UOS~{Y=W;U>)HQuR0?CNPU1(hVODg-uwg-ziL|d zK-vO$Se;7mngyDc2Hx}jA=M<{>vn1q3fjY#>05*k7Ml2VT}XR`mFjAm2gA1)Ddh_#GkwLLXMYrAc zbAyfOh&}qK-J5r}XjV~jX%!^{QaD4^^tGp>63MK=5iY!z=U(C(fy-NT{+^EB>=Zb1 zX~9|l55^unsOx9O4bEfp2gQ))MK;;kEXFL#@Ut_h27}u#mi;~e)IiB|t$}QIn?h>O z<-Q{o3Zk(;q@I?54|U}oraZ@Yz_Aq6*>0qqZ%uW`C^*j60qAwAemVEGhd+R67CGyb z!`{SLcYm2i!ERIZ|&l`}b-g7frCBXEvjzk#FzWoq&58TCN^+pw#6h7?L zVtAh*CK`pJ1T9A*I&(8?H~_5=3&cD^GokSl>$r~Q_-Uo#0J^axSnbCBmMbip7l2wcK^)0XyUR|)zBq3~N` zHMO^!EnRpqXItrWMP&x0K__IU*01JNi}YHEle2{E3=@&6%wo#w@q zcT?JNUxvRjbA4SssSt-XpX?153Y>a@ZMtX?$x;VVc`rxh1KP@M{+5Y+5*{FHbm+sK zVqC5yvcUSYX8*a5@{Dzb`E(C;*&*|S>44Ugq$1On{OGIx)py%mKipEb!Hmo*aOZK{ zjCtF}o$05v=e_4Q8C$v`O&%T`R+QckRpa|*c*c#2W}9=5k)M34^<@3cg6W|Ak1+vR97__Z@MctVCx_$5sg!@@xVG*~k9@j>F)aFePRF^{g+_33- z{CYDmvW>|kEQ-SzR$S=A7?b!JKS6+AUd+^75wN*11**3Dnp1*3m zv%GjQWtuWV&Eip-uxM`onilB5{O>xzAMN=UBanIgd{t%r+lS>EcS!Nwgf|K^q&ozloRp`j;GT>r9$zAH354()S54PU5ALJ`?f+TZZsxw!*Xs$#M7h>0vt zo+Co%s_*?xywg5@@LD9_RVRmMdm-FslQ^Q>WC7W>9R`okP8rQPwIo}a#eATO0 zT*zL>-Cl>ne>1ehyX%jDdAQ|CPUROUN`3q4EVai9AH3<2s|02r@p!&(K|w(;aKl~` zXfhBLwRD31z@=Lis;PgZ zy$(@JK?z~i+r@1f8kCrx2Rm+N+NUrPPwR%X7_Ek2V6YbeiAdDSupE_s@9mD5gd z#H_b{+oD+vixmvC%QIRdy+52T0Ht(8;N0Z3(*FP@d{6rMQwity9~)I_1=LV)Sr|qI zomw=%xn*`42;CZpoOmMm@=DEYOMJ!34yXP^5vbTy7je`qcD9J0M>^WD|%ybHI z+43zHaq;TQ5mDYX*?VG|O!BXNR{wh_M^H>R`3rE(Z+VZoZk;AU18rYH@Md60%HVyLkFo{TLDYMhUpz5!=%c<7;6r(cc7LFuix3$EeVE&Umhb%bAP)fyqOQK5q$SnFEl}q2+l~>0EU#0#W~{oJG@8|3O2<&S89!%{ zn2F&cKj~j)T$#ZC*?|y2u^)|{Hf&eVV151S+qB)N#E|*%qoG+H+`^alD?YoCWO;qb zHJ#!M^zj2=3ChmT&$n*7VPK8y$`()Cmn)QpGDU zuYDYJb1e$bKf4p~>M1wG{*)jNdJiO=z|&>@F^Cb`dHfxs-z}GTZI!0bSBCTNYLd$J z?yYh!cEPe?+Vl$U4nn{e;=+YN1?-tw6MFEP|5PTgAgD+YVSLb$P2Et|IYz3U3yiOA z%oN7Tz_wr`6g$0F6&nk}G_c4T`X~63PW5;T3GpX9kS!(>E=qHhZZl>SGdjU3%+N@c z#MtH>vTeh|4#vrnZdU%G;@R7GDthrVCiWa(;qSiJ*yWf>Ua|nb4swG!!rH*&J8rp> zSZkiCiI+u|*#C@=AbYJ$rAMfbH$=y@>ZnGhUCyw3p3B3^I&h82E<0SNAj@gMAdG)$ zRBDR?v|%BR>B>T>x_H?(HJ+&F$70$}>u6;9VE=f=)-0VFY-7U6IX(#1` zhasA(A?tjgpGEihDPT|_PP!ZpGqp`qXe)CIwws~Ji{ek36~MHCl|e+bHPQp0`JUt; z3@p?xtZHEp%8&aXwV#rwsUtirw@>!BI5jue#)aSy1Q%~6*}!wNUI2rZc832mu~@Pe zCa^rj?#DNB-{z%dzNlOGDwBbezA-y4gwB~4<;JIsRp3taPf++{(Xtt)9H|bH)&$(Y zYf=d;nY%Gu026-oYBwguKHPY?pvTm3m`-T3;Lv{mCI8i8jU0#Xy{vof#@e+4flA$S zvnnL&zr@SiRp3OM(@R=zpn1Obd~&(LrAaN>E-7e$kx!xjlYKE8FKM{wdP1nl-6wZI zO%DAJ%G5_7Ta#74Gc8it0%xDW(bh71a4+}j)VFq*MO z9MM-@+qypD|M86&SOklU;LJV?W!uzN=(JjY%k$(gF7x9cY4=_xTx4IO4l(59{j;hR z}wz6})|rB<+}FAlD_DcvRHgs_6>L<4l%*Ex&Px7C{DvC(_U<)y)-;IrwEK*ls-_wz z_u+_lzf81a$@9#8;0Ty-sJMorPC`)qGHh>DsXPJZXpn$lV5DllFXL?|AAL%P{UH;T z3am3OL?!pwcjkkCu6)v>LjzRtkf2pGMO%_?1S0U7{M+Q*!9+kH2Xo4fy{?2Wmc@}{aTiQk8~;$@e*CvgI*nKKRkA+ zXjo(tto7&cvNhFJQcUb&8jVG=Gc0sZMo^JzI<4>Dfs~KT_3;SfY1X4uw3`wU6nE6% z=dx0Evm)jbta)DL^u@QF>D)b(Hs58@ATM;$#D#ZIVEiO)NurUmGp45ScJn&8x@TKG z`diM9O6YyF-%##vv1tzc#{B`NX>$m_@&GOP(}ryAPhR(4tDYliElp5nt=eRYwrYcKd{r{&SR4)*uq%Lh_$^;fA z%{Ja)+8c24Zm8O*z&232WjW58_P1bLPv(hU9g?!*p=Nw^^zz6qgN^+5CEP6Vf_C_V ztt6lS-*9x51r~?Rx_h=+YNFtSq29?>_bZI=o)wNxs1L|=YSJW0-A_`}37Su^HG3tc z&OIY*^9~g+)&9-?^xz8n`r1%WIFV<(u+{~m>H3yy)Oo0=oC(4A>lvgL$dW44DavCv z5XlrM*d?==t+JT^b5QljhJd1GV z^%`~pD^qETw8Saub~_mb)x<{i@F20=5u@`#-1hHx6Qa^A&oBXN-amb_s)zCip^gC< zh#yd;F5~8f*4ZxD;>r`(t72)wgLHFGZYD>mH(y~9k~(nle%~W;FI8%FnDK9<^|?4x z8vS3ST5MLES97F$nIB6 zUzzLndsh!fe|!J&5&bhTYl*Gj+UHtMN6t+Ch`6Hgobi&LG}656x|(2Ha1>>iZST@m z$rW|Uu2b!0C04;WiUFyhS6PS6FN}-z>uSvr{kskXiVOgu$+!0QvNA3;Cb$#htUevG z;BZmAk)?(*Vvhvdo)E7MzTXV|6c+r%ugoG%%i>G7wYcTak0hz@6-09~chvI~-}4k= zyKOmRl8G=boUu?{EE#l9I7O}XYs=f}K4^<0c$wapk&2d$Sg%+#R?PW$f>iYPcK>yF zFpIj+*CwTTHp89IS>kwUyIko*kE6^&ZVkN-+}tvZU~3?tk#MTz&4NDcgPcj>?!z#^ z0u|$-@u407#IJ6^Hv-NEx?eAim3F3+QkD)nL2(_XLpc|%0hP$TF4G<1@@ zEpps|Q;y+Y7aYs`E|Yid$eC=$bOk{{P~!DbjPvg?%ym57ieynEI1iCW8q=}Q)i)&fsI@KdL;hsLhA-X3_Q7_ z9((wx3RQgwZ|d>kwtYV;FBTejg0?OCj4^%VY1>yejJJMGZi{FIS^!nMGQEWADcb4k z>#?^3sI-6673qIm|3w14GH`iYn%j@xpSa3HMc-R*p1!L#LWK*JbA!9%$noYmma zd|%z_m{;+wp6GW8ElBzTk%z;dTt-yexPb!YdCvmK0ngu3OVpU32hEU-E){KrRLF!{ zx-90qhKV9RS^Vh;wRBy@mT}&L2VhCbb_Io(pXY!Pt@U@REhO?leGU6Tpasug7h%vw zA@J3jd#lu`*E*ras;pGhw6azWf!`or|1=3sNsXDnV6kf9E&e&CAO-8VLb}V%RvyM= zXs~bF9VJL3v>a>vsN>_n+ecHLWHC)22E!0ynR^B)XPP{}Gq3Pn1QHSyl;WNtH7886 zOGz0>t=(ur9qqg*_!~L*7LVw?>iaoURti`FAEJyjZeK7VMu3K<3D8+R;KOf2nd~U| zFtsC%R;R`!UCGJ~rtm!=E~fe1+Te-$Lt1WImr~RSQUA;`sqh^Lh~Gi&XPk)Id*xNE z9_+trp|?rzOeLDgJf(jRiXO&JEzAN-zd{{6Q8*N)e~c8hakQ{|l;56n?^ z5jt8%`-VAaB2(td38`GSeMliBe^z0nU_BN1nX}}xJXYnTGjy%(5+O?}<~$TZ<#C-Z z#PLgyG%G^jBQ=6gDw7z&7{cXk7;uEbol3eXn(LVf+s~NVs zKJmL9B*d--AA&|I?*ueZ1kyB2oA?<0Vtz747*c13hekddS@Rr4TvrloBJqZTSy<$Z zGjVkcZ6Eyzhe$F?x_)L|seshJPH1Nh$+~j1t%3iBC!Ok5sctUO4q=TA*0+u-<0?kA2x;& zt;i>PA*mo3_K$o#{Q@KbD&Jzy{6`MJ2_^jIK_pc*Rv~NPtHu>RmMa42vR0W8{g*Du zCYtw(mv6Oru+xIg8*(gKD4&JlH3g$0aWS7}&Xo41CJ(laL$muxOd314tgw`0vVrhm z9#y`!9v`=@8(+IpLG)$v$2IArGcFUnioY2s z2rNRoiGrYm9|AQKv5V;2vGL=vos8jXmP$K>bGC6aY8Xf{Zp(&;g@RJ2mC&A{qK4ED z?p=43+;?uxv#qDmVX30h9i-r_`QY1!xA#X8M;(XC<#(W(ooroS;ItAW>pd?C5wKb?$7nm3Q6%?29?6OdIurY)D3zkf|*P-26amRr8Pq=&Elm15L8!(gWNbC)l< zN8dqbfmUC#b$WwcD=mBJ5C0!s?*Y_Q^zMs>4icImT|iKZAfXD< zLQ#++RVgA}KsqR$kkETkQL0h|1VyAuhtN?0LFv6qFQJ5xkmPOr-}COd_nkMBVTPH^ zPImTM-}=h0Trdl)R~>228Ayh;s9AFa(?RA=?B+VuF<>%TmBq$b$(?1AEF&GsVsiVZ zIJp`#>E#_nb@|LUqFbo1@^m19jqMw;UVY9W^4L{{Bk29-jEVStIU78~npuXW@#2jy zL?-I1D;-NbDwxJNMlo5i*x!y!9(9Qh{2yzbstjZvNaCKzyRbt`CTC)r$NM5;kyYw# zG*SMf-h}t!$`Jzs|Io_J09x4^GG9Z!4zI5#d3O5o!F-)Wh<;VB@y=&=!~y#-*3A65WT(^#1qn^ie589mZI z0=0Q`h=8uHZN;ZHwOu)6NR_8n2CY7$#MiPV?x>0Rv)aZhNA>(-1hy2YJySB?&W)wH z+-OHut8$35tLTwB&D+V73D z4X~rL9M~m=Bpg|cZupO6`I92|c`3^Clv}4$IUEYG2*wXK^`C9Z%>cgmwYW02vzavn zxL2Z`N-^W8_6?($1b8yZE|bd6U!L9{B|0nwn0e6kA)rL&bP1e+G*BYIZx0dA&sA#( z3zv2g%iH&IeuT57w-dkjcZV>=S+qNE+*(s{0k-8!#y4l}>z+ETAe0LHUhtr3`JHJZ zU^MGQJaxEz0*B{Y5WVhA|07-*0K_Z5R*d^yd7=?iqdKoef6$q9<1K0D;eZkoBhM?R zzq^GjD@g_4+1>LL9Pg*K7nlPubCqsoZ<_z{F|kp3`hXdK>_6?Tpg-yU0Wpw1r$09` z+|H=VjE9%7CB9b^t6{TiY^Cnsxo7Uq@If_1!b#sYRW<>b<@-Mlsp_AO1;(%@nl!&^ zbCQ6x%G3_UYi;z(fE!*~pG?-h_=zwy z?@dAJVcie_LgEnL3ew%BFn@Bj)3}aNLmvueOv*}|bW5?XmyMVkSJ|o3l(0{6_#<3E z*<8@#zefbfI=oc9<{O0l*iz^K0T>;>wExd@a{fttirKxL&Uu0IF-6%9@T<3jb_!U4 zu~yC4O@C7Mzh)72oX-r6w!Na?RlLU`$F(L3lh+YGKw|Jc4%@YXhtW385+!&7e>|0< z+x15=adah;i2YT|f_H^= zk#&YN5~nmiDJrH)K4gJj-$%GAlU@x(0fNN3FP)U#G%o0cwQYq!eZMzeG6zU^18T^9 z&Wq|_7$Q*2?<dv5h#=Sgl zpR_F2PFliy#kfo51-SW3=;W)Z z#P{RYJ9TKgygMl(h2YG+Te|#XBCn2d0W~T+1h&x<4u{f*H-Xu|#}QG@@9dR7pcox| zJCV>wDsi7Wor@Cauc750e31f+T_Y!N_w21qHg@;p26`EaXS+Xcx~g5$#v2&pTmbin z;PX`VNqj|?!LxBZ}n?b2=F=NHT;G3-R{g}qzKm(khI!|0?{sAvk3DFI6I@OCYYOuR_JRJ>oGm-Hgr7&w~S9ajQ=! zgeHBO)>a}yd0ZHQx1L1z~Vb2?UXum>h400j^P9@w)SR)pN~YTIK+yss)Oa`NMejN1{06K9*(&I+Rc>{@1A zj_6V1bC-?@{o`>t;3$899jf&j&uGyaEF1Y$rk5SSaRI{NfL?eyj;U6E&L`sV6TlKs z5v$G>%yeb-@1x=0#R8-+>A%XkzyB%a{?~5Y3OB)5@I%;yq{MnrT8zHuG$z)=@fs|n zE6(YTm0@Uy=vH>zSh|CU#|?D-ob5o^NUYrp761}eH8manAnR%%rDc_nVnn>k+I?V&t6 z??P|c0^wA2_r~Oqbqs#T(cHo^!SR>+syS=dUv_`)R?t?qM;xE_*{>uL> z`pmldYLuXTT#mI7{oB;`mS{_phl(KIh1#40mL0Cp6NKo)(1+b;Hsdmq-Bj|Yz+RMo z@TE%ZVn<4Vch+j`ZY$CQJqM-!yerZq?evv4Wgf2Ih;{0~1efU#k?Qwnf+>OO8WthC z4DcEevxHB%#Q5i(=@SD4JD_W*3}OXhb*3O1xabnmjGYoll7QK;e_sddUS1t=!Wt$p z=@@w$dzRtrueeM&#NZI3PLBZ&gWKyAVpKWwS*ttrmDXSxJpI}&IFbAo8~Ntg5a{K4 zy_Z#|bN3esu$b(FQ&z{Qz#4o1J1M7Pt*vh&#BADNk6p_7bIbkbO}8Uo1_&b|9O(@w zw9`h2?30w0_Qg}Cr2lwk|9iGWY`8MV(matoQ=77}#e+}fYC=ks%ir!X?#(4ClE2s< zYFCf3_+AaJ7K;Rnu@8VK?j=u_GI2c`HM}7UbkV5j*=fAkIG1joRxPsHVR zsUjx59)-jf&m2F8I-kRvq^F4ZpKmk1{i*+875oi+@`8m((s0V;@3lN)J-w+rTk(DN zR&v9qs8^K8Wh^T#s~CWCA_E%LvJHg0m@5-ChWTA>_XLyjX!u=;CY!an#+Uf5w5Kk~ z+5r09fc)uJHIU~ITxoqAgS``X{X}|?h~M#Ij3803oRz5>udbZ0_6~EjOLnx&aYQoVk118xnav1)QMcp$2nU>$wG zUcn75pa4{^B!Cq6wVXjp%K7a7*r@YN6RgU$e(o|jer_cp?ZxB^3Gnfiri*4~zw3^cy#~AY|R5C3cOq17W}OWiz?zB%e|YLDIuB zNFd(@(wq9J;}m&*X2D0(Opo4vS)zpQ2~{P9hrhyxm}%NdkqJt_3a3fTn$Q1A-Tm-B z-6P|B(WAf@c{*?TcZ}4!0yEn%PPg+irkssfHg;1}Q`1l^9dJ6;KR^4e zh3a-N$Tt=#95z!`Ss*)D0mR!4Swo51O~hg&gQ6G0w{=Yh*AyO!^(WNgrF`0u2|LhL zxDYn5_(|{RQznf_jldtMKH%0EG>PpXz$^h99MZwP2ffSdl#HL+K2?E7Nsva~C#d}} zA&Q*|BA*AgE{C!pI`6U_tI@Y4SkDfpD(CU53wUy64@A*S)SFA#Ns&>4JE(Q{uu;0=a7V zg1-Y|q?_bp{0Yoy;8GW8E%JSiaF29KWXajv^=9_2>n9BF1wEhuIbSP@07N1>6CI$Q%7R8@>2Ex;8UBh#W?7e;2*wlDI#Imj?~t|Xzsk18 zo{tXQwA-2Z0uJg;PQqH`i<@l^k#5L=#RSRwF}HpmOIyPX>3HAD0J#CB^?!o}9d!_L zi6yW_mOVa_Zz6(yLRGFOH{YF3A6@WbY?nUV%YU=HDU{b)1L*sr2WKR!Lng0^IRY)P zBKCo>g0>7o&ir#SRy_!C!Zwm6SI>ua%#xT_B?0XtrYNSa;^e$FA0tx9h^=p|C@vPi z1(RiZ)8KHXWqO+?vg|z^XAKEyX7}BgEFio+7mMT`Q=_#+QUN7b!gC5%-%_e#8g7K9W=WL&$r$Fn|EOt!)9s zz5MC7_2s0RU)>+>(KZqTIdcG1jSTe?rAY1zc1cF(eGR!#wADCenkx?^zh_v>>+#ZLx6sw(Y$O_~=t zVnYF%=(_GS;r<5k1%UQZzaO*Azs)IW(iFsC>XQi(%V5rJII z^9qKP%N6>kt?W1b{0yCbe3yZ-4t7(q(8S5HZ_w!lN2cr{zRI5gAZjAmHPSnssYBy72|url<|+S-5)V~ppLw+Q~H_{5;^g+ zzRDVTzHC;+yi94;t@_zK1+Mb5_{5aT+J1ur z(cpSJCwY#THhR%iDGEjqQ3@@)yb#oRU+==){)t(q7tWE9jB>5j^it;c{SqpJC%g`U z1g$S7FuKw9a^alyjIBd!YeUUTz2s-ifA`4d8=KgQN(<4CgVJfExh7wdLFkFAly=?E z|BA1xw1+KG1RaURau4$LSAUnHr7sYEbtysVyCN`6UJbWCWsMsxw;XV~w&?fM@=^dT z8L8Gw82B3bo1k1OP^B+$Cr|#}Nk!l>1ku5q3JnL?oU2D?F%~k|5Sj61a+da@jtXPU3~Q*YM- z5<1##h-Sbo8R!L1SEK=}VF95%<8}MQ0z`|c;TX>p9Ot40fIUD3m(EN|)vm9D63hE` z3eMxGNi$9|PRM?2+l|HFw})OI4amU*etIgm&KpC%{^mo6X8sQoP{+=007^0mc6w3|pbcG)htid^aBOW{P}! zIJV*0em8e%d0wTD?(-~22d-ZK1x%ox(Fdh#M)3SkoH=QeAtkb*CVnD37 z9rm$)G!As?ShDqO0{$&JXZY3)Uc>q#q;P&&9|9gem)@H*tyr zPMyNQ&iU}Hp~jxu3!Q73JL!2E3Yf;@a}NAI(8SF!Y`LA;s5j&VaRM&x-GG63mG=@q z;N~TR$pUUj=;Xqe7yfbAV09*qgA#z!aesI20Sbs!nhx>a${#)lZ#B#~;F7_&d;qijre!X7tqeYG0iWbvgC|%LoAsV;l2u#!s zUSDMsnW(w#+j9K`z`uRI7^~x9l}I^nojIzWMRw}dZB@VUh_`gL z(Bor38AQ%oosWn07Ujd@EO8iUEaHxG>GGh{D^e+I?_z7pr6Ch0OTMq>Y%`1W*$E`Z z;p}>TcIUC3wWoCTe?Bq1OX$#&+`b2n3+{TOG`ws`C4qUgd7g0WM8Zy$!X>d3p2?H0 z#V`mo-2znwX{lK56(-TVxU}+|FXmyZLbsuiT4WZQhdTz;2sdZaik-AWX}Z#zJz9w%$&3)`C2OP5@56Y-pFyntBycz? zmQ0}YzRH1)MeBtvhrEpH{zw3U4J{Q@4!b?z)O&DIgRIyx6ldBmKM~+|#T#jV_y?*` z+~Gx^%RLK~Ze5UiYZ}hXfjoS?iI;hqzTK{Sx0UZlO5*>}yIGKVAn{XGq^B(uSNZ(x z(i8u+wZP>nA@9@o{2Rtde%Q2aX+Vzx((k3*vuTVqIQysBmmG;XOFES3e5+pzyG(#{PS0-kU1x)2yhve^)F)EP_DoA_{2HRU3d^(HX4&X^ zqt0_C=0VPFyNO>`=9S*z^euO7RgQsEYz*+o0oN zZapUehN;9W4ctVh7=Y=Se^JU=$8j#5=hKHtVhi}h8BAh&u-O0iK~9yMSz(^`(f&V0 zI4IjrUX>UN0F6?wgaT`gW5EdBruqwEW#wb@HGeC4mjG4 zxZz?)oT)oV)hpi(&00EVo4aLCE=W{%%Df^2U{CH#@GTA%X(z?vNnH^g6%q%vOl;1p zyZ@#f{*%z1Gp}K+Q!vu;W;v;l6nyR5ADj!{t%>lAxL~#apP=HBolk$SN9oCn90V%sE_CEG_H3A#w&h4P5;yY> z4kLQwinld5u~L#Ckpun+p$~n{{lK|Cm*H(Aam&2RhOWly?iqiDC1S4dz{7E`=F8(V zW}QzV;=3cxN>F|ZaX#f!iqeIjx){pd(3o}JBHP3rM2nK~VsubjG%8G2*>K&zHP1bZW$S--H{kZ({vypmi(@j20kwqay=eIG_c=xz{)$4xojc8!CdweJbA@ z?>K<3Sli5E0Xe1%bdgsqzAKkVS?=}m)bit>o8J5@X4ayud6a(ur}+3%pbGVQ_5A

9!iuL=}1qm>}>O0J~5YNN6sG>arKJZUD>J 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 typed reducer) diff --git a/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Public/ModuleBindings/SpacetimeDBClient.g.h b/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Public/ModuleBindings/SpacetimeDBClient.g.h index 3269ea4c120..c991307b61b 100644 --- a/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Public/ModuleBindings/SpacetimeDBClient.g.h +++ b/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Public/ModuleBindings/SpacetimeDBClient.g.h @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 2.0.1 (commit 6f8639a69dac2047da00b1fc8550c94ea2505892). +// This was generated using spacetimedb cli version 2.0.3 (commit b6045fcc908d2846f8fb26570c2f300f5d685996). #pragma once #include "CoreMinimal.h" @@ -1230,7 +1230,7 @@ class TESTPROCCLIENT_API UDbConnection : public UDbConnectionBase USubscriptionBuilder* SubscriptionBuilder(); /** Static entry point for constructing a connection. */ - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB", DisplayName = "SpacetimeDB Builder") + UFUNCTION(BlueprintCallable, Category = "SpacetimeDB", DisplayName = "SpacetimeDB TestProcClient Builder") static UDbConnectionBuilder* Builder(); // Error handling @@ -1271,6 +1271,8 @@ class TESTPROCCLIENT_API UDbConnection : public UDbConnectionBase // Override the procedure event failed handler virtual void ProcedureEventFailed(const FProcedureEvent& Event, const FString ErrorMessage) override; + friend class USubscriptionBuilder; + friend class UDbConnectionBuilder; friend class URemoteReducers; // Internal reducer correlation helpers (request_id -> typed reducer) From 59d348d0f0ee73a79c837c1e2080c5a50650e29b Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Wed, 4 Mar 2026 10:02:31 -0800 Subject: [PATCH 09/15] Linting fix that didn't pop up locally --- crates/codegen/src/unrealcpp.rs | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/crates/codegen/src/unrealcpp.rs b/crates/codegen/src/unrealcpp.rs index a9e83433b65..d68d39273ae 100644 --- a/crates/codegen/src/unrealcpp.rs +++ b/crates/codegen/src/unrealcpp.rs @@ -1280,19 +1280,17 @@ fn generate_table_cpp( writeln!(output); // Add DeriveUpdatesByPrimaryKey for persistent tables with a primary key. - if !table.is_event { - if let Some(pk) = schema.pk() { - let pk_field_name = pk.col_name.deref().to_case(Case::Pascal); - let pk_type = &product_type.unwrap().elements[pk.col_pos.idx()].1; - let pk_type_str = cpp_ty_fmt_with_module(module_prefix, module, pk_type, module_name).to_string(); - writeln!(output, " Diff.DeriveUpdatesByPrimaryKey<{pk_type_str}>("); - writeln!(output, " [](const {row_struct}& Row) "); - writeln!(output, " {{"); - writeln!(output, " return Row.{pk_field_name}; "); - writeln!(output, " }}"); - writeln!(output, " );"); - writeln!(output); - } + if let (false, Some(pk)) = (table.is_event, schema.pk()) { + let pk_field_name = pk.col_name.deref().to_case(Case::Pascal); + let pk_type = &product_type.unwrap().elements[pk.col_pos.idx()].1; + let pk_type_str = cpp_ty_fmt_with_module(module_prefix, module, pk_type, module_name).to_string(); + writeln!(output, " Diff.DeriveUpdatesByPrimaryKey<{pk_type_str}>("); + writeln!(output, " [](const {row_struct}& Row) "); + writeln!(output, " {{"); + writeln!(output, " return Row.{pk_field_name}; "); + writeln!(output, " }}"); + writeln!(output, " );"); + writeln!(output); } // Reset cache for indexes From 5790ba469d5c297697bd755d7280bf43f68014f2 Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Thu, 5 Mar 2026 15:38:30 -0800 Subject: [PATCH 10/15] Small codegen fixes to treat unknown request ids as a protocol violation --- crates/codegen/src/unrealcpp.rs | 13 +++++-------- .../Private/ModuleBindings/SpacetimeDBClient.g.cpp | 10 +++++----- .../Private/ModuleBindings/SpacetimeDBClient.g.cpp | 10 +++++----- .../Private/ModuleBindings/SpacetimeDBClient.g.cpp | 10 +++++----- 4 files changed, 20 insertions(+), 23 deletions(-) diff --git a/crates/codegen/src/unrealcpp.rs b/crates/codegen/src/unrealcpp.rs index d68d39273ae..bab5d0bfed5 100644 --- a/crates/codegen/src/unrealcpp.rs +++ b/crates/codegen/src/unrealcpp.rs @@ -3514,8 +3514,7 @@ fn generate_client_implementation( output, " const FString ErrorMessage = FString::Printf(TEXT(\"Reducer result for unknown request_id %u\"), Event.RequestId);" ); - writeln!(output, " UE_LOG(LogTemp, Error, TEXT(\"%s\"), *ErrorMessage);"); - writeln!(output, " ReducerEventFailed(Event, ErrorMessage);"); + writeln!(output, " HandleProtocolViolation(ErrorMessage);"); writeln!(output, " return;"); writeln!(output, " }}"); writeln!(output); @@ -3876,6 +3875,7 @@ fn generate_client_implementation( "void U{module_prefix}DbConnection::ForwardOnDisconnect(UDbConnectionBase* BaseConnection, const FString& Error)" ); writeln!(output, "{{"); + writeln!(output, "\tPendingTypedReducers.Empty();"); writeln!(output, "\tif (OnDisconnectDelegate.IsBound())"); writeln!(output, "\t{{"); writeln!(output, "\t\tOnDisconnectDelegate.Execute(this, Error);"); @@ -3911,13 +3911,10 @@ fn generate_client_implementation( writeln!(output, " {{"); writeln!( output, - " UE_LOG(LogTemp, Warning, TEXT(\"Missing typed reducer for request_id %u while building table-update event context; using UnknownTransaction event\"), ReducerEvent.RequestId);" + " const FString ErrorMessage = FString::Printf(TEXT(\"Reducer result for unknown request_id %u\"), ReducerEvent.RequestId);" ); - writeln!( - output, - " BaseEvent = F{module_name_pascal}Event::UnknownTransaction(FSpacetimeDBUnit());" - ); - writeln!(output, " break;"); + writeln!(output, " HandleProtocolViolation(ErrorMessage);"); + writeln!(output, " return;"); writeln!(output, " }}"); writeln!( output, diff --git a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Private/ModuleBindings/SpacetimeDBClient.g.cpp b/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Private/ModuleBindings/SpacetimeDBClient.g.cpp index 0b792c07051..c8cd8a18549 100644 --- a/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Private/ModuleBindings/SpacetimeDBClient.g.cpp +++ b/sdks/unreal/examples/QuickstartChat/Source/QuickstartChat/Private/ModuleBindings/SpacetimeDBClient.g.cpp @@ -226,8 +226,7 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) if (!TryTakePendingTypedReducer(Event.RequestId, DecodedReducer)) { const FString ErrorMessage = FString::Printf(TEXT("Reducer result for unknown request_id %u"), Event.RequestId); - UE_LOG(LogTemp, Error, TEXT("%s"), *ErrorMessage); - ReducerEventFailed(Event, ErrorMessage); + HandleProtocolViolation(ErrorMessage); return; } @@ -431,6 +430,7 @@ void UDbConnection::ForwardOnConnect(UDbConnectionBase* BaseConnection, FSpaceti } void UDbConnection::ForwardOnDisconnect(UDbConnectionBase* BaseConnection, const FString& Error) { + PendingTypedReducers.Empty(); if (OnDisconnectDelegate.IsBound()) { OnDisconnectDelegate.Execute(this, Error); @@ -451,9 +451,9 @@ void UDbConnection::DbUpdate(const FDatabaseUpdateType& Update, const FSpacetime FReducer Reducer; if (!TryGetPendingTypedReducer(ReducerEvent.RequestId, Reducer)) { - UE_LOG(LogTemp, Warning, TEXT("Missing typed reducer for request_id %u while building table-update event context; using UnknownTransaction event"), ReducerEvent.RequestId); - BaseEvent = FQuickstartChatEvent::UnknownTransaction(FSpacetimeDBUnit()); - break; + const FString ErrorMessage = FString::Printf(TEXT("Reducer result for unknown request_id %u"), ReducerEvent.RequestId); + HandleProtocolViolation(ErrorMessage); + return; } BaseEvent = FQuickstartChatEvent::Reducer(Reducer); break; diff --git a/sdks/unreal/tests/TestClient/Source/TestClient/Private/ModuleBindings/SpacetimeDBClient.g.cpp b/sdks/unreal/tests/TestClient/Source/TestClient/Private/ModuleBindings/SpacetimeDBClient.g.cpp index 73ff83aeee0..22169073be0 100644 --- a/sdks/unreal/tests/TestClient/Source/TestClient/Private/ModuleBindings/SpacetimeDBClient.g.cpp +++ b/sdks/unreal/tests/TestClient/Source/TestClient/Private/ModuleBindings/SpacetimeDBClient.g.cpp @@ -9662,8 +9662,7 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) if (!TryTakePendingTypedReducer(Event.RequestId, DecodedReducer)) { const FString ErrorMessage = FString::Printf(TEXT("Reducer result for unknown request_id %u"), Event.RequestId); - UE_LOG(LogTemp, Error, TEXT("%s"), *ErrorMessage); - ReducerEventFailed(Event, ErrorMessage); + HandleProtocolViolation(ErrorMessage); return; } @@ -11037,6 +11036,7 @@ void UDbConnection::ForwardOnConnect(UDbConnectionBase* BaseConnection, FSpaceti } void UDbConnection::ForwardOnDisconnect(UDbConnectionBase* BaseConnection, const FString& Error) { + PendingTypedReducers.Empty(); if (OnDisconnectDelegate.IsBound()) { OnDisconnectDelegate.Execute(this, Error); @@ -11057,9 +11057,9 @@ void UDbConnection::DbUpdate(const FDatabaseUpdateType& Update, const FSpacetime FReducer Reducer; if (!TryGetPendingTypedReducer(ReducerEvent.RequestId, Reducer)) { - UE_LOG(LogTemp, Warning, TEXT("Missing typed reducer for request_id %u while building table-update event context; using UnknownTransaction event"), ReducerEvent.RequestId); - BaseEvent = FTestClientEvent::UnknownTransaction(FSpacetimeDBUnit()); - break; + const FString ErrorMessage = FString::Printf(TEXT("Reducer result for unknown request_id %u"), ReducerEvent.RequestId); + HandleProtocolViolation(ErrorMessage); + return; } BaseEvent = FTestClientEvent::Reducer(Reducer); break; diff --git a/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Private/ModuleBindings/SpacetimeDBClient.g.cpp b/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Private/ModuleBindings/SpacetimeDBClient.g.cpp index c08e7fea1dd..e324c566449 100644 --- a/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Private/ModuleBindings/SpacetimeDBClient.g.cpp +++ b/sdks/unreal/tests/TestProcClient/Source/TestProcClient/Private/ModuleBindings/SpacetimeDBClient.g.cpp @@ -474,8 +474,7 @@ void UDbConnection::ReducerEvent(const FReducerEvent& Event) if (!TryTakePendingTypedReducer(Event.RequestId, DecodedReducer)) { const FString ErrorMessage = FString::Printf(TEXT("Reducer result for unknown request_id %u"), Event.RequestId); - UE_LOG(LogTemp, Error, TEXT("%s"), *ErrorMessage); - ReducerEventFailed(Event, ErrorMessage); + HandleProtocolViolation(ErrorMessage); return; } @@ -673,6 +672,7 @@ void UDbConnection::ForwardOnConnect(UDbConnectionBase* BaseConnection, FSpaceti } void UDbConnection::ForwardOnDisconnect(UDbConnectionBase* BaseConnection, const FString& Error) { + PendingTypedReducers.Empty(); if (OnDisconnectDelegate.IsBound()) { OnDisconnectDelegate.Execute(this, Error); @@ -693,9 +693,9 @@ void UDbConnection::DbUpdate(const FDatabaseUpdateType& Update, const FSpacetime FReducer Reducer; if (!TryGetPendingTypedReducer(ReducerEvent.RequestId, Reducer)) { - UE_LOG(LogTemp, Warning, TEXT("Missing typed reducer for request_id %u while building table-update event context; using UnknownTransaction event"), ReducerEvent.RequestId); - BaseEvent = FTestProcClientEvent::UnknownTransaction(FSpacetimeDBUnit()); - break; + const FString ErrorMessage = FString::Printf(TEXT("Reducer result for unknown request_id %u"), ReducerEvent.RequestId); + HandleProtocolViolation(ErrorMessage); + return; } BaseEvent = FTestProcClientEvent::Reducer(Reducer); break; From 3cc7206875e4dd953339042a6210f8a6e0f58670 Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Tue, 10 Mar 2026 08:00:15 -0700 Subject: [PATCH 11/15] Reworked Unreal Blackholio tutorial for pathing issues --- .../00400-unreal-tutorial/00300-part-2.md | 19 +++++++++---------- .../00400-unreal-tutorial/00400-part-3.md | 2 +- .../00400-unreal-tutorial/00500-part-4.md | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00300-part-2.md b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00300-part-2.md index efff8f629e8..8b4f28c9deb 100644 --- a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00300-part-2.md +++ b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00300-part-2.md @@ -14,7 +14,7 @@ This progressive tutorial is continued from [part 1](./00200-part-1.md). ## Project Structure -Now that we have our client project setup we can configure the module directory. Regardless of what language you choose, your module will always go into a `blackholio` directory within your client directory like this: +Now that we have our client project setup we can configure the module directory. Regardless of what language you choose, your module will always go into a `spacetimedb` directory within your client directory like this: ``` blackholio/ # Unreal project root @@ -26,8 +26,7 @@ blackholio/ # Unreal project root ├── Plugins/ │ └── SpacetimeDbSdk/ # This is where the SpacetimeDB Unreal SDK lives ├── ... rest of Unreal files -└── blackholio/ # This is where the server module lives -│ └── spacetimedb/ +└── spacetimedb/ # This is where the server module lives ``` ## Create a Server Module @@ -49,19 +48,19 @@ The `blackholio` directory specified here is the same `blackholio` directory you Run the following command to initialize the SpacetimeDB server module project with C# as the language: ```bash -spacetime init --lang csharp --server-only blackholio +spacetime init --lang csharp --server-only --project-path . blackholio ``` -This command creates a new folder named `blackholio` inside of your Unreal project `blackholio` directory and sets up the SpacetimeDB server project with C# as the programming language. +This command creates a new folder named `spacetimedb` inside of your Unreal project `blackholio` directory and sets up the SpacetimeDB server project with C# as the programming language. Run the following command to initialize the SpacetimeDB server module project with Rust as the language: ```bash -spacetime init --lang rust --server-only blackholio +spacetime init --lang rust --server-only --project-path . blackholio ``` -This command creates a new folder named `blackholio` inside of your Unreal project `blackholio` directory and sets up the SpacetimeDB server project with Rust as the programming language. +This command creates a new folder named `spacetimedb` inside of your Unreal project `blackholio` directory and sets up the SpacetimeDB server project with Rust as the programming language. @@ -69,10 +68,10 @@ This command creates a new folder named `blackholio` inside of your Unreal proje Run the following command to initialize the SpacetimeDB server module project with C++ as the language: ```bash -spacetime init --lang cpp --server-only blackholio +spacetime init --lang cpp --server-only --project-path . blackholio ``` -This command creates a new folder named `blackholio` inside of your Unreal project `blackholio` directory and sets up the SpacetimeDB server project with Rust as the programming language. +This command creates a new folder named `spacetimedb` inside of your Unreal project `blackholio` directory and sets up the SpacetimeDB server project with Rust as the programming language. @@ -650,7 +649,7 @@ Let's generate our types for our module. In the `blackholio/spacetimedb` directo ```sh -spacetime generate --lang unrealcpp --uproject-dir ../.. --module-path ./ --unreal-module-name blackholio +spacetime generate --lang unrealcpp --uproject-dir .. --module-path ./ --unreal-module-name blackholio ``` This will generate a set of files in the `blackholio/Source/blackholio/Private/ModuleBindings` and `blackholio/Source/blackholio/Public/ModuleBindings` directories which contain the code generated types and reducer functions that are defined in your module, but usable on the client. diff --git a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00400-part-3.md b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00400-part-3.md index baf1a9b24c1..50e2d1b19fd 100644 --- a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00400-part-3.md +++ b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00400-part-3.md @@ -2400,7 +2400,7 @@ Update **Event BeginPlay** as follows: At this point, you may need to regenerate your bindings the following command from the `blackholio/spacetimedb` directory. ```sh -spacetime generate --lang unrealcpp --uproject-dir ../.. --module-path ./ --unreal-module-name blackholio +spacetime generate --lang unrealcpp --uproject-dir .. --module-path ./ --unreal-module-name blackholio ``` diff --git a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00500-part-4.md b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00500-part-4.md index 5cc3955d686..608f01795d3 100644 --- a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00500-part-4.md +++ b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00500-part-4.md @@ -526,7 +526,7 @@ spacetime publish --server local blackholio --delete-data Regenerate your server bindings with: ```sh -spacetime generate --lang unrealcpp --uproject-dir ../.. --module-path ./ --unreal-module-name blackholio +spacetime generate --lang unrealcpp --uproject-dir .. --module-path ./ --unreal-module-name blackholio ``` ### Moving on the Client From 14bcde1e163e7ac8c306eb071082e4a904742cc0 Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Thu, 12 Mar 2026 13:08:40 -0700 Subject: [PATCH 12/15] Update for sender to sender() for C++ module bindings --- crates/bindings-cpp/ARCHITECTURE.md | 4 ++-- crates/bindings-cpp/QUICKSTART.md | 12 +++++------ crates/bindings-cpp/README.md | 10 +++++----- crates/bindings-cpp/REFERENCE.md | 20 +++++++++---------- .../include/spacetimedb/procedure_context.h | 20 ++++++++++++------- .../include/spacetimedb/reducer_context.h | 13 +++++++++--- .../include/spacetimedb/reducer_macros.h | 4 ++-- .../include/spacetimedb/tx_context.h | 6 +++--- .../include/spacetimedb/view_context.h | 12 +++++++---- .../server-cpp/spacetimedb/src/lib.cpp | 16 +++++++-------- .../00400-key-architecture.md | 2 +- .../00300-tutorials/00100-chat-app.md | 10 +++++----- .../00300-unity-tutorial/00300-part-2.md | 4 ++-- .../00300-unity-tutorial/00400-part-3.md | 10 +++++----- .../00300-unity-tutorial/00500-part-4.md | 4 ++-- .../00400-unreal-tutorial/00300-part-2.md | 4 ++-- .../00400-unreal-tutorial/00400-part-3.md | 10 +++++----- .../00400-unreal-tutorial/00500-part-4.md | 4 ++-- .../00100-databases/00500-cheat-sheet.md | 4 ++-- .../00300-reducers/00400-reducer-context.md | 4 ++-- .../00300-reducers/00500-lifecycle.md | 10 +++++----- .../00300-reducers/00600-error-handling.md | 2 +- .../00200-functions/00500-views.md | 6 +++--- docs/docs/00200-core-concepts/00300-tables.md | 4 ++-- .../00300-tables/00400-access-permissions.md | 8 ++++---- .../00100-how-to/00300-logging.md | 4 ++-- .../00100-how-to/00600-migrating-to-2.0.md | 2 +- modules/module-test-cpp/src/lib.cpp | 18 ++++++++--------- .../src/lib.cpp | 4 ++-- modules/sdk-test-cpp/src/lib.cpp | 8 ++++---- modules/sdk-test-view-cpp/src/lib.cpp | 10 +++++----- 31 files changed, 133 insertions(+), 116 deletions(-) diff --git a/crates/bindings-cpp/ARCHITECTURE.md b/crates/bindings-cpp/ARCHITECTURE.md index c5fc1f2151e..d5f74910d7f 100644 --- a/crates/bindings-cpp/ARCHITECTURE.md +++ b/crates/bindings-cpp/ARCHITECTURE.md @@ -77,7 +77,7 @@ SPACETIMEDB_REDUCER(create_user, ReducerContext ctx, std::string name) { } // Success path - ctx.db[user].insert(User{ctx.sender, name, false}); + ctx.db[user].insert(User{ctx.sender(), name, false}); return Ok(); // No value needed - just success } ``` @@ -638,4 +638,4 @@ SpacetimeDB loading → Server-side validation and error reporting - [Type System Details](README.md#features) - [Constraint Validation Tests](tests/type-isolation-test/) - [API Reference](REFERENCE.md) -- [Quick Start Guide](QUICKSTART.md) \ No newline at end of file +- [Quick Start Guide](QUICKSTART.md) diff --git a/crates/bindings-cpp/QUICKSTART.md b/crates/bindings-cpp/QUICKSTART.md index 84dd3194531..d8b12c25242 100644 --- a/crates/bindings-cpp/QUICKSTART.md +++ b/crates/bindings-cpp/QUICKSTART.md @@ -109,7 +109,7 @@ SPACETIMEDB_REDUCER(set_name, ReducerContext ctx, std::string name) { } // Find and update the user by identity (primary key) - auto user_row = ctx.db[user_identity].find(ctx.sender); + auto user_row = ctx.db[user_identity].find(ctx.sender()); if (user_row.has_value()) { auto user = user_row.value(); user.name = validated.value(); @@ -127,7 +127,7 @@ SPACETIMEDB_REDUCER(send_message, ReducerContext ctx, std::string text) { return Err(validated.error()); } - Message msg{ctx.sender, ctx.timestamp, validated.value()}; + Message msg{ctx.sender(), ctx.timestamp, validated.value()}; ctx.db[message].insert(msg); return Ok(); } @@ -140,13 +140,13 @@ Lifecycle reducers are special functions called automatically by SpacetimeDB: ```cpp // Called when a client connects SPACETIMEDB_CLIENT_CONNECTED(client_connected, ReducerContext ctx) { - auto user_row = ctx.db[user_identity].find(ctx.sender); + auto user_row = ctx.db[user_identity].find(ctx.sender()); if (user_row.has_value()) { auto user = user_row.value(); user.online = true; ctx.db[user_identity].update(user); } else { - User new_user{ctx.sender, std::nullopt, true}; + User new_user{ctx.sender(), std::nullopt, true}; ctx.db[user].insert(new_user); } return Ok(); @@ -154,7 +154,7 @@ SPACETIMEDB_CLIENT_CONNECTED(client_connected, ReducerContext ctx) { // Called when a client disconnects SPACETIMEDB_CLIENT_DISCONNECTED(client_disconnected, ReducerContext ctx) { - auto user_row = ctx.db[user_identity].find(ctx.sender); + auto user_row = ctx.db[user_identity].find(ctx.sender()); if (user_row.has_value()) { auto user = user_row.value(); user.online = false; @@ -291,4 +291,4 @@ For more complex examples, see: --- -Ready to learn more? Check out the [C++ Reference Documentation](REFERENCE.md) for detailed API information. \ No newline at end of file +Ready to learn more? Check out the [C++ Reference Documentation](REFERENCE.md) for detailed API information. diff --git a/crates/bindings-cpp/README.md b/crates/bindings-cpp/README.md index c3d2ef2a2af..ef31361c10b 100644 --- a/crates/bindings-cpp/README.md +++ b/crates/bindings-cpp/README.md @@ -102,7 +102,7 @@ SPACETIMEDB_NAMESPACE(UserRole, "Auth") // Will be "Auth.UserRole" in client co // User-defined reducer SPACETIMEDB_REDUCER(add_user, ReducerContext ctx, std::string name, std::string email) { - User user{ctx.sender, name, email}; // id will be auto-generated + User user{ctx.sender(), name, email}; // id will be auto-generated ctx.db[users].insert(user); LOG_INFO("Added user: " + name); return Ok(); @@ -110,7 +110,7 @@ SPACETIMEDB_REDUCER(add_user, ReducerContext ctx, std::string name, std::string // Delete user by id (using primary key) SPACETIMEDB_REDUCER(delete_user, ReducerContext ctx) { - ctx.db[users_identity].delete_by_key(ctx.sender); + ctx.db[users_identity].delete_by_key(ctx.sender()); return Ok(); } @@ -121,19 +121,19 @@ SPACETIMEDB_INIT(init, ReducerContext ctx) { } SPACETIMEDB_CLIENT_CONNECTED(on_connect, ReducerContext ctx) { - LOG_INFO("Client connected: " + ctx.sender.to_hex_string()); + LOG_INFO("Client connected: " + ctx.sender().to_hex_string()); return Ok(); } SPACETIMEDB_CLIENT_DISCONNECTED(on_disconnect, ReducerContext ctx) { - LOG_INFO("Client disconnected: " + ctx.sender.to_hex_string()); + LOG_INFO("Client disconnected: " + ctx.sender().to_hex_string()); return Ok(); } // Define a view for querying data (finds the calling user) SPACETIMEDB_VIEW(std::optional, find_my_user, Public, ViewContext ctx) { // Use indexed field to find user by their identity - return ctx.db[users_identity].find(ctx.sender); + return ctx.db[users_identity].find(ctx.sender()); } // Define a procedure (pure function with return value) diff --git a/crates/bindings-cpp/REFERENCE.md b/crates/bindings-cpp/REFERENCE.md index 7983c451d51..3da3c0ee40f 100644 --- a/crates/bindings-cpp/REFERENCE.md +++ b/crates/bindings-cpp/REFERENCE.md @@ -191,7 +191,7 @@ SPACETIMEDB_INIT(init, ReducerContext ctx) { // Called when a client connects SPACETIMEDB_CLIENT_CONNECTED(on_connect, ReducerContext ctx) { LOG_INFO("Client connected"); - // ctx.sender contains the client's Identity + // ctx.sender() contains the client's Identity return Ok(); } @@ -213,7 +213,7 @@ SPACETIMEDB_REDUCER(example, ReducerContext ctx, /* params */) { ctx.db[table_name].insert(record); // Client identity - Identity client = ctx.sender; + Identity client = ctx.sender(); // Current timestamp Timestamp now = ctx.timestamp; @@ -893,7 +893,7 @@ SPACETIMEDB_TABLE(User, user, Public); FIELD_PrimaryKey(user, id); SPACETIMEDB_REDUCER(create_user, ReducerContext ctx, std::string name) { - User user{ctx.sender, name}; // ctx.sender is the calling client's identity + User user{ctx.sender(), name}; // ctx.sender() is the calling client's identity ctx.db[user_id].insert(user); return Ok(); } @@ -1138,12 +1138,12 @@ FIELD_Index(user, active); // Register new user SPACETIMEDB_REDUCER(register_user, ReducerContext ctx, std::string username, std::string email) { // Check if user already exists - auto user_opt = ctx.db[user_identity].find(ctx.sender); + auto user_opt = ctx.db[user_identity].find(ctx.sender()); if (user_opt && user_opt->active) { return Err("User already registered"); } - User new_user{0, ctx.sender, username, email, ctx.timestamp, true}; + User new_user{0, ctx.sender(), username, email, ctx.timestamp, true}; ctx.db[user].insert(new_user); LOG_INFO("User registered: " + username); return Ok(); @@ -1151,7 +1151,7 @@ SPACETIMEDB_REDUCER(register_user, ReducerContext ctx, std::string username, std // Update user profile SPACETIMEDB_REDUCER(update_profile, ReducerContext ctx, std::string new_username) { - auto user_opt = ctx.db[user_identity].find(ctx.sender); + auto user_opt = ctx.db[user_identity].find(ctx.sender()); if (user_opt && user_opt->active) { User updated_user = *user_opt; updated_user.username = new_username; @@ -1164,7 +1164,7 @@ SPACETIMEDB_REDUCER(update_profile, ReducerContext ctx, std::string new_username // Deactivate user SPACETIMEDB_REDUCER(deactivate_user, ReducerContext ctx) { - auto user_opt = ctx.db[user_identity].find(ctx.sender); + auto user_opt = ctx.db[user_identity].find(ctx.sender()); if (user_opt && user_opt->active) { User updated_user = *user_opt; updated_user.active = false; @@ -1227,7 +1227,7 @@ FIELD_Index(messages, sender); // Create channel SPACETIMEDB_REDUCER(create_channel, ReducerContext ctx, std::string name, std::string description, bool is_public) { - Channel channel{0, name, description, ctx.sender, is_public}; + Channel channel{0, name, description, ctx.sender(), is_public}; ctx.db[channels].insert(channel); LOG_INFO("Channel created: " + name); return Ok(); @@ -1249,7 +1249,7 @@ SPACETIMEDB_REDUCER(send_message, ReducerContext ctx, uint32_t channel_id, std:: return Err("Channel not found"); } - Message message{0, channel_id, ctx.sender, content, ctx.timestamp}; + Message message{0, channel_id, ctx.sender(), content, ctx.timestamp}; ctx.db[messages].insert(message); return Ok(); } @@ -1281,4 +1281,4 @@ SPACETIMEDB_REDUCER(update_age, ReducerContext ctx, uint32_t new_age) { --- -This completes the C++ reference documentation. For more examples and advanced patterns, see the working modules in [`modules/sdk-test-cpp`](../../modules/sdk-test-cpp) and [`modules/module-test-cpp`](../../modules/module-test-cpp). \ No newline at end of file +This completes the C++ reference documentation. For more examples and advanced patterns, see the working modules in [`modules/sdk-test-cpp`](../../modules/sdk-test-cpp) and [`modules/module-test-cpp`](../../modules/module-test-cpp). diff --git a/crates/bindings-cpp/include/spacetimedb/procedure_context.h b/crates/bindings-cpp/include/spacetimedb/procedure_context.h index e7c100200dc..1ee1b88f71f 100644 --- a/crates/bindings-cpp/include/spacetimedb/procedure_context.h +++ b/crates/bindings-cpp/include/spacetimedb/procedure_context.h @@ -53,16 +53,18 @@ namespace SpacetimeDB { * @endcode */ struct ProcedureContext { +private: // Caller's identity - who invoked this procedure - Identity sender; - + Identity sender_; + +public: // Timestamp when the procedure was invoked Timestamp timestamp; - + // Connection ID for the caller // Used to track which client connection initiated this procedure ConnectionId connection_id; - + #ifdef SPACETIMEDB_UNSTABLE_FEATURES // HTTP client for making external requests // IMPORTANT: HTTP calls are NOT allowed inside transactions! @@ -81,7 +83,11 @@ struct ProcedureContext { ProcedureContext() = default; ProcedureContext(Identity s, Timestamp t, ConnectionId conn_id) - : sender(s), timestamp(t), connection_id(conn_id) {} + : sender_(s), timestamp(t), connection_id(conn_id) {} + + Identity sender() const { + return sender_; + } /** * @brief Read the current module's Identity @@ -197,7 +203,7 @@ struct ProcedureContext { // Create a ReducerContext for this transaction // Note: connection_id converted to std::optional ReducerContext reducer_ctx( - sender, + sender(), std::optional(connection_id), Timestamp::from_micros_since_epoch(tx_timestamp) ); @@ -260,7 +266,7 @@ struct ProcedureContext { // Create a ReducerContext for this transaction ReducerContext reducer_ctx( - sender, + sender(), std::optional(connection_id), Timestamp::from_micros_since_epoch(tx_timestamp) ); diff --git a/crates/bindings-cpp/include/spacetimedb/reducer_context.h b/crates/bindings-cpp/include/spacetimedb/reducer_context.h index 313a3fd8d87..307c107e566 100644 --- a/crates/bindings-cpp/include/spacetimedb/reducer_context.h +++ b/crates/bindings-cpp/include/spacetimedb/reducer_context.h @@ -17,8 +17,11 @@ namespace SpacetimeDB { // Enhanced ReducerContext with database access - matches Rust pattern struct ReducerContext { - // Core fields - directly accessible like in Rust - Identity sender; +private: + Identity sender_; + +public: + // Core fields - sender is exposed via sender() like Rust, other fields remain directly accessible std::optional connection_id; Timestamp timestamp; @@ -37,6 +40,10 @@ struct ReducerContext { mutable uint32_t counter_uuid_ = 0; public: + Identity sender() const { + return sender_; + } + // Returns the authorization information for the caller of this reducer const AuthCtx& sender_auth() const { return sender_auth_; @@ -110,7 +117,7 @@ struct ReducerContext { ReducerContext() : sender_auth_(AuthCtx::internal()) {} ReducerContext(Identity s, std::optional cid, Timestamp ts) - : sender(s), connection_id(cid), timestamp(ts), + : sender_(s), connection_id(cid), timestamp(ts), sender_auth_(AuthCtx::from_connection_id_opt(cid, s)) {} }; diff --git a/crates/bindings-cpp/include/spacetimedb/reducer_macros.h b/crates/bindings-cpp/include/spacetimedb/reducer_macros.h index d11380ead52..b9d6edcda07 100644 --- a/crates/bindings-cpp/include/spacetimedb/reducer_macros.h +++ b/crates/bindings-cpp/include/spacetimedb/reducer_macros.h @@ -125,7 +125,7 @@ * @usage * ```cpp * SPACETIMEDB_CLIENT_CONNECTED(on_connect, ReducerContext ctx) { - * LOG_INFO("Client connected: " + ctx.sender.to_hex()); + * LOG_INFO("Client connected: " + ctx.sender().to_hex()); * return Ok(); * } * ``` @@ -149,7 +149,7 @@ * @usage * ```cpp * SPACETIMEDB_CLIENT_DISCONNECTED(on_disconnect, ReducerContext ctx) { - * LOG_INFO("Client disconnected: " + ctx.sender.to_hex()); + * LOG_INFO("Client disconnected: " + ctx.sender().to_hex()); * return Ok(); * } * ``` diff --git a/crates/bindings-cpp/include/spacetimedb/tx_context.h b/crates/bindings-cpp/include/spacetimedb/tx_context.h index 10f28e28f9b..68d1d3181e5 100644 --- a/crates/bindings-cpp/include/spacetimedb/tx_context.h +++ b/crates/bindings-cpp/include/spacetimedb/tx_context.h @@ -53,9 +53,9 @@ struct TxContext { public: // Public references to ReducerContext fields for consistent API with Rust // In Rust, Deref makes tx.db work the same as ctx.db - // In C++, we explicitly expose references to achieve the same ergonomics + // In C++, we explicitly expose references where possible and provide + // accessors for fields exposed as methods on ReducerContext. DatabaseContext& db; - const Identity& sender; const Timestamp& timestamp; const std::optional& connection_id; @@ -63,11 +63,11 @@ struct TxContext { explicit TxContext(ReducerContext& ctx) : ctx_(ctx), db(ctx.db), - sender(ctx.sender), timestamp(ctx.timestamp), connection_id(ctx.connection_id) {} // Access to ReducerContext methods + Identity sender() const { return ctx_.sender(); } const AuthCtx& sender_auth() const { return ctx_.sender_auth(); } Identity identity() const { return ctx_.identity(); } StdbRng& rng() const { return ctx_.rng(); } diff --git a/crates/bindings-cpp/include/spacetimedb/view_context.h b/crates/bindings-cpp/include/spacetimedb/view_context.h index cc1a5c63094..3a7fdd577f0 100644 --- a/crates/bindings-cpp/include/spacetimedb/view_context.h +++ b/crates/bindings-cpp/include/spacetimedb/view_context.h @@ -25,7 +25,7 @@ namespace SpacetimeDB { * SPACETIMEDB_VIEW(std::vector, get_my_items, Public, ViewContext ctx) { * std::vector my_items; * // Filter by caller's identity using indexed field - * for (const auto& item : ctx.db[item_owner].filter(ctx.sender)) { + * for (const auto& item : ctx.db[item_owner].filter(ctx.sender())) { * my_items.push_back(item); * } * return Ok(my_items); @@ -33,9 +33,11 @@ namespace SpacetimeDB { * @endcode */ struct ViewContext { +private: // Caller's identity - who invoked this view - Identity sender; - + Identity sender_; + +public: // Read-only database access - no mutations allowed ReadOnlyDatabaseContext db; @@ -43,7 +45,9 @@ struct ViewContext { ViewContext() = default; explicit ViewContext(Identity s) - : sender(s) {} + : sender_(s) {} + + Identity sender() const { return sender_; } }; /** diff --git a/demo/Blackholio/server-cpp/spacetimedb/src/lib.cpp b/demo/Blackholio/server-cpp/spacetimedb/src/lib.cpp index d7297bbb074..208fdae1d79 100644 --- a/demo/Blackholio/server-cpp/spacetimedb/src/lib.cpp +++ b/demo/Blackholio/server-cpp/spacetimedb/src/lib.cpp @@ -294,7 +294,7 @@ SPACETIMEDB_INIT(init, ReducerContext ctx) { } SPACETIMEDB_CLIENT_CONNECTED(connect, ReducerContext ctx) { - auto logged_out = ctx.db[logged_out_player_identity].find(ctx.sender); + auto logged_out = ctx.db[logged_out_player_identity].find(ctx.sender()); if (logged_out.has_value()) { ctx.db[player].insert(logged_out.value()); (void)ctx.db[logged_out_player_identity].delete_by_key(logged_out->identity); @@ -313,14 +313,14 @@ SPACETIMEDB_CLIENT_CONNECTED(connect, ReducerContext ctx) { (void)ctx.db[logged_out_circle_entity_id].delete_by_key(circle_row.entity_id); } } else { - Player new_player{ctx.sender, 0, std::string()}; + Player new_player{ctx.sender(), 0, std::string()}; ctx.db[player].insert(new_player); } return Ok(); } SPACETIMEDB_CLIENT_DISCONNECTED(disconnect, ReducerContext ctx) { - auto player_opt = ctx.db[player_identity].find(ctx.sender); + auto player_opt = ctx.db[player_identity].find(ctx.sender()); if (!player_opt.has_value()) { return Err("Player not found"); } @@ -349,7 +349,7 @@ SPACETIMEDB_CLIENT_DISCONNECTED(disconnect, ReducerContext ctx) { SPACETIMEDB_REDUCER(enter_game, ReducerContext ctx, std::string name) { LOG_INFO("Creating player with name " + name); - auto player_opt = ctx.db[player_identity].find(ctx.sender); + auto player_opt = ctx.db[player_identity].find(ctx.sender()); if (!player_opt.has_value()) { return Err("Player not found"); } @@ -367,7 +367,7 @@ SPACETIMEDB_REDUCER(enter_game, ReducerContext ctx, std::string name) { } SPACETIMEDB_REDUCER(respawn, ReducerContext ctx) { - auto player_opt = ctx.db[player_identity].find(ctx.sender); + auto player_opt = ctx.db[player_identity].find(ctx.sender()); if (!player_opt.has_value()) { return Err("No such player found"); } @@ -381,7 +381,7 @@ SPACETIMEDB_REDUCER(respawn, ReducerContext ctx) { } SPACETIMEDB_REDUCER(suicide, ReducerContext ctx) { - auto player_opt = ctx.db[player_identity].find(ctx.sender); + auto player_opt = ctx.db[player_identity].find(ctx.sender()); if (!player_opt.has_value()) { return Err("No such player found"); } @@ -397,7 +397,7 @@ SPACETIMEDB_REDUCER(suicide, ReducerContext ctx) { } SPACETIMEDB_REDUCER(update_player_input, ReducerContext ctx, DbVector2 direction) { - auto player_opt = ctx.db[player_identity].find(ctx.sender); + auto player_opt = ctx.db[player_identity].find(ctx.sender()); if (!player_opt.has_value()) { return Err("Player not found"); } @@ -605,7 +605,7 @@ SPACETIMEDB_REDUCER(consume_entity, ReducerContext ctx, ConsumeEntityTimer reque } SPACETIMEDB_REDUCER(player_split, ReducerContext ctx) { - auto player_opt = ctx.db[player_identity].find(ctx.sender); + auto player_opt = ctx.db[player_identity].find(ctx.sender()); if (!player_opt.has_value()) { return Err("Sender has no player"); } diff --git a/docs/docs/00100-intro/00100-getting-started/00400-key-architecture.md b/docs/docs/00100-intro/00100-getting-started/00400-key-architecture.md index 9c1828e7d29..f17edf027cb 100644 --- a/docs/docs/00100-intro/00100-getting-started/00400-key-architecture.md +++ b/docs/docs/00100-intro/00100-getting-started/00400-key-architecture.md @@ -537,7 +537,7 @@ A view can be written in C++ like so: ```cpp SPACETIMEDB_VIEW(std::optional, my_player, Public, ViewContext ctx) { - return ctx.db[player_identity].find(ctx.sender); + return ctx.db[player_identity].find(ctx.sender()); } ``` diff --git a/docs/docs/00100-intro/00300-tutorials/00100-chat-app.md b/docs/docs/00100-intro/00300-tutorials/00100-chat-app.md index 2baa7ecb1d9..ad5069481c6 100644 --- a/docs/docs/00100-intro/00300-tutorials/00100-chat-app.md +++ b/docs/docs/00100-intro/00300-tutorials/00100-chat-app.md @@ -477,7 +477,7 @@ SPACETIMEDB_REDUCER(set_name, ReducerContext ctx, std::string name) { } // Find and update the user by identity (primary key) - auto user_row = ctx.db[user_identity].find(ctx.sender); + auto user_row = ctx.db[user_identity].find(ctx.sender()); if (user_row.has_value()) { auto user = user_row.value(); user.name = validated.value(); @@ -598,7 +598,7 @@ SPACETIMEDB_REDUCER(send_message, ReducerContext ctx, std::string text) { return Err(validated.error()); } - Message msg{ctx.sender, ctx.timestamp, validated.value()}; + Message msg{ctx.sender(), ctx.timestamp, validated.value()}; ctx.db[message].insert(msg); return Ok(); } @@ -724,20 +724,20 @@ Add to `spacetimedb/src/lib.cpp`: ```cpp server SPACETIMEDB_CLIENT_CONNECTED(client_connected, ReducerContext ctx) { - auto user_row = ctx.db[user_identity].find(ctx.sender); + auto user_row = ctx.db[user_identity].find(ctx.sender()); if (user_row.has_value()) { auto user = user_row.value(); user.online = true; ctx.db[user_identity].update(user); } else { - User new_user{ctx.sender, std::nullopt, true}; + User new_user{ctx.sender(), std::nullopt, true}; ctx.db[user].insert(new_user); } return Ok(); } SPACETIMEDB_CLIENT_DISCONNECTED(client_disconnected, ReducerContext ctx) { - auto user_row = ctx.db[user_identity].find(ctx.sender); + auto user_row = ctx.db[user_identity].find(ctx.sender()); if (user_row.has_value()) { auto user = user_row.value(); user.online = false; diff --git a/docs/docs/00100-intro/00300-tutorials/00300-unity-tutorial/00300-part-2.md b/docs/docs/00100-intro/00300-tutorials/00300-unity-tutorial/00300-part-2.md index c2f52bdd50d..3df6b0b735a 100644 --- a/docs/docs/00100-intro/00300-tutorials/00300-unity-tutorial/00300-part-2.md +++ b/docs/docs/00100-intro/00300-tutorials/00300-unity-tutorial/00300-part-2.md @@ -470,7 +470,7 @@ pub fn debug(ctx: &ReducerContext) -> Result<(), String> { ```cpp SPACETIMEDB_REDUCER(debug, ReducerContext ctx) { - LOG_INFO("This reducer was called by " + ctx.sender.to_string()); + LOG_INFO("This reducer was called by " + ctx.sender().to_string()); return Ok(); } ``` @@ -614,7 +614,7 @@ Next let's connect our client to our database. Let's start by modifying our `deb ```cpp SPACETIMEDB_CLIENT_CONNECTED(connect, ReducerContext ctx) { - LOG_INFO(ctx.sender.to_string() + " just connected."); + LOG_INFO(ctx.sender().to_string() + " just connected."); return Ok(); } ``` diff --git a/docs/docs/00100-intro/00300-tutorials/00300-unity-tutorial/00400-part-3.md b/docs/docs/00100-intro/00300-tutorials/00300-unity-tutorial/00400-part-3.md index 00329cd3f68..8de2e8d1610 100644 --- a/docs/docs/00100-intro/00300-tutorials/00300-unity-tutorial/00400-part-3.md +++ b/docs/docs/00100-intro/00300-tutorials/00300-unity-tutorial/00400-part-3.md @@ -585,21 +585,21 @@ Next, modify your `connect` reducer and add a new `disconnect` reducer below it: ```cpp SPACETIMEDB_CLIENT_CONNECTED(connect, ReducerContext ctx) { // Check if this player was previously logged out - auto logged_out_player_opt = ctx.db[logged_out_player_identity].find(ctx.sender); + auto logged_out_player_opt = ctx.db[logged_out_player_identity].find(ctx.sender()); if (logged_out_player_opt.has_value()) { // Move player from logged_out_player to player table ctx.db[player].insert(logged_out_player_opt.value()); ctx.db[logged_out_player_identity].delete_by_key(logged_out_player_opt.value().identity); } else { // New player - create and insert into player table - ctx.db[player].insert(Player{ctx.sender, 0, ""}); + ctx.db[player].insert(Player{ctx.sender(), 0, ""}); } return Ok(); } SPACETIMEDB_CLIENT_DISCONNECTED(disconnect, ReducerContext ctx) { // Find the player in the player table - auto player_opt = ctx.db[player_identity].find(ctx.sender); + auto player_opt = ctx.db[player_identity].find(ctx.sender()); if (!player_opt.has_value()) { return Err("Player not found"); } @@ -801,7 +801,7 @@ SPACETIMEDB_REDUCER(enter_game, ReducerContext ctx, std::string name) { LOG_INFO("Creating player with name " + name); // Find the player - auto player_opt = ctx.db[player_identity].find(ctx.sender); + auto player_opt = ctx.db[player_identity].find(ctx.sender()); if (!player_opt.has_value()) { return Err("Player not found"); } @@ -877,7 +877,7 @@ pub fn disconnect(ctx: &ReducerContext) -> Result<(), String> { ```cpp SPACETIMEDB_CLIENT_DISCONNECTED(disconnect, ReducerContext ctx) { // Find the player in the player table - auto player_opt = ctx.db[player_identity].find(ctx.sender); + auto player_opt = ctx.db[player_identity].find(ctx.sender()); if (!player_opt.has_value()) { return Err("Player not found"); } diff --git a/docs/docs/00100-intro/00300-tutorials/00300-unity-tutorial/00500-part-4.md b/docs/docs/00100-intro/00300-tutorials/00300-unity-tutorial/00500-part-4.md index e39977ffea4..5ca13a1b85c 100644 --- a/docs/docs/00100-intro/00300-tutorials/00300-unity-tutorial/00500-part-4.md +++ b/docs/docs/00100-intro/00300-tutorials/00300-unity-tutorial/00500-part-4.md @@ -306,7 +306,7 @@ Next, add the following reducer to the end of your `lib.cpp` file. ```cpp SPACETIMEDB_REDUCER(update_player_input, ReducerContext ctx, DbVector2 direction) { // Find the player - auto player_opt = ctx.db[player_identity].find(ctx.sender); + auto player_opt = ctx.db[player_identity].find(ctx.sender()); if (!player_opt.has_value()) { return Err("Player not found"); } @@ -324,7 +324,7 @@ SPACETIMEDB_REDUCER(update_player_input, ReducerContext ctx, DbVector2 direction } ``` -This is a simple reducer that takes the movement input from the client and applies them to all circles that that player controls. Note that it is not possible for a player to move another player's circles using this reducer, because the `ctx.sender` value is not set by the client. Instead `ctx.sender` is set by SpacetimeDB after it has authenticated that sender. You can rest assured that the caller has been authenticated as that player by the time this reducer is called. +This is a simple reducer that takes the movement input from the client and applies them to all circles that that player controls. Note that it is not possible for a player to move another player's circles using this reducer, because the `ctx.sender()` value is not set by the client. Instead `ctx.sender()` is set by SpacetimeDB after it has authenticated that sender. You can rest assured that the caller has been authenticated as that player by the time this reducer is called. diff --git a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00300-part-2.md b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00300-part-2.md index 8b4f28c9deb..972f2c37c9a 100644 --- a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00300-part-2.md +++ b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00300-part-2.md @@ -468,7 +468,7 @@ pub fn debug(ctx: &ReducerContext) -> Result<(), String> { ```cpp SPACETIMEDB_REDUCER(debug, ReducerContext ctx) { - LOG_INFO("This reducer was called by " + ctx.sender.to_string()); + LOG_INFO("This reducer was called by " + ctx.sender().to_string()); return Ok(); } ``` @@ -610,7 +610,7 @@ Next let's connect our client to our database. Let's start by modifying our `deb ```cpp SPACETIMEDB_CLIENT_CONNECTED(connect, ReducerContext ctx) { - LOG_INFO(ctx.sender.to_string() + " just connected."); + LOG_INFO(ctx.sender().to_string() + " just connected."); return Ok(); } ``` diff --git a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00400-part-3.md b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00400-part-3.md index 50e2d1b19fd..0f3c370f0f0 100644 --- a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00400-part-3.md +++ b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00400-part-3.md @@ -578,21 +578,21 @@ Next, modify your `connect` reducer and add a new `disconnect` reducer below it: ```cpp SPACETIMEDB_CLIENT_CONNECTED(connect, ReducerContext ctx) { // Check if this player was previously logged out - auto logged_out_player_opt = ctx.db[logged_out_player_identity].find(ctx.sender); + auto logged_out_player_opt = ctx.db[logged_out_player_identity].find(ctx.sender()); if (logged_out_player_opt.has_value()) { // Move player from logged_out_player to player table ctx.db[player].insert(logged_out_player_opt.value()); ctx.db[logged_out_player_identity].delete_by_key(logged_out_player_opt.value().identity); } else { // New player - create and insert into player table - ctx.db[player].insert(Player{ctx.sender, 0, ""}); + ctx.db[player].insert(Player{ctx.sender(), 0, ""}); } return Ok(); } SPACETIMEDB_CLIENT_DISCONNECTED(disconnect, ReducerContext ctx) { // Find the player in the player table - auto player_opt = ctx.db[player_identity].find(ctx.sender); + auto player_opt = ctx.db[player_identity].find(ctx.sender()); if (!player_opt.has_value()) { return Err("Player not found"); } @@ -788,7 +788,7 @@ SPACETIMEDB_REDUCER(enter_game, ReducerContext ctx, std::string name) { LOG_INFO("Creating player with name " + name); // Find the player - auto player_opt = ctx.db[player_identity].find(ctx.sender); + auto player_opt = ctx.db[player_identity].find(ctx.sender()); if (!player_opt.has_value()) { return Err("Player not found"); } @@ -864,7 +864,7 @@ pub fn disconnect(ctx: &ReducerContext) -> Result<(), String> { ```cpp SPACETIMEDB_CLIENT_DISCONNECTED(disconnect, ReducerContext ctx) { // Find the player in the player table - auto player_opt = ctx.db[player_identity].find(ctx.sender); + auto player_opt = ctx.db[player_identity].find(ctx.sender()); if (!player_opt.has_value()) { return Err("Player not found"); } diff --git a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00500-part-4.md b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00500-part-4.md index 608f01795d3..6a5f45264a7 100644 --- a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00500-part-4.md +++ b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00500-part-4.md @@ -305,7 +305,7 @@ Next, add the following reducer to the end of your `lib.cpp` file. ```cpp SPACETIMEDB_REDUCER(update_player_input, ReducerContext ctx, DbVector2 direction) { // Find the player - auto player_opt = ctx.db[player_identity].find(ctx.sender); + auto player_opt = ctx.db[player_identity].find(ctx.sender()); if (!player_opt.has_value()) { return Err("Player not found"); } @@ -323,7 +323,7 @@ SPACETIMEDB_REDUCER(update_player_input, ReducerContext ctx, DbVector2 direction } ``` -This is a simple reducer that takes the movement input from the client and applies them to all circles that that player controls. Note that it is not possible for a player to move another player's circles using this reducer, because the `ctx.sender` value is not set by the client. Instead `ctx.sender` is set by SpacetimeDB after it has authenticated that sender. You can rest assured that the caller has been authenticated as that player by the time this reducer is called. +This is a simple reducer that takes the movement input from the client and applies them to all circles that that player controls. Note that it is not possible for a player to move another player's circles using this reducer, because the `ctx.sender()` value is not set by the client. Instead `ctx.sender()` is set by SpacetimeDB after it has authenticated that sender. You can rest assured that the caller has been authenticated as that player by the time this reducer is called. diff --git a/docs/docs/00200-core-concepts/00100-databases/00500-cheat-sheet.md b/docs/docs/00200-core-concepts/00100-databases/00500-cheat-sheet.md index ec05ce1fe13..5768274a9ab 100644 --- a/docs/docs/00200-core-concepts/00100-databases/00500-cheat-sheet.md +++ b/docs/docs/00200-core-concepts/00100-databases/00500-cheat-sheet.md @@ -679,7 +679,7 @@ using namespace SpacetimeDB; // Return single row using unique indexed field SPACETIMEDB_VIEW(std::optional, my_player, Public, ViewContext ctx) { - return ctx.db[player_identity].find(ctx.sender); + return ctx.db[player_identity].find(ctx.sender()); } // Return multiple rows using indexed field @@ -733,7 +733,7 @@ ctx.rng() // Random number generator ```cpp ctx.db // Database access (Table accessor) -ctx.sender // Identity of caller (Identity type) +ctx.sender() // Identity of caller (Identity type) ctx.connection_id // std::optional ctx.timestamp // Timestamp of current transaction (Timestamp type) ctx.identity() // Module's own identity (Identity type) diff --git a/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00400-reducer-context.md b/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00400-reducer-context.md index 7bd4ed6f429..0dbd82df838 100644 --- a/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00400-reducer-context.md +++ b/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00400-reducer-context.md @@ -238,7 +238,7 @@ FIELD_PrimaryKey(player, identity); SPACETIMEDB_REDUCER(update_score, ReducerContext ctx, uint32_t new_score) { // Get the caller's identity - auto caller = ctx.sender; + auto caller = ctx.sender(); // Find and update their player record if (auto player = ctx.db[player_identity].find(caller)) { @@ -385,7 +385,7 @@ SPACETIMEDB_SCHEDULE(scheduled_task, 1, send_reminder); SPACETIMEDB_REDUCER(send_reminder, ReducerContext ctx, ScheduledTask task) { // Only allow the scheduler (module identity) to call this - if (ctx.sender != ctx.identity()) { + if (ctx.sender() != ctx.identity()) { return Err("This reducer can only be called by the scheduler"); } diff --git a/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00500-lifecycle.md b/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00500-lifecycle.md index d51a704b415..5a9b58e9adf 100644 --- a/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00500-lifecycle.md +++ b/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00500-lifecycle.md @@ -114,7 +114,7 @@ The `init` reducer: - Failure prevents publishing or clearing :::tip Module Owner -In the `init` reducer, `ctx.sender` is the **module owner** — the identity of the user who published the database. This is the only place where the owner identity is automatically provided, so if you need to reference it later (e.g. for authorization), store it in a table during `init`: +In the `init` reducer, `ctx.sender()` is the **module owner** — the identity of the user who published the database. This is the only place where the owner identity is automatically provided, so if you need to reference it later (e.g. for authorization), store it in a table during `init`: @@ -169,7 +169,7 @@ pub fn init(ctx: &ReducerContext) -> Result<(), String> { -You can then check `ctx.sender` against the stored owner identity in other reducers to restrict admin-only operations. +You can then check `ctx.sender()` against the stored owner identity in other reducers to restrict admin-only operations. ::: ## Client Connected @@ -256,7 +256,7 @@ SPACETIMEDB_TABLE(Session, sessions, Private); FIELD_PrimaryKey(sessions, connection_id); SPACETIMEDB_CLIENT_CONNECTED(on_connect, ReducerContext ctx) { - LOG_INFO("Client connected: " + ctx.sender.to_string()); + LOG_INFO("Client connected: " + ctx.sender().to_string()); // ctx.connection_id is guaranteed to be present auto conn_id = ctx.connection_id.value(); @@ -264,7 +264,7 @@ SPACETIMEDB_CLIENT_CONNECTED(on_connect, ReducerContext ctx) { // Initialize client session ctx.db[sessions].insert(Session{ conn_id, - ctx.sender, + ctx.sender(), ctx.timestamp }); @@ -352,7 +352,7 @@ SPACETIMEDB_TABLE(Session, sessions, Private); FIELD_PrimaryKey(sessions, connection_id); SPACETIMEDB_CLIENT_DISCONNECTED(on_disconnect, ReducerContext ctx) { - LOG_INFO("Client disconnected: " + ctx.sender.to_string()); + LOG_INFO("Client disconnected: " + ctx.sender().to_string()); // ctx.connection_id is guaranteed to be present auto conn_id = ctx.connection_id.value(); diff --git a/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00600-error-handling.md b/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00600-error-handling.md index 02b31568a8c..4fb03251e06 100644 --- a/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00600-error-handling.md +++ b/docs/docs/00200-core-concepts/00200-functions/00300-reducers/00600-error-handling.md @@ -119,7 +119,7 @@ pub fn transfer_credits( FIELD_PrimaryKey(users, identity); SPACETIMEDB_REDUCER(transfer_credits, ReducerContext ctx, Identity to_user, uint32_t amount) { - auto from_user = ctx.db[users_identity].find(ctx.sender); + auto from_user = ctx.db[users_identity].find(ctx.sender()); if (!from_user) { return Err("User not found"); } diff --git a/docs/docs/00200-core-concepts/00200-functions/00500-views.md b/docs/docs/00200-core-concepts/00200-functions/00500-views.md index 869d63911bd..a0f8f026f97 100644 --- a/docs/docs/00200-core-concepts/00200-functions/00500-views.md +++ b/docs/docs/00200-core-concepts/00200-functions/00500-views.md @@ -266,7 +266,7 @@ SPACETIMEDB_STRUCT(PlayerAndLevel, id, name, level) // At-most-one row: return std::optional SPACETIMEDB_VIEW(std::optional, my_player, Public, ViewContext ctx) { - return ctx.db[player_identity].find(ctx.sender); + return ctx.db[player_identity].find(ctx.sender()); } // Multiple rows: return std::vector @@ -366,7 +366,7 @@ fn my_player(ctx: &ViewContext) -> Option { ```cpp // Per-user: each client sees their own player SPACETIMEDB_VIEW(std::optional, my_player, Public, ViewContext ctx) { - return ctx.db[player_identity].find(ctx.sender); + return ctx.db[player_identity].find(ctx.sender()); } ``` @@ -694,7 +694,7 @@ SPACETIMEDB_VIEW(std::vector, entities_in_my_chunk, Public, ViewContext std::vector results; // Find the player's current location - auto player_opt = ctx.db[player_identity].find(ctx.sender); + auto player_opt = ctx.db[player_identity].find(ctx.sender()); if (!player_opt) { return results; // Player not found } diff --git a/docs/docs/00200-core-concepts/00300-tables.md b/docs/docs/00200-core-concepts/00300-tables.md index 1778ab3d1aa..79ca0a40cb5 100644 --- a/docs/docs/00200-core-concepts/00300-tables.md +++ b/docs/docs/00200-core-concepts/00300-tables.md @@ -499,10 +499,10 @@ FIELD_UniqueAutoInc(player, player_id) FIELD_UniqueAutoInc(logged_out_player, player_id) // Move a row between tables -auto maybe_logged_out = ctx.db[logged_out_player_identity].find(ctx.sender); +auto maybe_logged_out = ctx.db[logged_out_player_identity].find(ctx.sender()); if (maybe_logged_out) { ctx.db[player].insert(*maybe_logged_out); - ctx.db[logged_out_player_identity].delete_by_key(ctx.sender); + ctx.db[logged_out_player_identity].delete_by_key(ctx.sender()); } ``` diff --git a/docs/docs/00200-core-concepts/00300-tables/00400-access-permissions.md b/docs/docs/00200-core-concepts/00300-tables/00400-access-permissions.md index 4a8f76be9c6..93cb8db3675 100644 --- a/docs/docs/00200-core-concepts/00300-tables/00400-access-permissions.md +++ b/docs/docs/00200-core-concepts/00300-tables/00400-access-permissions.md @@ -543,8 +543,8 @@ FIELD_Index(message, recipient) // Public view that only returns messages the caller can see SPACETIMEDB_VIEW(std::vector, my_messages, Public, ViewContext ctx) { // Look up messages by index where caller is sender or recipient - auto sent = ctx.db[message_sender].filter(ctx.sender).collect(); - auto received = ctx.db[message_recipient].filter(ctx.sender).collect(); + auto sent = ctx.db[message_sender].filter(ctx.sender()).collect(); + auto received = ctx.db[message_recipient].filter(ctx.sender()).collect(); // Combine both vectors sent.insert(sent.end(), received.begin(), received.end()); @@ -734,7 +734,7 @@ SPACETIMEDB_STRUCT(PublicUserProfile, id, username, created_at) // Public view that returns the caller's profile without sensitive data SPACETIMEDB_VIEW(std::optional, my_profile, Public, ViewContext ctx) { // Look up the caller's account by their identity (unique index) - auto user_opt = ctx.db[user_account_identity].find(ctx.sender); + auto user_opt = ctx.db[user_account_identity].find(ctx.sender()); if (!user_opt.has_value()) { return std::nullopt; } @@ -937,7 +937,7 @@ SPACETIMEDB_STRUCT(Colleague, id, name, department) // View that returns colleagues in the caller's department, without salary info SPACETIMEDB_VIEW(std::vector, my_colleagues, Public, ViewContext ctx) { // Find the caller's employee record by identity (unique index) - auto me_opt = ctx.db[employee_identity].find(ctx.sender); + auto me_opt = ctx.db[employee_identity].find(ctx.sender()); if (!me_opt.has_value()) { return std::vector(); } diff --git a/docs/docs/00300-resources/00100-how-to/00300-logging.md b/docs/docs/00300-resources/00100-how-to/00300-logging.md index 6d58e58418c..0e43daee80a 100644 --- a/docs/docs/00300-resources/00100-how-to/00300-logging.md +++ b/docs/docs/00300-resources/00100-how-to/00300-logging.md @@ -138,7 +138,7 @@ SPACETIMEDB_REDUCER(process_data, ReducerContext ctx, uint32_t value) { return Err("Value cannot be zero"); } - LOG_DEBUG("Debug information: ctx.sender = " + ctx.sender.to_string()); + LOG_DEBUG("Debug information: ctx.sender = " + ctx.sender().to_string()); return Ok(); } @@ -276,7 +276,7 @@ Include relevant context in your log messages: using namespace SpacetimeDB; SPACETIMEDB_REDUCER(transfer_credits, ReducerContext ctx, uint64_t to_user, uint32_t amount) { - LOG_INFO("Credit transfer: from=" + ctx.sender.to_string() + + LOG_INFO("Credit transfer: from=" + ctx.sender().to_string() + ", to=" + std::to_string(to_user) + ", amount=" + std::to_string(amount)); diff --git a/docs/docs/00300-resources/00100-how-to/00600-migrating-to-2.0.md b/docs/docs/00300-resources/00100-how-to/00600-migrating-to-2.0.md index e0e48d00891..748b1a871b0 100644 --- a/docs/docs/00300-resources/00100-how-to/00600-migrating-to-2.0.md +++ b/docs/docs/00300-resources/00100-how-to/00600-migrating-to-2.0.md @@ -1400,7 +1400,7 @@ spacetime sql "SELECT * FROM my_table" - [ ] Set your module's case conversion policy to `None` - [ ] Change `with_module_name` to `with_database_name` - [ ] Change `ctx.sender` to `ctx.sender()` - - Only necessary in Rust modules. + - Necessary in Rust modules and in C++ module code/docs after the C++ context migration. - [ ] Remove `update` calls on non-primary key unique indexes - When leaving the primary key value unchanged, update using the primary key index - When altering the primary key value, delete and insert diff --git a/modules/module-test-cpp/src/lib.cpp b/modules/module-test-cpp/src/lib.cpp index 5a5e36be08c..a50f8e74fc8 100644 --- a/modules/module-test-cpp/src/lib.cpp +++ b/modules/module-test-cpp/src/lib.cpp @@ -217,7 +217,7 @@ FIELD_Default(table_with_defaults, active, true) // View to find the player associated with the calling identity SPACETIMEDB_VIEW(std::optional, my_player, Public, ViewContext ctx) { - return ctx.db[player_identity].find(ctx.sender); + return ctx.db[player_identity].find(ctx.sender()); } // ============================================================================= @@ -287,7 +287,7 @@ SPACETIMEDB_REDUCER(log_module_identity, ReducerContext ctx) { // Complex test reducer with multiple parameters SPACETIMEDB_REDUCER(test, ReducerContext ctx, TestAlias arg, TestB arg2, TestC arg3, TestF arg4) { LOG_INFO("BEGIN"); - LOG_INFO("sender: " + ctx.sender.to_string()); + LOG_INFO("sender: " + ctx.sender().to_string()); LOG_INFO("timestamp: " + ctx.timestamp.to_string()); LOG_INFO("bar: " + arg2.foo); @@ -550,8 +550,8 @@ SPACETIMEDB_REDUCER(test_btree_index_args, ReducerContext ctx) { // Test reducer for assertions SPACETIMEDB_REDUCER(assert_caller_identity_is_module_identity, ReducerContext ctx) { - LOG_INFO("Sender: " + ctx.sender.to_string() + " Identity: " + ctx.identity().to_string()); - if (ctx.sender != ctx.identity()) { + LOG_INFO("Sender: " + ctx.sender().to_string() + " Identity: " + ctx.identity().to_string()); + if (ctx.sender() != ctx.identity()) { LOG_ERROR("Assertion failed: caller identity does not match module identity"); } else { LOG_INFO("Assertion passed: caller identity matches module identity"); @@ -639,14 +639,14 @@ SPACETIMEDB_REDUCER(test_jwt_auth, ReducerContext ctx) { LOG_INFO("JWT Identity: " + identity.to_string()); // Compare with caller identity - LOG_INFO("Caller Identity: " + ctx.sender.to_string()); + LOG_INFO("Caller Identity: " + ctx.sender().to_string()); - // Verify that get_caller_identity returns the same as ctx.sender + // Verify that get_caller_identity returns the same as ctx.sender() auto caller_identity = auth.get_caller_identity(); - if (caller_identity == ctx.sender) { - LOG_INFO("get_caller_identity matches ctx.sender"); + if (caller_identity == ctx.sender()) { + LOG_INFO("get_caller_identity matches ctx.sender()"); } else { - LOG_ERROR("get_caller_identity does NOT match ctx.sender"); + LOG_ERROR("get_caller_identity does NOT match ctx.sender()"); } } else { LOG_INFO("No JWT present (anonymous or scheduled reducer)"); diff --git a/modules/sdk-test-connect-disconnect-cpp/src/lib.cpp b/modules/sdk-test-connect-disconnect-cpp/src/lib.cpp index a8e4f43cb47..4090ea8d05b 100644 --- a/modules/sdk-test-connect-disconnect-cpp/src/lib.cpp +++ b/modules/sdk-test-connect-disconnect-cpp/src/lib.cpp @@ -22,11 +22,11 @@ SPACETIMEDB_TABLE(Disconnected, disconnected, Public) // Reducers: client lifecycle callbacks SPACETIMEDB_CLIENT_CONNECTED(identity_connected, ReducerContext ctx) { - ctx.db[connected].insert(Connected{ ctx.sender }); + ctx.db[connected].insert(Connected{ ctx.sender() }); return Ok(); } SPACETIMEDB_CLIENT_DISCONNECTED(identity_disconnected, ReducerContext ctx) { - ctx.db[disconnected].insert(Disconnected{ ctx.sender }); + ctx.db[disconnected].insert(Disconnected{ ctx.sender() }); return Ok(); } diff --git a/modules/sdk-test-cpp/src/lib.cpp b/modules/sdk-test-cpp/src/lib.cpp index 18a093ec6f7..6a238395537 100644 --- a/modules/sdk-test-cpp/src/lib.cpp +++ b/modules/sdk-test-cpp/src/lib.cpp @@ -1882,25 +1882,25 @@ SPACETIMEDB_REDUCER(insert_table_holds_table, ReducerContext ctx, OneU8 a, VecU8 SPACETIMEDB_REDUCER(insert_caller_one_identity, ReducerContext ctx) { - ctx.db[one_identity].insert(OneIdentity{ctx.sender}); + ctx.db[one_identity].insert(OneIdentity{ctx.sender()}); return Ok(); } SPACETIMEDB_REDUCER(insert_caller_vec_identity, ReducerContext ctx) { - ctx.db[vec_identity].insert(VecIdentity{{ctx.sender}}); + ctx.db[vec_identity].insert(VecIdentity{{ctx.sender()}}); return Ok(); } SPACETIMEDB_REDUCER(insert_caller_unique_identity, ReducerContext ctx, int32_t data) { - ctx.db[unique_identity].insert(UniqueIdentity{ctx.sender, data}); + ctx.db[unique_identity].insert(UniqueIdentity{ctx.sender(), data}); return Ok(); } SPACETIMEDB_REDUCER(insert_caller_pk_identity, ReducerContext ctx, int32_t data) { - ctx.db[pk_identity].insert(PkIdentity{ctx.sender, data}); + ctx.db[pk_identity].insert(PkIdentity{ctx.sender(), data}); return Ok(); } diff --git a/modules/sdk-test-view-cpp/src/lib.cpp b/modules/sdk-test-view-cpp/src/lib.cpp index 4594d6cd8bf..c12b63cce32 100644 --- a/modules/sdk-test-view-cpp/src/lib.cpp +++ b/modules/sdk-test-view-cpp/src/lib.cpp @@ -95,12 +95,12 @@ SPACETIMEDB_REDUCER(delete_player, ReducerContext ctx, Identity identity) SPACETIMEDB_REDUCER(move_player, ReducerContext ctx, int32_t dx, int32_t dy) { // Find or create player - auto my_player_opt = ctx.db[player_identity].find(ctx.sender); + auto my_player_opt = ctx.db[player_identity].find(ctx.sender()); Player my_player; if (!my_player_opt.has_value()) { // Create new player - my_player = ctx.db[player].insert(Player{0, ctx.sender}); + my_player = ctx.db[player].insert(Player{0, ctx.sender()}); } else { my_player = my_player_opt.value(); } @@ -133,14 +133,14 @@ SPACETIMEDB_REDUCER(move_player, ReducerContext ctx, int32_t dx, int32_t dy) // View: my_player - Returns the player for the caller SPACETIMEDB_VIEW(std::optional, my_player, Public, ViewContext ctx) { - auto player_opt = ctx.db[player_identity].find(ctx.sender); + auto player_opt = ctx.db[player_identity].find(ctx.sender()); return player_opt; } // View: my_player_and_level - Returns player with level joined SPACETIMEDB_VIEW(std::optional, my_player_and_level, Public, ViewContext ctx) { // Find the caller's player - auto player_opt = ctx.db[player_identity].find(ctx.sender); + auto player_opt = ctx.db[player_identity].find(ctx.sender()); if (!player_opt.has_value()) { return std::optional(); } @@ -183,7 +183,7 @@ SPACETIMEDB_VIEW(std::vector, nearby_players, Public, ViewContex std::vector results; // Find the caller's player - auto my_player_opt = ctx.db[player_identity].find(ctx.sender); + auto my_player_opt = ctx.db[player_identity].find(ctx.sender()); if (!my_player_opt.has_value()) { return results; // No player, return empty } From 527dda97ef92b9a149170d96afd679a505bdeb8a Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Fri, 13 Mar 2026 10:36:30 -0700 Subject: [PATCH 13/15] Documentation update and final change for upgrade-version to update C++ path --- .../00600-clients/00800-unreal-reference.md | 37 +- .../00100-how-to/00600-migrating-to-2.0.md | 395 ++++++++++++++++++ tools/upgrade-version/src/main.rs | 6 - 3 files changed, 403 insertions(+), 35 deletions(-) diff --git a/docs/docs/00200-core-concepts/00600-clients/00800-unreal-reference.md b/docs/docs/00200-core-concepts/00600-clients/00800-unreal-reference.md index 6f707793efe..906d62f3b0a 100644 --- a/docs/docs/00200-core-concepts/00600-clients/00800-unreal-reference.md +++ b/docs/docs/00200-core-concepts/00600-clients/00800-unreal-reference.md @@ -19,7 +19,7 @@ Before diving into the reference, you may want to review: | [DbConnection type](#type-dbconnection) | A connection to a remote database. | | [Context interfaces](#context-interfaces) | Context objects for interacting with the remote database in callbacks. | | [Access the client cache](#access-the-client-cache) | Access to your local view of the database. | -| [Observe and invoke reducers](#observe-and-invoke-reducers) | Send requests to the database to run reducers, and register callbacks to run when notified of reducers. | +| [Observe and invoke reducers](#observe-and-invoke-reducers) | Send requests to the database to run reducers, and register callbacks for reducer results on the calling connection. | | [Subscriptions](#subscriptions) | Subscribe to queries and manage subscription lifecycle. | | [Identify a client](#identify-a-client) | Types for identifying users and client connections. | @@ -182,7 +182,7 @@ class UDbConnectionBuilder }; ``` -Finalize configuration and open the connection. This creates a WebSocket connection to `ws:///v1/database//subscribe?compression=` and begins processing messages. +Finalize configuration and open the connection. This creates a WebSocket connection to `ws:///v1/database//subscribe?compression=` and begins processing messages using the Unreal SDK's binary v2 WebSocket subprotocol. ### Advance the connection and process messages @@ -198,13 +198,10 @@ class UDbConnection UPROPERTY(BlueprintReadOnly, Category="SpacetimeDB") URemoteReducers* Reducers; - - UPROPERTY(BlueprintReadOnly, Category="SpacetimeDB") - USetReducerFlags* SetReducerFlags; }; ``` -The `Db` property provides access to the client cache, the `Reducers` property allows invoking reducers, and the `SetReducerFlags` property configures reducer behavior. +The `Db` property provides access to the client cache, and the `Reducers` property allows invoking reducers and handling the results of reducers called by this connection. ## Context interfaces @@ -450,12 +447,12 @@ int32 CountPlayersAtLevel(URemoteTables* Tables, uint32 Level) ## Observe and invoke reducers -All context types provide access to reducers through the `.Reducers` property, which contains generated methods for invoking reducers defined by the module and registering callbacks. +All context types provide access to reducers through the `.Reducers` property, which contains generated methods for invoking reducers defined by the module and generated delegates for reducer results. Each reducer defined by the module has methods on the `.Reducers`: - An invoke method, whose name matches the reducer's name (e.g., `SendMessage`, `SetName`). This requests that the module run the reducer. -- A callback registration delegate, whose name is prefixed with `On` (e.g., `OnSendMessage`, `OnSetName`). This registers a callback to run whenever we are notified that the reducer ran. +- A generated delegate, whose name is prefixed with `On` (e.g., `OnSendMessage`, `OnSetName`). This runs when the result for a reducer call made by this connection is received and correlated by `request_id`. ### Invoke reducers @@ -470,7 +467,7 @@ class URemoteReducers }; ``` -### Observe reducer events +### Observe reducer results ```cpp class URemoteReducers @@ -493,24 +490,7 @@ class URemoteReducers }; ``` -### Reducer flags - -```cpp -class USetReducerFlags -{ - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void SendMessage(ECallReducerFlags Flag); - - UFUNCTION(BlueprintCallable, Category = "SpacetimeDB") - void SetName(ECallReducerFlags Flag); -}; -``` - -Configure how much data to receive when a reducer runs: - -- `ECallReducerFlags::FullUpdate` - Receive all table updates (default) -- `ECallReducerFlags::NoUpdate` - Don't receive table updates -- `ECallReducerFlags::LightUpdate` - Receive minimal table updates +The generated `On` delegates are the Unreal equivalent of a per-call callback. They are not global reducer broadcasts for other clients' reducer calls. ## Subscriptions @@ -717,9 +697,8 @@ void AMyActor::BeginPlay() Conn->Db->User->OnUpdate.AddDynamic(this, &AMyActor::OnUserUpdate); Conn->Db->User->OnDelete.AddDynamic(this, &AMyActor::OnUserDelete); - // Register reducer callbacks + // Register reducer result callbacks for calls made by this connection Conn->Reducers->OnSendMessage.AddDynamic(this, &AMyActor::OnSendMessage); - Conn->SetReducerFlags->SendMessage(ECallReducerFlags::FullUpdate); } void AMyActor::OnConnected(UDbConnection* Connection, FSpacetimeDBIdentity Identity, const FString& Token) diff --git a/docs/docs/00300-resources/00100-how-to/00600-migrating-to-2.0.md b/docs/docs/00300-resources/00100-how-to/00600-migrating-to-2.0.md index 748b1a871b0..4db91e67cd5 100644 --- a/docs/docs/00300-resources/00100-how-to/00600-migrating-to-2.0.md +++ b/docs/docs/00300-resources/00100-how-to/00600-migrating-to-2.0.md @@ -57,6 +57,20 @@ conn.reducers.on_deal_damage(|ctx, target, amount| { }); ``` + + + +```cpp +// 1.0-style global reducer callback semantics (no longer true in 2.0) +UFUNCTION() +void OnDealDamage(const FReducerEventContext& Context, const FSpacetimeDBIdentity& Target, int32 Amount) +{ + UE_LOG(LogTemp, Log, TEXT("Someone called DealDamage with args: (%s, %d)"), *Target.ToString(), Amount); +} + +Conn->Reducers->OnDealDamage.AddDynamic(this, &AMyActor::OnDealDamage); +``` + @@ -127,6 +141,34 @@ The fire-and-forget form still works: ctx.reducers.deal_damage(target, amount).unwrap(); ``` + + + +```cpp +// 2.0 -- per-call callback on the calling connection +UFUNCTION() +void OnDealDamage(const FReducerEventContext& Context, const FSpacetimeDBIdentity& Target, int32 Amount) +{ + if (Context.Event.Status.IsCommitted()) + { + UE_LOG(LogTemp, Log, TEXT("Reducer succeeded")); + } + else if (Context.Event.Status.IsFailed()) + { + UE_LOG(LogTemp, Error, TEXT("Reducer failed: %s"), *Context.Event.Status.GetAsFailed()); + } + else if (Context.Event.Status.IsOutOfEnergy()) + { + UE_LOG(LogTemp, Error, TEXT("Reducer failed: out of energy")); + } +} + +Conn->Reducers->OnDealDamage.AddDynamic(this, &AMyActor::OnDealDamage); +Conn->Reducers->DealDamage(Target, Amount); +``` + +In Unreal, there is no `_then()` method. The generated `On` delegate is correlated by `request_id` and only fires on the connection that called the reducer. + @@ -227,6 +269,39 @@ fn deal_damage(ctx: &ReducerContext, target: Identity, amount: u32) { } ``` + + + +**Server (module) -- before:** +```cpp +// 1.0-style reducer arguments were effectively observable through reducer callbacks +SPACETIMEDB_REDUCER(deal_damage, ReducerContext ctx, Identity target, uint32_t amount) { + // update game state... + return Ok(); +} +``` + +**Server (module) -- after:** +```cpp +// 2.0 server -- explicitly publish events via an event table +#include +using namespace SpacetimeDB; + +struct DamageEvent { + Identity target; + uint32_t amount; +}; +SPACETIMEDB_STRUCT(DamageEvent, target, amount); +SPACETIMEDB_TABLE(DamageEvent, damage_event, Public); + +SPACETIMEDB_REDUCER(deal_damage, ReducerContext ctx, Identity target, uint32_t amount) { + // update game state... + + ctx.db[damage_event].insert(DamageEvent{target, amount}); + return Ok(); +} +``` + @@ -293,6 +368,40 @@ conn.db.damage_event().on_insert(|ctx, event| { }); ``` + + + +**Client -- before:** +```cpp +// 1.0 -- NO LONGER VALID in 2.0 (global reducer callback) +UFUNCTION() +void OnDealDamage(const FReducerEventContext& Context, const FSpacetimeDBIdentity& Target, int32 Amount) +{ + PlayDamageAnimation(Target, Amount); +} + +Conn->Reducers->OnDealDamage.AddDynamic(this, &AMyActor::OnDealDamage); +``` + +**Client -- after:** +```cpp +// 2.0 client -- event table callback +// Note that although this callback fires, the `DamageEvent` +// table will never have any rows present in the client cache +UFUNCTION() +void OnDamageEvent(const FEventContext& Context, const FDamageEventType& DamageEvent) +{ + PlayDamageAnimation(DamageEvent.Target, DamageEvent.Amount); +} + +Conn->Db->DamageEvent->OnInsert.AddDynamic(this, &AMyActor::OnDamageEvent); + +Conn->SubscriptionBuilder() + ->OnApplied(OnAppliedDelegate) + ->OnError(OnErrorDelegate) + ->Subscribe({ TEXT("SELECT * FROM damage_event") }); +``` + @@ -394,6 +503,31 @@ conn.db.my_table().on_insert(|ctx, row| { }); ``` + + + +In 1.0, table callbacks could receive a reducer event with full reducer information when a reducer caused a table change. In 2.0: + +- **The caller** sees `Context.Event.IsReducer()` with `FReducerEvent { Timestamp, Status, Reducer }`. +- **Other clients** see `Context.Event.IsTransaction()` with no reducer details. + +```cpp +// 2.0 -- checking who caused a table change +UFUNCTION() +void OnPersonInsert(const FEventContext& Context, const FPersonType& Row) +{ + if (Context.Event.IsReducer()) + { + const auto ReducerEvent = Context.Event.GetAsReducer(); + UE_LOG(LogTemp, Log, TEXT("Our reducer: %s"), *ReducerEvent.ReducerName); + } + else if (Context.Event.IsTransaction()) + { + // Another client's action caused this insert. + } +} +``` + @@ -447,6 +581,19 @@ ctx.subscription_builder() .subscribe(); ``` + + + +```cpp +// 2.0 -- same as 1.0 today +Conn->SubscriptionBuilder() + ->OnApplied(OnAppliedDelegate) + ->OnError(OnErrorDelegate) + ->Subscribe({ TEXT("SELECT * FROM person") }); +``` + +The Unreal SDK does not expose typed query builders yet. For now, use SQL strings. Typed query builder support is planned. + @@ -485,6 +632,17 @@ ctx.subscription_builder() .subscribe(); ``` + + + +```cpp +// Event tables are excluded from SubscribeToAllTables(), so subscribe explicitly: +Conn->SubscriptionBuilder() + ->OnApplied(OnAppliedDelegate) + ->OnError(OnErrorDelegate) + ->Subscribe({ TEXT("SELECT * FROM damage_event") }); +``` + @@ -602,6 +760,31 @@ struct MyTable { } ``` + + + +The C++ module API does not have a direct `name -> accessor` rename like C# and Rust. + +In C++, the second argument to `SPACETIMEDB_TABLE(...)` is already the table accessor you use in module code, and the second argument to `FIELD_NamedMultiColumnIndex(...)` is already the index accessor. + +So for this migration step, keep using the accessor names you want in code: + +```cpp +struct MyTable { + uint32_t id; + uint32_t x; + uint32_t y; +}; +SPACETIMEDB_STRUCT(MyTable, id, x, y); + +// 2.0 +SPACETIMEDB_TABLE(MyTable, my_table, Public); +FIELD_PrimaryKeyAutoInc(my_table, id); +FIELD_NamedMultiColumnIndex(my_table, position, x, y); +``` + +If you also need to preserve or override the canonical SQL names that appear in migrations or SQL, use the explicit-name forms described in Option 2 below. + @@ -641,6 +824,15 @@ use spacetimedb::CaseConversionPolicy; const CASE_CONVERSION_POLICY: CaseConversionPolicy = CaseConversionPolicy::None; ``` + + + +```cpp +SPACETIMEDB_SETTING_CASE_CONVERSION(SpacetimeDB::CaseConversionPolicy::None) +``` + +Use `SPACETIMEDB_SETTING_CASE_CONVERSION(...)` to preserve 1.0-style canonical names when migrating a C++ module. + @@ -707,6 +899,23 @@ struct MyTable { } ``` + + + +If you need to preserve an existing canonical SQL name during migration, pass it directly to `SPACETIMEDB_TABLE(...)`. Use the `_NAMED` field/index macros only for index canonical names. + +```cpp +struct MyTable { + uint32_t id; + uint32_t x; + uint32_t y; +}; +SPACETIMEDB_STRUCT(MyTable, id, x, y); +SPACETIMEDB_TABLE(MyTable, my_table, Public, "MyTable"); +FIELD_PrimaryKeyAutoInc(my_table, id); +FIELD_MultiColumnIndex_NAMED(my_table, position, "Position", x, y); +``` + @@ -777,6 +986,26 @@ let conn = DbConnection::builder() .expect("Failed to connect"); ``` + + + +When constructing a `UDbConnection` to a remote database, use `WithDatabaseName` in 2.0. The Unreal 2.0 builder does not expose `WithModuleName`. + +```cpp +// 1.0 terminology in other SDKs / older docs +// UDbConnection::Builder() +// ->WithUri(TEXT("https://maincloud.spacetimedb.com")) +// ->WithModuleName(TEXT("my-database")) +// ->Build(); + +// 2.0 +UDbConnection* Conn = UDbConnection::Builder() + ->WithUri(TEXT("https://maincloud.spacetimedb.com")) + ->WithDatabaseName(TEXT("my-database")) + // other options... + ->Build(); +``` + @@ -813,6 +1042,26 @@ fn my_reducer(ctx: &ReducerContext) { } ``` + + +In C++ modules, the sender is now accessed with `ctx.sender()` rather than a `ctx.sender` field. + +```cpp +// 1.0 -- NO LONGER CORRECT +SPACETIMEDB_REDUCER(my_reducer, ReducerContext ctx) { + auto sender_identity = ctx.sender; + // Do stuff with `sender_identity`... + return Ok(); +} + +// 2.0 +SPACETIMEDB_REDUCER(my_reducer, ReducerContext ctx) { + auto sender_identity = ctx.sender(); + // Do stuff with `sender_identity`... + return Ok(); +} +``` + ## Only Primary Keys Have Update Methods @@ -1014,6 +1263,65 @@ fn change_user_identity(ctx: &ReducerContext, name: String, identity: Identity) } ``` + + + +In 2.0 modules, updates should go through the primary key index. If you were previously treating another unique index like an update handle, migrate to primary-key updates or an explicit delete-plus-insert. + +### Updates which preserve the primary key - update with the primary key index + +```cpp +struct User { + Identity identity; + std::string name; + uint32_t apples_owned; +}; +SPACETIMEDB_STRUCT(User, identity, name, apples_owned); +SPACETIMEDB_TABLE(User, user, Public); +FIELD_PrimaryKey(user, identity); +FIELD_Unique(user, name); + +// 2.0 +SPACETIMEDB_REDUCER(add_apple, ReducerContext ctx, std::string name) { + auto user_row = ctx.db[user_name].find(name); + if (!user_row) { + return Err("User not found"); + } + + user_row->apples_owned += 1; + ctx.db[user_identity].update(*user_row); + return Ok(); +} +``` + +### Updates which change the primary key - explicitly delete and insert + +```cpp +struct User { + Identity identity; + std::string name; + uint32_t apples_owned; +}; +SPACETIMEDB_STRUCT(User, identity, name, apples_owned); +SPACETIMEDB_TABLE(User, user, Public); +FIELD_PrimaryKey(user, identity); +FIELD_Unique(user, name); + +// 2.0 +SPACETIMEDB_REDUCER(change_user_identity, ReducerContext ctx, std::string name, Identity identity) { + auto user_row = ctx.db[user_name].find(name); + if (!user_row) { + return Err("User not found"); + } + + User updated = *user_row; + ctx.db[user_identity].delete_by_key(updated.identity); + updated.identity = identity; + ctx.db[user].insert(updated); + return Ok(); +} +``` + @@ -1119,6 +1427,35 @@ fn run_my_timer(ctx: &ReducerContext, timer: MyTimer) { } ``` + + + +```cpp +struct MyTimer { + uint64_t scheduled_id; + ScheduleAt scheduled_at; +}; +SPACETIMEDB_STRUCT(MyTimer, scheduled_id, scheduled_at); +SPACETIMEDB_TABLE(MyTimer, my_timer, Private); +FIELD_PrimaryKeyAutoInc(my_timer, scheduled_id); +SPACETIMEDB_SCHEDULE(my_timer, 1, run_my_timer); + +// 1.0 - SUPERFLUOUS IN 2.0 +SPACETIMEDB_REDUCER(run_my_timer, ReducerContext ctx, MyTimer timer) { + if (ctx.sender() != ctx.identity()) { + return Err("`run_my_timer` should only be invoked by the database!"); + } + // Do stuff... + return Ok(); +} + +// 2.0 +SPACETIMEDB_REDUCER(run_my_timer, ReducerContext ctx, MyTimer timer) { + // Do stuff... + return Ok(); +} +``` + @@ -1194,6 +1531,29 @@ fn run_my_timer(ctx: &ReducerContext, timer: MyTimer) { } ``` + + + +```cpp +struct MyTimer { + uint64_t scheduled_id; + ScheduleAt scheduled_at; +}; +SPACETIMEDB_STRUCT(MyTimer, scheduled_id, scheduled_at); +SPACETIMEDB_TABLE(MyTimer, my_timer, Private); +FIELD_PrimaryKeyAutoInc(my_timer, scheduled_id); +SPACETIMEDB_SCHEDULE(my_timer, 1, run_my_timer_private); + +SPACETIMEDB_REDUCER(run_my_timer_private, ReducerContext ctx, MyTimer timer) { + // Do stuff... + return Ok(); +} + +SPACETIMEDB_REDUCER(run_my_timer, ReducerContext ctx, MyTimer timer) { + return run_my_timer_private(ctx, timer); +} +``` + @@ -1241,6 +1601,14 @@ DbConnection::builder() // ... ``` + + + +```cpp +// 1.0 equivalent removed in 2.0 +// The Unreal 2.0 builder does not expose WithLightMode(...) +``` + @@ -1282,6 +1650,20 @@ DbConnection::builder() .build() ``` + + + +```cpp +// 2.0 +UDbConnection* Conn = UDbConnection::Builder() + ->WithUri(Uri) + ->WithDatabaseName(DatabaseName) + // no WithLightMode needed + ->Build(); +``` + +This migration item does not apply directly to Unreal. The 2.0 Unreal builder has no public `WithLightMode(...)` API. + @@ -1318,6 +1700,11 @@ ctx.reducers.my_reducer(args).unwrap(); In 2.0, the success notification is lightweight (just `request_id` and `timestamp`, no reducer args or full event data), so there is no need to suppress it. Remove any `set_reducer_flags` calls and `CallReducerFlags` imports. + + + +This migration item does not apply to Unreal. The 2.0 Unreal SDK has no public `CallReducerFlags` or `setReducerFlags` equivalent. + @@ -1373,6 +1760,11 @@ DbConnection::builder() .expect("Failed to connect"); ``` + + + +The Unreal SDK gets confirmed reads by default in 2.0. There is currently no Unreal builder method for opting out. + @@ -1388,6 +1780,7 @@ spacetime sql "SELECT * FROM my_table" - [ ] Remove all `ctx.reducers.on_()` calls - Replace with `_then()` callbacks for your own reducer calls + - Unreal: replace with generated `On` delegates on the calling connection - Replace with event tables + `on_insert` for cross-client notifications - [ ] Update `Event::UnknownTransaction` matches to `Event::Transaction` - [ ] For each reducer whose args you were observing from other clients: @@ -1408,6 +1801,8 @@ spacetime sql "SELECT * FROM my_table" - [ ] Define wrappers around scheduled functions which are called by clients - [ ] Use `spacetime generate --include-private` if you rely on bindings for private tables or functions - [ ] Remove `with_light_mode()` from `DbConnectionBuilder` + - Unreal: no action if you are already on the 2.0 Unreal SDK; there is no public `WithLightMode(...)` - [ ] Remove `set_reducer_flags()` calls and `CallReducerFlags` imports + - Unreal: no action if you are already on the 2.0 Unreal SDK; there is no public reducer-flags API - [ ] Remove `unstable::CallReducerFlags` from imports - [ ] Note that confirmed reads are now enabled by default (no action needed unless you want to opt out with `.withConfirmedReads(false)`) diff --git a/tools/upgrade-version/src/main.rs b/tools/upgrade-version/src/main.rs index 0d5c7904ce9..a7a6bc41d31 100644 --- a/tools/upgrade-version/src/main.rs +++ b/tools/upgrade-version/src/main.rs @@ -376,12 +376,6 @@ fn main() -> anyhow::Result<()> { )?; } if matches.get_flag("cpp") || matches.get_flag("all") { - // TODO(26-02-17 jlarabie): Keep C++ pinned to 1.12.x for the 2.0 release train. - // Re-enable this codepath when C++ 2.0 is ready and we're intentionally - // moving the C++ SDK/template versions forward. - eprintln!("Warning: Not bumping C++ version. See inline comment for details."); - return Ok(()); - #[allow(unreachable_code)] { rewrite_cmake_version_inplace("crates/bindings-cpp/CMakeLists.txt", &full_version)?; From 1b136834760c94e7ec9606f05a95f117f3120cde Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Fri, 13 Mar 2026 12:33:22 -0700 Subject: [PATCH 14/15] Update docs/docs/00300-resources/00100-how-to/00600-migrating-to-2.0.md Co-authored-by: Ryan Signed-off-by: Jason Larabie --- .../docs/00300-resources/00100-how-to/00600-migrating-to-2.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/00300-resources/00100-how-to/00600-migrating-to-2.0.md b/docs/docs/00300-resources/00100-how-to/00600-migrating-to-2.0.md index 4db91e67cd5..d3de7a145c3 100644 --- a/docs/docs/00300-resources/00100-how-to/00600-migrating-to-2.0.md +++ b/docs/docs/00300-resources/00100-how-to/00600-migrating-to-2.0.md @@ -1793,7 +1793,7 @@ spacetime sql "SELECT * FROM my_table" - [ ] Set your module's case conversion policy to `None` - [ ] Change `with_module_name` to `with_database_name` - [ ] Change `ctx.sender` to `ctx.sender()` - - Necessary in Rust modules and in C++ module code/docs after the C++ context migration. + - Only necessary in Rust and C++ modules. - [ ] Remove `update` calls on non-primary key unique indexes - When leaving the primary key value unchanged, update using the primary key index - When altering the primary key value, delete and insert From 60ef6128bbed302524d4f9bf82a2b2614ea844f7 Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Fri, 13 Mar 2026 12:33:44 -0700 Subject: [PATCH 15/15] Update docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00300-part-2.md Co-authored-by: Ryan Signed-off-by: Jason Larabie --- .../00300-tutorials/00400-unreal-tutorial/00300-part-2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00300-part-2.md b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00300-part-2.md index 972f2c37c9a..4ae2a3e84e8 100644 --- a/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00300-part-2.md +++ b/docs/docs/00100-intro/00300-tutorials/00400-unreal-tutorial/00300-part-2.md @@ -659,7 +659,7 @@ This will generate a set of files in the `blackholio/Source/blackholio/Private/M ::: :::warning -After generating external code with `spacetime generate` highly recommended you restart the Unreal Editor, it can also help to run the `Generate project files` against the `.uproject` file. +After generating external code with `spacetime generate` it is highly recommended you restart the Unreal Editor, it can also help to run the `Generate project files` against the `.uproject` file. ::: ```