엔진 어댑터¶
← E2E 클라이언트 | 목차 | 다음: 패키징 →
엔진 어댑터는 core connector를 private 구현으로 소유하고, 각 엔진의 타입과 thread 규칙에 맞는 표면만 노출한다. core의 result_t<T>, connector_t 같은 타입은 어댑터 public header에 드러나지 않는다. Main thread 전달, packet 이름별 callback 등록, 호출별 요청 완료는 C++ 계약 §7을 따른다.
Unreal Engine¶
배포¶
.uplugin 형식으로 배포한다. Plugins/ZLinkStreamConnector/ 아래에 배치한다.
Plugins/
└── ZLinkStreamConnector/
├── ZLinkStreamConnector.uplugin
└── Source/
├── ZLinkStreamConnector/ ← Runtime module
└── ZLinkStreamConnectorTests/ ← Automation Test module
기본 사용법¶
Engine Lobby 샘플의 Actor는 connector를 만들고 서버 push인 ChatNotify의 delegate를 등록한 뒤 연결한다.
void AZLinkClientActor::BeginPlay ()
{
Super::BeginPlay ();
Connector = NewObject<UZLinkStreamConnector> (this);
PacketHandle =
Connector->On (PacketName (engine_lobby::packet::chat_notify),
[this] (const FZLinkStreamPacket &Packet) { HandlePacket (Packet); });
SetStatus (TEXT ("Engine Lobby: connecting"));
Connector->Connect (Endpoint);
if (!Connector->IsConnected ()) {
SetStatus (TEXT ("Engine Lobby: connection failed"), FColor::Red);
return;
}
SendPing ();
}
Tick에서 connector를 pump하면 delegate가 Game Thread에서 실행된다.
void AZLinkClientActor::Tick (float DeltaSeconds)
{
Super::Tick (DeltaSeconds);
if (Connector != nullptr) {
Connector->Tick (DeltaSeconds);
}
}
Blueprint에서 사용¶
Connect, Close, SendJson, RequestJson, On, Dispatch는 모두 BlueprintCallable이다. On(PacketName, Delegate)는 해제 handle을 반환하고, RequestJson(..., OnCompleted)는 해당 요청의 결과를 delegate로 전달한다.
PIE 종료, map unload, game instance shutdown에서 Close()가 자동 호출된다.
Automation Test 실행¶
UnrealEditor-Cmd MyProject.uproject \
-ExecCmds="Automation RunTests ZLink.StreamConnector; Quit" \
-unattended -NullRHI
Godot 4¶
배포¶
GDExtension source package로 배포한다. Godot project의 addons/zlink_stream_connector/ 아래에 배치한다.
.gdextension 파일이 빌드된 shared library를 등록한다.
기본 사용법 (C++)¶
Engine Lobby 샘플의 node는 ChatNotify의 callback을 등록한 뒤 연결한다.
void EngineLobbyNode::_ready ()
{
status_ = get_node<Label> ("Status");
chat_subscription_ =
connector_.on (chat_notify, [this] (const auto &packet) { handle_packet (packet); });
const CharString endpoint = endpoint_.utf8 ();
connector_.connect (std::string (endpoint.get_data (), endpoint.length ()));
if (connector_.state () != zlink::godot_stream_connector::connection_state_t::connected) {
fail ("connection failed");
return;
}
connector_.request_json (ping_req, encode_field ("sentAtUnixMs", "1000"), 5.0,
[this] (const auto &result) { handle_ping_response (result); });
set_process (true);
}
Godot main thread의 _process에서 connector를 pump한다.
void EngineLobbyNode::_process (double)
{
if (!failed_) {
connector_.dispatch ();
}
}
Axmol Engine¶
배포¶
CMake source package로 배포한다. Axmol project CMakeLists.txt에 포함하거나 vcpkg/Conan으로 core를 설치한다.
add_subdirectory(third_party/zlink_axmol_connector)
target_link_libraries(${APP_NAME} PRIVATE zlink_axmol_connector)
기본 사용법¶
Engine Lobby 샘플의 Scene은 ChatNotify의 callback을 등록한 뒤 연결한다.
chat_subscription_ = connector_.on (engine_lobby::packet::chat_notify,
[this] (const auto &packet) { handle_packet (packet); });
connector_.connect (endpoint);
if (connector_.state () != zlink::axmol_stream_connector::connection_state_t::connected) {
set_status ("Engine Lobby: connection failed");
return true;
}
send_ping ();
Axmol scheduler update에서 connector를 pump한다.
schedule ([this] (float) { connector_.dispatch (); }, "engine-lobby-pump");
공통 엔진 어댑터 API 대응표¶
| 동작 | Unreal | Godot | Axmol |
|---|---|---|---|
| 연결 | Connect(Endpoint) |
connect(endpoint) |
connect(endpoint) |
| 종료 | Close() |
close() |
close() |
| 단방향 송신 | SendJson(Name, Json) |
send_json(name, json) |
send_json(name, json) |
| 요청/응답 | RequestJson(Name, Json, Timeout, OnCompleted) |
request_json(name, json, timeout, callback) |
request_json(name, json, timeout, callback) |
| push 등록 | On(PacketName, Delegate) → handle |
on(packet_name, callback) → handle |
on(packet_name, callback) → handle |
| dispatch | Dispatch() (Tick에서 호출) |
dispatch() (프레임에서 호출) |
dispatch() (프레임에서 호출) |
| 상태 변경 | OnConnectionStateChanged delegate |
on_connection_state_changed callback |
on_connection_state_changed callback |