What is the proper way to derive from the Common Subsystem classes?
I tried to create a game specific version of CommonSessionSubsystem, but CommonUserBasicPresence complained about it.
void UCommonUserBasicPresence::Initialize(FSubsystemCollectionBase& Collection)
{
UCommonSessionSubsystem* CommonSession = Collection.InitializeDependency<UCommonSessionSubsystem>();
if(ensure(CommonSession))
{
CommonSession->OnSessionInformationChangedEvent.AddUObject(this, &UCommonUserBasicPresence::OnNotifySessionInformationChanged);
}
}
The ensure was being triggered because InitializeDependency was not creating UCommonSessionSubsystem, which makes sense because UCommonSessionSubsystem has this section of code in it
TArray<UClass *> ChildClasses;
GetDerivedClasses(GetClass(), ChildClasses, false);
// Only create an instance if there is not a game-specific subclass
return ChildClasses.Num() == 0;
preventing it from being created when there is a derived class. I ended up doing something like this:
Collection.InitializeDependency<UCommonSessionSubsystem>();
UCommonSessionSubsystem* CommonSession = GetGameInstance()->GetSubsystem<UCommonSessionSubsystem>();
if(ensure(CommonSession))
to get around, but I didn’t know if there was a more correct way to do this without editing the common plugin
Hello there. I see that the UCommonSessionSubsystem code you called out which checks for child classes implies it’s meant to be extended by design.
However, the call to Collection.InitializeDependency<UCommonSessionSubsystem>() in UCommonUserBasicPresence will not try to look for any child classes. For the time being I recommend making the following change to UCommonUserBasicPresence so that it will find and initialize a subclass of CommonSessionSubsystem. I’ll ask internally whether we’d consider modifying the implementation of InitializeDependency to consider subclasses.
void UCommonUserBasicPresence::Initialize(FSubsystemCollectionBase& Collection)
{
UCommonSessionSubsystem* CommonSession = Collection.InitializeDependency<UCommonSessionSubsystem>();
// START MODIFICATION
// Game code can make a subclass, preventing the parent class creation by design
if (CommonSession == nullptr)
{
TArray<UClass*> CommonSessionSubsystemClasses;
GetDerivedClasses(UCommonSessionSubsystem::StaticClass(), CommonSessionSubsystemClasses);
for (UClass* ChildClass : CommonSessionSubsystemClasses)
{
CommonSession = Cast<UCommonSessionSubsystem>(Collection.InitializeDependency(ChildClass));
if (CommonSession)
{
UE_LOG(LogTemp, Warning, TEXT("Initialized '%s' as CommonSessionSubsystem"), *ChildClass->GetName());
break;
}
}
}
// END MODIFICATION
if (ensure(CommonSession))
{
CommonSession->OnSessionInformationChangedEvent.AddUObject(this, &UCommonUserBasicPresence::OnNotifySessionInformationChanged);
}
}
I’ll close this case. But to summarize the answer to your question: “What is the proper way to derive from the Common Subsystem classes?”
You didn’t miss a better way. Modifying UCommonUserBasicPresence to consider that UCommonSessionSubsystem might have been extended by the game project is currently the way.