pass a userdefined structure param to blueprintcallable function in C++ ?

I know there is a meta tag CustomStructureParam to use to get the value address of the struct, but how to get the struct’s definition ?

code like this :

in C++

UFUNCTION( *** meta=“CustomStructureParam=StructAddr” **)
static void DisplayStructMembers(void
StructAddr, param of the definition of this struct);

in BP

Property declare:
EquipItem Equip;

function call Graph:
Equip—>DisplayStructMembers

You mean you want to expose the struct to BPs?

no , the struct is defined in BP, a UserDefinedStruct, I want to use this struct in C++.

Just needed to do this, worked it out by following the code in GetDataTableRowFromName and SetStructurePropertyByName blueprint nodes, this has general purpose struct passing (out in this case, but it’s easy to switch it to in by setting the struct parameter to const, the mechanism is the same). You need to do the following:

  1. Declare a UFUNCTION as you would for a normal blueprint function.
  2. Add the “CustomThunk” attribute, and (in the “meta” section) add a CustomStructureParam that refers to your parameter.
  3. The parameter should be of type FGenericStruct& (and const for input, non-const for output)
  4. You also need a (static) function that has almost the same signature except void* for the type, these are named Generic_* by Unreal convention.
  5. You need to declare a custom thunk implementation of exec[YourFunctionName] using the DECLARE_FUNCTION macro and a series of P_GET_OBJECT/PROPERTY/etc/P_FINISH/P_NATIVE_BEGIN/P_NATIVE_END (and RESULT_PARAM if you have a return value).
  6. For the generic structure passing you use Stack.StepCompiledIn(NULL); and void* SrcStructAddr = Stack.MostRecentPropertyAddress; together to produce a pointer to the data structure in memory that is passed in.
  7. This can then be used as the void* parameter to pass to the Generic_* function where the struct is referred to.

This gets you a void* but that’s not that useful unless you have also passed in some more information about the structure, e.g. a UScriptStruct or UStruct pointer perhaps. (my use case was UUserDefinedStruct).

With this extra information you can do things like:

  1. Get a pointer to the first field definition of the struct: FField* prop = pstruct_type->ChildProperties;
  2. loop through them using while(prop) { … prop = prop->Next; }
  3. Check for the types you are interested in handling by casting to the various FProperty types, e.g. FNumericProperty num_prop = CastField(prop);
  4. Make a pointer to the field within the struct memory image: const uint8* pdata = (uint8*)in_struct_instance_ptr + num_prop->GetOffset_ForUFunction();
  5. Set/Get it’s value (in this case I want integer numerics): if (num_prop->IsInteger()) {
    int value = (int)num_prop->GetSignedIntPropertyValue(pdata); //do something with value… }

Hope that is enough to get anyone still reading this started.

Sam

3 Likes