Skip to main content
  » »

2016年09月04日 21:44:051075110

ue4的代码是模块的情势去构造

正在源码层面,一个包罗*.build.cs的目次就是一个模块

这个目次里的文件正在编译后都邑被链接在一起,好比一个静态库lib,大概一个静态库dll。

不管是哪种情势,皆需求供应一个给内部操纵的接口,也就是一个IModuleInterface-葡京赌场的网站指针。

*注重这里其实不是道挪用模块内任何函数(或类)皆要经由过程该指针去停止,实际上内部代码只要include了响应的头文件,便能间接挪用对应的功用了(好比new一个类,调一个全局函数等),由于实现代码要末做为lib被链接进exe,或是做为dll被动态加载了。

这个IModuleInterface指针是用来操纵做为整体的模块自己的,比如说模块的加载、初始化和卸载,和接见模块内的一些全局变量(向下转成详细的模块范例后)

 

内部获得这个指针,只要一个设施,就是经由过程FModuleManager上的LoadModule/GetModule。

而FModuleManager去那里找需求的模块呢?

1、正在静态链接状况下,凭据名字间接找对应的dll便止了,做为正当ue4模块的dll,肯定要导出一些商定的函数,去返回本身IModuleInterface指针。

2、正在静态链接时,去一个叫StaticallyLinkedModuleInitializers的Map里找,那就要供一切模块已把本身注册到这个Map里。

以上2点根基就是FModuleManager::LoadModule的内容。

 

而每一个模块为知足以上商定,也需求插入一些例程代码,那就是IMPLEMENT_MODULE干的事。

正在静态链接时:

    // If we're linking monolithically we assume all modules are linked in with the main binary.
    #define IMPLEMENT_MODULE( ModuleImplClass, ModuleName ) \        /** Global registrant object for this module when linked statically */ \        static FStaticallyLinkedModuleRegistrant< ModuleImplClass > ModuleRegistrant##ModuleName( #ModuleName ); \        /** Implement an empty function so that if this module is built as a statically linked lib, */ \        /** static initialization for this lib can be forced by referencing this symbol */ \        void EmptyLinkFunctionForStaticInitialization##ModuleName(){} \
        PER_MODULE_BOILERPLATE_ANYLINK(ModuleImplClass, ModuleName)
template< class ModuleClass >class FStaticallyLinkedModuleRegistrant
{public:
    FStaticallyLinkedModuleRegistrant( const ANSICHAR* InModuleName )
    {        // Create a delegate to our InitializeModule method
        FModuleManager::FInitializeStaticallyLinkedModule InitializerDelegate = FModuleManager::FInitializeStaticallyLinkedModule::CreateRaw(                this, &FStaticallyLinkedModuleRegistrant<ModuleClass>::InitializeModule );        // Register this module        FModuleManager::Get().RegisterStaticallyLinkedModule(
            FName( InModuleName ),    // Module name
            InitializerDelegate );    // Initializer delegate    }     
    IModuleInterface* InitializeModule( )
    {        return new ModuleClass();
    }
};

FStaticallyLinkedModuleRegistrant是一个注册辅佐类,它应用全局变量的组织函数被crt主动挪用的特性,实现主动注册逻辑。

它正在组织函数里把一个“注册器”加到前面说的StaticallyLinkedModuleInitializers里,而这个注册器的内容就是建立并返回响应模块。

 

正在静态链接时:

    #define IMPLEMENT_MODULE( ModuleImplClass, ModuleName ) \
        \        /**/ \        /* InitializeModule function, called by module manager after this module's DLL has been loaded */ \        /**/ \        /* @return    Returns an instance of this module */ \        /**/ \        extern "C" DLLEXPORT IModuleInterface* InitializeModule() \
        { \            return new ModuleImplClass(); \
        } \
        PER_MODULE_BOILERPLATE \
        PER_MODULE_BOILERPLATE_ANYLINK(ModuleImplClass, ModuleName)

声明了一个dllexport函数,功用就是建立并返回响应模块。

 

现实的运用:

1、若是模块自己着实没什么特其余,那么便:

IMPLEMENT_MODULE(FDefaultModuleImpl, ModuleName)

FDefaultModuleImpl是一个IModuleInterface的空实现,甚么都没干,ModuleName则是模块名字,很重要,别的中央要加载模块,便靠这个名字了。

 

2、若是模块有本身的初始化逻辑,那么应当实现本身的IModuleInterface子类,比如说MyUtilModule,然后:

IMPLEMENT_MODULE(MyUtilModule,MyUtil-www.25800.com)

这里类名带Module后缀,而模块名不带,是ue4的老例。

 

3、若是模块是一个包罗游戏逻辑的模块(相对通用功能型模块),那么能够用一个特别的宏IMPLEMENT_GAME_MODULE,不外现在看来它和前者出啥差异,能够将来有所扩大

4、更特其余是,若是模块是示意当前游戏项目的“主模块”,那么应当用一个更特别的宏IMPLEMENT_PRIMARY_GAME_MODULE,并且正在构建一个UEBuildGame范例的Target时,必需有一个如许的模块。

当IS_MONOLITHIC,构建成单个exe时:

 IMPLEMENT_PRIMARY_GAME_MODULE( ModuleImplClass, ModuleName, DEPRECATED_GameName ) \            ] = GIsGameAgnosticExe =

非单体构建时:

#define IMPLEMENT_PRIMARY_GAME_MODULE( ModuleImplClass, ModuleName, GameName ) \        /* Nothing special to do for modular builds.  The game name will be set via the command-line */ \
        IMPLEMENT_GAME_MODULE( ModuleImplClass, ModuleName )

 

同一来看,实在也便比一般模块多做了三件事,一是设置游戏名字GInternalGameName,二是设置了GIsGameAgnosticExe=false,三是多了个UELinkerFixupCheat临时不究。

GIsGameAgnosticExe是一个风趣的变量,它示意当前这个exe是特定于某游戏的?照样一个通用的加载器?

若是整体编成一个exe文件,即IS_MONOLITHIC,那一定是特定于某游戏,这时候游戏名GInternalGameName肯定是已知流动的,以是以宏参数的情势间接硬编码正在exe里了。

与之相反,当运用模块化构建时(经由过程给ubt传入-modular参数),将会天生一个exe和一堆dll,而且能加载任何别的以dll情势存的游戏模块,游戏名是未知的,是经由过程命令行参数去决意要加载哪一个游戏,以是也便用不着GInternalGameName变量了。

 

5、当构建一个东西顺序(TargetType.Program)时,能够运用专门定制的IMPLEMENT_APPLICATION

最特其余是它居然供应了一个FEngineLoop GEngineLoop,而这个变量存在于一样平常的Game/Editor构建时都邑链接的【Launch模块】中。

不外那也一般,由于正在东西顺序中一样平常是要本身写main函数的,以是便用不着重量级的Launch模块了。


上一篇:

下一篇:

相干推荐

批评列表久无批评
宣布批评