首页 > 其他分享 >【UE4】插件与模块

【UE4】插件与模块

时间:2023-05-23 11:44:38浏览次数:43  
标签:插件 string 模块 new UE4 加载 Target

一、什么是插件与模块

模块是实现某一个或一类功能的集合,当模块足够独立和庞大、复杂之后,可以将其提升为插件。UE4引擎就是由众多模块组成,而插件也可以包含一个或多个模块,但模块却不能包含插件。相对于模块来说,插件具有更高的独立性,除使用引擎模块外,一般不使用其它插件或模块。并且插件可以非常方便地移植到不同项目中使用。

二、创建插件

我们可以在插件窗口(Edit → Plugins)选择创建新的插件。 以下为UE4提供的默认插件类型:

 

三、插件目录介绍

我们创建了一个带有独立窗口的插件,并命名为SlateUI。SlateUI插件的目录:

插件被放置在Plugins目录下,这个目录包含的是项目插件。 在Source目录下有个SlateUI的文件夹,这个文件夹就是SlateUI插件下的SlateUI模块,每个插件有且至少有一个模块,这个SlateUI模块就是创建插件时生成的默认模块。每个模块拥有在Source目录下的独立文件夹,并且还有一个“ModuleName.Build.cs”的模块配置文件。

四、配置文件

1、插件

SlateUI.uplugin文件:

{
    "FileVersion": 3,
    "Version": 1,                   //版本号
    "VersionName": "1.0",           //版本名
    "FriendlyName": "SlateUI",      //插件名
    "Description": "",              //插件描述
    "Category": "Other",            //插件目录,这个会将其分类到插件启用页面的相应目录下
    "CreatedBy": "",                //作者
    "CreatedByURL": "", 
    "DocsURL": "",
    "MarketplaceURL": "",
    "SupportURL": "",
    "CanContainContent": false,             //是否包含Content目录
    "IsBetaVersion": false,
    "Installed": false,
    "Modules": [                            //插件包含的模块,新创建的插件会默认包含一个同名的模块
        {
            "Name": "SlateUI",              //模块名,这里就是创建插件时,默认创建的模块SlateUI
            "Type": "Editor",               //模块类型,表示模块在什么场景下使用,类型为EHostType
            "LoadingPhase": "Default"       //模块加载的阶段,类型为ELoadingPhase
        }
    ]
}

Type可填写的值范围:

namespace EHostType
{
    enum Type
    {
        Runtime,                    //运行时,任何情况下
        RuntimeNoCommandlet,
        RuntimeAndProgram,
        CookedOnly,
        Developer,                  //开发时使用的插件
        Editor,                     //编辑器类型插件
        EditorNoCommandlet,
        Program,                    //只有运行独立程序时的插件
        ServerOnly,
        ClientOnly,
        Max
    };
}

LoadingPhase的值范围:

namespace ELoadingPhase
{
    enum Type
    {
        PostConfigInit,             //引擎完全加载前,配置文件加载后。适用于较底层的模块。
        PreEarlyLoadingScreen,      //在UObject加载前,用于补丁系统
        PreLoadingScreen,           //在引擎模块完全加载和加载页面之前
        PreDefault,                 //默认模块加载之前阶段
        Default,                    //默认加载阶段,在引擎初始化时,游戏模块加载之后
        PostDefault,                //默认加载阶段之后加载
        PostEngineInit,             //引擎初始化后
        None,                       //不自动加载模块
        Max
    };
}

2、模块

SlateUI.build.cs文件:

using UnrealBuildTool;

public class SlateUI : ModuleRules
{
    public SlateUI(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
	//填入引擎模块的某个子目录后,引用包含的头文件可以省去前面的路径
	PublicIncludePaths.AddRange(new string[] {/* ......*/});
	//填入项目或项目插件某个模块的子目录后,引用包含的头文件可以省去前面的路径
        PrivateIncludePaths.AddRange(new string[] {/* ......*/});
        //如果此模块依赖其它模块,需要将其添加到下面两个变量中的一个,区别如下
        //如果其它模块依赖此模块,则其也可以访问Core模块
        PublicDependencyModuleNames.AddRange(new string[]{"Core",});
        //如果其它模块依赖此模块,但其不可以访问下面的模块
        PrivateDependencyModuleNames.AddRange(
            new string[]
            {
                "Projects", "InputCore", "UnrealEd", "LevelEditor", "CoreUObject", "Engine", "Slate", "SlateCore",
            }
            );

        //动态加载的模块,动态加载和静态加载不在本节讨论范围
        DynamicallyLoadedModuleNames.AddRange(new string[]{/* ......*/});
    }
}

3、项目

如果我们想使用插件中的某个模块,首先要启用这个插件,我们可以在插件窗口选择Enable插件,或者在文件中配置属性。 Game.uproject文件:

{
    "FileVersion": 3,
    "EngineAssociation": "4.21",
    "Category": "",
    "Description": "",
    "Modules": [
        {
            "Name": "StartGame",
            "Type": "Runtime",
            "LoadingPhase": "Default",
            "AdditionalDependencies": [
                "Engine"
            ]
        }
    ],
    "Plugins":[     //添加插件
        {
            "Name": "BlankP",
            "Enabled": true
        }
    ]
}

