Bridge Internals¶
Deep dive into the C++ framework that powers
libqsbridge.so— the shared library injected into game server processes.
Overview¶
The bridge is a C++17 shared library (8.6 MB) loaded via LD_PRELOAD into game server processes. It contains 225+ files and 17,200+ lines of code organised into 5 build layers.
graph TD
LIB[libqsbridge.so]
LIB --> L1[Layer 1 — bsatn_core<br/>BSATN binary codec, 18 headers]
LIB --> L2[Layer 2 — stdb_client<br/>SpacetimeDB WebSocket client]
LIB --> L3[Layer 3 — bridge_core<br/>RPC dispatch, message queue, class registry]
LIB --> L4[Layer 4 — engine_ue4<br/>UE4 4.27 engine adapter]
LIB --> L5[Layer 5 — game_humanitz<br/>HumanitZ game module hooks]
CMake Build System¶
# 5-layer build → single shared library
bsatn_core → STATIC library (codec only, no dependencies)
stdb_client → STATIC library (depends on bsatn_core + libwebsockets)
bridge_core → STATIC library (depends on stdb_client)
engine_ue4 → STATIC library (depends on bridge_core)
game_humanitz → STATIC library (depends on engine_ue4)
libqsbridge.so → SHARED library (--whole-archive all 5 layers)
Core Components¶
Engine Adapter (engine_adapter.h, 164 lines)¶
Abstract interface that all engine implementations must satisfy:
class EngineAdapter {
public:
virtual ~EngineAdapter() = default;
// Lifecycle
virtual bool init() = 0;
virtual void shutdown() = 0;
virtual void tick(float delta_time) = 0;
// Identity
virtual std::string get_engine_name() const = 0;
virtual std::string get_engine_version() const = 0;
// Hook management
virtual bool hook_function(const char* name, void* callback) = 0;
virtual bool unhook_function(const char* name) = 0;
// Player tracking
virtual std::vector<PlayerInfo> get_connected_players() const = 0;
virtual std::string extract_player_id(void* player_controller) const = 0;
};
STDB Connection (stdb_connection.h, 242 lines)¶
WebSocket client using libwebsockets with BSATN binary framing:
- Auto-reconnect with exponential backoff
- SpacetimeDB v2 binary protocol (
v2.bsatn.spacetimedb) - Subscribe, CallReducer, ReducerResult, TransactionUpdate handling
- Thread-safe outbound message queue
RPC Dispatcher (rpc_dispatcher.h)¶
Routes engine RPC calls to registered handler functions:
class RpcDispatcher {
std::unordered_map<std::string, RpcHandler> dispatch_table_;
public:
void register_handler(const char* rpc_name, RpcHandler handler);
bool dispatch(const char* rpc_name, void* params, void* player);
};
Game Interface (game_interface.h, 142 lines)¶
Base class for game modules:
class GameInterface {
public:
virtual const char* module_name() = 0;
virtual void on_init(StdbConnection* conn) = 0;
virtual void on_tick(float delta_time) = 0;
virtual void on_player_join(const char* player_id) = 0;
virtual void on_player_leave(const char* player_id) = 0;
virtual void register_hooks(EngineAdapter* adapter) = 0;
};
Message Queue (message_queue.h)¶
Thread-safe MPSC (Multiple Producer, Single Consumer) queue for cross-thread communication between worker threads and the main bridge thread.
Class Registry (class_registry.h)¶
Tracks player controllers, actors, and their SpacetimeDB identities for the game module.
Game Action (game_action.h)¶
Async action queue with 5 variant types for deferred game state mutations.
File Inventory¶
| Directory | Files | Purpose |
|---|---|---|
include/qsbridge/ |
11 | Public headers (framework API) |
include/qsbridge/bsatn/ |
18 | BSATN codec (header-only) |
include/qsbridge/engines/ |
4 | Engine-specific headers |
lib/core/ |
6 | Engine-agnostic sources |
lib/engines/ue4/ |
4 | UE4 adapter sources |
games/humanitz/include/ |
2 | Game module headers |
games/humanitz/src/ |
7 | Game module sources |
games/humanitz/schema/ |
218 | Codegen'd BSATN types |
tests/ |
7 | Test suites (860+ assertions) |
tools/ |
1 | codegen.py |
Entry Point¶
The bridge loads via LD_PRELOAD using GCC's constructor attribute:
// lib/engines/ue4/entry.cpp
__attribute__((constructor))
void qs_bridge_init() {
// 1. Detect game engine
// 2. Create engine adapter
// 3. Create STDB connection
// 4. Create game module
// 5. Register hooks
// 6. Start worker threads
// 7. Connect to SpacetimeDB
}
Related Pages¶
- BSATN Wire Format — binary protocol details
- Engine Adapters — adapter architecture
- UE4 Implementation — vtable hooking details