Skip to content

Commit 1d00d29

Browse files
committed
fix: better ecsact runner world association
1 parent 7ee07cd commit 1d00d29

File tree

9 files changed

+151
-31
lines changed

9 files changed

+151
-31
lines changed

Source/Ecsact/Public/EcsactUnreal/Blueprint/EcsactAsyncConnectBlueprintAction.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ auto UEcsactAsyncConnectBlueprintAction::AsyncConnect( //
1414

1515
auto UEcsactAsyncConnectBlueprintAction::Activate() -> void {
1616
UE_LOG(Ecsact, Warning, TEXT("AsyncConnectActivate()"));
17-
auto runner = EcsactUnrealExecution::Runner();
17+
auto runner = EcsactUnrealExecution::Runner(GetWorld());
1818
auto async_events = Cast<IEcsactAsyncRunnerEvents>(runner);
1919
if(!async_events) {
2020
UE_LOG(
@@ -56,7 +56,7 @@ auto UEcsactAsyncConnectBlueprintAction::Activate() -> void {
5656
}
5757

5858
auto UEcsactAsyncConnectBlueprintAction::OnRequestDone() -> void {
59-
auto runner = EcsactUnrealExecution::Runner();
59+
auto runner = EcsactUnrealExecution::Runner(GetWorld());
6060
auto async_events = Cast<IEcsactAsyncRunnerEvents>(runner);
6161
UE_LOG(Ecsact, Error, TEXT("OnRequestDone??"));
6262
if(!bConnectFailed) {

Source/Ecsact/Public/EcsactUnreal/Ecsact.cpp

Lines changed: 98 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "Ecsact.h"
22
#include "CoreGlobals.h"
33
#include "EcsactUnreal/EcsactSettings.h"
4+
#include "Engine/World.h"
45
#include "HAL/PlatformProcess.h"
56
#include "Logging/LogVerbosity.h"
67
#include "Misc/Paths.h"
@@ -64,7 +65,6 @@ auto FEcsactModule::LoadEcsactRuntime() -> void {
6465
static_assert(true, "require ;")
6566
FOR_EACH_ECSACT_API_FN(LOAD_ECSACT_FN);
6667
#undef LOAD_ECSACT_FN
67-
StartRunner();
6868
}
6969

7070
auto FEcsactModule::UnloadEcsactRuntime() -> void {
@@ -74,7 +74,9 @@ auto FEcsactModule::UnloadEcsactRuntime() -> void {
7474
ecsact_async_disconnect();
7575
}
7676

77-
StopRunner();
77+
for(auto i = 0; RunnerWorlds.Num() > i; ++i) {
78+
StopRunner(i);
79+
}
7880

7981
#define RESET_ECSACT_FN(fn, UNUSED_PARAM) fn = nullptr
8082
FOR_EACH_ECSACT_API_FN(RESET_ECSACT_FN);
@@ -95,8 +97,53 @@ auto FEcsactModule::StartupModule() -> void {
9597
}
9698
#if WITH_EDITOR
9799
FEditorDelegates::PreBeginPIE.AddRaw(this, &FEcsactModule::OnPreBeginPIE);
98-
FEditorDelegates::EndPIE.AddRaw(this, &FEcsactModule::OnPrePIEEnded);
100+
FEditorDelegates::ShutdownPIE.AddRaw(this, &FEcsactModule::OnShutdownPIE);
99101
#endif
102+
FWorldDelegates::OnPreWorldInitialization.AddRaw(
103+
this,
104+
&FEcsactModule::OnPreWorldInitialization
105+
);
106+
FWorldDelegates::OnPostWorldCleanup.AddRaw(
107+
this,
108+
&FEcsactModule::OnPostWorldCleanup
109+
);
110+
}
111+
112+
auto FEcsactModule::OnPreWorldInitialization( //
113+
UWorld* World,
114+
const UWorld::InitializationValues IVS
115+
) -> void {
116+
switch(World->WorldType.GetValue()) {
117+
case EWorldType::None:
118+
case EWorldType::Editor:
119+
case EWorldType::EditorPreview:
120+
case EWorldType::GamePreview:
121+
case EWorldType::GameRPC:
122+
case EWorldType::Inactive:
123+
return;
124+
case EWorldType::PIE:
125+
case EWorldType::Game:
126+
break;
127+
}
128+
129+
auto index = RunnerWorlds.Num();
130+
RunnerWorlds.Add(World);
131+
Runners.AddDefaulted();
132+
check(RunnerWorlds.Num() == Runners.Num());
133+
StartRunner(index);
134+
}
135+
136+
auto FEcsactModule::OnPostWorldCleanup( //
137+
UWorld* World,
138+
bool bSessionEnded,
139+
bool bCleanupResources
140+
) -> void {
141+
for(auto i = 0; RunnerWorlds.Num() > i; ++i) {
142+
if(RunnerWorlds[i].Get() == World) {
143+
StopRunner(i);
144+
break;
145+
}
146+
}
100147
}
101148

102149
auto FEcsactModule::ShutdownModule() -> void {
@@ -116,55 +163,91 @@ auto FEcsactModule::OnPreBeginPIE(bool _) -> void {
116163
LoadEcsactRuntime();
117164
}
118165

119-
auto FEcsactModule::OnPrePIEEnded(bool _) -> void {
166+
auto FEcsactModule::OnShutdownPIE(bool _) -> void {
120167
UnloadEcsactRuntime();
121168
}
122169

123-
auto FEcsactModule::StartRunner() -> void {
170+
auto FEcsactModule::StartRunner(int32 Index) -> void {
124171
const auto* settings = GetDefault<UEcsactSettings>();
125172

126-
if(Runner != nullptr) {
173+
if(Index >= Runners.Num()) {
174+
UE_LOG(
175+
Ecsact,
176+
Error,
177+
TEXT("StartRunner() was called before the associated world was "
178+
"initialized")
179+
);
180+
return;
181+
}
182+
183+
for(auto Runner : Runners) {
184+
if(Runner.IsValid()) {
185+
UE_LOG(
186+
Ecsact,
187+
Error,
188+
TEXT("Multiple Ecsact runners are not supported at this time")
189+
);
190+
return;
191+
}
192+
}
193+
194+
if(auto Runner = Runners[Index].Get(); Runner) {
127195
UE_LOG(
128196
Ecsact,
129197
Warning,
130198
TEXT("StartRunner() was called while runner was already running. "
131199
"Stopping previous one before starting new.")
132200
);
133-
StopRunner();
201+
StopRunner(Index);
202+
}
203+
204+
auto World = RunnerWorlds[Index].Get();
205+
206+
if(!World) {
207+
UE_LOG(Ecsact, Error, TEXT("StartRunner() was called on invalid world"));
208+
return;
134209
}
135210

136211
switch(settings->Runner) {
137212
case EEcsactRuntimeRunnerType::Automatic:
138213
if(ecsact_async_flush_events == nullptr) {
139-
Runner = NewObject<UEcsactSyncRunner>();
214+
Runners[Index] = NewObject<UEcsactSyncRunner>();
140215
} else {
141-
Runner = NewObject<UEcsactAsyncRunner>();
216+
Runners[Index] = NewObject<UEcsactAsyncRunner>();
142217
}
143218
break;
144219
case EEcsactRuntimeRunnerType::Asynchronous:
145-
Runner = NewObject<UEcsactAsyncRunner>();
220+
Runners[Index] = NewObject<UEcsactAsyncRunner>();
146221
break;
147222
case EEcsactRuntimeRunnerType::Custom:
148223
if(settings->CustomRunnerClass != nullptr) {
149-
Runner = NewObject<UEcsactRunner>(nullptr, settings->CustomRunnerClass);
224+
Runners[Index] =
225+
NewObject<UEcsactRunner>(nullptr, settings->CustomRunnerClass);
150226
}
151227
break;
152228
}
153229

154-
if(Runner != nullptr) {
230+
if(auto Runner = Runners[Index].Get(); Runner) {
155231
UE_LOG(
156232
Ecsact,
157233
Log,
158234
TEXT("Starting ecsact runner: %s"),
159235
*Runner->GetClass()->GetName()
160236
);
237+
Runner->World = World;
161238
Runner->AddToRoot();
162239
Runner->Start();
163240
}
164241
}
165242

166-
auto FEcsactModule::StopRunner() -> void {
167-
if(Runner != nullptr) {
243+
auto FEcsactModule::StopRunner(int32 Index) -> void {
244+
if(Index >= Runners.Num()) {
245+
return;
246+
}
247+
248+
auto Runner = Runners[Index].Get();
249+
250+
if(Runner) {
168251
UE_LOG(
169252
Ecsact,
170253
Log,
@@ -174,7 +257,7 @@ auto FEcsactModule::StopRunner() -> void {
174257
Runner->Stop();
175258
Runner->RemoveFromRoot();
176259
Runner->MarkAsGarbage();
177-
Runner.Reset();
260+
Runners[Index].Reset();
178261
}
179262
}
180263

Source/Ecsact/Public/EcsactUnreal/Ecsact.h

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include "CoreMinimal.h"
4+
#include "Engine/World.h"
45
#include "Modules/ModuleManager.h"
56
#include "UObject/WeakObjectPtr.h"
67

@@ -9,18 +10,31 @@ DECLARE_LOG_CATEGORY_EXTERN(Ecsact, Log, All);
910
class FEcsactModule : public IModuleInterface {
1011
friend class EcsactUnrealExecution;
1112

12-
static FEcsactModule* Self;
13-
void* EcsactRuntimeHandle;
14-
TWeakObjectPtr<class UEcsactRunner> Runner;
13+
static FEcsactModule* Self;
14+
void* EcsactRuntimeHandle;
15+
16+
TArray<TWeakObjectPtr<UWorld>> RunnerWorlds;
17+
TArray<TWeakObjectPtr<class UEcsactRunner>> Runners;
1518

1619
auto LoadEcsactRuntime() -> void;
1720
auto UnloadEcsactRuntime() -> void;
1821
auto Abort() -> void;
1922
auto OnPreBeginPIE(bool bIsSimulating) -> void;
20-
auto OnPrePIEEnded(const bool bIsSimulating) -> void;
23+
auto OnShutdownPIE(const bool bIsSimulating) -> void;
24+
25+
auto OnPreWorldInitialization( //
26+
UWorld* World,
27+
const UWorld::InitializationValues IVS
28+
) -> void;
29+
30+
auto OnPostWorldCleanup( //
31+
UWorld* World,
32+
bool bSessionEnded,
33+
bool bCleanupResources
34+
) -> void;
2135

22-
auto StartRunner() -> void;
23-
auto StopRunner() -> void;
36+
auto StartRunner(int32 Index) -> void;
37+
auto StopRunner(int32 Index) -> void;
2438

2539
public:
2640
static auto Get() -> FEcsactModule&;

Source/Ecsact/Public/EcsactUnreal/EcsactBlueprintLibrary.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
#include "EcsactUnreal/EcsactAsyncRunnerEvents.h"
44
#include "ecsact/runtime/async.h"
55

6-
auto UEcsactBlueprintLibrary::AsyncDisconnect() -> void {
7-
auto runner = EcsactUnrealExecution::Runner();
6+
auto UEcsactBlueprintLibrary::AsyncDisconnect(const UObject* WorldContext
7+
) -> void {
8+
auto world = WorldContext->GetWorld();
9+
check(world);
10+
auto runner = EcsactUnrealExecution::Runner(world);
811
auto async_events = Cast<IEcsactAsyncRunnerEvents>(runner);
912
ecsact_async_disconnect();
1013
if(async_events) {

Source/Ecsact/Public/EcsactUnreal/EcsactBlueprintLibrary.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ class ECSACT_API UEcsactBlueprintLibrary : public UBlueprintFunctionLibrary {
1010
UFUNCTION(
1111
BlueprintCallable,
1212
Category = "Ecsact Runtime",
13-
Meta = (BlueprintFunctionLibraryIcon = "Ecsact.ecsact-color-32x32")
13+
Meta =
14+
(WorldContext = "WorldContext",
15+
BlueprintFunctionLibraryIcon = "Ecsact.ecsact-color-32x32")
1416
)
15-
static void AsyncDisconnect();
17+
static void AsyncDisconnect(const UObject* WorldContext);
1618
};

Source/Ecsact/Public/EcsactUnreal/EcsactExecution.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ auto EcsactUnrealExecution::DeltaTime() -> float {
77
return DeltaTime_;
88
}
99

10-
auto EcsactUnrealExecution::Runner() -> TWeakObjectPtr<class UEcsactRunner> {
11-
return FEcsactModule::Get().Runner;
10+
auto EcsactUnrealExecution::Runner( //
11+
class UWorld* World
12+
) -> TWeakObjectPtr<class UEcsactRunner> {
13+
check(World);
14+
auto mod = FEcsactModule::Get();
15+
for(auto i = 0; mod.RunnerWorlds.Num() > i; ++i) {
16+
if(mod.RunnerWorlds[i].Get() == World) {
17+
return mod.Runners[i];
18+
}
19+
}
20+
21+
return {};
1222
}

Source/Ecsact/Public/EcsactUnreal/EcsactExecution.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ class ECSACT_API EcsactUnrealExecution {
1919
static auto DeltaTime() -> float;
2020

2121
/**
22+
* Gets the runner for the given world.
2223
*
24+
* NOTE: Prefer using GetRunner() in your associated class. Most Ecsact
25+
* classes will have this methods available. e.g. UEcsactRunnerSubsystem
2326
*/
24-
static auto Runner() -> TWeakObjectPtr<class UEcsactRunner>;
27+
static auto Runner( //
28+
class UWorld* World
29+
) -> TWeakObjectPtr<class UEcsactRunner>;
2530
};

Source/Ecsact/Public/EcsactUnreal/EcsactRunner.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ UEcsactRunner::UEcsactRunner() : EventsCollector{} {
3030
}
3131

3232
auto UEcsactRunner::GetWorld() const -> UWorld* {
33-
return GEngine->GameViewport->GetWorld();
33+
return World;
3434
}
3535

3636
auto UEcsactRunner::GetRunnerSubsystems()

Source/Ecsact/Public/EcsactUnreal/EcsactRunner.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ UCLASS(Abstract)
1111
class ECSACT_API UEcsactRunner : public UObject, public FTickableGameObject {
1212
GENERATED_BODY() // NOLINT
1313

14+
friend class FEcsactModule;
15+
16+
UWorld* World;
1417
TArray<class UEcsactRunnerSubsystem*> RunnerSubsystems;
1518
ecsact_execution_events_collector EventsCollector;
1619
bool bIsStopped = false;

0 commit comments

Comments
 (0)