How to avoid the repetition of UFUNCTION / UPROPERTY declarations ?

At first, let me introduce a “problem” I’ve encountered.
I’m creating a multiplayer game, in which every action/mechanic is based on the “state” (Replicated UPROPERTY variable or pointer).

For example:
If I want my Charater to Grab a StaticMesh, I just change the UPrimitiveComponent* GrabTarget to point at desired StaticMeshComponent.
And then I can execute a Grab-related logic based on this one single pointer.
(This explanation is ofcourse really simplified)

Because of that it’s really easy to create something that works well with OnRep calls and handles multiple edge cases (like late joining to session), at least for me.
However, I’ve found myself copy-pasting a lot of boilerplate code of multiple function declarations/definitions despite that these functions always do the same thing, just have a diffrent names or parameter types.

Example:

// ACTION_NAME - the name of action/mechanic that appears in Blueprints, e.g. "Grab"
// STATE_TYPE - the type of Replicated Property, on which the action/mechanic is based, e.g. "UPrimitiveComponent*"
// STATE_NAME - the name of Replicated Property, on which the action/mechanic is based, e.g. "GrabTarget"

public:

	UFUNCTION(BlueprintCallable)
	void ACTION_NAME(STATE_TYPE NewValue);

protected:
	
	UFUNCTION()
	void ExecuteACTION_NAME(STATE_TYPE NewValue);

	UFUNCTION(BlueprintNativeEvent, meta = (DisplayName = "ACTION_NAME"))
	void EventACTION_NAME(STATE_TYPE NewValue);

	UFUNCTION(BlueprintImplementableEvent, BlueprintCosmetic, meta = (DisplayName = "ACTION_NAME (Cosmetic)"))
	void CosmeticACTION_NAME(STATE_TYPE NewValue);

private:

	UPROPERTY(ReplicatedUsing = OnRep_STATE_NAME)
	STATE_TYPE STATE_NAME;

	UFUNCTION()
	void OnRep_STATE_NAME();

	UFUNCTION(Server, Reliable)
	void ServerACTION_NAME(STATE_TYPE NewValue);
	void ServerACTION_NAME_Implementation(STATE_TYPE NewValue);

	UFUNCTION(NetMulticast, Reliable)
	void MulticastACTION_NAME(STATE_TYPE NewValue);
	void MulticastACTION_NAME_Implementation(STATE_TYPE NewValue);

So my question is:
Can I somehow wrap this repetitive declaration code to the one single place?

What I’ve already tried:

  1. Using a C++ macro
    As I understand, this is imposible. Unreal’s Reflection system checks every header file before preprocesor swaps directives to the proper code. It compiles corectly but Unreal doesn’t see any UFUNCTION/UPROPERTY within a macro. (Using UFUNCTION within a macro)
  2. Creating a templated Class
    To my knowleadge, this is impossible while using UCLASS (Template UClass or an other way ?)

What I haven’t tried yet:

  1. “Some kind” of code generation script. I belive that Visual Studio might be able to handle it. I’m already using UnrealMacroGenerator exstension which basically swaps a code. The repetitive code would still be visible in multiple files but managing it would be easier.
  2. Gameplay Ability System - I believe this plugin might does the same compared to what I wanna achieve. Though it will be an obvious overkill.

I will be really thankful for any answear :pray:
Please, have in mind that I’m not some kind of C++/Unreal programmer, and there might be an easy solution I just couldn’t figure it out

Right, UnrealHeaderTool processes source files prior to the C preprocessor being run, so you can’t use macros with it (macros are expanded by the C preprocessor).

Right, UCLASSes cannot be class templates. Class templates denote a family of classes, whereas a UCLASS must be a (singular) class.

A code generator would work. You can write a script in your favorite scripting language that produces source files as output, and you can run that script whenever its input files change prior to building. The Unreal toolchain doesn’t know (and doesn’t care) whether the source files were written by hand or generated by a script. (We use this technique to generate a protobuf RPC client for example.)

2 Likes

Hey @zos, thanks for the answer!

Could You futher explain about “a protobuf RPC”? Or point me towards any source about it?
I have no knowleade about this technique but I believe you refer to Google’s Protocol Buffers. Let me know If I’m correct.
(Note to myself: GitHub - protocolbuffers/protobuf, GitHub - thejinchao/libprotobuf )

I would love to check any example of script for swapping/generating a code, just as an entry point so I could learn how it works.

Don’t get me wrong but if you are not too comfortable with programming, metaprogramming is not the best approach here.

I really did not grasp the whole idea of what you are trying to do, why functions with different names are doing the same thing or whatever, so I cannot give you exact answer, but I believe there should be a way of doing this with interfaces and using macros for declarations of overrides in the inherited classes.

Again, I have no idea why are you doing things like this or what is the scope of all of it, but if it’s all the same, use interfaces. Those will provide you with UPROPERTY/UFUNCTION macros so you can use classic C++ macro to override those. UHT won’t complain.

