Files
UnrealEngine/Engine/Plugins/Runtime/Metasound/Source/MetasoundFrontend/Public/MetasoundFrontendModuleRegistrationMacros.h
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

287 lines
12 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "HAL/PreprocessorHelpers.h"
#include "UObject/NameTypes.h"
#define UE_API METASOUNDFRONTEND_API
// These macros are required in order to create module local registration actions.
#ifndef METASOUND_ENABLE_PER_MODULE_REGISTRATION
#if defined(METASOUND_MODULE) && defined(METASOUND_PLUGIN)
#define METASOUND_ENABLE_PER_MODULE_REGISTRATION 1
#else
#define METASOUND_ENABLE_PER_MODULE_REGISTRATION 0
#endif // if defined(METASOUND_MODULE) && defined(METASOUND_PLUGIN)
#endif // ifndef METASOUND_ENABLE_PER_MODULE_REGISTRATION
/** MetaSound Frontend Registration Actions
*
* MetaSound Frontend Registration Actions are used to register and unregister
* MetaSound nodes and data types at the module level.
*
* Usage:
*
* Node Developers can utilize these actions by implementing the following:
* - Add private definitions to the module's Build.cs file for METASOUND_PLUGIN and METASOUND_MODULE
* PrivateDefinitions.Add("METASOUND_PLUGIN=MyPlugin")
* PrivateDefinitions.Add("METASOUND_MODULE=MyModule")
* These definitions must be private to the module.
*
* - Implement a module registration group using the provided macros.
* In MyModule.cpp
* METASOUND_IMPLEMENT_MODULE_REGISTRATION_LIST
*
* - Use METASOUND_REGISTER_NODE(...) and METASOUND_REGISTER_NODE_AND_CONFIGURATION(...)
* in the cpp files to setup registration actions for their nodes.
*
* - Trigger registration in their module's StartupModule and ShutdownModule calls
* void FMyModule::StartupModule()
* {
* METASOUND_REGISTER_ITEMS_IN_MODULE
* }
* void FMyModule::ShutdownModule()
* {
* METASOUND_UNREGISTER_ITEMS_IN_MODULE
* }
*
*
* Implementation:
*
* This system uses creates a linked list of FRegistrationActions that is constructed
* during static initialization. Each module contains it's own linked list of FRegistrationActions
* and thus only performs registration and unregistration actions associated with
* the module. This allows registration actions to be declared locally within the
* cpp file containing the node or data type, while maintaining the association
* with the owning plugin and module.
*
* Each module's linked list contains a unique class name and does not export it's
* API. This is in order to protect against modules accidentally adding their registration
* actions to the wrong linked list. The unique name for the module's list is created
* by combining the METASOUND_PLUGIN and METASOUND_MODULE private macro definitions.
* If those definitions are missing, a global linked list serves as a backup.
*
* Thread safety for this system is provided by two mechanisms.
* - Initialization of the registration actions linked list is thread safe by the
* fact that static initialization in C++ is single threaded. The list structure
* (e.g. Head & Next pointers) should not be modified outside of static initialization.
*
* - RegisterAll and UnregisterAll should only be called during StartupModule and
* ShutdownModule because module startup and shutdown are also run single threaded.
*/
namespace Metasound::Frontend
{
// FModuleInfo captures information about the module which registers an item.
struct FModuleInfo
{
#if WITH_EDITORONLY_DATA
FLazyName PluginName;
FLazyName ModuleName;
#endif
};
namespace RegistrationPrivate
{
// Function signature of a registration function
typedef bool (*FRegistrationFunction)(const FModuleInfo&);
// Registration actions build a linked list during static initialization.
struct FRegistrationAction
{
UE_API FRegistrationAction(FRegistrationAction*& InOutHead, FRegistrationFunction InRegister, FRegistrationFunction InUnregister);
#if WITH_EDITORONLY_DATA
// Include debug name info in editoronly_data builds.
template<size_t N>
FRegistrationAction(FRegistrationAction*& InOutHead, FRegistrationFunction InRegister, FRegistrationFunction InUnregister, const TCHAR(&NameLiteral)[N])
: FRegistrationAction(InOutHead, InRegister, InUnregister)
{
Name = NameLiteral;
}
#endif
FRegistrationAction* Next = nullptr;
FRegistrationFunction Register = nullptr;
FRegistrationFunction Unregister = nullptr;
#if WITH_EDITORONLY_DATA
const TCHAR* Name = nullptr; // Warning: Expected to be only used with string literals which provide static storage duration.
#endif
};
// FRegistrationListBase implements common functionality used by all registration
// list classes
class FRegistrationListBase
{
public:
// Calls "Register" all FRegistrationActions in the linked list beginning with the provided Head.
UE_API static void RegisterAll(const FModuleInfo& InOwningModuleInfo, FRegistrationAction* Head);
// Calls "Unregister" all FRegistrationActions in the linked list beginning with the provided Head.
UE_API static void UnregisterAll(const FModuleInfo& InOwningModuleInfo, FRegistrationAction* Head);
};
// FGlobalRegistrationList is a fallback for when the module has not defined
// the proper macros to create it's own registration list. This class should not
// be used because it cannot appropriately execute unregister actions for a
// single plugin or module unloading.
class FGlobalRegistrationList
{
public:
UE_API static FModuleInfo ModuleInfo;
/* If you've hit this deprecation warning it is because you are using
* a backwards compatible MetaSound node registration code path for your
* module. In order to better support loading and unloading of MetaSound,
* perform the following updates. This will remove this deprecation
* warning.
*
* - Add private definitions to the module's Build.cs file for METASOUND_PLUGIN
* and METASOUND_MODULE
* PrivateDefinitions.Add("METASOUND_PLUGIN=MyPlugin")
* PrivateDefinitions.Add("METASOUND_MODULE=MyModule")
* These definitions must be private to the module.
*
* - Implement a module registration group using the provided macros.
* In MyModule.cpp
* METASOUND_IMPLEMENT_MODULE_REGISTRATION_LIST
*
* - Trigger registration in your module's StartupModule and ShutdownModule calls
*
* void FMyModule::StartupModule()
* {
* METASOUND_REGISTER_ITEMS_IN_MODULE
* }
* void FMyModule::ShutdownModule()
* {
* METASOUND_UNREGISTER_ITEMS_IN_MODULE
* }
*
*/
#if METASOUND_ENABLE_PER_MODULE_REGISTRATION
UE_DEPRECATED(5.7, "Macro based registration has been updated. See MetasoundFrontendModuleRegistrationMacros.h for a guide on defining module level registration.")
UE_API static FRegistrationAction*& GetHeadAction();
#else
UE_API static FRegistrationAction*& GetHeadAction();
#endif
// Used internally to do incremental registration on a global list.
static FRegistrationAction*& GetRegisterTailAction();
UE_API static void RegisterAll(const FModuleInfo& InOwningModuleInfo, FRegistrationAction* Head);
UE_API static void UnregisterAll(const FModuleInfo& InOwningModuleInfo, FRegistrationAction* Head);
};
} // namespace RegistrationPrivate
} // namespace Metasound::Frontend
#if METASOUND_ENABLE_PER_MODULE_REGISTRATION
// By default, always unregister on module shutdown. The only time we do not unregister
// is when things cannot be associated with a module. This currently only happens
// when using the deprecated global registration list.
#define METASOUND_UNREGISTER_ON_MODULE_SHUTDOWN 1
// Module registration list class name
#define METASOUND_MODULE_REGISTRATION_LIST_CLASS UE_JOIN(F, UE_JOIN(METASOUND_PLUGIN, UE_JOIN(_, UE_JOIN(METASOUND_MODULE, _Registration))))
// Declare a module registration list. This needs to be visible wherever METASOUND_REGISTER_NODE
// is called. Generally this can be a header file within the module's Private directory.
#define METASOUND_DEFINE_MODULE_REGISTRATION_LIST \
namespace Metasound::Frontend::RegistrationPrivate \
{\
/* Methods in this class are purposely not exported because they should only be accessed within the module. */ \
class METASOUND_MODULE_REGISTRATION_LIST_CLASS : public FRegistrationListBase \
{\
static_assert(sizeof(UE_STRINGIZE(METASOUND_PLUGIN)) > 1, "\"METASOUND_PLUGIN\" macro definition cannot be empty"); \
static_assert(sizeof(UE_STRINGIZE(METASOUND_MODULE)) > 1, "\"METASOUND_MODULE\" macro definition cannot be empty"); \
\
public: \
static const Metasound::Frontend::FModuleInfo ModuleInfo; \
static FRegistrationAction*& GetHeadAction(); \
};\
}
// Only allow module registration lists to be defined once.
#ifndef METASOUND_MODULE_REGISTRATION_LIST_DEFINED
#define METASOUND_MODULE_REGISTRATION_LIST_DEFINED
METASOUND_DEFINE_MODULE_REGISTRATION_LIST
#endif
// ModuleRegistrationInfo only exists WITH_EDITORONLY_DATA
#if WITH_EDITORONLY_DATA
#define METASOUND_IMPLEMENT_MODULE_REGISTRATION_LIST_INFO \
const FModuleInfo METASOUND_MODULE_REGISTRATION_LIST_CLASS::ModuleInfo\
{\
UE_STRINGIZE(METASOUND_PLUGIN), \
UE_STRINGIZE(METASOUND_MODULE) \
};
#else
#define METASOUND_IMPLEMENT_MODULE_REGISTRATION_LIST_INFO const FModuleInfo METASOUND_MODULE_REGISTRATION_LIST_CLASS::ModuleInfo = {};
#endif // if WITH_EDITORONLY_DATA
// Implement a module registration list. This should be placed within a CPP file.
#define METASOUND_IMPLEMENT_MODULE_REGISTRATION_LIST \
namespace Metasound::Frontend::RegistrationPrivate \
{ \
METASOUND_IMPLEMENT_MODULE_REGISTRATION_LIST_INFO \
FRegistrationAction*& METASOUND_MODULE_REGISTRATION_LIST_CLASS::GetHeadAction() \
{ \
static FRegistrationAction* Head = nullptr; \
return Head; \
} \
}
#else // if METASOUND_ENABLE_PER_MODULE_REGISTRATION
// If METASOUND_MODULE and METASOUND_PLUGIN are not both defined, we rely on the
// global registration list class as a fallback for ensuring the registration
// actions still execute.
#define METASOUND_MODULE_REGISTRATION_LIST_CLASS FGlobalRegistrationList
// Disable unregistering on module shutdown because the actions are not associated with
// a module specific registration list. If this were enabled, one module would incidentally
// run unregister actions from another module.
#define METASOUND_UNREGISTER_ON_MODULE_SHUTDOWN 0
// The module registration lists cannot be defined or implemented. The global
// registration list is used instead.
#define METASOUND_IMPLEMENT_MODULE_REGISTRATION_LIST
#endif
// The registration list class including global namespace access
#define METASOUND_MODULE_REGISTRATION_LIST_CLASS_NS ::Metasound::Frontend::RegistrationPrivate::METASOUND_MODULE_REGISTRATION_LIST_CLASS
// Retrieve the head action from the registration list class
#define METASOUND_GET_HEAD_REGISTRATION_ACTION METASOUND_MODULE_REGISTRATION_LIST_CLASS_NS::GetHeadAction()
// Retrieve the module info from the registration list class
#define METASOUND_GET_MODULE_LIST_INFO METASOUND_MODULE_REGISTRATION_LIST_CLASS_NS::ModuleInfo
// Register all nodes in the registration list class
#define METASOUND_REGISTER_ITEMS_IN_MODULE METASOUND_MODULE_REGISTRATION_LIST_CLASS_NS::RegisterAll(METASOUND_GET_MODULE_LIST_INFO, METASOUND_GET_HEAD_REGISTRATION_ACTION);
// Only run unregister actions if it is safe to do s.
#if METASOUND_UNREGISTER_ON_MODULE_SHUTDOWN
#define METASOUND_UNREGISTER_ITEMS_IN_MODULE METASOUND_MODULE_REGISTRATION_LIST_CLASS_NS::UnregisterAll(METASOUND_GET_MODULE_LIST_INFO, METASOUND_GET_HEAD_REGISTRATION_ACTION);
#else // if METASOUND_UNREGISTER_ON_MODULE_SHUTDOWN
#define METASOUND_UNREGISTER_ITEMS_IN_MODULE
#endif
// Implement a registration action by declaring statically initialized FRegistrationAction
#if WITH_EDITORONLY_DATA
// With editoronly data includes additional debug logging info
#define METASOUND_IMPLEMENT_REGISTRATION_ACTION(UniqueName, RegisterFunction, UnregisterFunction) static ::Metasound::Frontend::RegistrationPrivate::FRegistrationAction UE_JOIN(RegistrationAction,UniqueName)(METASOUND_GET_HEAD_REGISTRATION_ACTION, RegisterFunction, UnregisterFunction, TEXT(UE_STRINGIZE(UniqueName)));
#else
#define METASOUND_IMPLEMENT_REGISTRATION_ACTION(UniqueName, RegisterFunction, UnregisterFunction) static ::Metasound::Frontend::RegistrationPrivate::FRegistrationAction UE_JOIN(RegistrationAction,UniqueName)(METASOUND_GET_HEAD_REGISTRATION_ACTION, RegisterFunction, UnregisterFunction);
#endif
#undef UE_API