Nuke.Unreal
Build Unreal apps in Style.
Loading...
Searching...
No Matches
UnrealBuild.Targets.cs
1using System;
2using System.Diagnostics;
3using System.IO;
4using System.Linq;
5using Nuke.Common;
6using Nuke.Common.IO;
7using Nuke.Common.Utilities.Collections;
8using GlobExpressions;
9using Nuke.Common.Tools.Git;
11using Nuke.Cola;
12using Nuke.Common.Utilities;
13using Nuke.Common.ProjectModel;
14using Serilog;
15using System.Runtime.InteropServices;
16using Nuke.Cola.Tooling;
17using Nuke.Common.Tooling;
20
21// Maximum line length of long parameter description:
22// ------------------------------------------------------------
23
24namespace Nuke.Unreal;
25
26public abstract partial class UnrealBuild : NukeBuild, IUnrealBuild
27{
28 /// <summary>
29 /// <para>
30 /// **NUKE TARGET**
31 /// </para>
32 /// Opens the Nuke.Unreal online documentation
33 /// </summary>
34 public virtual Target HelpNukeUnreal => _ => _
35 .Description(
36 """
37 |
38 | Opens Nuke.Unreal online documentation.
39
40 """
41 )
42 .Executes(() =>
43 {
44 Process.Start(new ProcessStartInfo
45 {
46 UseShellExecute = true,
47 FileName = "https://mcro.de/Nuke.Unreal"
48 });
49 });
50
51 /// <summary>
52 /// <para>
53 /// **NUKE TARGET**
54 /// </para>
55 /// Prints curated information about project
56 /// </summary>
57 public virtual Target Info => _ => _
58 .Description(
59 """
60 |
61 | Prints curated information about project
62
63 """
64 )
65 .Executes(PrintInfo);
66
67 /// <summary>
68 /// <para>
69 /// **NUKE TARGET**
70 /// </para>
71 /// Removes previous deployment folder
72 /// </summary>
73 public virtual Target CleanDeployment => _ => _
74 .Description(
75 """
76 |
77 | Removes previous deployment folder
78
79 """
80 )
81 .Executes(() => GetOutput().DeleteDirectory());
82
83 /// <summary>
84 /// <para>
85 /// **NUKE TARGET**
86 /// </para>
87 /// Removes auto generated folders of Unreal Engine from the project
88 /// </summary>
89 public virtual Target CleanProject => _ => _
90 .Description(
91 """
92 |
93 | Removes auto generated folders of Unreal Engine from the project
94
95 """
96 )
97 .Executes(() => Unreal.ClearFolder(ProjectFolder));
98
99 /// <summary>
100 /// <para>
101 /// **NUKE TARGET**
102 /// </para>
103 /// Removes auto generated folders of Unreal Engine from the plugins
104 /// </summary>
105 public virtual Target CleanPlugins => _ => _
106 .Description(
107 """
108 |
109 | Removes auto generated folders of Unreal Engine from the plugins
110
111 """
112 )
113 .OnlyWhenDynamic(() => PluginsFolder.DirectoryExists())
114 .Executes(() =>
115 {
116 void recurseBody(AbsolutePath path)
117 {
118 if (Glob.Files(path, "*.uplugin", GlobOptions.CaseInsensitive).Any())
119 {
120 Log.Debug("Cleaning plugin {0}", path);
121 Unreal.ClearFolder(path);
122 }
123 else
124 {
125 foreach (var dir in Directory.EnumerateDirectories(path))
126 {
127 recurseBody((AbsolutePath)dir);
128 }
129 }
130 }
131
132 foreach (var pluginDir in Directory.EnumerateDirectories(PluginsFolder))
133 {
134 recurseBody((AbsolutePath)pluginDir);
135 }
136 });
137
138 /// <summary>
139 /// <para>
140 /// **NUKE TARGET**
141 /// </para>
142 /// Removes auto generated folders of Unreal Engine
143 /// </summary>
144 public virtual Target Clean => _ => _
145 .Description(
146 """
147 |
148 | Removes auto generated folders of Unreal Engine
149
150 """
151 )
152 .DependsOn(CleanProject)
153 .DependsOn(CleanPlugins);
154
155 /// <summary>
156 /// <para>
157 /// **NUKE TARGET**
158 /// </para>
159 /// Switch to an explicit Engine versionű
160 /// <code>
161 /// \--unreal (req.)
162 /// </code>
163 /// </summary>
164 public virtual Target Switch => _ => _
165 .Description(
166 """
167 |
168 | Switch to an explicit Engine version
169 |
170 | --unreal (req.)
171
172 """
173 )
174 .DependsOn(Clean)
176 .Requires(() => UnrealVersion)
177 .Executes(() =>
178 {
179 Log.Information($"Targeting Unreal Engine {UnrealVersion} on platform {Platform}");
181 ProjectDescriptor = ProjectDescriptor with { EngineAssociation = UnrealVersion };
183 _projectDescriptor = null;
184 _engineVersionCache = null;
185 });
186
187 /// <summary>
188 /// <para>
189 /// **NUKE TARGET**
190 /// </para>
191 /// <para>
192 /// Run necessary preparations which needs to be done before Unreal tools can handle
193 /// the project. By default it is empty and the main build project may override it or
194 /// other Targets can depend on it / hook into it.
195 /// </para>
196 /// </summary>
197 public virtual Target Prepare => _ => _
198 .Description(
199 """
200 |
201 | Run necessary preparations which needs to be done before Unreal tools can handle
202 | the project. By default it is empty and the main build project may override it or
203 | other Targets can depend on it / hook into it.
204
205 """
206 );
207
208 /// <summary>
209 /// <para>
210 /// **NUKE TARGET**
211 /// </para>
212 /// Generate project files for the default IDE of the current platform. You can specify further details with
213 /// `-->ubt` argument block. It is equivalent to right clicking the uproject and selecting "Generate _IDE_
214 /// project files".
215 /// <code>
216 /// \-->ubt (args.)
217 /// </code>
218 /// </summary>
219 public virtual Target Generate => _ => _
220 .Description(
221 """
222 |
223 | Generate project files for the default IDE of the current platform.
224 | You can specify further details with -->ubt argument block It is equivalent to
225 | right clicking the uproject and selecting "Generate _IDE_ project files".
226 |
227 | -->ubt (args.)
228
229 """
230 )
231 .DependsOn(Prepare)
232 .Executes(() =>
233 {
234 Unreal.BuildTool(this, _ => _
235 .ProjectFiles()
237 .Game()
238 .If(Unreal.IsSource(this), _ => _
239 .Engine()
240 )
241 .Progress()
242 .AppendRaw(GetArgumentBlock("ubt"))
243 )();
244 });
245
246 public virtual Target SetupPlatformSdk => _ => _
247 .Unlisted()
248 .Executes(() =>
249 {
250 var sdk = Platform.GetSdk();
251 if (sdk != null)
252 {
253 if (sdk.IsValid(this))
254 {
255 Log.Information("Preparing SDK for {0}", Platform);
256 sdk.Setup(this);
257 }
258 else
259 {
260 Log.Error("An SDK for {0} cannot be prepared for current build", Platform);
261 }
262 }
263 });
264
265 /// <summary>
266 /// <para>
267 /// **NUKE TARGET**
268 /// </para>
269 /// Build the editor binaries so this project can be opened properly in the Unreal editor
270 /// <code>
271 /// \--EditorConfig
272 /// \-->ubt (args.)
273 /// </code>
274 /// </summary>
275 public virtual Target BuildEditor => _ => _
276 .Description(
277 """
278 |
279 | Build the editor binaries so this project can be opened properly in the
280 | Unreal editor
281 |
282 | --EditorConfig
283 | -->ubt (args.)
284
285 """
286 )
287 .After(Prepare)
288 .Executes(() =>
289 {
290 Unreal.BuildTool(this, _ => _
291 .Target(
295 )
296 .Project(ProjectPath, true)
297 .If(Unreal.IsSource(this), _ => _
298 .Target(
299 "ShaderCompileWorker",
301 [UnrealConfig.Development]
302 )
303 .Quiet()
304 )
305 .FromMsBuild()
307 .AppendRaw(GetArgumentBlock("ubt"))
308 )();
309 });
310
311 /// <summary>
312 /// <para>
313 /// **NUKE TARGET**
314 /// </para>
315 /// Build this project for execution
316 /// <code>
317 /// \--TargetType
318 /// \--Config
319 /// \--Platform
320 /// \-->ubt (args.)
321 /// </code>
322 /// </summary>
323 public virtual Target Build => _ => _
324 .Description(
325 """
326 |
327 | Build this project for execution
328 |
329 | --TargetType
330 | --Config
331 | --Platform
332 | -->ubt (args.)
333
334 """
335 )
336 .DependsOn(SetupPlatformSdk)
337 .After(Cook) // Android needs Cook to happen before building the APK, so OBB files can be included in the APK
338 .After(Prepare)
339 .Executes(() =>
340 {
341 var targets = TargetType.Select(tt => tt == UnrealTargetType.Game
343 : ProjectName + tt
344 );
345 Unreal.BuildTool(this, _ => _
346 .For(targets, (t, _) => _
347 .Target(t, Platform, Config)
348 )
350 .Apply<UbtConfig, UbtConfig>(UbtGlobal)
351 .AppendRaw(GetArgumentBlock("ubt"))
352 )();
353 });
354
355
356 /// <summary>
357 /// UAT arguments to be applied every time UAT is called for Cooking. Override this function
358 /// in your main build class if your project needs extra intricacies for Cooking.
359 /// For example specifying maps explicitly.
360 /// </summary>
361 public virtual UatConfig UatCook(UatConfig _) => _;
362
363 /// <summary>
364 /// Enforce packaging for distribution when that is set from `Game` ini files.
365 /// Override this function in your main build class if you want a different logic set for
366 /// flagging packages for distribution.
367 /// </summary>
368 public virtual bool ForDistribution()
369 {
370 var section = ReadIniHierarchy("Game")["/Script/UnrealEd.ProjectPackagingSettings"];
371 return section != null && section
372 .GetFirst("ForDistribution", new() { Value = "" }).Value
373 .EqualsAnyOrdinalIgnoreCase("true", "1");
374 }
375
376 /// <summary>
377 /// <para>
378 /// **NUKE TARGET**
379 /// </para>
380 /// Cook Unreal assets for standalone game execution
381 /// <code>
382 /// \--Config
383 /// \--Platform
384 /// \--AndroidTextureMode
385 /// \-->ubt (args.)
386 /// \-->uat (args.)
387 /// </code>
388 /// </summary>
389 public virtual Target Cook => _ => _
390 .Description(
391 """
392 |
393 | Cook Unreal assets for standalone game execution
394 |
395 | --Config
396 | --Platform
397 | --AndroidTextureMode
398 | -->ubt (args.)
399 | -->uat (args.)
400
401 """
402 )
403 .DependsOn(BuildEditor, SetupPlatformSdk)
404 .Executes(() =>
405 {
406 var isAndroidPlatform = Platform == UnrealPlatform.Android;
407
408 Config.ForEach(config =>
409 {
410 Unreal.AutomationTool(this, _ => _
411 .BuildCookRun(_ => _
413 .Clientconfig(config)
414 .Skipstage()
415 .Manifests()
416 .If(ForDistribution(), _ => _
417 .Distribution()
418 )
419 )
420 .ScriptsForProject(ProjectPath)
421 .Targetplatform(Platform)
422 .Cook()
423 .If(InvokedTargets.Contains(BuildEditor), _ => _
424 .NoCompileEditor()
425 )
426 .If(isAndroidPlatform, _ => _
427 .Cookflavor(AndroidTextureMode)
428 )
430 .Apply<UatConfig, UatConfig>(UatCook)
431 .AppendRaw(GetArgumentBlock("uat"))
432 )(
433 workingDirectory: UnrealEnginePath
434 );
435 });
436 });
437
438 /// <summary>
439 /// <para>
440 /// **NUKE TARGET**
441 /// </para>
442 /// Ensure support for plain C# build plugins without the need for CSX or dotnet projects. This only needs to
443 /// be done once, you can check the results into source control.
444 /// </summary>
445 public virtual Target EnsureBuildPluginSupport => _ => _
446 .Description(
447 """
448 |
449 | Ensure support for plain C# build plugins without the need for CSX or dotnet
450 | projects. This only needs to be done once, you can check the results into
451 | source control.
452
453 """
454 )
455 .Executes(() =>
456 {
457 var project = ProjectModelTasks.ParseProject(BuildProjectFile);
458 project.SkipEvaluation = true;
459 var compileItems = project.GetItems("Compile");
460 var pattern = "../**/*.nuke.cs";
461
462 if (BuildProjectFile.ReadAllText().Contains(pattern))
463 Log.Debug("Build project already supports standalone C# build plugins.");
464 else
465 {
466 Log.Information("Preparing build project to accept standalone C# files. {0}, in {1}", pattern, BuildProjectFile);
467 project.AddItem("Compile", pattern);
468 project.Save();
469 Log.Information("This only needs to be done once, you can check the results into source control.");
470 }
471 });
472
473 /// <summary>
474 /// <para>
475 /// **NUKE PARAMETER**
476 /// </para>
477 /// Do not use globally applicable UBT/UAT arguments with run-uat/run-ubt
478 /// </summary>
479 [Parameter]
480 public bool IgnoreGlobalArgs = false;
481
482 /// <summary>
483 /// <para>
484 /// **NUKE TARGET**
485 /// </para>
486 /// Simply run UAT with arguments passed after `-->`
487 /// <code>
488 /// \--> (args.)
489 /// \--IgnoreGlobalArgs (adv.)
490 /// </code>
491 /// <para>
492 /// The following symbols are replaced by Nuke.Unreal:
493 /// </para>
494 /// <code>
495 /// ~p : Project file path
496 /// ~pdir : Project folder
497 /// ~ue : Unreal Engine folder
498 /// </code>
499 /// </summary>
500 public virtual Target RunUat => _ => _
501 .Description(
502 """
503 |
504 | Simply run UAT with arguments passed after `-->`
505 |
506 | The following symbols are replaced by Nuke.Unreal:
507 | ~p : Project file path
508 | ~pdir : Project folder
509 | ~ue : Unreal Engine folder
510 |
511 | --> (args.)
512 | --IgnoreGlobalArgs (adv.)
513
514 """
515 )
516 .DependsOn(SetupPlatformSdk)
517 .Executes(() =>
518 {
519 Unreal.AutomationTool(this, _ => _
520 .AppendRaw(GetArgumentBlock())
521 .If(!IgnoreGlobalArgs, _ => _.Apply<UatConfig, UatConfig>(UatGlobal))
522 )(
523 workingDirectory: ProjectFolder
524 );
525 });
526
527 /// <summary>
528 /// <para>
529 /// **NUKE TARGET**
530 /// </para>
531 /// Simply run UBT with arguments passed after `-->`
532 /// <code>
533 /// \--> (args.)
534 /// \--IgnoreGlobalArgs (adv.)
535 /// </code>
536 /// <para>
537 /// The following symbols are replaced by Nuke.Unreal:
538 /// </para>
539 /// <code>
540 /// ~p : Project file path
541 /// ~pdir : Project folder
542 /// ~ue : Unreal Engine folder
543 /// </code>
544 /// </summary>
545 public virtual Target RunUbt => _ => _
546 .Description(
547 """
548 |
549 | Simply run UBT with arguments passed after `-->`
550 |
551 | The following symbols are replaced by Nuke.Unreal:
552 | ~p : Project file path
553 | ~pdir : Project folder
554 | ~ue : Unreal Engine folder
555 |
556 | --> (args.)
557 | --IgnoreGlobalArgs (adv.)
558
559 """
560 )
561 .DependsOn(SetupPlatformSdk)
562 .Executes(() =>
563 {
564 Unreal.BuildTool(this, _ => _
565 .AppendRaw(GetArgumentBlock())
566 .If(!IgnoreGlobalArgs, _ => _.Apply<UbtConfig, UbtConfig>(UbtGlobal))
567 )(
568 workingDirectory: ProjectFolder
569 );
570 });
571
572 /// <summary>
573 /// <para>
574 /// **NUKE TARGET**
575 /// </para>
576 /// Start a UShell session. This opens a new console window, and nuke will exit immadiately. Working directory
577 /// is the project folder, regardless of actual working directory.
578 /// </summary>
579 public virtual Target RunShell => _ => _
580 .Description(
581 """
582 |
583 | Start a UShell session. This opens a new console window, and nuke will exit
584 | immadiately. Working directory is the project folder, regardless of actual
585 | working directory.
586
587 """
588 )
589 .DependsOn(SetupPlatformSdk)
590 .Executes(() =>
591 {
592 var ushellDir = UnrealEnginePath / "Engine" / "Extras" / "ushell";
593 var scriptExt = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "bat" : "sh";
594 var ushellScript = ushellDir / ("ushell." + scriptExt);
595 ProcessTasks.StartShell(
596 ushellScript,
598 );
599 });
600
601 /// <summary>
602 /// <para>
603 /// **NUKE PARAMETER**
604 /// </para>
605 /// Name the Unreal tool to be run, You can omit the `Unreal` prefix and the extension. For example:
606 /// <code>
607 /// nuke run \--tool pak \--> ./Path/To/MyProject.pak -Extract "D:/temp"
608 /// nuke run \--tool editor-cmd \--> ~p -run=MyCommandlet
609 /// </code>
610 /// </summary>
611 [Parameter]
612 public string? Tool;
613
614 /// <summary>
615 /// <para>
616 /// **NUKE TARGET**
617 /// </para>
618 /// <para>
619 /// Run an Unreal tool from the engine binaries folder. You can omit the `Unreal` prefix and the extension.
620 /// For example:
621 /// </para>
622 /// <code>
623 /// nuke run \--tool pak \--> ./Path/To/MyProject.pak -Extract "D:/temp"
624 /// nuke run \--tool editor-cmd \--> ~p -run=MyCommandlet
625 /// </code>
626 /// <para>
627 /// Working directory is the project folder, regardless of actual working directory.
628 /// </para>
629 /// <para>
630 /// The following symbols are replaced by Nuke.Unreal:
631 /// </para>
632 /// <code>
633 /// ~p : Project file path
634 /// ~pdir : Project folder
635 /// ~ue : Unreal Engine folder
636 /// </code>
637 /// <code>
638 /// \--Tool (req.)
639 /// \--> (args.)
640 /// </code>
641 /// </summary>
642 public virtual Target Run => _ => _
643 .Description(
644 """
645 |
646 | Run an Unreal tool from the engine binaries folder. You can omit the `Unreal`
647 | prefix and the extension. For example:
648 |
649 | nuke run --tool pak --> ./Path/To/MyProject.pak -Extract "D:/temp"
650 | nuke run --tool editor-cmd --> ~p -run=MyCommandlet
651 |
652 | Working directory is the project folder, regardless of actual working
653 | directory.
654 |
655 | The following symbols are replaced by Nuke.Unreal:
656 | ~p : Project file path
657 | ~pdir : Project folder
658 | ~ue : Unreal Engine folder
659 |
660 | --Tool (req.)
661 | --> (args.)
662
663 """
664 )
665 .Requires(() => Tool)
666 .Executes(() =>
667 {
668 Unreal.GetTool(this, Tool!).WithSemanticLogging()
669 (
670 GetArgumentBlock().JoinSpace(), ProjectFolder
671 );
672 });
673
674 /// <summary>
675 /// <para>
676 /// **NUKE PARAMETER**
677 /// </para>
678 /// Name of the editor commandlet to run
679 /// </summary>
680 [Parameter]
681 public string? Cmd;
682
683 /// <summary>
684 /// <para>
685 /// **NUKE TARGET**
686 /// </para>
687 /// Run an editor commandlet with arguments passed in after `-->`
688 /// <para>
689 /// The following symbols are replaced by Nuke.Unreal:
690 /// </para>
691 /// <code>
692 /// ~p : Project file path
693 /// ~pdir : Project folder
694 /// ~ue : Unreal Engine folder
695 /// </code>
696 /// <code>
697 /// \--Cmd (req.)
698 /// \--> (args.)
699 /// </code>
700 /// </summary>
701 public virtual Target RunEditorCmd => _ => _
702 .Description(
703 """
704 |
705 | Run an editor commandlet with arguments passed in after -->
706 |
707 | The following symbols are replaced by Nuke.Unreal:
708 | ~p : Project file path
709 | ~pdir : Project folder
710 | ~ue : Unreal Engine folder
711 |
712 | --Cmd (req.)
713 | --> (args.)
714
715 """
716 )
717 .Requires(() => Cmd)
718 .Executes(() =>
719 {
720 Unreal.GetTool(this, "Editor-Cmd").WithSemanticLogging()
721 (
723 .Prepend($"{ProjectPath} -run={Cmd}")
724 .JoinSpace()
725 ,
727 );
728 });
729}
Unreal Automation Tool is a vast collection of scripts solving all aspects of deploying a program mad...
Definition UatConfig.cs:13
Unreal Build Tool defines the Unreal project structure and provides unified source building utilities...
Definition UbtConfig.cs:13
The main build class Unreal projects using Nuke.Unreal should inherit from. This class contains all b...
AbsolutePath ProjectFolder
Path to folder containing the .project file.
virtual IEnumerable< string > GetArgumentBlock(string name="")
Get optionally named argument block (section after -->) with contextual data substituted....
virtual AbsolutePath ProjectPath
string ProjectName
Short name of the project.
ProjectDescriptor ProjectDescriptor
"Immutable" C# representation of the .uproject contents
AbsolutePath UnrealEnginePath
Path to the root of the associated Unreal Engine installation/source.
virtual UbtConfig UbtGlobal(UbtConfig _)
UBT arguments to be applied globally for all UBT invocations. Override this function in your main bui...
virtual UatConfig UatCook(UatConfig _)
UAT arguments to be applied every time UAT is called for Cooking. Override this function in your main...
virtual AbsolutePath GetOutput()
Get an output folder where the targets should store their artifacts. Override this function in your m...
virtual UnrealConfig[] Config
virtual UnrealConfig[] EditorConfig
virtual ? string UnrealVersion
virtual bool ForDistribution()
Enforce packaging for distribution when that is set from Game ini files. Override this function in yo...
AbsolutePath PluginsFolder
Path to the Unreal plugins folder of this project.
ConfigIni ReadIniHierarchy(string shortName, IniHierarchyLevel lowestLevel=IniHierarchyLevel.Base, IniHierarchyLevel highestLevel=IniHierarchyLevel.Saved, bool considerPlugins=true, IEnumerable< string >? extraConfigSubfolder=null)
Read INI configuration emulating the same hierarchy of importance as Unreal Engine also does.
virtual void PrintInfo()
Print some rudimentary information onto console about this project and it's environment....
virtual Target EnsureBuildPluginSupport
virtual AndroidCookFlavor[] AndroidTextureMode
virtual UnrealPlatform Platform
virtual UatConfig UatGlobal(UatConfig _)
UAT arguments to be applied globally for all UAT invocations. Override this function in your main bui...
Build configurations UBT supports.
High level representation of common platforms supported by Unreal Engine (NDA ones excluded) and extr...
static UnrealPlatform FromFlag(UnrealPlatformFlag flag)
Get the high-level platform from a bit-field platform flag.
The regular target types UBT supports.
static readonly UnrealTargetType Editor
Editor builds for the project.
static readonly UnrealTargetType Game
Can act as both client and server.
A collection of utilities around basic functions regarding the environment of the Engine we're workin...
Definition Unreal.cs:24
static void WriteJson(object input, AbsolutePath path)
Write data in JSON with Unreal conventions of JSON format.
Definition Unreal.cs:82
static ToolEx AutomationTool(EngineVersion ofVersion)
Prepare invocation for UAT.
Definition Unreal.cs:281
static ToolEx GetTool(IUnrealBuild build, string name)
Get a native binary tool from Engine/Binaries folder. Unreal tools written in C# or stored in other f...
Definition Unreal.cs:362
static UnrealPlatformFlag GetHostPlatformFlag()
Get the current development platform flag Nuke.Unreal is ran on.
Definition Unreal.cs:197
static ToolEx BuildTool(EngineVersion ofVersion)
Prepare invocation for UBT.
Definition Unreal.cs:231
static void InvalidateEnginePathCache()
In the rare and unlikely case that the Engine location may have changed during one session.
static bool IsSource(AbsolutePath enginePath)
Is given path an engine built from source?
static void ClearFolder(AbsolutePath folder)
Clear intermediate folders of Unreal from a given folder.
Definition Unreal.cs:328
Base interface for build components which require an UnrealBuild main class.
@ Project
Enable debug info for project modules.
TargetType
The type of target.
@ Game
Cooked monolithic game executable (GameName.exe). Also used for a game-agnostic engine executable (UE...