Files
UnrealEngine/Engine/Source/Runtime/MassEntity/Private/MassSubsystemBase.cpp
2025-05-18 13:04:45 +08:00

175 lines
6.9 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MassSubsystemBase.h"
#include "HAL/IConsoleManager.h"
#include "Engine/World.h"
#include "MassEntityManager.h"
#include "MassEntitySubsystem.h"
namespace UE::Mass
{
namespace Subsystems
{
void RegisterSubsystemType(TSharedRef<FMassEntityManager> EntityManager, TSubclassOf<USubsystem> SubsystemClass, FSubsystemTypeTraits&& Traits)
{
EntityManager->GetTypeManager().RegisterType(SubsystemClass, MoveTemp(Traits));
}
void RegisterSubsystemType(FSubsystemCollectionBase& Collection, TSubclassOf<USubsystem> SubsystemClass, FSubsystemTypeTraits&& Traits)
{
if (UMassEntitySubsystem* EntitySubsystem = Collection.InitializeDependency<UMassEntitySubsystem>())
{
RegisterSubsystemType(EntitySubsystem->GetMutableEntityManager().AsShared(), SubsystemClass, MoveTemp(Traits));
}
}
} // namespace UE::Mass::Subsystem
namespace Private
{
/**
* A helper function calling PostInitialize and OnWorldBeginPlay for the given subsystem, provided the world has already begun play.
* @see UMassSubsystemBase::HandleLateCreation for more detail
*/
void HandleLateCreation(UWorldSubsystem& MassWorldSubsystem, const UE::Mass::Subsystems::FInitializationState InitializationState)
{
// handle late creation
UWorld* World = MassWorldSubsystem.GetWorld();
if (World)
{
if (World->IsInitialized() == true && InitializationState.bPostInitializeCalled == false)
{
MassWorldSubsystem.PostInitialize();
}
if (World->HasBegunPlay() == true && InitializationState.bOnWorldBeginPlayCalled == false)
{
MassWorldSubsystem.OnWorldBeginPlay(*World);
}
}
}
bool bRuntimeSubsystemsEnabled = true;
namespace
{
FAutoConsoleVariableRef AnonymousCVars[] =
{
{ TEXT("mass.RuntimeSubsystemsEnabled")
, bRuntimeSubsystemsEnabled
, TEXT("true by default, setting to false will prevent auto-creation of game-time Mass-related subsystems. Needs to be set before world loading.")
, ECVF_Default }
};
}
} // UE::Mass::Private
} // namespace UE::Mass
//-----------------------------------------------------------------------------
// UMassSubsystemBase
//-----------------------------------------------------------------------------
bool UMassSubsystemBase::AreRuntimeMassSubsystemsAllowed(UObject* Outer)
{
return UE::Mass::Private::bRuntimeSubsystemsEnabled;
}
bool UMassSubsystemBase::ShouldCreateSubsystem(UObject* Outer) const
{
return UMassSubsystemBase::AreRuntimeMassSubsystemsAllowed(Outer) && Super::ShouldCreateSubsystem(Outer);
}
void UMassSubsystemBase::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
// This ensure is here to make sure we handle HandleLateCreation() gracefully, we don't expect it to ever trigger unless users start to manually call the functions
ensureMsgf(InitializationState.bInitializeCalled == false, TEXT("%hs called multiple times"), __FUNCTION__);
InitializationState.bInitializeCalled = true;
// register the given child class with default traits. Child-class can always override the traits data registered here.
// Note that we're not performing the registration for UMassEntitySubsystem since that's the subsystem
// we use to get access to the EntityManager instance in the first place. UMassEntitySubsystem has to perform the registration manually
if (GetClass()->IsChildOf(UMassEntitySubsystem::StaticClass()) == false)
{
// register the given child class with default traits. Child-class can always override the traits data registered here.
UE::Mass::Subsystems::RegisterSubsystemType(Collection, GetClass(), UE::Mass::FSubsystemTypeTraits::Make<UMassSubsystemBase>());
}
}
void UMassSubsystemBase::PostInitialize()
{
Super::PostInitialize();
// This ensure is here to make sure we handle HandleLateCreation() gracefully, we don't expect it to ever trigger unless users start to manually call the functions
ensureMsgf(InitializationState.bPostInitializeCalled == false, TEXT("%hs called multiple times"), __FUNCTION__);
InitializationState.bPostInitializeCalled = true;
}
void UMassSubsystemBase::Deinitialize()
{
InitializationState = UE::Mass::Subsystems::FInitializationState();
Super::Deinitialize();
}
void UMassSubsystemBase::OnWorldBeginPlay(UWorld& InWorld)
{
Super::OnWorldBeginPlay(InWorld);
// This ensure is here to make sure we handle HandleLateCreation() gracefully, we don't expect it to ever trigger unless users start to manually call the functions
ensureMsgf(InitializationState.bOnWorldBeginPlayCalled == false, TEXT("%hs called multiple times"), __FUNCTION__);
InitializationState.bOnWorldBeginPlayCalled = true;
}
void UMassSubsystemBase::HandleLateCreation()
{
UE::Mass::Private::HandleLateCreation(*this, InitializationState);
}
//-----------------------------------------------------------------------------
// UMassTickableSubsystemBase
//-----------------------------------------------------------------------------
bool UMassTickableSubsystemBase::ShouldCreateSubsystem(UObject* Outer) const
{
return UMassSubsystemBase::AreRuntimeMassSubsystemsAllowed(Outer) && Super::ShouldCreateSubsystem(Outer);
}
void UMassTickableSubsystemBase::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
// This ensure is here to make sure we handle HandleLateCreation() gracefully, we don't expect it to ever trigger unless users start to manually call the functions
ensureMsgf(InitializationState.bInitializeCalled == false, TEXT("%hs called multiple times"), __FUNCTION__);
InitializationState.bInitializeCalled = true;
// register the given child class with default traits. Child-class can always override the traits data registered here.
UE::Mass::Subsystems::RegisterSubsystemType(Collection, GetClass(), UE::Mass::FSubsystemTypeTraits::Make<UMassTickableSubsystemBase>());
}
void UMassTickableSubsystemBase::PostInitialize()
{
Super::PostInitialize();
// This ensure is here to make sure we handle HandleLateCreation() gracefully, we don't expect it to ever trigger unless users start to manually call the functions
ensureMsgf(InitializationState.bPostInitializeCalled == false, TEXT("%hs called multiple times"), __FUNCTION__);
InitializationState.bPostInitializeCalled = true;
}
void UMassTickableSubsystemBase::Deinitialize()
{
InitializationState = UE::Mass::Subsystems::FInitializationState();
Super::Deinitialize();
}
void UMassTickableSubsystemBase::OnWorldBeginPlay(UWorld& InWorld)
{
Super::OnWorldBeginPlay(InWorld);
// This ensure is here to make sure we handle HandleLateCreation() gracefully, we don't expect it to ever trigger unless users start to manually call the functions
ensureMsgf(InitializationState.bOnWorldBeginPlayCalled == false, TEXT("%hs called multiple times"), __FUNCTION__);
InitializationState.bOnWorldBeginPlayCalled = true;
}
void UMassTickableSubsystemBase::HandleLateCreation()
{
UE::Mass::Private::HandleLateCreation(*this, InitializationState);
}