benui-dev/benui-site

Subsystems and data.

Opened this issue · 2 comments

Regarding:
https://benui.ca/unreal/subsystem-singleton/

I found that you can override your c++ subsystem with a blueprint and this way be able to define data in it.

Here is an example.
First defining it Abstract for unreal so that the c++ version will not be created.

UCLASS(Abstract, Blueprintable)
class MY_API UQuestManager : public UGameInstanceSubsystem
{
	GENERATED_BODY()
	
public:	
	UQuestManager();

	// All quests.
	UPROPERTY( EditAnywhere, BlueprintReadWrite )
	TArray<UDA_QuestData*> quests;

};

In Unreal, make a new blueprint based of UQuestManager. In this one, set your data.

For the blueprint subsystem to work, the class needs to be refered so the system gets created.. (When you work on it, the editor will have it loaded and you might be fooled to think it works fine.) So in my case I added an array of object classes variable in my gameinstance, tricking unreal to load them.

@Arnleif Inside GameInstance are you referencing the BP subclass? What is the type of the array, TArray<TSubclassOf<UObject>> ?

Here to add a little more of what I did.

.h

UCLASS(Abstract, Blueprintable)
class MY_API ResourceGameInstanceSubsystem : public UGameInstanceSubsystem
{
	GENERATED_BODY()

public:
	ResourceGameInstanceSubsystem() {};
	virtual void Initialize(FSubsystemCollectionBase& Collection) override;
	bool ShouldCreateSubsystem(UObject* Outer) const override;
protected:
	UPROPERTY(EditDefaultsOnly, meta = (RowType = ResourceDataRow))
	TObjectPtr<UDataTable> ResourceDataTable;

.cpp

void ResourceGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);

	check(ResourceDataTable);
}

bool ResourceGameInstanceSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	return this->GetClass()->IsInBlueprint();
}

In the editor I created a blueprint inheriting from my C++ subsystem and assigned the data table I wanted to use. In the C++, I just refer to ResourceDataTable as I would any other pointer assigned in a blueprint. The blueprint check in ShouldCreateSubsystem() (and making the C++ class abstract) ensures that only the blueprint subclass is initialized so I know I'm fetching the right one in other files.

It's important to follow the steps at https://forums.unrealengine.com/t/gameinstancesubsystem-not-initializing/489646/2 - otherwise the blueprint class will only initialize if it's opened in the editor before hitting play.