1 Like

I was just giving an example of where we use a code generator in our projects. The set of remote procedure calls (RPCs) offered by a service is specified in a .proto file, and then we run a python script that reads that .proto file and generates a .h/.cpp file containing a UCLASS that is a service client, and has a member function for each RPC.

A code generator is just a script that writes a text file. There is nothing mysterious about it. For example, here is a python script that writes the hello world program in C:

print('#include "stdio.h"\n')
print('int main() { printf("Hello, World!"); }')

and then run it like:

$ python myscript.py > hello.c

and viola - a code generator.

1 Like

Hey, thanks for more answers

@Ligazetom

  1. Futher explanation

These functions are just boilerplates that either are needed to expose nodes to blueprints or call diffrent functions (like Server RPCs).
Imagine that in Blueprints there is a node DoSomething, when it is called, it actually triggers a whole chain in the C++, e.g:
DoSomethingServerDoSomethingMulticastDoSomethingExecuteDoSomething
The functions DoSomething, ServerDoSomething, MulticastDoSomething are always declared in the same way and always do the same thing that is leading to a call of ExecuteDoSomething, which is the only one function at the end of this chain that will result in a diffrent behavior.
In the same Class I may would like to create a similiar chain, this time for DoSomethingElse node. The only one diffrence between DoSomething and DoSomethingElse will be that they take a diffrent parameters and result in the difrent behavior at the very end of its chains.

So now I believe You’ve already realized the “problem” here (or not as I’m really bad at explaining).
In the example above, I would have to create altmost the same chain for DoSomethingElse node. It will lead to very repetetive chunks of code, which only differ in a few keywords.
In the “perfect world” I could create a macro for it:

#define CHAIN(NAME, TYPE)\
protected:\
	\
	UFUNCTION(BlueprintCallable)\
	void NAME(TYPE Value);\
	\
private:\
	\
	UFUNCTION(Server, Reliable)\
	void Server##NAME(TYPE Value); \
	void Server##NAME##_Implementation(TYPE Value); \
	\
	UFUNCTION(Multicast, Reliable)\
	void Multicast##NAME(TYPE Value); \
	void Multicast##NAME##_Implementation(TYPE Value); \
	\
	UFUNCTION(BlueprintNativeEvent, meta = (DisplayName = #NAME)) \
	void Execute##NAME(TYPE Value); \
	void Execute##NAME##_Implementation(TYPE Value);

This approach is even valid with regular C++:

Sadly, It’s not going to work in Unreal due to how UFUNCTION macro is being handled by Reflection.

  1. Interfaces as solution

Not sure about this one to be honest.
I think I understand what You are suggesting, but I belive this is impossible in this case.
Because I CANNOT make them templated, change the function names and implement more than one interface of the same type.
However, I might be mistaken so please correct me if I’m wrong.

  1. Code swapping script as sollution

You are perfectly right and I’m also aware of it.
Though it could be a good opportunity to learn something new that would payoff in the future (or at least I want to believe in that :smiley: ).

@zos

Alright, I just wanted to be sure that I’m not missing something important :slight_smile:

It’s not like I don’t understand what you want, but I think it doesn’t have to work like this. It is unfortunately true you cannot just macro anything, well that’s the price we pay for exposing something to editor and we have to work within these limits.

The thing is you cannot create macros only for UFUNCTION() methods, otherwise it’s completely fine.

Obviously the “simplest” approach is to generate it using some script and you are off the hook, but I believe you should reorganize this whole idea that can live only because of using macros. Imagine there are no macros. You have to duplicate the code, changing only one little thing. That sucks. Think of something that allows you to not do it this way.

Can you group some of the functionality and wrap it within an interface or a component?

If you add all of these “DoSomething” to different components, you could just add the components to the actors, expose the components to editor and call functions on them. Then you could add/remove functionality however you like.

Or do some base interface with UObject* as param and create macro that will redeclare it in the header and another macro that you’d put in .cpp and do cast on the argument from UObject to Type you want.

I know there sometimes are simple solutions like these that we cannot use, trust me I hated that I cannot use templates and macros as well, but that is where the fun developing part starts.

If you think about it, is all that engine is allowing you to do worth not using macros and templates? I believe so.

You should get inspired by the quote " imposing restrictions is more likely to encourage creativity" which cannot be more true.

Macros are obviously very useful tool, but not the only one there is. The best approach whenever you come across something like this, is to stop and think about the architecture, is there really only one way to do it, why, what can I do different etc. It can help you identify code smells early on.

1 Like

100% true and I believe you just solved it:

I think I’ll try:
A component that stores the whole chain based on UObject* or FProperty.
Then I’ll try to handle this via macros.
Not sure how I will end up with exposing it to blueprints but I’ll try my best.

For me, it’s now an everyday struggle :smiley: - I learned a lot about C++ in the past which is basically invalid when it comes to Unreal.