Skip to content

Commit

Permalink
feat: unreal specific ecsact plugin + starting on ecsact runner (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
zaucy authored Aug 15, 2024
1 parent b730f14 commit 9846f84
Show file tree
Hide file tree
Showing 28 changed files with 1,025 additions and 58 deletions.
2 changes: 2 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
Checks: 'clang-diagnostic-*,clang-analyzer-*,cppcoreguidelines-*,modernize-*,-modernize-use-trailing-return-type'
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
*.png filter=lfs diff=lfs merge=lfs -text
*.dll filter=lfs diff=lfs merge=lfs -text
1 change: 0 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,5 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: greut/eclint-action@v0
- uses: jidicula/[email protected]
with: { clang-format-version: "18" }
8 changes: 8 additions & 0 deletions Config/FilterPlugin.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[FilterPlugin]
; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and
; may include "...", "*", and "?" wildcards to match directories, files, and individual characters respectively.
;
; Examples:
; /README.txt
; /Extras/...
; /Binaries/ThirdParty/*.dll
5 changes: 5 additions & 0 deletions Ecsact.uplugin
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
"Name": "EcsactEditor",
"Type": "Editor",
"LoadingPhase": "Default"
},
{
"Name": "EcsactUnrealCodegenPlugin",
"Type": "Editor",
"LoadingPhase": "None"
}
]
}
42 changes: 34 additions & 8 deletions Source/Ecsact/Ecsact.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
using System.IO;
using System.Diagnostics;
using System;
using System.Linq;
using System.Collections.Generic;
using UnrealBuildBase;
using EpicGames.Core;

[Serializable]
Expand Down Expand Up @@ -33,13 +31,29 @@ public Ecsact(ReadOnlyTargetRules Target) : base(Target) {
"SlateCore",
});

DynamicallyLoadedModuleNames.AddRange(new string[] {
"EcsactUnrealCodegenPlugin",
});

var EcsactUnrealCodegenPluginPath = Path.Combine(
ModuleDirectory,
"..",
"..",
"Binaries",
Target.Platform.ToString(),
"UnrealEditor-EcsactUnrealCodegenPlugin.dll"
);

if(Target.bBuildEditor) {
PrivateDependencyModuleNames.Add("UnrealEd");
}

var EcsactSdkVersion = GetEcsactSdkVersion();
Environment.SetEnvironmentVariable("EcsactPlugin_SdkVersion", EcsactSdkVersion);

Environment.SetEnvironmentVariable(
"EcsactPlugin_SdkVersion",
EcsactSdkVersion
);

var EcsactSdkIncludeDir = GetEcsactSdkIncludeDir();
PublicIncludePaths.Add(EcsactSdkIncludeDir);

Expand All @@ -64,6 +78,16 @@ public Ecsact(ReadOnlyTargetRules Target) : base(Target) {
"--plugin=cpp_systems_header",
"--plugin=cpp_systems_source"
};

// if(!File.Exists(EcsactUnrealCodegenPluginPath)) {
// Console.WriteLine(
// "warning: EcsactUnrealCodegenPlugin was not built. It should have "
// + "been shipped with the Ecsact Unreal integration plugin."
// );
// } else {
// CodegenArgs.Add($"--plugin={EcsactUnrealCodegenPluginPath}");
// }

CodegenArgs.AddRange(EcsactSources);
ExecEcsactCli(CodegenArgs);
}
Expand Down Expand Up @@ -158,14 +182,16 @@ private void ExecEcsactCli(IList<string> Args) {
}

private DirectoryReference GetProjectRoot(ReadOnlyTargetRules Target) {
if (Target.ProjectFile != null) {
if(Target.ProjectFile != null) {
return Target.ProjectFile.Directory;
}

// Without a Target.ProjectFile we're probably installed as an Engine plugin.
// Only information we have about the project is the current directory.
// Without a Target.ProjectFile we're probably installed as an Engine
// plugin. Only information we have about the project is the current
// directory.
var Root = new DirectoryReference(Directory.GetCurrentDirectory());
while (Root != null && !File.Exists(Path.Combine(Root.FullName, "*.uproject"))) {
while(Root != null &&
!File.Exists(Path.Combine(Root.FullName, "*.uproject"))) {
Root = Root.ParentDirectory;
}
return Root;
Expand Down
75 changes: 74 additions & 1 deletion Source/Ecsact/Private/Ecsact.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#include "Ecsact.h"
#include "CoreGlobals.h"
#include "EcsactSettings.h"
#include "HAL/PlatformProcess.h"
#include "Logging/LogVerbosity.h"
#include "Misc/Paths.h"
#include "EcsactAsyncRunner.h"
#include "ecsact/runtime.h"

#define LOCTEXT_NAMESPACE "FEcsactModule"
Expand All @@ -12,6 +15,13 @@ DEFINE_LOG_CATEGORY(Ecsact);
FOR_EACH_ECSACT_API_FN(INIT_ECSACT_API_FN, UNUSED_PARAM);
#undef INIT_ECSACT_API_FN

FEcsactModule* FEcsactModule::Self = nullptr;

auto FEcsactModule::Get() -> FEcsactModule& {
check(Self != nullptr);
return *Self;
}

auto FEcsactModule::Abort() -> void {
#ifdef WITH_EDITOR
if(GEditor) {
Expand All @@ -26,6 +36,7 @@ auto FEcsactModule::LoadEcsactRuntime() -> void {
FPaths::ProjectDir(),
TEXT("Binaries/Win64/EcsactRuntime.dll")
);
UE_LOG(Ecsact, Log, TEXT("Loading ecsact runtime %s"), *ecsact_runtime_path);

EcsactRuntimeHandle = FPlatformProcess::GetDllHandle(*ecsact_runtime_path);

Expand All @@ -43,12 +54,22 @@ auto FEcsactModule::LoadEcsactRuntime() -> void {
#define LOAD_ECSACT_FN(fn, UNUSED_PARAM) \
fn = reinterpret_cast<decltype(fn)>( \
FPlatformProcess::GetDllExport(EcsactRuntimeHandle, TEXT(#fn)) \
)
); \
if(fn != nullptr) { \
UE_LOG(Ecsact, Log, TEXT("loaded %s"), TEXT(#fn)); \
} else { \
UE_LOG(Ecsact, Error, TEXT("failed to load %s"), TEXT(#fn)); \
} \
static_assert(true, "require ;")
FOR_EACH_ECSACT_API_FN(LOAD_ECSACT_FN);
#undef LOAD_ECSACT_FN
StartRunner();
}

auto FEcsactModule::UnloadEcsactRuntime() -> void {
UE_LOG(Ecsact, Log, TEXT("Unloading ecsact runtime"));

StopRunner();
if(EcsactRuntimeHandle) {
FPlatformProcess::FreeDllHandle(EcsactRuntimeHandle);
EcsactRuntimeHandle = nullptr;
Expand All @@ -60,6 +81,7 @@ auto FEcsactModule::UnloadEcsactRuntime() -> void {
}

auto FEcsactModule::StartupModule() -> void {
Self = this;
if(!GIsEditor) {
LoadEcsactRuntime();
}
Expand All @@ -78,6 +100,7 @@ auto FEcsactModule::ShutdownModule() -> void {
FEditorDelegates::PreBeginPIE.RemoveAll(this);
FEditorDelegates::EndPIE.RemoveAll(this);
#endif
Self = nullptr;
}

auto FEcsactModule::OnPreBeginPIE(bool _) -> void {
Expand All @@ -88,6 +111,56 @@ auto FEcsactModule::OnEndPIE(bool _) -> void {
UnloadEcsactRuntime();
}

auto FEcsactModule::StartRunner() -> void {
const auto* settings = GetDefault<UEcsactSettings>();

if(Runner != nullptr) {
UE_LOG(
Ecsact,
Warning,
TEXT("StartRunner() was called while runner was already running. "
"Stopping previous one before starting new.")
);
StopRunner();
}

switch(settings->Runner) {
case EEcsactRuntimeRunnerType::Automatic:
if(ecsact_async_flush_events == nullptr) {
Runner = NewObject<UEcsactSyncRunner>();
} else {
Runner = NewObject<UEcsactAsyncRunner>();
}
break;
case EEcsactRuntimeRunnerType::Asynchronous:
Runner = NewObject<UEcsactAsyncRunner>();
break;
case EEcsactRuntimeRunnerType::Custom:
if(settings->CustomRunnerClass != nullptr) {
Runner = NewObject<UEcsactRunner>(nullptr, settings->CustomRunnerClass);
}
break;
}

if(Runner != nullptr) {
UE_LOG(
Ecsact,
Verbose,
TEXT("Using ecsact runner: %s"),
*Runner->StaticClass()->GetName()
);
Runner->AddToRoot();
}
}

auto FEcsactModule::StopRunner() -> void {
if(Runner != nullptr) {
Runner->RemoveFromRoot();
Runner->ConditionalBeginDestroy();
Runner = nullptr;
}
}

#undef LOCTEXT_NAMESPACE

IMPLEMENT_MODULE(FEcsactModule, Ecsact)
22 changes: 16 additions & 6 deletions Source/Ecsact/Public/Ecsact.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,24 @@
DECLARE_LOG_CATEGORY_EXTERN(Ecsact, Log, All);

class FEcsactModule : public IModuleInterface {
void* EcsactRuntimeHandle;
auto LoadEcsactRuntime() -> void;
auto UnloadEcsactRuntime() -> void;
auto Abort() -> void;
auto OnPreBeginPIE(bool bIsSimulating) -> void;
auto OnEndPIE(const bool bIsSimulating) -> void;
friend class EcsactUnrealExecution;

static FEcsactModule* Self;
void* EcsactRuntimeHandle;
class UEcsactRunner* Runner;

auto LoadEcsactRuntime() -> void;
auto UnloadEcsactRuntime() -> void;
auto Abort() -> void;
auto OnPreBeginPIE(bool bIsSimulating) -> void;
auto OnEndPIE(const bool bIsSimulating) -> void;

auto StartRunner() -> void;
auto StopRunner() -> void;

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

auto StartupModule() -> void override;
auto ShutdownModule() -> void override;
};
17 changes: 17 additions & 0 deletions Source/Ecsact/Public/EcsactAsyncRunner.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "EcsactAsyncRunner.h"
#include "Ecsact.h"
#include "EcsactUnrealEventsCollector.h"
#include "ecsact/runtime/async.h"
#include "ecsact/runtime/common.h"

auto UEcsactAsyncRunner::Tick(float DeltaTime) -> void {
if(ecsact_async_flush_events == nullptr) {
UE_LOG(Ecsact, Error, TEXT("ecsact_async_flush_events is unavailable"));
} else {
ecsact_execution_events_collector* evc_c = nullptr;
if(EventsCollector != nullptr) {
evc_c = EventsCollector->GetCEVC();
}
ecsact_async_flush_events(evc_c, nullptr);
}
}
19 changes: 19 additions & 0 deletions Source/Ecsact/Public/EcsactAsyncRunner.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

#pragma once

#include "CoreMinimal.h"
#include "Tickable.h"
#include "UObject/NoExportTypes.h"
#include "EcsactRunner.h"
#include "EcsactAsyncRunner.generated.h"

UCLASS(NotBlueprintable)

class UEcsactAsyncRunner : public UEcsactRunner {
GENERATED_BODY()
public:
UPROPERTY()
class UEcsactUnrealEventsCollector* EventsCollector;

auto Tick(float DeltaTime) -> void override;
};
12 changes: 12 additions & 0 deletions Source/Ecsact/Public/EcsactExecution.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include "EcsactExecution.h"
#include "Ecsact.h"

float EcsactUnrealExecution::DeltaTime_ = 0.f;

auto EcsactUnrealExecution::DeltaTime() -> float {
return DeltaTime_;
}

auto EcsactUnrealExecution::Runner() -> class UEcsactRunner* {
return FEcsactModule::Get().Runner;
}
22 changes: 22 additions & 0 deletions Source/Ecsact/Public/EcsactExecution.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

class EcsactUnrealExecution {
friend class UEcsactSyncRunner;
friend class UEcsactAsyncRunner;
static float DeltaTime_;

public:
/**
* Get the DeltaTime for the current EcsactRunner execution. This should be
* used by Ecsact systems that are built by unreal build tool.
*
* NOTE: This is a workaround until 'execution metadata' is available.
* SEE: https://github.com/ecsact-dev/ecsact_parse/issues/163
*/
static auto DeltaTime() -> float;

/**
*
*/
static auto Runner() -> class UEcsactRunner*;
};
8 changes: 8 additions & 0 deletions Source/Ecsact/Public/EcsactRunner.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "EcsactRunner.h"

auto UEcsactRunner::Tick(float DeltaTime) -> void {
}

auto UEcsactRunner::GetStatId() const -> TStatId {
RETURN_QUICK_DECLARE_CYCLE_STAT(UTickableObject, STATGROUP_Tickables);
}
15 changes: 15 additions & 0 deletions Source/Ecsact/Public/EcsactRunner.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include "CoreMinimal.h"
#include "Tickable.h"
#include "UObject/NoExportTypes.h"
#include "EcsactRunner.generated.h"

UCLASS(Abstract)

class UEcsactRunner : public UObject, public FTickableGameObject {
GENERATED_BODY()
public:
auto Tick(float DeltaTime) -> void override;
auto GetStatId() const -> TStatId override;
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
UEcsactSettings::UEcsactSettings() {
}

#if WITH_EDITORONLY_DATA
auto UEcsactSettings::GetValidRecipes() const -> TArray<FString> {
return Recipes.FilterByPredicate([](const FString& recipe) -> bool {
return !recipe.TrimStartAndEnd().IsEmpty();
});
}
#endif
Loading

0 comments on commit 9846f84

Please sign in to comment.