Nuke.Unreal
Build Unreal apps in Style.
Loading...
Searching...
No Matches
Unreal.cs
1using System;
2using System.Linq;
3using System.IO;
4using System.Collections.Generic;
5using Nuke.Common.IO;
6using System.Runtime.InteropServices;
7using Nuke.Common.Tooling;
8using Newtonsoft.Json;
9using Serilog;
10using System.Text;
12using Nuke.Cola.Tooling;
13using Nuke.Common;
14using Nuke.Common.Utilities;
15using Newtonsoft.Json.Converters;
16
17namespace Nuke.Unreal
18{
19 /// <summary>
20 /// A collection of utilities around basic functions regarding the environment of the Engine
21 /// we're working with.
22 /// </summary>
23 public static class Unreal
24 {
25 /// <summary>
26 /// Frankly this is not really relevant anymore
27 /// </summary>
28 public static readonly HashSet<AbsolutePath>? EngineSearchPaths;
29
30 /// <summary>
31 /// Once the Engine location is found for the current session, it ain't gonna move around,
32 /// so we cache it.
33 /// </summary>
34 public static AbsolutePath? EnginePathCache = null;
35
36 static Unreal()
37 {
38 if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
39 {
40 // Use UnrealLocator
41 return;
42 }
43
44 // TODO: Use UnrealLocator on other platforms as well
45 if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
46 {
47 EngineSearchPaths = new()
48 {
49 (AbsolutePath) @"/Users/Shared/Epic Games",
50 };
51 return;
52 }
53 if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
54 {
55 // TODO: build and use UnrealLocator on linux
56 EngineSearchPaths = new()
57 {
58 (AbsolutePath) @"/Users/Shared/Epic Games",
59 };
60 return;
61 }
62
63 throw new Exception("Attempting to build on an unsupported platform");
64 }
65
66 /// <summary>
67 /// Common `JsonSerializerSettings` for Unreal conventions of JSON format
68 /// </summary>
69 public static readonly JsonSerializerSettings JsonReadSettings = new()
70 {
71 MissingMemberHandling = MissingMemberHandling.Ignore,
72 DefaultValueHandling = DefaultValueHandling.Populate,
73 NullValueHandling = NullValueHandling.Include,
74 Converters = {
75 new StringEnumConverter(false)
76 }
77 };
78
79 /// <summary>
80 /// Write data in JSON with Unreal conventions of JSON format
81 /// </summary>
82 public static void WriteJson(object input, AbsolutePath path)
83 {
84 var sb = new StringBuilder();
85 var sw = new StringWriter(sb);
86
87 using var jtw = new JsonTextWriter(sw)
88 {
89 Formatting = Formatting.Indented,
90 Indentation = 1,
91 IndentChar = '\t'
92 };
93
94 var serializer = new JsonSerializer()
95 {
96 NullValueHandling = NullValueHandling.Ignore,
97 Formatting = Formatting.Indented,
98 Converters = {
99 new StringEnumConverter(false)
100 }
101 };
102 serializer.Serialize(jtw, input);
103 File.WriteAllText(path, sb.ToString());
104 }
105
106 /// <summary>
107 /// In the rare and unlikely case that the Engine location may have changed during one
108 /// session
109 /// </summary>
110 public static void InvalidateEnginePathCache() => EnginePathCache = null;
111
112 /// <summary>
113 /// Get the Unreal Engine path based on an input association text.
114 /// (version, GUID or absolute path)
115 /// </summary>
116 public static AbsolutePath GetEnginePath(string engineAssociation, bool ignoreCache = false)
117 {
118 if (!ignoreCache && EnginePathCache != null) return EnginePathCache;
119
120 IUnrealLocator locator = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
122 : new GenericUnrealLocator();
123
124 Log.Debug("Looking for Unreal Engine installation {0}", engineAssociation);
125
126 EnginePathCache = locator.GetEngine(engineAssociation);
127 Assert.NotNull(EnginePathCache, "Couldn't find Unreal Engine with that association");
128
129 Log.Debug("Found at: {0}", EnginePathCache!);
130 return EnginePathCache!;
131 }
132
133 /// <summary>
134 /// Get high-level version of currently used Engine
135 /// </summary>
136 public static EngineVersion Version(UnrealBuild build) => build.GetEngineVersionFromProject();
137
138 /// <summary>
139 /// Create a compatibility flag mask which indicates that a feature is available un-broken
140 /// in given and the following versions of Unreal Engine
141 /// </summary>
142 public static UnrealCompatibility AndLater(this UnrealCompatibility compatibility)
143 => ~(compatibility - 1);
144
145 /// <summary>
146 /// Are we working with UE4
147 /// </summary>
148 public static bool Is4(UnrealBuild build) => Version(build).SemanticalVersion.Major == 4;
149
150 /// <summary>
151 /// Are we working with UE5
152 /// </summary>
153 public static bool Is5(UnrealBuild build) => Version(build).SemanticalVersion.Major == 5;
154
155 /// <summary>
156 /// Is given path a vanilla engine most probably installed via the Marketplace?
157 /// </summary>
158 public static bool IsInstalled(AbsolutePath enginePath)
159 => (enginePath / "Engine" / "Build" / "InstalledBuild.txt").FileExists();
160
161 /// <summary>
162 /// Are we working with a vanilla engine most probably installed via the Marketplace?
163 /// </summary>
164 public static bool IsInstalled(EngineVersion ofVersion)
165 => IsInstalled(ofVersion.EnginePath);
166
167 /// <summary>
168 /// Are we working with a vanilla engine most probably installed via the Marketplace?
169 /// </summary>
170 public static bool IsInstalled(UnrealBuild build)
171 => IsInstalled(GetEnginePath(build));
172
173 /// <summary>
174 /// Is given path an engine built from source?
175 /// </summary>
176 public static bool IsSource(AbsolutePath enginePath)
177 => !IsInstalled(enginePath);
178
179 /// <summary>
180 /// Are we working with an engine built from source?
181 /// </summary>
182 public static bool IsSource(EngineVersion ofVersion)
183 => IsSource(ofVersion.EnginePath);
184
185 /// <summary>
186 /// Are we working with an engine built from source?
187 /// </summary>
188 public static bool IsSource(UnrealBuild build)
189 => IsSource(GetEnginePath(build));
190
191 public static AbsolutePath GetEnginePath(UnrealBuild build)
192 => Version(build).EnginePath;
193
194 /// <summary>
195 /// Get the current development platform Nuke.Unreal is ran on.
196 /// </summary>
198 {
199 if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
200 return UnrealPlatformFlag.Win64;
201
202 if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
203 return UnrealPlatformFlag.Mac;
204
205 if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
206 return UnrealPlatformFlag.Linux;
207
208 throw new Exception("Attempting to build on an unsupported platform");
209 }
210
211 /// <summary>
212 /// On Mac many Unreal tools need the Mono bootstrap.
213 /// </summary>
214 public static AbsolutePath MacRunMono(EngineVersion ofVersion) =>
215 ofVersion.EnginePath / "Engine" / "Build" / "BatchFiles" / "Mac" / "RunMono.sh";
216
217 /// <summary>Prepare invocation for UBT</summary>
218 /// <returns>A Tool delegate for UBT</returns>
219 public static Tool BuildTool(EngineVersion ofVersion)
220 {
221 var ubtPath = ofVersion.SemanticalVersion.Major >= 5
222 ? ofVersion.EnginePath / "Engine" / "Binaries" / "DotNET" / "UnrealBuildTool" / "UnrealBuildTool.exe"
223 : ofVersion.EnginePath / "Engine" / "Binaries" / "DotNET" / "UnrealBuildTool.exe";
224
225 return ToolResolver.GetTool(ubtPath).WithSemanticLogging();
226
227 // TODO: MacOS: "sh", $"\"{MacRunMono(ofVersion)}\" \"{ubtPath}\" " + arguments
228 // TODO: Linux: "mono", $"\"{ubtPath}\" " + arguments
229 }
230
231 /// <summary>
232 /// Prepare invocation for UBT with extra fluent-API configuration
233 /// </summary>
234 /// <param name="ofVersion"></param>
235 /// <param name="config">
236 /// Auto-generated Configuration facilities mirroring UBT arguments
237 /// </param>
238 /// <returns>A Tool delegate for UBT</returns>
239 public static Tool BuildTool(EngineVersion ofVersion, Action<UbtConfig> config)
240 {
241 var toolConfig = new UbtConfig();
242 config?.Invoke(toolConfig);
243 return BuildTool(ofVersion).With(
244 arguments: $"{toolConfig.Gather(ofVersion):nq}",
245 workingDirectory: ofVersion.EnginePath / "Engine" / "Source",
246 logInvocation: true
247 );
248 }
249
250 /// <summary>Prepare invocation for UBT</summary>
251 /// <returns>A Tool delegate for UBT</returns>
252 public static Tool BuildTool(UnrealBuild build) => BuildTool(Version(build));
253
254 /// <summary>
255 /// Prepare invocation for UBT with extra fluent-API configuration
256 /// </summary>
257 /// <param name="build"></param>
258 /// <param name="config">
259 /// Auto-generated Configuration facilities mirroring UBT arguments
260 /// </param>
261 /// <returns>A Tool delegate for UBT</returns>
262 public static Tool BuildTool(UnrealBuild build, Action<UbtConfig> config) => BuildTool(Version(build), config);
263
264 /// <summary>Prepare invocation for UAT</summary>
265 /// <returns>A Tool delegate for UAT</returns>
266 public static Tool AutomationTool(EngineVersion ofVersion)
267 {
268 var scriptExt = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "bat" : "sh";
269 return ToolResolver.GetTool(ofVersion.EnginePath / "Engine" / "Build" / "BatchFiles" / $"RunUAT.{scriptExt}")
270 .WithSemanticLogging(filter: l =>
271 !(l.Contains("Reading chunk manifest") && l.Contains("which contains 0 entries"))
272 );
273 }
274
275 /// <summary>
276 /// Prepare invocation for UAT with extra fluent-API configuration
277 /// </summary>
278 /// <param name="ofVersion"></param>
279 /// <param name="config">
280 /// Auto-generated Configuration facilities mirroring UAT arguments
281 /// </param>
282 /// <returns>A Tool delegate for UAT</returns>
283 public static Tool AutomationTool(EngineVersion ofVersion, Action<UatConfig> config)
284 {
285 var toolConfig = new UatConfig();
286 config?.Invoke(toolConfig);
287 return AutomationTool(ofVersion).With(
288 arguments: $"{toolConfig.Gather(ofVersion):nq}",
289 workingDirectory: ofVersion.EnginePath / "Engine" / "Source",
290 logInvocation: true
291 );
292 }
293
294 /// <summary>Prepare invocation for UAT</summary>
295 /// <returns>A Tool delegate for UAT</returns>
296 public static Tool AutomationTool(UnrealBuild build) => AutomationTool(Version(build));
297
298 /// <summary>
299 /// Prepare invocation for UAT with extra fluent-API configuration
300 /// </summary>
301 /// <param name="build"></param>
302 /// <param name="config">
303 /// Auto-generated Configuration facilities mirroring UAT arguments
304 /// </param>
305 /// <returns>A Tool delegate for UAT</returns>
306 public static Tool AutomationTool(UnrealBuild build, Action<UatConfig> config) => AutomationTool(Version(build), config);
307
308 /// <summary>
309 /// Clear intermediate folders of Unreal from a given folder
310 /// </summary>
311 public static void ClearFolder(AbsolutePath folder)
312 {
313 (folder / "Intermediate").ExistingDirectory()?.DeleteDirectory();
314 (folder / "Binaries").ExistingDirectory()?.DeleteDirectory();
315 (folder / "DerivedDataCache").ExistingDirectory()?.DeleteDirectory();
316 }
317
318 /// <summary>
319 /// Read copyright info from the project's `DefaultGame.ini`
320 /// </summary>
321 public static string ReadCopyrightFromProject(AbsolutePath projectFolder)
322 {
323 var configPath = projectFolder / "Config" / "DefaultGame.ini";
324 if (!File.Exists(configPath)) return "Fill in Copyright info...";
325
326 var crLine = File.ReadAllLines(configPath)
327 .FirstOrDefault(l => l.StartsWith("CopyrightNotice="));
328
329 if (string.IsNullOrWhiteSpace(crLine)) return "Fill in Copyright info...";
330
331 var crEntry = crLine.Split('=', 2, StringSplitOptions.TrimEntries);
332 if (crEntry.Length < 2) return "Fill in Copyright info...";
333
334 return crEntry[1];
335 }
336
337 /// <summary>
338 /// Get a native binary tool from `Engine/Binaries` folder. Unreal tools written in C# or
339 /// stored in other folders/sub-folders are not supported. You can omit the `Unreal` part
340 /// of the tool name.
341 /// </summary>
342 /// <param name="build"></param>
343 /// <param name="name">You can omit the `Unreal` part of the tool name.</param>
344 /// <returns>A Tool delegate for selected Unreal tool</returns>
345 public static Tool GetTool(UnrealBuild build, string name)
346 {
347 var binaries = GetEnginePath(build) / "Engine" / "Binaries" / GetDefaultPlatform().ToString();
348 var ext = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : "";
349 var path = binaries / (name + ext);
350
351 if (!path.FileExists())
352 path = binaries / ("Unreal" + name + ext);
353
354 Assert.FileExists(path, $"Requested tool {name} doesn't exist.");
355 return ToolResolver.GetTool(path);
356 }
357 }
358}
High level representation of an Unreal Engine version.
Version SemanticalVersion
Semantical version representation of the given Unreal Engine.
AbsolutePath EnginePath
Cached engine path.
An empty Unreal Locator implementation which doesn't know about installed instances,...
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...
A collection of utilities around basic functions regarding the environment of the Engine we're workin...
Definition Unreal.cs:24
static Tool AutomationTool(UnrealBuild build, Action< UatConfig > config)
Prepare invocation for UAT with extra fluent-API configuration.
static bool IsSource(EngineVersion ofVersion)
Are we working with an engine built from source?
static Tool BuildTool(UnrealBuild build, Action< UbtConfig > config)
Prepare invocation for UBT with extra fluent-API configuration.
static void WriteJson(object input, AbsolutePath path)
Write data in JSON with Unreal conventions of JSON format.
Definition Unreal.cs:82
static bool Is4(UnrealBuild build)
Are we working with UE4.
static bool IsSource(UnrealBuild build)
Are we working with an engine built from source?
static Tool AutomationTool(EngineVersion ofVersion)
Prepare invocation for UAT.
Definition Unreal.cs:266
static Tool BuildTool(UnrealBuild build)
Prepare invocation for UBT.
static bool IsInstalled(UnrealBuild build)
Are we working with a vanilla engine most probably installed via the Marketplace?
static Tool BuildTool(EngineVersion ofVersion, Action< UbtConfig > config)
Prepare invocation for UBT with extra fluent-API configuration.
Definition Unreal.cs:239
static AbsolutePath MacRunMono(EngineVersion ofVersion)
On Mac many Unreal tools need the Mono bootstrap.
static Tool GetTool(UnrealBuild 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:345
static bool Is5(UnrealBuild build)
Are we working with UE5.
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 string ReadCopyrightFromProject(AbsolutePath projectFolder)
Read copyright info from the project's DefaultGame.ini
Definition Unreal.cs:321
static Tool BuildTool(EngineVersion ofVersion)
Prepare invocation for UBT.
Definition Unreal.cs:219
static UnrealCompatibility AndLater(this UnrealCompatibility compatibility)
Create a compatibility flag mask which indicates that a feature is available un-broken in given and t...
static readonly JsonSerializerSettings JsonReadSettings
Common JsonSerializerSettings for Unreal conventions of JSON format.
Definition Unreal.cs:69
static Tool AutomationTool(UnrealBuild build)
Prepare invocation for UAT.
static EngineVersion Version(UnrealBuild build)
Get high-level version of currently used Engine.
static UnrealPlatformFlag GetDefaultPlatform()
Get the current development platform Nuke.Unreal is ran on.
Definition Unreal.cs:197
static bool IsInstalled(AbsolutePath enginePath)
Is given path a vanilla engine most probably installed via the Marketplace?
static ? AbsolutePath EnginePathCache
Once the Engine location is found for the current session, it ain't gonna move around,...
Definition Unreal.cs:34
static bool IsInstalled(EngineVersion ofVersion)
Are we working with a vanilla engine most probably installed via the Marketplace?
static void ClearFolder(AbsolutePath folder)
Clear intermediate folders of Unreal from a given folder.
Definition Unreal.cs:311
static readonly? HashSet< AbsolutePath > EngineSearchPaths
Frankly this is not really relevant anymore.
Definition Unreal.cs:28
static AbsolutePath GetEnginePath(string engineAssociation, bool ignoreCache=false)
Get the Unreal Engine path based on an input association text. (version, GUID or absolute path)
Definition Unreal.cs:116
static Tool AutomationTool(EngineVersion ofVersion, Action< UatConfig > config)
Prepare invocation for UAT with extra fluent-API configuration.
Definition Unreal.cs:283
Common interface for locating Unreal Engine instances in different environments.
AbsolutePath? GetEngine(string name)
Get the path to an installed engine by its name or its absolute path.
UnrealPlatformFlag
Bit-field representation of Unreal platforms and platform-families.
UnrealCompatibility
A flag enum representation for checking the Unreal version compatibility of various features....