09 — Engine Adapters¶
← E2E Client | Table Of Contents | Next: Packaging →
An engine adapter owns the core connector as a private implementation, exposing only a surface that
fits each engine's types and thread rules. Core types like result_t<T>, connector_t aren't
revealed in the adapter's public header.
Common principles:
- A callback always runs on the engine's main thread.
- The core callback is put into an adapter queue, and pulled out on the engine's Tick/Update/
Dispatch() to deliver to the delegate.
- No dependency on exceptions or coroutines.
- Core private headers (connector/core/src/runtime/) are not included.
Unreal Engine¶
Distribution¶
Distributed in .uplugin format. Placed under Plugins/ZLinkStreamConnector/.
Plugins/
└── ZLinkStreamConnector/
├── ZLinkStreamConnector.uplugin
└── Source/
├── ZLinkStreamConnector/ ← Runtime module
└── ZLinkStreamConnectorTests/ ← Automation Test module
Basic Usage¶
#include "ZLinkStreamConnector.h"
UCLASS()
class AMyGameMode : public AGameModeBase
{
GENERATED_BODY()
UPROPERTY()
UZLinkStreamConnector* Connector;
void BeginPlay() override
{
Connector = NewObject<UZLinkStreamConnector>(this);
Connector->OnPacketReceived.AddDynamic(this, &AMyGameMode::HandlePacket);
Connector->OnRequestCompleted.AddDynamic(this, &AMyGameMode::HandleReply);
Connector->Connect(TEXT("tcp://game.example.com:7000"));
}
void Tick(float DeltaSeconds) override
{
Connector->Dispatch();
}
UFUNCTION()
void HandlePacket(FName PacketName, const FString& JsonPayload)
{
// Runs on the Game Thread
}
};
Using It From Blueprint¶
Connect, Close, SendJson, RequestJson, Dispatch are all BlueprintCallable.
OnPacketReceived, OnRequestCompleted are BlueprintAssignable delegates.
Thread Rules¶
Regardless of which thread a core callback comes from, UObject is never touched directly. The
adapter puts it into the adapter queue and broadcasts the delegate on Dispatch() or a Game
Thread-scheduled path. Close() is called automatically on PIE shutdown, map unload, and game
instance shutdown.
Running Automation Tests¶
UnrealEditor-Cmd MyProject.uproject \
-ExecCmds="Automation RunTests ZLink.StreamConnector; Quit" \
-unattended -NullRHI
Godot 4¶
Distribution¶
Distributed as a GDExtension source package. Placed under the Godot project's
addons/zlink_stream_connector/.
The .gdextension file registers the built shared library.
Basic Usage (GDScript)¶
extends Node
var connector: ZLinkStreamConnector
func _ready():
connector = ZLinkStreamConnector.new()
connector.packet_received.connect(_on_packet)
connector.connect_to_server("tcp://game.example.com:7000")
func _process(_delta):
connector.dispatch()
func _on_packet(packet_name: StringName, payload: String):
# Runs on the Godot main thread
pass
Thread Rules¶
A signal is emitted only on the Godot main thread. The adapter puts the core callback into the
adapter queue and emits the signal on dispatch() or a main-thread update.
Headless Testing¶
Axmol Engine¶
Distribution¶
Distributed as a CMake source package. Include it in the Axmol project's CMakeLists.txt, or
install core via vcpkg/Conan.
add_subdirectory(third_party/zlink_axmol_connector)
target_link_libraries(${APP_NAME} PRIVATE zlink_axmol_connector)
Basic Usage¶
#include "zlink_axmol_stream_connector.hpp"
class GameScene : public ax::Scene
{
ZLinkAxmolStreamConnector* _connector;
bool init() override
{
_connector = ZLinkAxmolStreamConnector::create();
_connector->setPacketCallback([this](const std::string& name, const std::string& json) {
// Runs on the Axmol main thread
});
_connector->connect("tcp://game.example.com:7000");
this->schedule([this](float) { _connector->dispatch(); }, "update");
return true;
}
};
Thread Rules¶
A core background callback is delivered to the Axmol main thread via
ax::Scheduler::runOnAxmolThread before running the user callback.
Common Engine Adapter API Mapping¶
| Operation | Unreal | Godot | Axmol |
|---|---|---|---|
| Connect | Connect(Endpoint) |
connect_to_server(url) |
connect(endpoint) |
| Terminate | Close() |
close() |
close() |
| One-way send | SendJson(Name, Json) |
send_json(name, json) |
sendJson(name, json) |
| Request/reply | RequestJson(Name, Json, Timeout) |
request_json(name, json, timeout) |
requestJson(name, json, timeout) |
| Dispatch | Dispatch() (called from Tick) |
dispatch() (called from _process) |
dispatch() (called from schedule) |
| Push receive | OnPacketReceived delegate |
packet_received signal |
packet callback |
| Status change | OnConnectionStateChanged delegate |
connection_state_changed signal |
state callback |