I’ve seen many questions on this and yet I seem to be missing something. Right now I simply want to return the ref to a private struct in a class so modification can happen. I also want to be able to use this in blue print.
Here is the code in the class. I attempted this with an array of structs first then tried with just a struct. I also tested this in both BP and C++ but both do not seem to work.
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class CPPTEST_API UActionQueueTest : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UActionQueueTest();
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<FMyStruct> MyStructArray;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FMyStruct MyStruct;
UFUNCTION(BlueprintCallable, BlueprintPure)
UPARAM(Ref) FMyStruct& GetRef(int32 index)
{
static FMyStruct DefaultStruct;
if (0 <= index && index < MyStructArray.Num())
{
return MyStructArray[index];
}
return DefaultStruct;
}
UFUNCTION(BlueprintCallable, BlueprintPure)
UPARAM(Ref) FMyStruct& GetStructRef()
{
return MyStruct;
}
};
The results are always an unchanged struct, unless I use the Get (by ref) BP node which works. My syntax seems to be fine and as far as I can tell if this was raw C++ it should work but the ref is acting like a copy it seems.
easier if you post the code text in a codeblock then people can quote parts in response.
I see 3 things at first:
“dot” shaped blueprint parameters are always copies squares are ref. modifying a ref property on a parent copy misses the point. Unsure how you can see ref (if any) on types like array in blueprints, I’m a c++ guy.
Do you need the UPARAM(ref) for the return type to work in BP? I think not. I only used this once in my entire code where an input parameter would show as output in BP (very interesting) and suggested was to add UPARAM(ref) to add support. I don’t know another use case.
easier if you post the code text in a codeblock then people can quote parts in response.
Good call, I didn’t think about that. I have updated the question to replace the images with the code.
So I’m actually confused by your first point. I know about the different pin shapes and am trying to achieve the square ones like on the Get node and the Set Members node. I don’t know what you mean by “Unsure how you can see ref (if any) on types like array in blueprints”.
I don’t know if UPARAM(ref) is actually doing anything anymore. It was something I came across and tried to get the return of the function to work. All it seemed to do was change the output pin to the square but not actually change anything functionality wise.
You are correct about me missing the ‘&’ when storing the ref (this probably shows my experience level with C++). I added it and that worked for the C++ side, so that test works now. But now I am back to being stuck on why this doesn’t work in BP. The C++ and BP tests seem to be the same so now I wonder if I’m missing some macro or something to bridge that functionality to BP.
I was getting ahead of myself there, just wondering why the funtion and direct property access in blueprints act differently, while they should not. The function clearly shows the square on the output parameter, so that function should work while it does not.
nice, then the issue is probably with blueprints.
I think we should try a few things one by one now.
If you remove all the “UPARAM(Ref)”, do you still get reference return values in blueprint?
Are you sure GetRef returns from MyStructArray properly? I see something going on there with DefaultStruct. You tested GetStructRef in C++ but perhaps not GetRef.
So for now I have shifted to only testing the “GetStructRef” since the array is not necessary till I can get a proper ref returned. The “DefaultStruct” was only used if the index was out of range.
Removing “UPARAM(Ref)”, results in the same behavior as far as I can tell, the only difference being that the pin shape is different in BP.
I have also come across another syntax for refs in functions
UFUNCTION(BlueprintCallable, BlueprintPure)
void GetStructRefOut(FMyStruct& out)
{
out = MyStruct;
}
UE will identify this as an out parameter and place the pin in BP on the output side, however I don’t know if this helps here.
Through our discussion I found that my usage of that format causes blueprints to create copy pins. I just used it as optimization in C++ but I see I need to inspect this mechanic closer myself for BP. oddly I never noticed:
I don’t know if that solves your situation, but that is what I use 99.99% the time (your FMyStruct& Out format)
I don’t think it does either. They seem to work different. A return ref allows for change to happen to the original object out side of the function while an argument ref is more for modification in the function. I am looking to modify outside the function.
Just checking, currently “GetStructRef” is verified working in c++ but not in blueprints? and can you verify the node itself is the issue?
yeah it seems to work in C++ but not BP.
// Called when the game starts
void UActionQueueTest::BeginPlay()
{
Super::BeginPlay();
// ...
MyStruct = FMyStruct(0, "name 0");
FMyStruct& ref = GetStructRef();
ref.Name = "name 1";
UE_LOG(LogTemp, Warning, TEXT("%d : %s"), MyStruct.ID, *FString(MyStruct.Name));
}
I don’t think the pin shape is a good indicator anymore because if I slap “UPARAM(Ref)” in front of the function it changes the pin shape but still has the same output.
Even the message when you hover over the pin claims its a ref when UPARAM(Ref) is there. When removed it doesn’t claim to be a ref. I suspect UPARAM(Ref) is cosmetic.
I’ve triple checked it all so far and while that would be a breaking node bug, it seems so. I hope someone can confirm that we didn’t miss anything.
Meantime, a temporary alternative could be to use a pointer to a UObject holding the data instead of a struct ref. (turn the struct into a uobject). If blueprints is a requirement for this part of the code. (otherwise remove the UFUNCTION) and move blueprint access to a lower layer.
So this might be a whole other topic but im actuality remaking a container I already have that works in BP and uses objects. Im remaking it specifically to support struct refs because I am trying to support multiplayer. From my experiments and bit of research, structs seem to be the way when communicating between client and server since objects get passed as pointers and that poiter is not the same between client and server. BP support is also a priority for me personally. Its where I work the most and this is actually my first time in UE C++, and first time back to C++ in a few years.
Thats weird considering there are functions in BP that return proper refs. Also why would they allow the out pin to be a square and say its a ref when using UPARAM?
I just tried returning a struct by ref from a purely BP function (no c++), but it also returns by copy. So this seems to be by design (or a big oversight), and is not limited to c++.
The output pin being by ref (square / diamond shaped) when you use the UPARAM(Ref) on the c++ function return is definitely misleading / potentially a bug.
UPARAM(Ref) is useful to avoid Unreal automatically converting a reference argument of a BlueprintCallable function into an output, as it often likes to do.
I know this isn’t the answer you are looking for but at the end of the day, instead of fighting against it or trying to wrap this around various containers / uobjects, if you want to allow Blueprint to edit these structs, you could just expose the array as UPROPERTY and use the array Get (by ref).
If you want to maintain encapsulation at least in c++, you should be able to keep the variable private and use:
private:
UPROPERTY(BlueprintReadWrite, meta = (AllowPrivateAccess = true))
TArray<FMyStruct> Structs;
I personally never use AllowPrivateAccess because it feels like a workaround, but in your case it might be the least painful way.
Depending on how and what you communicate, there’s also a way to convert struct to string or json and back. I have no idea about Unreal replication system, only general client / server communication in web.
And thanks guys for also confirming that something is definitely broken on the blueprint side.
Blueprints bites. You’ll definitely have the better experience once you go 99% c++. That might look like a lot of effort to dive into right now, but compared to how much time you lose with blueprints (limitations, corruption, non portable code) you will actually save time in the end.
Networked multiplayer is a thing lots of people avoid for its complexity and probable added costs (hosting, security) (some people have the MMO idea in mind). From my personal experience (say 10 years) of UE with blueprint and c++, I’d blueprint is certainly going to screw up a lot.