如何生成Commandlet

如何创建全新的自定义commandlet来分析或修改游戏中使用的内容。

Windows
MacOS
Linux

本页面是从虚幻引擎3的文档转换而来,目前正在审阅中。信息可能已过时。

Commandlet是运行在虚幻引擎环境中的命令行程序。它们通常用于对内容进行批量更改,遍历内容以获取有关内容的信息,或者作为单元测试机制。

它们基本上是一些小程序,初始化了引擎,但主要局限于Windows控制台输出。

引擎自动尝试查看您在命令行上传递的命令是否为Commandlet,如果匹配,则执行相关代码。

查看UContentCommandlets.cpp和UnPackageUtilities,以了解Commandlet的一些例子。

如何在脚本中生成Commandlet

为Commandlet创建一个脚本类,如下所示:

class HelloWorldCommandlet extends Commandlet;

event int Main( string Params )
{
   log( " hello world " );

   return 0;
}

对于本地Commandlet:

class HelloWorldCommandlet extends Commandlet
native;

cpptext
{
int32 Main(const FString& CmdLine)
{
   warnf(TEXT("hello world"));
   return 0;
}
}

native event int Main( string Params );

Main()函数是Commandlet的进入点。Commandlet被传递一个包含给定运行的所有参数的字符串。对于下列内容,注意这一点

gamename.exe helloworld param1 param2 param3

您的Commandlet将把字符串"param1 param2 param3"视为命令行参数。

如何在本地代码中生成Commandlet

大多数Commandlet是作为本地代码中的内部类实现的。以这种方式创建Commandlet的过程是非常不同的。您会发现大多数Commandlet声明都在"EditorCommandlets.h"。

首先,在像"EditorCommandlets.h"这样的类头文件中声明类:

BEGIN_COMMANDLET(Name,Package)
  // 在此处声明其他方法。
END_COMMANDLET

Commandlet将拥有一个名为"UNameCommandlet"的类名,并将放在您指定的包中(如编辑器)。

然后,在一个.cpp文件中(例如"UContentCommandlets.cpp"),实施您的Commandlet地"Main()"函数。必要时,也可覆盖"virtual !CreateCustomEngine()"函数。详情请参见UCommandlet源码。

int32 UNameCommandlet::Main(const FString& Params)
{
    // 在这里进行操作...
    return 0;
}

但您的操作还没有完成!由于这是一个内部类,您必须通知脚本系统它的存在。为此,您将必须手动编辑"UnrealEdClasses.h"文件,具体地说,是AUTO_INITIALIZE_REGISTRANTS_UNREALED #define。在该列表中,为您的Commandlet添加一个对"StaticClass()"函数的调用

#define AUTO_INITIALIZE_REGISTRANTS_UNREALED \
    UNameCommandlet::StaticClass(); \

下次重新构建脚本时,编译器将用这个列表中的Commandlet类按字母顺序覆盖这个文件。

为用户提供一些帮助

内置在Commandlet中的功能是显示有关它的帮助信息,以便用户能够发现它是什么以及它支持哪些选项。要使帮助信息对Commandlet可用,需要将条目添加到Commandlet所在的本地化文本文件中。如果包位于Core中,则需要修改Core.int以显示帮助信息。下面是驻留在Core中的"hello world"Commandlet的示例设置。

[HelloWorldCommandlet]
HelpDescription="This commandlet displays hello world" HelpUsage="gamename.exe helloworld"
HelpWebLink="https://udn.epicgames.com/bin/view/Three/MakingACommandlet"
HelpParamNames[0]="param1"
HelpParamDescriptions[0]="Ignored since helloworld doesn't need params"

注意,章节名必须包含 commandlet 作为类名的一部分。没有这个,就找不到Commandlet。要查看如何使用此信息,请运行以下命令:

game.exe help help
game.exe help list
game.exe help webhelp help

如何使用Commandlet

若要执行Commandlet,请使用希望运行的Commandlet名称运行游戏。例如:

examplegame make -full

在ExampleGame中启动make commandlet。注意,您不必为本地Commandlet指定包名。如果make commandlet是纯脚本Commandlet,那么将使用以下命令调用它:

examplegame editor.make -full

因为它不会在启动时加载。还要注意,不需要名称的 commandlet 部分。当试图找到指定的Commandlet时,启动代码会自动附加 _commandlet=。

常见Commandlet任务

常见的做法是遍历包并对它们执行一些数据处理。下面的代码(也是"UContentCommandlets.cpp"顶部的注释)可以帮助您开始:

// 下面是一个模板Commandlet,当您希望对所有包执行操作时可以使用它。
int32 UPerformAnOperationOnEveryPackage::Main(const FString& Params)
{
    // 解析命令行参数。
    TArray<FString> Tokens;
    TArray<FString> Switches;

    const TCHAR* Parms = *Params;
    ParseCommandLine(Parms, Tokens, Switches);

    // 构建包文件列表。
    const TArray<FString> FilesInPath( GPackageFileCache->GetPackageFileList() );
    if( FilesInPath.Num() == 0 )
    {
        warnf( NAME_Warning, TEXT("No packages found") );
        return 1;
    }

    // 遍历所有执行操作的文件。
    for( int32 FileIndex = 0 ; FileIndex < FilesInPath.Num() ; ++FileIndex )
    {
        const FString& Filename = FilesInPath(FileIndex);
        warnf( NAME_Log, TEXT("Loading %s"), *Filename );

        UPackage* Package = UObject::LoadPackage( NULL, *Filename, LOAD_None );
        if( Package == NULL )
        {
            warnf( NAME_Error, TEXT("Error loading %s!"), *Filename );
        }

        /////////////////
        //
        // 在此处执行您的操作。
        //
        /////////////////

        TObjectIterator<UStaticMesh> It;...

        UStaticMesh* StaticMesh = *It;
        if( StaticMesh->IsIn( Package )
        UObject::CollectGarbage( RF_Native );
    }

    return 0;
}

您可能还想查看"PackageHelperFunctions.h"(出现在QA_APPROVED_BUILD_JUNE_2007中)中的"NormalizePackageNames()"。这个函数可以创建一个过滤过的包列表来遍历,除了遍历"GPackageFileCache"之外,还有一些更细微的差别(详细信息请参阅代码)。

Commandlet列表

请参阅Commandlet列表 页面。

Select Skin
Light
Dark

Welcome to the new Unreal Engine 4 Documentation site!

We're working on lots of new features including a feedback system so you can tell us how we are doing. It's not quite ready for use in the wild yet, so head over to the Documentation Feedback forum to tell us about this page or call out any issues you are encountering in the meantime.

We'll be sure to let you know when the new system is up and running.

Post Feedback