Init
This commit is contained in:
186
03-UnrealEngine/Editor/UnrealEngine的命令行操作方式.md
Normal file
186
03-UnrealEngine/Editor/UnrealEngine的命令行操作方式.md
Normal file
@@ -0,0 +1,186 @@
|
||||
---
|
||||
title: UnrealEngine的命令行操作方式
|
||||
date: 2023-04-27 11:15:14
|
||||
excerpt:
|
||||
tags: CommandLet
|
||||
rating: ⭐
|
||||
---
|
||||
# 前言
|
||||
最近想实现使用UnrealEditor-Cmd进行资产处理并且渲染的功能,这里简单归纳一下。
|
||||
|
||||
# 命令行启动方式
|
||||
## CommandLet
|
||||
继承UCommandLet,重写Run()相关逻辑写在里面即可。启动参数大致如下:
|
||||
```bash
|
||||
UnrealEditor-Cmd.exe ProjectPath -run=CommandletName
|
||||
```
|
||||
|
||||
这里很推荐去看一下`UImportAssetsCommandlet`,里面实现了使用Json传参的方法。
|
||||
|
||||
### 变相执行ConsoleCommand
|
||||
创建一个CommandLet并且接收参数,并在最后下列代码即可。
|
||||
```c++
|
||||
GEditor->Exec(World, TEXT("MAP REBUILD ALLDIRTYFORLIGHTING"));
|
||||
```
|
||||
|
||||
## Python
|
||||
- 官方文档:https://docs.unrealengine.com/4.27/en-US/ProductionPipelines/ScriptingAndAutomation/Python/
|
||||
```bash
|
||||
UnrealEditor-Cmd.exe ProjectPath -ExecutePythonScript="c:\my_script.py"
|
||||
```
|
||||
|
||||
还存在另一种方法,编辑器启动时环境最小,不包含UI或渲染。该方法执行起来非常快,但是加载脚本需要交互的关卡和其他种类资源时比较棘手。在命令行中添加以下参数:-`run=pythonscript -script=<script_file>`比如:
|
||||
```bash
|
||||
UnrealEditor-Cmd.exe -run=pythonscript -script="c:\\my_script.py"
|
||||
```
|
||||
|
||||
## AutomationTest
|
||||
一个另类的思路就是使用自动测试工具。通过`IMPLEMENT_COMPLEX_AUTOMATION_TEST`实现一个自动测试类之后实现`RunTest`即可。启动参数:
|
||||
```bash
|
||||
UnrealEditor-Cmd.exe ProjectPath -AutomationTestName -Execcmds="Command-Line Arguments"
|
||||
```
|
||||
|
||||
大致过程可以参考视频:https://www.youtube.com/watch?v=kJd5-jY46Gk
|
||||
视频中的启动参数:
|
||||
```python
|
||||
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 list,Automation RunTest Project.Blueprints.compile Blueprints\"","-testexit=\ "Automation Test Queue Empty\"",
|
||||
cmd = " ".join(cmd)
|
||||
subprocess.run(cmd)
|
||||
```
|
||||
|
||||
引擎内的FCompileBlueprintsTest具体代码:
|
||||
```c++
|
||||
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
|
||||
- 官方文档:https://docs.unrealengine.com/4.27/en-US/ProductionPipelines/ScriptingAndAutomation/Python/
|
||||
将OutputLog的ConsoleCommand的类型从CMD=>Python,之后输入Python命令即可。
|
||||
|
||||
## CustomConsoleCommand
|
||||
除了UFUNCTION中指定Exec之外(因为这个只能在部分类中实现并不通用)就是使用`IConsoleManager::Get().RegisterConsoleCommand()`,卸载函数为`IConsoleManager::Get().UnregisterConsoleObject()`,一般会在Module的StartupModule()/ShutdownModule()或者Subsystem的对应函数中进行注册/卸载。用法如下:
|
||||
```c++
|
||||
IConsoleManager::Get().RegisterConsoleCommand(
|
||||
TEXT("ConsoleCommandName"),
|
||||
TEXT("Useage Info"),
|
||||
FConsoleCommandDelegate::CreateStatic(&UYourClass::Function),
|
||||
ECVF_Default);
|
||||
```
|
||||
|
||||
相关的FConsoleCommandDelegate委托都位于IConsoleManager.h,根据需求选择。
|
||||
|
||||
# 其他
|
||||
## CommandLet Server
|
||||
```c++
|
||||
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);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 日志写入文件
|
||||
```bash
|
||||
f"-abslog={log_location}"
|
||||
```
|
Reference in New Issue
Block a user