I’m integrating pybind11 and python 3.9.13 as a game plugin to use tensorflow or something else and I need to use wildcard input and output to create a global variables inside python interpeter.
So what I need is: create a “array(FString) or struct” as wildcard, then I need to get variable name, type(like float, bool, text etc…) and its value.
PythonFunctionLibrary.h
public:
UFUNCTION(BlueprintCallable, Category = "PythonBridge|Execution", CustomThunk, meta = ( Keywords = "Struct python", CustomStructureParam = "AnyStruct" ))
static int RunPythonScript( FString Script, UStruct* AnyStruct, UStruct* &Output);
DECLARE_FUNCTION(execRunPythonScript);
private:
/* Example function for parsing a single property
* @param Property the property reflection data
* @param ValuePtr the pointer to the property value
*/
static void ReceiveSomeStruct_impl(FProperty* Property, void* StructPtr);
static void ParseProperty(FProperty* Property, void* ValuePtr);
PythonFunctionLibrary.cpp
int UPythonFunctionLibrary::RunPythonScript(FString Script, UStruct* AnyStruct, UStruct* &Output)
{
check(0);
return 0;
}
DEFINE_FUNCTION(UPythonFunctionLibrary::execRunPythonScript)
{
P_GET_OBJECT(UStruct, AnyStruct);
// Steps into the stack, walking to the next property in it
Stack.Step(Stack.Object, NULL);
// Grab the last property found when we walked the stack
// This does not contains the property value, only its type information
FProperty* StructProperty = CastField<FProperty>(Stack.MostRecentProperty);
// Grab the base address where the struct actually stores its data
// This is where the property value is truly stored
void* StructPtr = Stack.MostRecentPropertyAddress;
P_GET_PROPERTY_REF(FStrProperty, Script);
// Steps into the stack, walking to the next property in it
Stack.Step(Stack.Object, NULL);
// Grab the last property found when we walked the stack
// This does not contains the property value, only its type information
FProperty* StrProperty = CastField<FProperty>(Stack.MostRecentProperty);
// Grab the base address where the struct actually stores its data
// This is where the property value is truly stored
void* StrPtr = Stack.MostRecentPropertyAddress;
P_GET_OBJECT(UStruct, Output);
// We need this to wrap up the stack
P_FINISH;
// Iterate through the struct
ReceiveSomeStruct_impl(StructProperty, StructPtr);
Output = AnyStruct;
*(int*)RESULT_PARAM = 0;
}
/*
* Example function for iterating through all properties of a struct
* @param StructProperty The struct property reflection data
* @param StructPtr The pointer to the struct value
*/
void UPythonFunctionLibrary::ReceiveSomeStruct_impl(FProperty* Property, void* StructPtr)
{
UE_LOG(LogTemp, Warning, TEXT("%s"), *Property->GetAuthoredName());
FStructProperty* StructProperty = CastField<FStructProperty>(Property);
//check for null
if (StructProperty)
{
// Walk the structs' properties
for (TFieldIterator<FProperty> PropertyIt(StructProperty->Struct); PropertyIt; ++PropertyIt)
{
// This is the variable name if you need it
UE_LOG(LogTemp, Warning, TEXT("%s"), *PropertyIt->GetAuthoredName());
// Never assume ArrayDim is always 1
for (int32 ArrayIndex = 0; ArrayIndex < PropertyIt->ArrayDim; ArrayIndex++)
{
// This grabs the pointer to where the property value is stored
void* ValuePtr = PropertyIt->ContainerPtrToValuePtr<void>(StructPtr, ArrayIndex);
// Parse this property
ParseProperty(*PropertyIt, ValuePtr);
}
}
}
}
void UPythonFunctionLibrary::ParseProperty(FProperty* Property, void* ValuePtr)
{
float FloatValue;
int32 IntValue;
bool BoolValue;
FString StringValue;
FName NameValue;
FText TextValue;
// Here's how to read integer and float properties
if (FNumericProperty* NumericProperty = CastField<FNumericProperty>(Property))
{
if (NumericProperty->IsFloatingPoint())
{
FloatValue = NumericProperty->GetFloatingPointPropertyValue(ValuePtr);
UE_LOG(LogTemp, Warning, TEXT("float:'%f'"), FloatValue);
}
else if (NumericProperty->IsInteger())
{
IntValue = NumericProperty->GetSignedIntPropertyValue(ValuePtr);
UE_LOG(LogTemp, Warning, TEXT("integer:'%i'"), IntValue);
}
}
// How to read booleans
else if (FBoolProperty* BoolProperty = CastField<FBoolProperty>(Property))
{
BoolValue = BoolProperty->GetPropertyValue(ValuePtr);
if (BoolValue)
{
UE_LOG(LogTemp, Warning, TEXT("Bool: True"));
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Bool: False"));
}
}
// Reading names
else if (FNameProperty* NameProperty = CastField<FNameProperty>(Property))
{
NameValue = NameProperty->GetPropertyValue(ValuePtr);
UE_LOG(LogTemp, Warning, TEXT("Name:'%s'"), *NameValue.ToString());
}
// Reading strings
else if (FStrProperty* StringProperty = CastField<FStrProperty>(Property))
{
StringValue = StringProperty->GetPropertyValue(ValuePtr);
UE_LOG(LogTemp, Warning, TEXT("String:'%s'"), *StringValue);
}
// Reading texts
else if (FTextProperty* TextProperty = CastField<FTextProperty>(Property))
{
TextValue = TextProperty->GetPropertyValue(ValuePtr);
UE_LOG(LogTemp, Warning, TEXT("Text:'%s'"), *TextValue.ToString());
}
// Reading an array
else if (FArrayProperty* ArrayProperty = CastField<FArrayProperty>(Property))
{
// We need the helper to get to the items of the array
FScriptArrayHelper Helper(ArrayProperty, ValuePtr);
for (int32 i = 0, n = Helper.Num(); i < n; ++i)
{
UE_LOG(LogTemp, Warning, TEXT("Array:%i"), i);
ParseProperty(ArrayProperty->Inner, Helper.GetRawPtr(i));
}
}
// Reading a nested struct
else if (Property)
{
ReceiveSomeStruct_impl(Property, ValuePtr);
}
}
I change the code that why the input and output are diferent, but I cant do a return as a wildcard using this method.
I wish to do a function like that.