Exec python in cpp async
In this example we want get SG context using SGTK in python in cpp.
Custom Interface for python Task object
We can create an custom interface inherited from IQueuedWork to execute custom python command asynchronously.
cpp
/**
* require: Builtin PythonScriptPlugin module in <YOUR_MODULE>.Build.cs
*/
#pragma once
#include "CoreMinimal.h"
#include "PythonScriptTypes.h"
class IPythonAutoDeleteAsyncTask : private IQueuedWork
{
DECLARE_DELEGATE_OneParam(FOnPythonTaskComplete, FString&);
public:
/**
* Create and initialize a new instance
*
* @param pythonCommand Python command container
*/
IPythonAutoDeleteAsyncTask(const FPythonCommandEx& pythonCommand);
public:
/**
* Override Methods
*/
/** todo Abandon behaviour implementation */
virtual void Abandon() override {};
virtual void DoThreadedWork() override;
virtual void DoWork() = 0;
virtual void Start();
public:
/**
* Public fields
*/
FOnPythonTaskComplete OnPythonTaskComplete;
FPythonCommandEx PythonCommand;
};
/** Inline Methods */
FORCEINLINE IPythonAutoDeleteAsyncTask::IPythonAutoDeleteAsyncTask(const FPythonCommandEx& pythonCommand):
PythonCommand(pythonCommand)
{}
inline void IPythonAutoDeleteAsyncTask::Start()
{
GThreadPool->AddQueuedWork(this);
}
inline void IPythonAutoDeleteAsyncTask::DoThreadedWork()
{
DoWork();
delete this;
}
Example of implementation
cpp
#pragma once
#include "Interfaces/IPythonAutoDeleteAsyncTask.h"
class FPythonTask final : public IPythonAutoDeleteAsyncTask
{
public:
explicit FPythonTask(const FPythonCommandEx& pythonCommand)
: IPythonAutoDeleteAsyncTask(pythonCommand)
{
}
virtual void DoWork() override;
};
// .cpp
void FPythonTask::DoWork()
{
IPythonScriptPlugin::Get()->ExecPythonCommandEx(PythonCommand);
if (PythonCommand.CommandResult.IsEmpty())
return;
OnPythonTaskComplete.ExecuteIfBound(PythonCommand.CommandResult);
}
Example of usage
cpp
FPythonCommandEx ccc;
ccc.Command = FString("current_context.project.get('id', '')");
ccc.ExecutionMode = EPythonCommandExecutionMode::EvaluateStatement;
ISWOPythonAutoDeleteAsyncTask* c = new FSWOPythonTask(ccc);
c->OnPythonTaskComplete.BindLambda([this](const FString& result)
{
UE_LOG(LogTemp, Warning, TEXT("Result: %s"), *result);
});
c->Start();
// Add this module in module.cs :
PythonScriptPlugin // builtin engine plugin
// [Warning] Due to async behaviour execution order cannot be ensure.
FPythonCommandEx setContextCommand;
setContextCommand.Command = FString("import sgtk;current_engine = sgtk.platform.current_engine();current_context = current_engine.context");
setContextCommand.ExecutionMode = EPythonCommandExecutionMode::ExecuteStatement;
ISWOPythonAutoDeleteAsyncTask* setContextTask = new FSWOPythonTask(setContextCommand);
setContextTask->Start();
FPythonCommandEx getProjectIDCommand;
getProjectIDCommand.Command = FString("current_context.project.get('id', '')");
getProjectIDCommand.ExecutionMode = EPythonCommandExecutionMode::EvaluateStatement;
ISWOPythonAutoDeleteAsyncTask* getProjectIDTask = new FSWOPythonTask(getProjectIDCommand);
getProjectIDTask->OnPythonTaskComplete.BindLambda([this](const FString& result)
{
UE_LOG(LogTemp, Warning, TEXT("Result: %s"), *result);
});
getProjectIDTask->Start();
Links:
- from engine
..\..\Source\Runtime\Core\Public\Async\AsyncWork.h
row 60 - this jdelezenne doc