并且,我们需要在项目模块中添加依赖的模块名: Game.build.cs文件:

using UnrealBuildTool;

public class StartGame : ModuleRules
{
    public StartGame(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
        //我们这里添加"BlankP"模块的依赖
        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "MoviePlayer", "UMG", "BlankP" });
        PrivateDependencyModuleNames.AddRange(new string[] {  });
    }
}

五、创建模块

1. 插件中创建模块

我们创建了一个名为BlankP的插件,它会默认创建一个包含BlankP的模块,我们在此插件下再创建一个名为PluginM的模块。 首先在BlankP插件Souce目录下,将BlankP目录复制一份,并将其命名为PluginM,并且修改其配置文件与代码,将所有BlankP修改为PluginM。并且在插件配置文件中包含PluginM模块。

添加新模块后的插件目录:

 

BlankP.uplugin文件:

"Modules": [
        {
            "Name": "BlankP",
            "Type": "Runtime",
            "LoadingPhase": "Default"
        },
        {   //添加新模块
            "Name": "PluginM",
            "Type": "Runtime",
            "LoadingPhase": "Default"
        }
    ]

另外,我们还需要重新生成这个它的VS项目文件。 所以,如果是在插件中创建模块,则除了创建模块内必须的类和文件,只需要在插件配置文件中包含模块即可。

2. 项目中创建模块

前边与创建插件模块相同,先创建模块所需的模块加载类以及模块配置文件。 项目目录:

创建完模块后,我们需要在StartGame.uproject中添加模块,这步操作类似在插件中添加模块:

"Modules": [
        {   //项目包含的模块,因为我没有创建新的项目模块,所以这里只有一个默认的StartGame
            "Name": "StartGame",
            "Type": "Runtime",
            "LoadingPhase": "Default",
            "AdditionalDependencies": [
                "Engine"
            ]
        }
    ]

其次,我们要在StartGame.Target.cs和StartGameEditor.Target.cs中添加模块,如果模块只是在编辑器中有效,则只需要在StartGameEditor.Target.cs中添加。在此处添加模块后,模块才会被链接编译。 StartGame.Target.cs文件:

using UnrealBuildTool;
using System.Collections.Generic;

public class StartGameTarget : TargetRules
{
    public StartGameTarget(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Game;
        ExtraModuleNames.AddRange( new string[] { "StartGame" } );  //新模块添加在此处
    }
}

StartGameEditor.Target.cs文件:

using UnrealBuildTool;
using System.Collections.Generic;

public class StartGameEditorTarget : TargetRules
{
    public StartGameEditorTarget(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Editor;
        ExtraModuleNames.AddRange( new string[] { "StartGame" } );  //新模块添加在此处
    }
}

在游戏项目中,我们可以按照LoadingScreen模块、AI模块、Gameplay模块等来将不同的模块分类。

六、模块加载与卸载

在模块文件中,有个继承IModuleInterface的类,其中定义了两个方法,分别是StartupModule()和ShutdownModule()。这两个方法分别在模块加载和卸载时执行,所以,我们可以在这两个方法中执行加载任务和内存清理的功能。 当然,我们也可以将其添加到游戏逻辑模块中,执行游戏模块加载和卸载的一些必要任务。 游戏模块的头文件:

//一般模块类继承的是IModuleInterface,FDefaultGameModuleImpl是IModuleInterface的封装,游戏模块可继承此类
class FStartGameModule : public FDefaultGameModuleImpl
{
public:
    virtual void StartupModule() override;      //模块加载完成后执行此方法
    virtual void ShutdownModule() override;     //模块卸载期间执行此方法
};

定义:

#define LOCTEXT_NAMESPACE "FStartGameModule"        //这个是为语言国际化用的
void FStartGameModule::StartupModule()
{
    //模块加载完成后执行此方法
}

void FStartGameModule::ShutdownModule()
{
    //模块卸载期间执行此方法
}
#undef LOCTEXT_NAMESPACE
//这个宏只有唯一的游戏模块可以使用,其它模块使用注释掉的宏,否则打包会失败!
//这个宏负责将模块注册,模块的加载与卸载进入生命周期流程
IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, StartGame, "StartGame" );
//IMPLEMENT_MODULE(FNewMModule, NewM)

七、插件封装

如果插件允许暴露类的定义给使用者的话,我们可以直接将Plugins下的插件目录直接提供给插件的使用者。 但,如果不想要插件中类的定义暴露给使用者,则需要进行一些处理。 首先,需要编译插件的不同版本。然后,编译好的动态库文件以及反射文件会分别被保存在Binaries和Intermediate文件夹中。 插件目录:

然后,在模块的配置文件中,将预编译变量设为true,这样再编译项目的时候,使用预编译的模块将跳过编译。

using UnrealBuildTool;

