forked from Unity-Technologies/UnityCsReference
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBuildPlayerWindowBuildMethods.cs
More file actions
391 lines (330 loc) · 18.5 KB
/
Copy pathBuildPlayerWindowBuildMethods.cs
File metadata and controls
391 lines (330 loc) · 18.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
// Unity C# reference source
// Copyright (c) Unity Technologies. For terms of use, see
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
using UnityEditor;
using UnityEditor.Modules;
using UnityEditor.Build;
using UnityEngine;
using UnityEditorInternal;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System;
using UnityEditor.Connect;
namespace UnityEditor
{
public partial class BuildPlayerWindow : EditorWindow
{
static Func<BuildPlayerOptions, BuildPlayerOptions> getBuildPlayerOptionsHandler;
static Action<BuildPlayerOptions> buildPlayerHandler;
static bool m_Building = false;
/// <summary>
/// Exception thrown when an abort or error condition is reached within a build method delegate.
/// </summary>
public class BuildMethodException : System.Exception
{
/// <summary>
/// Constructor for aborting a method without displaying an error.
/// </summary>
public BuildMethodException() : base("") {}
/// <summary>
/// Constructor for aborting on error that will print the log the given message as an error.
/// </summary>
/// <param name="message"></param>
public BuildMethodException(string message) : base(message) {}
}
/// <summary>
/// Register a delegate method to calculate BuildPlayerOptions that are passed to the build process.
/// </summary>
/// <param name="func">Delegate method</param>
public static void RegisterGetBuildPlayerOptionsHandler(Func<BuildPlayerOptions, BuildPlayerOptions> func)
{
// Display a warning if user scripts try to register this delegate multiple times
if (func != null && getBuildPlayerOptionsHandler != null)
Debug.LogWarning("The get build player options handler in BuildPlayerWindow is being reassigned!");
getBuildPlayerOptionsHandler = func;
}
/// <summary>
/// Register a delegate method to execute a player build process.
/// </summary>
/// <param name="func">Delegate method</param>
public static void RegisterBuildPlayerHandler(Action<BuildPlayerOptions> func)
{
// Display a warning if user scripts try to register this delegate multiple times
if (func != null && buildPlayerHandler != null)
Debug.LogWarning("The build player handler in BuildPlayerWindow is being reassigned!");
buildPlayerHandler = func;
}
/// <summary>
/// Method called by the UI when the "Build" or "Build and Run" buttons are pressed.
/// </summary>
/// <param name="defaultBuildOptions"></param>
static void CallBuildMethods(bool askForBuildLocation, BuildOptions defaultBuildOptions)
{
// One build at a time!
if (m_Building)
return;
try
{
m_Building = true;
BuildPlayerOptions options = new BuildPlayerOptions();
options.options = defaultBuildOptions;
if (getBuildPlayerOptionsHandler != null)
options = getBuildPlayerOptionsHandler(options);
else
options = DefaultBuildMethods.GetBuildPlayerOptionsInternal(askForBuildLocation, options);
if (buildPlayerHandler != null)
buildPlayerHandler(options);
else
DefaultBuildMethods.BuildPlayer(options);
}
catch (BuildMethodException e)
{
if (!string.IsNullOrEmpty(e.Message))
Debug.LogError(e);
}
finally
{
m_Building = false;
}
}
/// <summary>
/// Default (legacy) implementation of player window build methods.
/// </summary>
public static class DefaultBuildMethods
{
/// <summary>
/// Default implementation of the build player method.
/// </summary>
/// <param name="options"></param>
public static void BuildPlayer(BuildPlayerOptions options)
{
if (!UnityConnect.instance.canBuildWithUPID)
{
if (!EditorUtility.DisplayDialog("Missing Project ID", "Because you are not a member of this project this build will not access Unity services.\nDo you want to continue?", "Yes", "No"))
throw new BuildMethodException();
}
if (!BuildPipeline.IsBuildTargetSupported(options.targetGroup, options.target))
throw new BuildMethodException("Build target is not supported.");
string module = ModuleManager.GetTargetStringFrom(EditorUserBuildSettings.selectedBuildTargetGroup, options.target);
IBuildWindowExtension buildWindowExtension = ModuleManager.GetBuildWindowExtension(module);
if (buildWindowExtension != null && (options.options & BuildOptions.AutoRunPlayer) != 0 && !buildWindowExtension.EnabledBuildAndRunButton())
throw new BuildMethodException();
if (Unsupported.IsBleedingEdgeBuild())
{
var sb = new System.Text.StringBuilder();
sb.AppendLine("This version of Unity is a BleedingEdge build that has not seen any manual testing.");
sb.AppendLine("You should consider this build unstable.");
sb.AppendLine("We strongly recommend that you use a normal version of Unity instead.");
if (EditorUtility.DisplayDialog("BleedingEdge Build", sb.ToString(), "Cancel", "OK"))
throw new BuildMethodException();
}
// See if we need to switch platforms and delay the build. We do this whenever
// we're trying to build for a target different from the active one so as to ensure
// that the compiled script code we have loaded is built for the same platform we
// are building for. As we can't reload while our editor stuff is still executing,
// we need to defer to after the next script reload then.
bool delayToAfterScriptReload = false;
if (EditorUserBuildSettings.activeBuildTarget != options.target ||
EditorUserBuildSettings.activeBuildTargetGroup != options.targetGroup)
{
if (!EditorUserBuildSettings.SwitchActiveBuildTargetAsync(options.targetGroup, options.target))
{
// Switching the build target failed. No point in trying to continue
// with a build.
var errStr = string.Format("Could not switch to build target '{0}', '{1}'.",
BuildPipeline.GetBuildTargetGroupDisplayName(options.targetGroup),
BuildPlatforms.instance.GetBuildTargetDisplayName(options.targetGroup, options.target));
throw new BuildMethodException(errStr);
}
if (EditorApplication.isCompiling)
delayToAfterScriptReload = true;
}
// Trigger build.
// Note: report will be null, if delayToAfterScriptReload = true
var report = BuildPipeline.BuildPlayerInternalNoCheck(options.scenes, options.locationPathName, null, options.targetGroup, options.target, options.options, delayToAfterScriptReload);
if (report != null)
{
var resultStr = String.Format("Build completed with a result of '{0}'", report.buildResult.ToString("g"));
switch (report.buildResult)
{
case BuildReporting.BuildResult.Unknown:
Debug.LogWarning(resultStr);
break;
case BuildReporting.BuildResult.Failed:
Debug.LogError(resultStr);
throw new BuildMethodException(report.SummarizeErrors());
default:
Debug.Log(resultStr);
break;
}
}
}
/// <summary>
/// Default implementation for calculating build options before building the player.
/// </summary>
/// <param name="defaultBuildPlayerOptions"></param>
/// <returns></returns>
public static BuildPlayerOptions GetBuildPlayerOptions(BuildPlayerOptions defaultBuildPlayerOptions)
{
return GetBuildPlayerOptionsInternal(true, defaultBuildPlayerOptions);
}
internal static BuildPlayerOptions GetBuildPlayerOptionsInternal(bool askForBuildLocation, BuildPlayerOptions defaultBuildPlayerOptions)
{
var options = defaultBuildPlayerOptions;
bool updateExistingBuild = false;
BuildTarget buildTarget = CalculateSelectedBuildTarget();
BuildTargetGroup buildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
// Pick location for the build
string newLocation = "";
bool installInBuildFolder = EditorUserBuildSettings.installInBuildFolder && PostprocessBuildPlayer.SupportsInstallInBuildFolder(buildTargetGroup, buildTarget) && (Unsupported.IsDeveloperBuild()
|| IsMetroPlayer(buildTarget));
//Check if Lz4 is supported for the current buildtargetgroup and enable it if need be
if (PostprocessBuildPlayer.SupportsLz4Compression(buildTargetGroup, buildTarget))
{
if (EditorUserBuildSettings.GetCompressionType(buildTargetGroup) == Compression.Lz4)
options.options |= BuildOptions.CompressWithLz4;
else if (EditorUserBuildSettings.GetCompressionType(buildTargetGroup) == Compression.Lz4HC)
options.options |= BuildOptions.CompressWithLz4HC;
}
bool developmentBuild = EditorUserBuildSettings.development;
if (developmentBuild)
options.options |= BuildOptions.Development;
if (EditorUserBuildSettings.allowDebugging && developmentBuild)
options.options |= BuildOptions.AllowDebugging;
if (EditorUserBuildSettings.symlinkLibraries)
options.options |= BuildOptions.SymlinkLibraries;
if (buildTarget == BuildTarget.Android)
{
if (EditorUserBuildSettings.exportAsGoogleAndroidProject)
options.options |= BuildOptions.AcceptExternalModificationsToPlayer;
}
if (EditorUserBuildSettings.enableHeadlessMode)
options.options |= BuildOptions.EnableHeadlessMode;
if (EditorUserBuildSettings.connectProfiler && (developmentBuild || buildTarget == BuildTarget.WSAPlayer))
options.options |= BuildOptions.ConnectWithProfiler;
if (EditorUserBuildSettings.buildScriptsOnly)
options.options |= BuildOptions.BuildScriptsOnly;
if (installInBuildFolder)
options.options |= BuildOptions.InstallInBuildFolder;
if (!installInBuildFolder)
{
if (askForBuildLocation && !PickBuildLocation(buildTargetGroup, buildTarget, options.options, out updateExistingBuild))
throw new BuildMethodException();
newLocation = EditorUserBuildSettings.GetBuildLocation(buildTarget);
if (newLocation.Length == 0)
{
throw new BuildMethodException("Build location for buildTarget " + buildTarget.ToString() + "is not valid.");
}
if (!askForBuildLocation)
{
switch (UnityEditorInternal.InternalEditorUtility.BuildCanBeAppended(buildTarget, newLocation))
{
case CanAppendBuild.Unsupported:
break;
case CanAppendBuild.Yes:
updateExistingBuild = true;
break;
case CanAppendBuild.No:
if (!PickBuildLocation(buildTargetGroup, buildTarget, options.options, out updateExistingBuild))
throw new BuildMethodException();
newLocation = EditorUserBuildSettings.GetBuildLocation(buildTarget);
if (!BuildLocationIsValid(newLocation))
throw new BuildMethodException("Build location for buildTarget " + buildTarget.ToString() + "is not valid.");
break;
}
}
}
if (updateExistingBuild)
options.options |= BuildOptions.AcceptExternalModificationsToPlayer;
options.target = buildTarget;
options.targetGroup = buildTargetGroup;
options.locationPathName = EditorUserBuildSettings.GetBuildLocation(buildTarget);
options.assetBundleManifestPath = null;
// Build a list of scenes that are enabled
ArrayList scenesList = new ArrayList();
EditorBuildSettingsScene[] editorScenes = EditorBuildSettings.scenes;
foreach (EditorBuildSettingsScene scene in editorScenes)
{
if (scene.enabled)
scenesList.Add(scene.path);
}
options.scenes = scenesList.ToArray(typeof(string)) as string[];
return options;
}
static bool PickBuildLocation(BuildTargetGroup targetGroup, BuildTarget target, BuildOptions options, out bool updateExistingBuild)
{
updateExistingBuild = false;
var previousPath = EditorUserBuildSettings.GetBuildLocation(target);
string defaultFolder;
string defaultName;
if (previousPath == String.Empty)
{
defaultFolder = FileUtil.DeleteLastPathNameComponent(Application.dataPath);
defaultName = "";
}
else
{
defaultFolder = FileUtil.DeleteLastPathNameComponent(previousPath);
defaultName = FileUtil.GetLastPathNameComponent(previousPath);
}
// When exporting Eclipse project, we're saving a folder, not file,
// deal with it separately:
if (target == BuildTarget.Android
&& EditorUserBuildSettings.exportAsGoogleAndroidProject)
{
var exportProjectTitle = "Export Google Android Project";
var exportProjectFolder = EditorUtility.SaveFolderPanel(exportProjectTitle, previousPath, "");
if (exportProjectFolder == String.Empty)
return false;
EditorUserBuildSettings.SetBuildLocation(target, exportProjectFolder);
return true;
}
string extension = PostprocessBuildPlayer.GetExtensionForBuildTarget(targetGroup, target, options);
string title = "Build " + BuildPlatforms.instance.GetBuildTargetDisplayName(targetGroup, target);
string path = EditorUtility.SaveBuildPanel(target, title, defaultFolder, defaultName, extension, out updateExistingBuild);
if (path == string.Empty)
return false;
// Enforce extension if needed
if (extension != string.Empty && FileUtil.GetPathExtension(path).ToLower() != extension)
path += '.' + extension;
// A path may not be empty initially, but it could contain, e.g., a drive letter (as in Windows),
// so even appending an extention will work fine, but in reality the name will be, for example,
// G:/
//Debug.Log(path);
string currentlyChosenName = FileUtil.GetLastPathNameComponent(path);
if (currentlyChosenName == string.Empty)
return false; // No nameless projects, please
// We don't want to re-create a directory that already exists, this may
// result in access-denials that will make users unhappy.
string check_dir = extension != string.Empty ? FileUtil.DeleteLastPathNameComponent(path) : path;
if (!Directory.Exists(check_dir))
Directory.CreateDirectory(check_dir);
// On OSX we've got replace/update dialog, for other platforms warn about deleting
// files in target folder.
if ((target == BuildTarget.iOS) && (Application.platform != RuntimePlatform.OSXEditor))
if (!FolderIsEmpty(path) && !UserWantsToDeleteFiles(path))
return false;
EditorUserBuildSettings.SetBuildLocation(target, path);
return true;
}
static bool FolderIsEmpty(string path)
{
if (!Directory.Exists(path))
return true;
return (Directory.GetDirectories(path).Length == 0)
&& (Directory.GetFiles(path).Length == 0);
}
static bool UserWantsToDeleteFiles(string path)
{
string text =
"WARNING: all files and folders located in target folder: '" + path + "' will be deleted by build process.";
return EditorUtility.DisplayDialog("Deleting existing files", text, "OK", "Cancel");
}
static bool IsMetroPlayer(BuildTarget target)
{
return target == BuildTarget.WSAPlayer;
}
}
}
}