Download

Templated Interfaces is that possible?

Hey guys.

I’m trying to solve a problem of serialization in my 'lil project: I need to be able to take any UStruct from a class that would inherit my Interface and dump it into JSON object.
So far I’ve come up with a solution that looks like this:

Interface:


UINTERFACE(Blueprintable)
class NBS_API USavable : public UInterface
{
	GENERATED_UINTERFACE_BODY()
};

class ISavable
{
	GENERATED_IINTERFACE_BODY()

public:
        ....
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Saving")
	UStruct* GetSaveData();
        .... 
};


Example of class using it:


USTRUCT()
struct FCompValue
{
	GENERATED_BODY()

	int32 foo;
	
	bool bar;

        FHealthComponentValues();
};

UCLASS( ClassGroup=(Custom), Blueprintable, meta=(BlueprintSpawnableComponent) )
class NBS_API UHealthComponent : public UActorComponent, public ISavable
{
	GENERATED_BODY()
        FCompValue comValue; 

        ... code ... 
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Saving")
	UStruct* GetSaveData();
	virtual UStruct* GetSaveData_Implementation() override { return (UStruct*)&compValue; }
        ... more code ... 
};



it this point when I collect those UStructs with my manager, they all come out to be garbage, which is understandable because I’m down-casting them to UStruct.
I figured out to use templates for this problem, so I would want to make something like:


 
template<typename Data>
class ISavable
{
	GENERATED_IINTERFACE_BODY()

public:
        ....
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Saving")
	Data* GetSaveData();
        .... 
};


such that I can get those structs directly without down-casting them into just UStruct.

I’ve been looking around forums and Wiki’s to find a proper solution to templated interfaces in Unreal, but I could not… So here I’m asking for your advice.

Thanks!

As far as I know anything related to UCLASS, USTRUCT, UFUNCTION and UINTERFACE cannot be templated. Although you can still use things like TSubclassOf<> etc. these are handled by the engine. I’m not sure what would be required to make your own templated data types like those provided by the engine but I may involve creating a new UProperty subclass and changes to the Unreal Header Tool.

If you don’t want to go that route, you still have other alternatives available. Note that the following will be pseudo-code(ish).

[SPOILER]
For example your interface could look like this instead:


UINTERFACE(Blueprintable)
class NBS_API USavable : public UInterface
{
	GENERATED_UINTERFACE_BODY()
};

class ISavable
{
	GENERATED_IINTERFACE_BODY()

public:
        ....
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Saving")
	bool GetSaveData(TheJSONDataType* const TheJSONData);
        .... 
};

And the implementation like this:


virtual bool GetSaveData_Implementation(TheJSONDataType* const TheJSONData) override
{
	if (TheJSONData)
	{
		//write specific data into TheJSONData for this type

		return true;
	}

	return false;
}

Your Manager would only need to create an instance of TheJSONDataType and then call the method of the ISavable interface for each object that implements it. It would also need to write the final data into a file or whatever.
[/SPOILER]

A second solution would be closer to your original idea.

[SPOILER]
The interface could look like this:


UINTERFACE(Blueprintable)
class NBS_API USavable : public UInterface
{
	GENERATED_UINTERFACE_BODY()
};

class ISavable
{
	GENERATED_IINTERFACE_BODY()

public:
        ....
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Saving")
	class USavableData* GetSaveData();
        .... 
};


UCLASS(Abstract, Blueprintable)
class NBS_API USavableData : public UObject
{
	GENERATED_UCLASS_BODY()

public:
	void SaveDataTo(FArchive & Archive)
	{
		UClass* ThisClass = GetClass();

		//get all properties from ThisClass
		//only process properties declared in USavableData and subclasses, ignore properties declared in UObject
		//for each property to process, get its value and serialize it into the archive
	}
};

The HealthComponent becomes




and


UCLASS()
class NBS_API USavableData_HealthComponent : public USavableData
{
	GENERATED_UCLASS_BODY()

public:
	UPROPERTY()
	int32 foo;
	
	UPROPERTY()
	bool bar;
};

UCLASS( ClassGroup=(Custom), Blueprintable, meta=(BlueprintSpawnableComponent) )
class NBS_API UHealthComponent : public UActorComponent, public ISavable
{
	GENERATED_BODY()

	UPROPERTY()
        USavableData_HealthComponent* SavableData_HealthComponent; 

	virtual USavableData* GetSaveData_Implementation() override
	{
		return SavableData_HealthComponent;
	}
};

Your manager would do what it’s doing now but on each USavableData* it gets after calling the ISavable interface it would also call SaveDataTo passing in the FArchive or JSON data or whatever.
[/SPOILER]

Yeah, the second solution is something that I might end-up going with, looks like it would be better solution for my system.

Thanks!

You’re welcome.

Thinking about this again. The save game system which is already implemented in the engine uses a very similar approach so I would also recommend looking at how that is implemented. For example it only processes properties that have the SaveGame flag.

Ah, there is a Save Game system after all? I should have figured that Epic had that covered… So much for doing my home work before asking questions. :slight_smile:
Thanks for the tip!

Talking about that Unreals Save Game system without reading much into it, is there disadvantage using it compare to making your own save game? Just curious at this point, don’t really want to throw my code away not that there is much to it :slight_smile:

To be honest, I haven’t actually used the existing Save Game system myself. But I’ve had a look at the implementation in the engine and then created my own.

Other than that I can only suggest searching the forums, you’ll find helpful information like this: [SaveGame] How to handle Dynamic ActorComponents](https://forums.unrealengine.com/showthread.php?113174-SaveGame-How-to-handle-Dynamic-ActorComponents)