How to Access a BP Script array (FScriptArray) and members from C++?

Dear Friends at Epic,

Suffice it to say that it is a project specification that I must access a BP array from C++.

So context:

I have a blueprint

this blueprint has a dynamic array of FNames.

I want to access this array, its total, and its members from c++

I am not instancing this blueprint into the world, the array values are set in its defaults only.


Here’s as far as I got:

//Get BP Array, returns total count
static FORCEINLINE int32 GetBPArray( UClass* TheBP, const FName& Name)
{
	if(!TheBP) 			return -1;
	if(Name == NAME_None) 	return -1;
	//~~~~~~~~~~~~~~~
		
	UArrayProperty* ArrayProp = FindField(TheBP, Name);
	FScriptArray* ScriptArray = ((FScriptArray*)ArrayProp);
	if(ArrayProp != NULL && ScriptArray )
	{
		FScriptArrayHelper BPArrayHelper(ArrayProp,ScriptArray->GetData());
		return BPArrayHelper.Num();
	}
		
	return -1;
}

The FScriptArrayHelper returns garbage even though there are actually 4 array entries set in the default.

if I use this version

return ScriptArray->Num();

it returns 1, but there are actually 4 default entries :slight_smile:


Any ideas?


#And Accessing Members?

I still have very little idea of how to access the members of this ScriptArray, even if I can get the count correctly :slight_smile:

Thanks!

Rama

PS: Yes, I know it would be easier/better/faster/more efficient to have the array in C++, I know, please read the first line, :slight_smile:

I’m not the expert on this, but you need to do some massaging of the data before you can use it and FScriptArray is not what you want, although FScriptArrayHelper is. You want to operate on the default object, not the class, although you will need the class too. I believe this is right, but I know you’ll fiddle with it and let me know :slight_smile:

MyUObjectType* Object = MyClass->GetDefaultObject();
UArrayProperty* ArrayProp = FindField(MyClass, Name);

// Your data is inside a UObject, it needs to be accessed appropriately
FScriptArrayHelper_InContainer ArrayHelper(ArrayProp, Object);

FString Value;
for( int32 i=0; iInner->ExportTextItem( Value, ArrayHelper.GetRawPtr(i), ArrayHelper.GetRawPtr(i), Obj, PPF_IncludeTransient );
}
1 Like

Woohoo!

Great to hear from you Josh!

Yea I knew I wasnt using the Helper right, I will try out what you have here!

// Your data is inside a UObject, it needs to be accessed appropriately
FScriptArrayHelper_InContainer ArrayHelper(ArrayProp, Object);

And I had no idea about the string stuff

#Thanks for the Code Josh!

#:heart:

Rama

#For Your Entertainment Josh

For your entertainment Josh,

I have now posted a tutorial on how to access BP Arrays in C++, and also retrieve the type of the array as well as all the data!


I am posting pics and code here for future readers and for you to enjoy Josh!


I post code for converting Int, Float, and Vector BP arrays into their C++ TArray equivalents.

#My Test BP Extend AActor

I ran my tests on a blueprint that was extending the very base class of AActor itself!

Yay!

#Thanks for Your Help!

#Tutorial on Accessing BP-created Arrays in C++
http://forums.epicgames.com/threads/972861-43-TUTORIALS-C-for-UE4-gt-gt-New-How-to-Access-a-Blueprint-Created-Array-From-C?p=31799080#post31799080

#Pics

Enjoy!

#C++ Code

//Get BP Array, returns total count
static FORCEINLINE int32 GetBPArray( UObject* Obj, const FName& Name, FString& CPPMacroType,TArray& OutData)
{
	if(!Obj) 			return 0;
        if(!TheObj->IsValidLowLevel()) return 0;
	if(Name == NAME_None) 	return 0;
	//~~~~~~~~~~~~~~~
	
	UArrayProperty* ArrayProp = FindField(Obj->GetClass(), Name);
	 
	// Your data is inside a UObject, it needs to be accessed appropriately
	if(ArrayProp != NULL)
	{
		FScriptArrayHelper_InContainer ArrayHelper(ArrayProp, Obj);
		
		//Get the Array Type!!!
		ArrayProp->GetCPPMacroType(CPPMacroType);
		
		//Get FString Array of the Data
		FString Value;
		for( int32 i=0; iInner->ExportTextItem( Value, ArrayHelper.GetRawPtr(i), ArrayHelper.GetRawPtr(i), Obj, PPF_IncludeTransient );
			
			//Add
			OutData.Add(Value);
		}

		return ArrayHelper.Num();
	}
	
	return 0;
}

#Converting from FString Array to C++ Equivalent

void AMyBasePlayerController::GetBPArrayData(UObject* TheObj, const FName& ArrayName)
{
	if(!TheObj) return;
        if(!TheObj->IsValidLowLevel()) return;
	//~~~~~~~~~~~~~~~~
	
	FString BPArrayType = "";
	TArray StrVersionOfData;
	
	const int32 ArrayTotal = 
		UCoreFunctions::GetBPArray(TheObj, ArrayName,BPArrayType,StrVersionOfData);
	
	
	//Output
	FString Str = "";
	Str = FString::FromInt(ArrayTotal);
	ClientMessage(Str);
	
	ClientMessage("Array Type");
	ClientMessage(BPArrayType);
	
	//Is BP Array FName Array?
	if(BPArrayType == "FName")
	{
		TArray TheNames;
		for(int32 v = 0; v < ArrayTotal; v++)
		{
			TheNames.Add(*StrVersionOfData[v]);
		}
		
		//Display FName Array
		ClientMessage("This is the actual FName Array now");
		for(int32 v = 0; v < ArrayTotal; v++)
		{
			ClientMessage(TheNames[v].ToString());
		}
	}
	
	//Is BP Array Int Array?
	if(BPArrayType == "Int")
	{
		TArray TheInts;
		for(int32 v = 0; v < ArrayTotal; v++)
		{
			TheInts.Add(FCString::Atoi(*StrVersionOfData[v]));
		}
		
		//Display Array
		ClientMessage("This is the actual int Array now");
		for(int32 v = 0; v < ArrayTotal; v++)
		{
			ClientMessage(FString::FromInt(TheInts[v]));
		}
	}
	
	//Is BP Array Float Array?
	if(BPArrayType == "Float")
	{
		TArray TheFloats;
		for(int32 v = 0; v < ArrayTotal; v++)
		{
			TheFloats.Add(FCString::Atof(*StrVersionOfData[v]));
		}
		
		//Display Array
		ClientMessage("This is the actual float Array now");
		for(int32 v = 0; v < ArrayTotal; v++)
		{
			ClientMessage(FString::SanitizeFloat(TheFloats[v]));
		}
	}
	
	//Is BP Array Vector Array?
	if(BPArrayType == "FVector")
	{
		TArray TheVectors;
		for(int32 v = 0; v < ArrayTotal; v++)
		{
			FVector NewVector;
			NewVector.InitFromString(StrVersionOfData[v]);
			TheVectors.Add(NewVector);
		}
		
		//Display Vector Array
		ClientMessage("This is the actual Vector Array now");
		for(int32 v = 0; v < ArrayTotal; v++)
		{
			ClientMessage(TheVectors[v].ToString());
		}
	}
}