diff --git a/Source/Integration/Integration.Build.cs b/Source/Integration/Integration.Build.cs index 430186ac..0a11a6a7 100644 --- a/Source/Integration/Integration.Build.cs +++ b/Source/Integration/Integration.Build.cs @@ -8,7 +8,7 @@ public class Integration : ModuleRules { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; - PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" }); + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "Sockets", "Networking" }); PrivateDependencyModuleNames.AddRange(new string[] { }); diff --git a/Source/Integration/IntegrationGameModeBase.cpp b/Source/Integration/IntegrationGameModeBase.cpp index b260c9d0..a3950564 100644 --- a/Source/Integration/IntegrationGameModeBase.cpp +++ b/Source/Integration/IntegrationGameModeBase.cpp @@ -24,13 +24,18 @@ EngineWrapper AIntegrationGameModeBase::Luprex; AIntegrationGameModeBase::AIntegrationGameModeBase() { - Worker = nullptr; Thread = nullptr; + ThreadStopRequested = false; //PrimaryActorTick.bCanEverTick = true; // Probably wrong //PrimaryActorTick.bTickEvenWhenPaused = true; // Probably wrong //PrimaryActorTick.TickGroup = TG_PrePhysics; // Probably wrong - SetActorTickEnabled(true); // Probably wrong - SetActorTickInterval(1.0f); // Probably wrong + SetActorTickEnabled(true); + SetActorTickInterval(1.0f); +} + +AIntegrationGameModeBase::~AIntegrationGameModeBase() +{ + WaitForThread(); } void AIntegrationGameModeBase::HandleConsoleOutput() @@ -46,14 +51,44 @@ void AIntegrationGameModeBase::HandleConsoleOutput() ConsoleOutput.Append(fs); } -void AIntegrationGameModeBase::WaitForWorkerThread() +void AIntegrationGameModeBase::LaunchThread() +{ + if (Thread == nullptr) { + ThreadStopRequested = false; + Thread = FRunnableThread::Create(this, TEXT("Worker Thread")); + } +} + +// Init routine called by the worker thread. +bool AIntegrationGameModeBase::Init() +{ + engineutil::DPrint("WorkerRunnable::Init"); + return true; +} + +// Run routine called by the worker thread. +uint32 AIntegrationGameModeBase::Run() +{ + while (!ThreadStopRequested) + { + engineutil::DPrint("WorkerRunnable::Run"); + FPlatformProcess::Sleep(1.0); + } + engineutil::DPrint("WorkerRunnable Done"); + return 0; +} + +void AIntegrationGameModeBase::Stop() +{ + ThreadStopRequested = true; +} + +#pragma optimize( "", off ) +void AIntegrationGameModeBase::WaitForThread() { if (Thread == nullptr) return; - //Worker->Stop(); - //Thread->WaitForCompletion(); - delete Thread; - delete Worker; - Worker = nullptr; + Stop(); // Notifies the thread to clean up and exit. + delete Thread; // This waits for the thread to complete. Thread = nullptr; } @@ -68,10 +103,10 @@ void AIntegrationGameModeBase::Tick(float DeltaSeconds) EngineSeconds += DeltaSeconds; Luprex.play_invoke_event_update(&Luprex, EngineSeconds); } - for (const FString& fs : engineutil::DPrintGetStored()) { + TArray prints = engineutil::DPrintGetStored(); + for (const FString& fs : prints) { ConsoleOutput.AppendLine(fs); } - engineutil::DPrintClearStored(); if (ConsoleOutput.IsDirty()) { ConsoleSetOutput(ConsoleOutput.Get()); ConsoleOutput.ClearDirty(); @@ -94,7 +129,7 @@ void AIntegrationGameModeBase::ConsoleSendInput(const FString& fs) void AIntegrationGameModeBase::BeginPlay() { - engineutil::RawPrint("In BeginPlay"); + engineutil::DPrint("In BeginPlay"); Super::BeginPlay(); if (!luprex_initialized()) { engineutil::init_wrapper(&Luprex); @@ -122,16 +157,12 @@ void AIntegrationGameModeBase::BeginPlay() ConsoleOutput.AppendLine(FString("Initialize Luprex Success")); } EngineSeconds = 0; - - if (Thread == nullptr) { - Worker = new FWorkerRunnable(); - Thread = FRunnableThread::Create(Worker, TEXT("Worker Thread")); - } + LaunchThread(); } void AIntegrationGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason) { - engineutil::RawPrint("In EndPlay"); - WaitForWorkerThread(); + engineutil::DPrint("In EndPlay"); + WaitForThread(); } diff --git a/Source/Integration/IntegrationGameModeBase.h b/Source/Integration/IntegrationGameModeBase.h index dcdf1672..7e2bf513 100644 --- a/Source/Integration/IntegrationGameModeBase.h +++ b/Source/Integration/IntegrationGameModeBase.h @@ -6,23 +6,33 @@ #include "GameFramework/GameModeBase.h" #include "enginewrapper.hpp" #include "engineutil.hpp" -#include "WorkerRunnable.hpp" #include "IntegrationGameModeBase.generated.h" /** * */ UCLASS() -class INTEGRATION_API AIntegrationGameModeBase : public AGameModeBase +class INTEGRATION_API AIntegrationGameModeBase : public AGameModeBase, public FRunnable { GENERATED_BODY() public: AIntegrationGameModeBase(); + ~AIntegrationGameModeBase(); virtual void BeginPlay() override; virtual void Tick(float) override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason); + // Thread start and shutdown. + void LaunchThread(); + void WaitForThread(); + + // Methods of FRunnable, for the thread to use. + virtual bool Init() override; + virtual uint32 Run() override; + virtual void Stop() override; + + // Return true if luprex was successfully initialized. inline bool luprex_initialized() { return Luprex.play_initialize != nullptr; } @@ -31,16 +41,17 @@ public: UFUNCTION(BlueprintImplementableEvent) void ConsoleSetOutput(const FString& text); + // This is called by the GUI whenever the user hits enter. UFUNCTION(BlueprintCallable) void ConsoleSendInput(const FString& text); void HandleConsoleOutput(); - void WaitForWorkerThread(); - // Refresh the console output. - FWorkerRunnable* Worker; + // The worker thread is responsible for networking and event_update FRunnableThread* Thread; + bool ThreadStopRequested; + engineutil::ConsoleOutput ConsoleOutput; static EngineWrapper Luprex; float EngineSeconds; diff --git a/Source/Integration/WorkerRunnable.cpp b/Source/Integration/WorkerRunnable.cpp deleted file mode 100644 index 31cb1918..00000000 --- a/Source/Integration/WorkerRunnable.cpp +++ /dev/null @@ -1,26 +0,0 @@ - -#include "WorkerRunnable.hpp" -#include "engineutil.hpp" - - -bool FWorkerRunnable::Init() -{ - engineutil::RawPrint("WorkerRunnable::Init"); - return true; -} - -uint32 FWorkerRunnable::Run() -{ - while (!StopRequested) - { - engineutil::RawPrint("WorkerRunnable::Run"); - FPlatformProcess::Sleep(1.0); - } - engineutil::RawPrint("WorkerRunnable Done"); - return 0; -} - -void FWorkerRunnable::Stop() -{ - StopRequested = true; -} \ No newline at end of file diff --git a/Source/Integration/WorkerRunnable.hpp b/Source/Integration/WorkerRunnable.hpp deleted file mode 100644 index b37eff56..00000000 --- a/Source/Integration/WorkerRunnable.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" - -class FWorkerRunnable : public FRunnable -{ -public: - FWorkerRunnable() : StopRequested(false) {} - virtual bool Init() override; - virtual uint32 Run() override; - virtual void Stop() override; -private: - bool StopRequested; -}; - diff --git a/Source/Integration/engineutil.cpp b/Source/Integration/engineutil.cpp index b60c18de..497e8b52 100644 --- a/Source/Integration/engineutil.cpp +++ b/Source/Integration/engineutil.cpp @@ -14,34 +14,31 @@ void init_wrapper(EngineWrapper* w) { } } -// Print text using GEngine->Add... -void RawPrint(const char* text) { - if (GEngine) - { - GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, FString(text)); - } -} - -static TArray dprints; +// The DPrint array. This stores the dprints +// until they can be collected by the console implementation. +static TArray dprint_array; +static FCriticalSection dprint_mutex; void DPrint(const FString& fs) { - dprints.Emplace(fs); + FScopeLock lk(&dprint_mutex); + dprint_array.Emplace(fs); } void DPrint(const char* msg) { - dprints.Emplace(msg); + FScopeLock lk(&dprint_mutex); + dprint_array.Emplace(msg); } void DPrintHook(const char* msg, size_t len) { - dprints.Emplace(len, (const UTF8CHAR*)msg); + FScopeLock lk(&dprint_mutex); + dprint_array.Emplace(len, (const UTF8CHAR*)msg); } -const TArray& DPrintGetStored() { - return dprints; -} - -void DPrintClearStored() { - dprints.Reset(); +TArray DPrintGetStored() { + FScopeLock lk(&dprint_mutex); + TArray result = std::move(dprint_array); + dprint_array.Empty(); + return result; } void ConsoleOutput::Append(const FString& text) { diff --git a/Source/Integration/engineutil.hpp b/Source/Integration/engineutil.hpp index 7b78ac28..1e42b434 100644 --- a/Source/Integration/engineutil.hpp +++ b/Source/Integration/engineutil.hpp @@ -6,9 +6,6 @@ namespace engineutil { // Load the DLL and initialize the wrapper, if possible. void init_wrapper(EngineWrapper* w); -// Print text using GEngine->Add... -void RawPrint(const char* text); - // Print text on the console. void DPrint(const FString& fs); @@ -19,10 +16,7 @@ void DPrint(const char* msg); void DPrintHook(const char* msg, size_t len); // Get all the stored dprints. -const TArray& DPrintGetStored(); - -// Clear the stored dprints. -void DPrintClearStored(); +TArray DPrintGetStored(); class ConsoleOutput { private: