From efa9fd55ace59933b23e5af7ec0da7abb0de5d2b Mon Sep 17 00:00:00 2001 From: Jason Larabie Date: Wed, 25 Feb 2026 15:05:50 -0800 Subject: [PATCH 01/10] 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/10] 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/10] 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/10] 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/10] 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/10] 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/10] 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/10] 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 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

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/10] 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/10] 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;