public class BlankP : ModuleRules
{
    public BlankP(ReadOnlyTargetRules Target) : base(Target)
    {
        bUsePrecompiled = true;         //使用预编译设为true,模块将跳过编译

        PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
        PublicIncludePaths.AddRange(new string[] {});
        PrivateIncludePaths.AddRange(new string[] {});
        PublicDependencyModuleNames.AddRange(new string[]{"Core",});
        PrivateDependencyModuleNames.AddRange(new string[]{"CoreUObject", "Engine", "Slate", "SlateCore",});
        DynamicallyLoadedModuleNames.AddRange(new string[]{});
    }
}

然后,我们先预编译一遍各个版本的插件,然后将使用预编译设为true。这样,我们即使删除类定义文件(.cpp)也不会影响插件的使用。 但是,需要注意的是,项目不能被重新编译(Rebuilt),一旦项目被重新编译,则预编译的插件动态库及反射文件也会被清理。还有一点是,如果将插件封装、隐藏类的定义,有时会在团队开发时,因看不到源码,变得有些棘手。

标签:插件,string,模块,new,UE4,加载,Target
From: https://www.cnblogs.com/tomato-haha/p/17422822.html

相关文章

  • UE4插件与一些编辑器扩展总结
    前言:.uplugin与.uproject前面的版本号、版本名、插件名等在编辑器下创建插件就会有对应生成。值得一提的是"module"与"Plugins":比如我做的UCharts插件,这里头Type可填写的值范围:(此处参考【UE4】插件与模块-知乎(zhihu.com)namespaceEHostType{enumType{......
  • Android平台GB28181设备接入模块如何实现实时视频和本地录像双码流编码
    ​技术背景我们在做Android平台GB28181设备接入模块的时候,遇到这样的场景,比如执法记录仪或智慧工地等场景下,由于GB28181设备接入模块,注册到国标平台后,平时只是心跳保持,或还有实时位置订阅,查看视频的时候,是按需看,而且有时候,网络环境并不是太好,所以,催生了这样一个诉求:部分开发者希......
  • vueh5实现双指操作图片或者内容放大缩小拖动 (hammerjs插件)
    可在mounted钩子直接使用通过使用Hammer.js库来实现手势操作,包括缩放、拖动和双击重置功能1.在模板中添加了一个<div>元素,并为其设置了ref属性,以便在代码中引用该元素。2.在mounted生命周期钩子函数中,通过this.$refs.main获取之前设置的<div>元素。3.创建了一个新的Hammer实例,传入......
  • 聊聊如何利用spring插件来实现策略模式
    前言偶然的机会发现spring有个spring-plugin,官网对它的介绍是SpringPluginprovidesamorepragmaticapproachtoplugindevelopmentbyprovidingthecoreflexibilityofhavingpluginimplementationsextendingacoresystem'sfunctionalitybutofcoursenotdel......
  • Jenkins实战-钉钉构建提醒插件的二次开发
    本篇我们来讨论下关于jenkins社区中钉钉提醒这个插件的二次开发过程。为什么需要二次开发呢,很简单,这个插件只是提供了最基本的构建后的提醒,有时候,我们需要一些额外的功能。例如,我们在打完app的包后,利用这个插件是可以发送提醒,但是点击标题,这个插件默认跳转的是jenkins上当前构......
  • Apollo planning 模块(三):path decider
    lanefollow场景为例,包含一个stage,每个stage又包含若干个task。在路径决策方面,依次进行lane_change_decider、path_reuse_decider、path_lane_borrow_decider、path_bounds_decider。在路径优化方面,依次进行piecewise_jerk_path_optimizer、path_assessment_decider、path_decider......
  • webpack-安装和配置webpack-dev-server这个插件
    webpack插件的作用通过安装和配置第三方的插件,可以拓展webpack的能力,从而让webpack用起来更方便。最常用的webpack插件有如下两个:webpack-dev-server类似于node.js阶段用到的nodemon工具每当修改了源代码,webpack会自动进行项目的打包和构建html-webpack-pluginwebpack......
  • FL Studio21教程之如何插入第三方插件
    FLStudio21是一款非常容易上手同时又特别强大的编曲软件,FLStudio21拥有一些内置插件,如Soundgoodizer,也可以插入第三方插件。本文将介绍在FLStudio21使用过程中如何插入第三方插件的方法过程,感兴趣的一定要关注哦。首先,打开FLStudio21软件,在通道列表中任意选择一个通道,右击,......
  • kindle7插件开发笔记[2]-使用Rust重写插件
    前言上一篇笔记:kindle7插件开发笔记[1]-在折腾中入门代码地址:https://gitee.com/qsbye/kindle-plugin-touch摘要用Rust语言重写在Kindle上显示图片的插件,初步实现了图片完整显示及自动刷新屏幕的功能.说明Kindle7的屏幕信息eips-i结果:Fixedframebufferinfoi......
  • 分析双网口以太网IO模块在智能制造中的角色
    双网口可级联远程IO模块用于工业自动化在当今时代,工业自动化控制有着广泛的应用,而远程I/O模块是其不可或缺的一部分。工业自动化需要远距离数据采集传输的场景越来越多,其中双网口可级联远程I/O模块已成为业界的常用设备之一。本文将从工业自动化的角度出发,讨论双网口可级联远程I/O......