• UE4自动打包工具编写


    在UE的开发中,有些项目需要针对不同版本出不同的包,并有一个对应的UI界面方便大家使用。

    本文就来实现一下这个功能(UE4.27)。

     

    1.插件编写

    先使用UE4自己的插件模板进行创建,做成插件形式

    然后注册Slate UI,编写打开逻辑。并在按钮点击函数PluginButtonClicked内触发。

    .cpp部分代码如下:

    #include "PackageHelper.h"
    #include "PackageHelperStyle.h"
    #include "PackageHelperCommands.h"
    #include "Misc/MessageDialog.h"
    #include "ToolMenus.h"
    
    #include "GameMapsSettings.h"
    #include "Misc/FileHelper.h"
    #include "FileHelpers.h"
    
    static const FName PackageHelperTabName("PackageHelper");
    
    #define LOCTEXT_NAMESPACE "FPackageHelperModule"
    
    TSharedRef FPackageHelperModule::WindowBody(const FSpawnTabArgs& SpawnTabArgs)
    {
        return SNew(SDockTab)
            .TabRole(ETabRole::NomadTab)
            [
                SNew(SVerticalBox)
                + SVerticalBox::Slot()
                [
                    SNew(SButton)
                    .Content()
                    [
                        SNew(STextBlock)
                        .Justification(ETextJustify::Center)
                        .Text(LOCTEXT("Build Test Package1", "Build Test Package1"))
                    ]
                    .OnClicked_Lambda([this]()
                    {
                        //Clicked Test Package1.
    
                        return FReply::Handled();
                    })
                ]
                + SVerticalBox::Slot()
                [
                    SNew(SButton)
                    .Content()
                    [
                        SNew(STextBlock)
                        .Justification(ETextJustify::Center)
                        .Text(LOCTEXT("Build Test Package2", "Build Test Package2"))
                    ]
                    .OnClicked_Lambda([this]()
                    {
                        //Clicked Test Package2.
    
                        return FReply::Handled();
                    })
                ]
                + SVerticalBox::Slot()
                [
                    SNew(SButton)
                    .Content()
                    [
                        SNew(STextBlock)
                        .Justification(ETextJustify::Center)
                        .Text(LOCTEXT("Build Test Package3", "Build Test Package3"))
                    ]
                    .OnClicked_Lambda([this]()
                    {
                        //Clicked Test Package3.
    
                        return FReply::Handled();
                    })
                ]
        ];
    }
    
    void FPackageHelperModule::StartupModule()
    {
        FPackageHelperStyle::Initialize();
        FPackageHelperStyle::ReloadTextures();
        FPackageHelperCommands::Register();
        
        PluginCommands = MakeShareable(new FUICommandList);
    
        PluginCommands->MapAction(
            FPackageHelperCommands::Get().PluginAction,
            FExecuteAction::CreateRaw(this, &FPackageHelperModule::PluginButtonClicked),
            FCanExecuteAction());
    
        UToolMenus::RegisterStartupCallback(FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FPackageHelperModule::RegisterMenus));
    
        FGlobalTabmanager::Get()->RegisterNomadTabSpawner(PackageHelperTabName
                , FOnSpawnTab::CreateRaw(this, &FPackageHelperModule::WindowBody))
            .SetDisplayName(LOCTEXT("PackageHelper", "PackageHelper"))
            .SetMenuType(ETabSpawnerMenuType::Hidden);
    }
    
    void FPackageHelperModule::ShutdownModule()
    {
        UToolMenus::UnRegisterStartupCallback(this);
        UToolMenus::UnregisterOwner(this);
    
        FPackageHelperStyle::Shutdown();
        FPackageHelperCommands::Unregister();
    
        FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(PackageHelperTabName);
    }
    
    void FPackageHelperModule::PluginButtonClicked()
    {
        FGlobalTabmanager::Get()->TryInvokeTab(PackageHelperTabName);
    }
    
    void FPackageHelperModule::RegisterMenus()
    {
        FToolMenuOwnerScoped OwnerScoped(this);
        {
            UToolMenu* Menu = UToolMenus::Get()->ExtendMenu("LevelEditor.MainMenu.Window");
            {
                FToolMenuSection& Section = Menu->FindOrAddSection("WindowLayout");
                Section.AddMenuEntryWithCommandList(FPackageHelperCommands::Get().PluginAction, PluginCommands);
            }
        }
    
        {
            UToolMenu* ToolbarMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.LevelEditorToolBar");
            {
                FToolMenuSection& Section = ToolbarMenu->FindOrAddSection("Settings");
                {
                    FToolMenuEntry& Entry = Section.AddEntry(FToolMenuEntry::InitToolBarButton(FPackageHelperCommands::Get().PluginAction));
                    Entry.SetCommandList(PluginCommands);
                }
            }
        }
    }
    
    #undef LOCTEXT_NAMESPACE
        
    IMPLEMENT_MODULE(FPackageHelperModule, PackageHelper)
    PackageHelper.cpp

     

    2.DefaultEngine.ini配置文件修改

    因为打包不同内容加载的地图也不一样,所以在打包前先在配置文件里更新GameDefaultMap,

    虽然RunUAT.bat也可以传入打包地图,但那样灵活性稍差一些。

    此处使用GConfig写入配置文件:

    FString MapPath;//要用UE路径格式,例如:Game/Maps/ThirdPersonExampleMap.ThirdPersonExampleMap
    FString Path = FPaths::ConvertRelativePathToFull(FPaths::ProjectConfigDir() + TEXT("DefaultEngine.ini"));
    GConfig->SetString(TEXT("/Script/EngineSettings.GameMapsSettings"), TEXT("GameDefaultMap"), *MapPath, *Path);
    GConfig->Flush(false, *Path);//Read参数为false是针对写入Flush,true是针对读取

     

    3.RunUAT.bat打包

    与Unity直接封装好了打包函数不同,UE中需要用RunUAT.bat打包,位于引擎目录:

    Engine/Build/BatchFiles/RunUAT.bat

     

    打包时,需要阻塞UE自身线程,这样可以在打包完成后做一些事情,

    这里使用FPlatformProcess运行RunUAT.bat,具体代码如下:

    复制代码
    //打包函数,参数BuildPath为打包输出目录(注意路径结尾不带斜杠,否则打包失败)
    void BuildPackage(FString BuildPath)
    {
        FString RunUATPath = FPaths::ConvertRelativePathToFull(FPaths::EngineDir()) 
            + FString("Build/BatchFiles/RunUAT.bat");
        FString UE4EditorCmdPath = FPaths::ConvertRelativePathToFull(FPaths::EngineDir()) 
            + FString("Binaries/Win64/UE4Editor-Cmd.exe");
        FString UProjectPath = FPaths::ConvertRelativePathToFull(FPaths::GameSourceDir() 
            + TEXT("../"));
    
        TArray AssetName;
        IFileManager::Get().FindFiles(AssetName, *UProjectPath, TEXT(".uproject"));
        UProjectPath += AssetName[0];
    
        FString Arg = FString("-ScriptsForProject=\"" + UProjectPath + "\" BuildCookRun -project=\"" 
            + UProjectPath +"\" -targetplatform=Win64 -clientconfig=Development -ue4exe=\"" 
            + UE4EditorCmdPath + "\" -noP4 -iterate -cook -pak -package -stage -archive -archivedirectory=\""
            + BuildPath + "\" -nocompileeditor -prereqs -nodebuginfo -build -CrashReporter -utf8output -compressed");
    
        FProcHandle Handle = FPlatformProcess::CreateProc(*RunUATPath, *Arg
            , false, false, false, nullptr
            , 2, nullptr, nullptr);
        //创建进程打包,PriorityModifer可以填2,进程优先级会高一些
    
        FPlatformProcess::WaitForProc(Handle);
        //堵塞,等待新进程打包完成
    
        UE_LOG(LogTemp, Log, TEXT("Package Successful!"));
        //这里可以加一些打包完的后续操作
    }
    复制代码

     

    这样重启UE之后即可使用打包工具,提升开发效率。

    最后Build.cs中还需要添加一些模块依赖,参考如下:

    PrivateDependencyModuleNames.AddRange(
        new string[]
        {
            "Projects",
            "InputCore",
            "UnrealEd",
            "ToolMenus",
            "CoreUObject",
            "Engine",
            "Slate",
            "SlateCore",
            "EngineSettings"
        }
    );
    Build.cs依赖模块参考

     

  • 相关阅读:
    【容器网络】跨主通信网络实现方法之host-gw实现原理
    vue3 Driver.js 页面分步引导
    教你如何用python画出4种风格不一的树
    【微信小程序】电商移动前端API文档
    Modality to Modality Translation
    面试突击72:输入URL之后会执行什么流程?
    函数式编程
    xcode swift 单元测试 test
    Java基础知识面试题(三)(英语答案)
    【html5期末大作业】基于HTML仿QQ音乐官网网站
  • 原文地址:https://www.cnblogs.com/hont/p/16676652.html