BlueRoseNote/03-UnrealEngine/Editor/UnrealEngine的命令行操作方式.md
2023-06-29 11:55:02 +08:00

6.6 KiB
Raw Permalink Blame History

title, date, excerpt, tags, rating
title date excerpt tags rating
UnrealEngine的命令行操作方式 2023-04-27 11:15:14 CommandLet

前言

最近想实现使用UnrealEditor-Cmd进行资产处理并且渲染的功能这里简单归纳一下。

命令行启动方式

CommandLet

继承UCommandLet重写Run()相关逻辑写在里面即可。启动参数大致如下:

UnrealEditor-Cmd.exe ProjectPath -run=CommandletName

这里很推荐去看一下UImportAssetsCommandlet里面实现了使用Json传参的方法。

变相执行ConsoleCommand

创建一个CommandLet并且接收参数并在最后下列代码即可。

GEditor->Exec(World, TEXT("MAP REBUILD ALLDIRTYFORLIGHTING"));

Python

UnrealEditor-Cmd.exe ProjectPath -ExecutePythonScript="c:\my_script.py"

还存在另一种方法编辑器启动时环境最小不包含UI或渲染。该方法执行起来非常快但是加载脚本需要交互的关卡和其他种类资源时比较棘手。在命令行中添加以下参数-run=pythonscript -script=<script_file>比如:

UnrealEditor-Cmd.exe -run=pythonscript -script="c:\\my_script.py"

AutomationTest

一个另类的思路就是使用自动测试工具。通过IMPLEMENT_COMPLEX_AUTOMATION_TEST实现一个自动测试类之后实现RunTest即可。启动参数:

UnrealEditor-Cmd.exe ProjectPath -AutomationTestName -Execcmds="Command-Line Arguments"

大致过程可以参考视频:https://www.youtube.com/watch?v=kJd5-jY46Gk 视频中的启动参数:

import subprocess

engine = "C:/work/Epic/UE_5.0/Engine/Binaries/win64/UnrealEditor.exe"
project = "C:/Work/Prototypes/CompileBlueprintProj/CompileBlueprintProj.uproject"
log_location = "C:/Work/Prototypes/CompileBlueprintProj/blueprint_results.log"

cmd =[
engine,project,
f"-abslog={flog_location}",
"-editortest",
"-Execcmds= "Automation SetFilter Stress, Automation listAutomation RunTest Project.Blueprints.compile Blueprints\"","-testexit=\ "Automation Test Queue Empty\"",
cmd = " ".join(cmd)
subprocess.run(cmd)

引擎内的FCompileBlueprintsTest具体代码

IMPLEMENT_COMPLEX_AUTOMATION_TEST(FCompileBlueprintsTest, "Project.Blueprints.Compile Blueprints", EAutomationTestFlags::EditorContext | EAutomationTestFlags::StressFilter)

/************************************************************************/  
/* FCompileBlueprintsTest                                              */  
/************************************************************************/  
  
/** Requests a enumeration of all blueprints to be loaded */  
void FCompileBlueprintsTest::GetTests(TArray<FString>& OutBeautifiedNames, TArray <FString>& OutTestCommands) const  
{  
   FBlueprintAutomationTestUtilities::CollectTestsByClass(UBlueprint::StaticClass(), OutBeautifiedNames, OutTestCommands, /*bool bIgnoreLoaded =*/false);  
}  
  
  
bool FCompileBlueprintsTest::RunTest(const FString& Parameters)  
{  
   UE_LOG(LogBlueprintAutomationTests, Log, TEXT("Beginning compile test for %s"), *Parameters);  
   return FBlueprintAutomationTestUtilities::CompileBlueprint(Parameters);  
}

/**  
 * Simulates the user pressing the blueprint's compile button (will load the * blueprint first if it isn't already). ** @param  BlueprintAssetPath  The asset object path that you wish to compile. * @return False if we failed to load the blueprint, true otherwise 
 */
static bool CompileBlueprint(const FString& BlueprintAssetPath)  
{  
	UBlueprint* BlueprintObj = Cast<UBlueprint>(StaticLoadObject(UBlueprint::StaticClass(), NULL, *BlueprintAssetPath));  
	if (!BlueprintObj || !BlueprintObj->ParentClass)  
	{      
		UE_LOG(LogBlueprintAutomationTests, Error, TEXT("Failed to compile invalid blueprint, or blueprint parent no longer exists."));  
		return false;  
	}  
	UPackage* const BlueprintPackage = BlueprintObj->GetOutermost();  
	// compiling the blueprint will inherently dirty the package, but if there   
	// weren't any changes to save before, there shouldn't be after  
	bool const bStartedWithUnsavedChanges = (BlueprintPackage != nullptr) ? BlueprintPackage->IsDirty() : true;  
	
	FKismetEditorUtilities::CompileBlueprint(BlueprintObj, EBlueprintCompileOptions::SkipGarbageCollection);  
	
	if (BlueprintPackage != nullptr)  
	{      
	   BlueprintPackage->SetDirtyFlag(bStartedWithUnsavedChanges);  
	}  
	return true;  
}

编辑器内调用

Python

CustomConsoleCommand

除了UFUNCTION中指定Exec之外因为这个只能在部分类中实现并不通用就是使用IConsoleManager::Get().RegisterConsoleCommand(),卸载函数为IConsoleManager::Get().UnregisterConsoleObject()一般会在Module的StartupModule()/ShutdownModule()或者Subsystem的对应函数中进行注册/卸载。用法如下:

IConsoleManager::Get().RegisterConsoleCommand(  
TEXT("ConsoleCommandName"),  
TEXT("Useage Info"),  
FConsoleCommandDelegate::CreateStatic(&UYourClass::Function),  
ECVF_Default);

相关的FConsoleCommandDelegate委托都位于IConsoleManager.h根据需求选择。

其他

CommandLet Server

int32 FEditorDomainSaveServer::Run()
{
	if (!TryInitialize())
	{
		Shutdown();
		return 1;
	}

	while (PollShouldRun())
	{
		bool bIsIdle = true;
		TickPendingPackages(bIsIdle);
		PollIncomingConnections(bIsIdle);
		PollConnections(bIsIdle);
		TickMaintenance(bIsIdle);
	}

	Shutdown();
	return 0;
}

void FEditorDomainSaveServer::TickMaintenance(bool bIsIdle)  
{  
	using namespace UE::EditorDomainSave;  
  
	SetIdle(bIsIdle);  
	double CurrentTime = FPlatformTime::Seconds();  
	if (bIsIdle)  
	{  
		if (!HasExpectedConnections() && CurrentTime - IdleStartTime > Constants::ServerAbdicationCooldownSeconds)  
		{  
			if (TryAbdicate())  
			{  
				return;  
			}  
		}  
	}  
  
	double CollectGarbageCooldownSeconds = bIsIdle ?  
	Constants::CollectGarbageIdleCooldownSeconds :  
	Constants::CollectGarbageActiveCooldownSeconds;  
	bool bCollectedGarbageAfterIdle = bIsIdle && LastGarbageTime >= IdleStartTime;  
	if (!bCollectedGarbageAfterIdle && CurrentTime - LastGarbageTime > CollectGarbageCooldownSeconds)  
	{  
		CollectGarbage(RF_NoFlags);  
		LastGarbageTime = FPlatformTime::Seconds();  
	}  
	  
	if (bIsIdle)  
	{  
		FPlatformProcess::Sleep(Constants::ServerIdleSleepPeriodSeconds);  
	}  
}

日志写入文件

f"-abslog={log_location}"