Skip to content

Commit b9634e6

Browse files
committed
feat: added async connect/disconnect blueprint nodes
1 parent 98656b9 commit b9634e6

10 files changed

+325
-2
lines changed

Content/ecsact-color-32x32.uasset

10.9 KB
Binary file not shown.

Source/Ecsact/Ecsact.Build.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public Ecsact(ReadOnlyTargetRules Target) : base(Target) {
2929
"Engine",
3030
"Slate",
3131
"SlateCore",
32+
"Kismet",
3233
});
3334

3435
DynamicallyLoadedModuleNames.AddRange(new string[] {
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#include "EcsactAsyncConnectBlueprintAction.h"
2+
#include "EcsactExecution.h"
3+
#include "EcsactAsyncRunnerEvents.h"
4+
#include "ecsact/runtime/async.h"
5+
#include "Ecsact.h"
6+
7+
auto UEcsactAsyncConnectBlueprintAction::AsyncConnect( //
8+
const FString& ConnectionString
9+
) -> UEcsactAsyncConnectBlueprintAction* {
10+
auto action = NewObject<UEcsactAsyncConnectBlueprintAction>();
11+
action->Utf8ConnectionString = TCHAR_TO_UTF8(*ConnectionString);
12+
return action;
13+
}
14+
15+
auto UEcsactAsyncConnectBlueprintAction::Activate() -> void {
16+
UE_LOG(Ecsact, Warning, TEXT("AsyncConnectActivate()"));
17+
auto runner = EcsactUnrealExecution::Runner();
18+
auto async_events = Cast<IEcsactAsyncRunnerEvents>(runner);
19+
if(!async_events) {
20+
UE_LOG(
21+
Ecsact,
22+
Error,
23+
TEXT("Cannot use Ecsact async blueprint api with runner that does not "
24+
"implement IEcsactAsyncRunnerEvents")
25+
);
26+
return;
27+
}
28+
29+
auto req_id = ecsact_async_connect(Utf8ConnectionString.c_str());
30+
31+
async_events->OnRequestDone(
32+
req_id,
33+
IEcsactAsyncRunnerEvents::FAsyncRequestDoneCallback::CreateUObject(
34+
this,
35+
&ThisClass::OnRequestDone
36+
)
37+
);
38+
39+
async_events->OnRequestError(
40+
req_id,
41+
IEcsactAsyncRunnerEvents::FAsyncRequestErrorCallback::CreateUObject(
42+
this,
43+
&ThisClass::OnRequestError
44+
)
45+
);
46+
}
47+
48+
auto UEcsactAsyncConnectBlueprintAction::OnRequestDone() -> void {
49+
if(!bConnectFailed) {
50+
OnSuccess.Broadcast({});
51+
}
52+
OnDone.Broadcast({});
53+
}
54+
55+
auto UEcsactAsyncConnectBlueprintAction::OnRequestError( //
56+
ecsact_async_error Error
57+
) -> void {
58+
switch(Error) {
59+
case ECSACT_ASYNC_ERR_PERMISSION_DENIED:
60+
OnError.Broadcast(EAsyncConnectError::PermissionDenied);
61+
break;
62+
case ECSACT_ASYNC_INVALID_CONNECTION_STRING:
63+
OnError.Broadcast(EAsyncConnectError::PermissionDenied);
64+
break;
65+
}
66+
67+
bConnectFailed = true;
68+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include "Kismet/BlueprintAsyncActionBase.h"
5+
#include "ecsact/runtime/async.h"
6+
#include "EcsactAsyncConnectBlueprintAction.generated.h"
7+
8+
UENUM()
9+
enum class EAsyncConnectError : uint8 {
10+
NoError,
11+
PermissionDenied,
12+
InvalidConnectionString,
13+
};
14+
15+
/**
16+
*
17+
*/
18+
UCLASS()
19+
20+
class ECSACT_API UEcsactAsyncConnectBlueprintAction
21+
: public UBlueprintAsyncActionBase {
22+
GENERATED_BODY() // NOLINT
23+
24+
std::string Utf8ConnectionString;
25+
bool bConnectFailed = false;
26+
27+
auto OnRequestDone() -> void;
28+
auto OnRequestError(ecsact_async_error Error) -> void;
29+
30+
public:
31+
/**
32+
* Called everytime an async request is updated. Error parameter is only
33+
* valid during `OnError`.
34+
*/
35+
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam( // NOLINT
36+
FAsyncConnectDoneCallback,
37+
EAsyncConnectError,
38+
Error
39+
);
40+
41+
UFUNCTION(
42+
BlueprintCallable,
43+
Category = "Ecsact Runtime",
44+
Meta = (BlueprintInternalUseOnly = true)
45+
)
46+
static UEcsactAsyncConnectBlueprintAction* AsyncConnect(
47+
const FString& ConnectionString
48+
);
49+
50+
/**
51+
* Async request is finally done.
52+
*/
53+
UPROPERTY(BlueprintAssignable)
54+
FAsyncConnectDoneCallback OnDone;
55+
56+
/**
57+
* Async request is done and no errors occured.
58+
*/
59+
UPROPERTY(BlueprintAssignable)
60+
FAsyncConnectDoneCallback OnSuccess;
61+
62+
/**
63+
* Async request had an error. May be called multiple times.
64+
*/
65+
UPROPERTY(BlueprintAssignable)
66+
FAsyncConnectDoneCallback OnError;
67+
68+
auto Activate() -> void override;
69+
};

Source/Ecsact/Public/EcsactAsyncRunner.cpp

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,69 @@
11
#include "EcsactAsyncRunner.h"
22
#include "Ecsact.h"
3+
#include <span>
34
#include "EcsactUnrealExecutionOptions.h"
45
#include "EcsactUnrealEventsCollector.h"
56
#include "ecsact/runtime/async.h"
67
#include "ecsact/runtime/common.h"
78

9+
UEcsactAsyncRunner::UEcsactAsyncRunner() {
10+
async_evc.async_error_callback = ThisClass::OnAsyncErrorRaw;
11+
async_evc.system_error_callback = ThisClass::OnExecuteSysErrorRaw;
12+
async_evc.async_request_done_callback = ThisClass::OnAsyncRequestDoneRaw;
13+
14+
async_evc.async_error_callback_user_data = this;
15+
async_evc.system_error_callback_user_data = this;
16+
async_evc.async_request_done_callback_user_data = this;
17+
}
18+
19+
auto UEcsactAsyncRunner::OnAsyncErrorRaw(
20+
ecsact_async_error async_err,
21+
int request_ids_length,
22+
ecsact_async_request_id* request_ids_data,
23+
void* callback_user_data
24+
) -> void {
25+
auto self = static_cast<ThisClass*>(callback_user_data);
26+
auto request_ids =
27+
std::span{request_ids_data, static_cast<size_t>(request_ids_length)};
28+
29+
for(auto req_id : request_ids) {
30+
auto cbs = self->RequestErrorCallbacks.Find(req_id);
31+
if(cbs) {
32+
for(auto& cb : *cbs) {
33+
cb.ExecuteIfBound(async_err);
34+
}
35+
}
36+
}
37+
}
38+
39+
auto UEcsactAsyncRunner::OnExecuteSysErrorRaw(
40+
ecsact_execute_systems_error execute_err,
41+
void* callback_user_data
42+
) -> void {
43+
auto self = static_cast<ThisClass*>(callback_user_data);
44+
}
45+
46+
auto UEcsactAsyncRunner::OnAsyncRequestDoneRaw(
47+
int request_ids_length,
48+
ecsact_async_request_id* request_ids_data,
49+
void* callback_user_data
50+
) -> void {
51+
auto self = static_cast<ThisClass*>(callback_user_data);
52+
auto request_ids =
53+
std::span{request_ids_data, static_cast<size_t>(request_ids_length)};
54+
55+
for(auto req_id : request_ids) {
56+
auto cbs = self->RequestDoneCallbacks.Find(req_id);
57+
if(cbs) {
58+
for(auto& cb : *cbs) {
59+
cb.ExecuteIfBound();
60+
}
61+
62+
cbs->Empty();
63+
}
64+
}
65+
}
66+
867
auto UEcsactAsyncRunner::Tick(float DeltaTime) -> void {
968
EnqueueExecutionOptions();
1069

@@ -15,7 +74,7 @@ auto UEcsactAsyncRunner::Tick(float DeltaTime) -> void {
1574
if(EventsCollector != nullptr) {
1675
evc_c = EventsCollector->GetCEVC();
1776
}
18-
ecsact_async_flush_events(evc_c, nullptr);
77+
ecsact_async_flush_events(evc_c, &async_evc);
1978
}
2079
}
2180

@@ -44,3 +103,21 @@ auto UEcsactAsyncRunner::GetStatId() const -> TStatId {
44103
STATGROUP_Tickables
45104
);
46105
}
106+
107+
auto UEcsactAsyncRunner::OnRequestDone(
108+
ecsact_async_request_id RequestId,
109+
FAsyncRequestDoneCallback Callback
110+
) -> void {
111+
check(RequestId != ECSACT_INVALID_ID(async_request));
112+
113+
RequestDoneCallbacks.FindOrAdd(RequestId).Add(Callback);
114+
}
115+
116+
auto UEcsactAsyncRunner::OnRequestError(
117+
ecsact_async_request_id RequestId,
118+
FAsyncRequestErrorCallback Callback
119+
) -> void {
120+
check(RequestId != ECSACT_INVALID_ID(async_request));
121+
122+
RequestErrorCallbacks.FindOrAdd(RequestId).Add(Callback);
123+
}

Source/Ecsact/Public/EcsactAsyncRunner.h

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,43 @@
55
#include "Tickable.h"
66
#include "UObject/NoExportTypes.h"
77
#include "EcsactRunner.h"
8+
#include "EcsactAsyncRunnerEvents.h"
89
#include "EcsactAsyncRunner.generated.h"
910

1011
UCLASS(NotBlueprintable)
1112

12-
class UEcsactAsyncRunner : public UEcsactRunner {
13+
class UEcsactAsyncRunner : public UEcsactRunner,
14+
public IEcsactAsyncRunnerEvents {
1315
GENERATED_BODY() // NOLINT
16+
17+
ecsact_async_events_collector async_evc;
18+
19+
TMap<ecsact_async_request_id, TArray<FAsyncRequestDoneCallback>>
20+
RequestDoneCallbacks;
21+
TMap<ecsact_async_request_id, TArray<FAsyncRequestErrorCallback>>
22+
RequestErrorCallbacks;
23+
24+
static auto OnAsyncErrorRaw(
25+
ecsact_async_error async_err,
26+
int request_ids_length,
27+
ecsact_async_request_id* request_ids,
28+
void* callback_user_data
29+
) -> void;
30+
31+
static auto OnExecuteSysErrorRaw(
32+
ecsact_execute_systems_error execute_err,
33+
void* callback_user_data
34+
) -> void;
35+
36+
static auto OnAsyncRequestDoneRaw(
37+
int request_ids_length,
38+
ecsact_async_request_id* request_ids,
39+
void* callback_user_data
40+
) -> void;
41+
1442
public:
43+
UEcsactAsyncRunner();
44+
1545
auto Tick(float DeltaTime) -> void override;
1646
auto GetStatId() const -> TStatId override;
1747

@@ -21,4 +51,14 @@ class UEcsactAsyncRunner : public UEcsactRunner {
2151
* enqueue the execution options.
2252
*/
2353
auto EnqueueExecutionOptions() -> void;
54+
55+
auto OnRequestDone(
56+
ecsact_async_request_id RequestId,
57+
FAsyncRequestDoneCallback Callback
58+
) -> void override;
59+
60+
auto OnRequestError(
61+
ecsact_async_request_id RequestId,
62+
FAsyncRequestErrorCallback Callback
63+
) -> void override;
2464
};
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include "EcsactAsyncRunnerEvents.h"
2+
3+
auto IEcsactAsyncRunnerEvents::OnRequestDone(
4+
ecsact_async_request_id RequestId,
5+
FAsyncRequestDoneCallback Callback
6+
) -> void {
7+
}
8+
9+
auto IEcsactAsyncRunnerEvents::OnRequestError(
10+
ecsact_async_request_id RequestId,
11+
FAsyncRequestErrorCallback Callback
12+
) -> void {
13+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#pragma once
2+
3+
#include "CoreMinimal.h"
4+
#include "ecsact/runtime/common.h"
5+
#include "ecsact/runtime/async.h"
6+
#include "EcsactAsyncRunnerEvents.generated.h"
7+
8+
UINTERFACE(MinimalAPI)
9+
10+
class UEcsactAsyncRunnerEvents : public UInterface {
11+
GENERATED_BODY() // NOLINT
12+
public:
13+
};
14+
15+
class IEcsactAsyncRunnerEvents {
16+
GENERATED_BODY() // NOLINT
17+
public:
18+
DECLARE_DELEGATE(FAsyncRequestDoneCallback); // NOLINT
19+
DECLARE_DELEGATE_OneParam( // NOLINT
20+
FAsyncRequestErrorCallback,
21+
ecsact_async_error
22+
);
23+
24+
virtual auto OnRequestDone(
25+
ecsact_async_request_id RequestId,
26+
FAsyncRequestDoneCallback Callback
27+
) -> void;
28+
29+
virtual auto OnRequestError(
30+
ecsact_async_request_id RequestId,
31+
FAsyncRequestErrorCallback Callback
32+
) -> void;
33+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include "EcsactBlueprintLibrary.h"
2+
#include "ecsact/runtime/async.h"
3+
4+
auto UEcsactBlueprintLibrary::AsyncDisconnect() -> void {
5+
ecsact_async_disconnect();
6+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#pragma once
2+
3+
#include "EcsactBlueprintLibrary.generated.h"
4+
5+
UCLASS()
6+
7+
class ECSACT_API UEcsactBlueprintLibrary : public UBlueprintFunctionLibrary {
8+
GENERATED_BODY() // NOLINT
9+
public:
10+
UFUNCTION(
11+
BlueprintCallable,
12+
Category = "Ecsact Runtime",
13+
Meta = (BlueprintFunctionLibraryIcon = "Ecsact.ecsact-color-32x32")
14+
)
15+
static void AsyncDisconnect();
16+
};

0 commit comments

Comments
 (0)