mirror of
https://github.com/clockworklabs/SpacetimeDB.git
synced 2026-07-25 11:32:30 -04:00
f8d6d76ee4
# Description of Changes - Updated the Unreal SDK and generated Unreal bindings for the websocket 2.0 protocol/model - Reworked DbConnectionBase to handle the updated message shapes - Switched subscription handling over to new message types and QuerySetId - Updated reducer to ReducerResult, removal of callbacks, and set reducer flags - Added event table support - Baked in multi-module support replacing [the old PR](<https://github.com/clockworklabs/SpacetimeDB/pull/3417>) - Added functionality to generate module support for multiple folders in the Unreal project (add <module>.Build.cs, <module>.h, <module>.cpp) using the --module-name - Add new configuration option for spacetime generate to handle module prefix - Regenerated Unreal Blackholio/TestClient/QuickstartChat bindings - Rebuilt Unreal Blackholio's consume entity to use event tables - Updated migration documentation - Updated the version bump tool to impact C++ # API and ABI breaking changes - Unreal websocket/message handling updated to the new protocol - Unreal generation now expects a real .uproject target and will stop immediately if project metadata is invalid instead of continuing past setup issues. # Expected complexity level and risk 3 - A large set of changes to update the websocket/message handling along with heavy codegen changes to handle multi-module support # Testing Test coverage of the Unreal SDK will need expansion in a future ticket once our issues with flakiness on CI is resolved. - [x] Updated Unreal Blackholio - [x] Ran full Unreal SDK test suite - [x] Built new test project using the new `--module-prefix` - [x] Run through Unreal Blackholio (C++ and Blueprint) - [x] Rebuilt Unreal Blackholio with multi-module, and duplicate generated module testing side-by-side modules that would overlap # Review Question(s) - [x] Updates to `spacetime init` have made the tutorial a little confusing with pathing for the Unreal Blackholio tutorial. To fix though we'd have to update all the commands to be more explicit, or update the tutorial `spacetime init` to use `--project-path .` to keep pathing simpler, thoughts? --------- Signed-off-by: Jason Larabie <jason@clockworklabs.io> Co-authored-by: Ryan <r.ekhoff@clockworklabs.io>
167 lines
6.4 KiB
C++
167 lines
6.4 KiB
C++
#pragma once
|
|
|
|
#include "spacetimedb/bsatn/types.h"
|
|
#include "spacetimedb/reducer_context.h"
|
|
#include "spacetimedb/internal/Module.h"
|
|
#include "spacetimedb/internal/v10_builder.h"
|
|
#include "spacetimedb/macros.h"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <sstream>
|
|
|
|
// Note: parseParameterNames() is now in macros.h for reuse across reducers and views
|
|
|
|
/**
|
|
* @brief Unified SPACETIMEDB_REDUCER macro for defining SpacetimeDB reducers
|
|
*
|
|
* This macro provides a clean, consistent syntax for defining reducers with
|
|
* automatic registration in the SpacetimeDB module system.
|
|
*
|
|
* Reducers now return SpacetimeDB::ReducerResult to support Result-based
|
|
* error handling matching Rust's Result<(), E> pattern.
|
|
*
|
|
* @usage
|
|
* ```cpp
|
|
* // Reducer with no extra parameters
|
|
* SPACETIMEDB_REDUCER(my_reducer, ReducerContext ctx) {
|
|
* if (some_error) {
|
|
* return Err("Error message");
|
|
* }
|
|
* ctx.db.table<MyTable>("my_table").insert(MyTable{});
|
|
* return Ok();
|
|
* }
|
|
*
|
|
* // Reducer with parameters
|
|
* SPACETIMEDB_REDUCER(my_reducer, ReducerContext ctx, uint32_t id, std::string name) {
|
|
* if (id == 0) {
|
|
* return Err("ID must be non-zero");
|
|
* }
|
|
* ctx.db.table<MyTable>("my_table").insert(MyTable{id, name});
|
|
* return Ok();
|
|
* }
|
|
* ```
|
|
*
|
|
* @param name The name of the reducer function
|
|
* @param ctx_param Must be ReducerContext ctx
|
|
* @param ... Additional parameters (optional)
|
|
*
|
|
* @details
|
|
* The macro generates:
|
|
* 1. A function declaration and definition with ReducerResult return type
|
|
* 2. A preinit registration function that registers the reducer with SpacetimeDB
|
|
*
|
|
* The first parameter must always be `ReducerContext ctx`. Additional parameters
|
|
* can be any types that support BSATN serialization.
|
|
*/
|
|
#undef SPACETIMEDB_REDUCER
|
|
#define SPACETIMEDB_REDUCER(name, ctx_param, ...) \
|
|
/* Forward declaration - returns ReducerResult */ \
|
|
SpacetimeDB::ReducerResult name(ctx_param __VA_OPT__(,) __VA_ARGS__); \
|
|
\
|
|
/* Preinit registration function */ \
|
|
/* This function is called during module initialization to register the reducer */ \
|
|
__attribute__((export_name("__preinit__30_reducer_" #name))) \
|
|
extern "C" void CONCAT(_spacetimedb_preinit_register_, name)() { \
|
|
/* Parse parameter names from the stringified parameter list */ \
|
|
std::string param_list = #__VA_ARGS__; \
|
|
std::vector<std::string> param_names = \
|
|
SpacetimeDB::Internal::parseParameterNames(param_list); \
|
|
/* Register the reducer with the unified V9Builder system */ \
|
|
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<std::string> 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
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Use unified macro system from macro_helpers.h
|
|
|
|
/**
|
|
* @brief Macro for defining an init reducer
|
|
*
|
|
* Init reducers are called when the module is first initialized.
|
|
* They require an explicit ReducerContext parameter and return ReducerResult.
|
|
*
|
|
* @usage
|
|
* ```cpp
|
|
* SPACETIMEDB_INIT(my_init, ReducerContext ctx) {
|
|
* ctx.db.table<MyTable>().insert({...});
|
|
* return Ok();
|
|
* }
|
|
* ```
|
|
*/
|
|
#ifdef SPACETIMEDB_INIT
|
|
#undef SPACETIMEDB_INIT
|
|
#endif
|
|
#define SPACETIMEDB_INIT(function_name, ctx_param) \
|
|
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::getV10Builder().RegisterLifecycleReducer(#function_name, function_name, ::SpacetimeDB::Internal::Lifecycle::Init); \
|
|
} \
|
|
SpacetimeDB::ReducerResult function_name(ctx_param)
|
|
|
|
/**
|
|
* @brief Macro for defining a client_connected reducer
|
|
*
|
|
* Client connected reducers require an explicit ReducerContext parameter and return ReducerResult.
|
|
*
|
|
* @usage
|
|
* ```cpp
|
|
* SPACETIMEDB_CLIENT_CONNECTED(on_connect, ReducerContext ctx) {
|
|
* LOG_INFO("Client connected: " + ctx.sender().to_hex());
|
|
* return Ok();
|
|
* }
|
|
* ```
|
|
*/
|
|
#ifdef SPACETIMEDB_CLIENT_CONNECTED
|
|
#undef SPACETIMEDB_CLIENT_CONNECTED
|
|
#endif
|
|
#define SPACETIMEDB_CLIENT_CONNECTED(function_name, ctx_param) \
|
|
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::getV10Builder().RegisterLifecycleReducer(#function_name, function_name, ::SpacetimeDB::Internal::Lifecycle::OnConnect); \
|
|
} \
|
|
SpacetimeDB::ReducerResult function_name(ctx_param)
|
|
|
|
/**
|
|
* @brief Macro for defining a client_disconnected reducer
|
|
*
|
|
* Client disconnected reducers require an explicit ReducerContext parameter and return ReducerResult.
|
|
*
|
|
* @usage
|
|
* ```cpp
|
|
* SPACETIMEDB_CLIENT_DISCONNECTED(on_disconnect, ReducerContext ctx) {
|
|
* LOG_INFO("Client disconnected: " + ctx.sender().to_hex());
|
|
* return Ok();
|
|
* }
|
|
* ```
|
|
*/
|
|
#ifdef SPACETIMEDB_CLIENT_DISCONNECTED
|
|
#undef SPACETIMEDB_CLIENT_DISCONNECTED
|
|
#endif
|
|
#define SPACETIMEDB_CLIENT_DISCONNECTED(function_name, ctx_param) \
|
|
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::getV10Builder().RegisterLifecycleReducer(#function_name, function_name, ::SpacetimeDB::Internal::Lifecycle::OnDisconnect); \
|
|
} \
|
|
SpacetimeDB::ReducerResult function_name(ctx_param)
|