app.hypergames.hypersdk 1.8.13 → 1.8.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,840 @@
1
+ #if UNITY_EDITOR
2
+ using System;
3
+ using System.IO;
4
+ using UnityEditor;
5
+ using UnityEditor.Build;
6
+ using UnityEditor.Build.Reporting;
7
+ using UnityEditor.SceneManagement;
8
+ using UnityEngine;
9
+ using UnityEngine.SceneManagement;
10
+ using Hyper.Internal;
11
+
12
+ namespace Hyper.Editor
13
+ {
14
+ internal enum HyperBuildProfile
15
+ {
16
+ Development,
17
+ Release
18
+ }
19
+
20
+ internal sealed class HyperBuildRequest
21
+ {
22
+ public HyperBuildProfile Profile { get; set; }
23
+ public string OutputPath { get; set; } = "";
24
+ public bool CleanOutputFolder { get; set; } = true;
25
+ public bool OpenOutputFolder { get; set; } = false;
26
+ public bool IsCliBuild { get; set; } = false;
27
+ }
28
+
29
+ internal sealed class HyperBuildResult
30
+ {
31
+ public bool Succeeded { get; set; }
32
+ public BuildResult BuildResult { get; set; } = BuildResult.Unknown;
33
+ public string OutputPath { get; set; } = "";
34
+ public string Message { get; set; } = "";
35
+ public long TotalSizeBytes { get; set; }
36
+ }
37
+
38
+ internal static class HyperBuildPipeline
39
+ {
40
+ internal static HyperGameContentConfig _gameContentConfig;
41
+ internal static HyperSDKSettings _sdkSettings;
42
+ private const string ReleaseDefine = "HYPER_RELEASE_BUILD";
43
+ private const string DevelopmentDefine = "HYPER_DEVELOPMENT_BUILD";
44
+
45
+ private struct BuildSettingsSnapshot
46
+ {
47
+ public bool HasCodeOptimization;
48
+ public object CodeOptimizationValue;
49
+
50
+ public bool HasDebugSymbolMode;
51
+ public object DebugSymbolModeValue;
52
+
53
+ public bool HasExceptionSupport;
54
+ public WebGLExceptionSupport ExceptionSupportValue;
55
+
56
+ public bool HasIl2CppCodeGeneration;
57
+ public Il2CppCodeGeneration Il2CppCodeGenerationValue;
58
+ }
59
+
60
+ internal static HyperBuildResult Build(HyperBuildRequest request)
61
+ {
62
+ if (request == null)
63
+ {
64
+ return Fail("Build request is null.");
65
+ }
66
+
67
+ if (string.IsNullOrWhiteSpace(request.OutputPath))
68
+ {
69
+ return Fail("Build output path is missing.");
70
+ }
71
+
72
+ if (EditorApplication.isCompiling)
73
+ {
74
+ return Fail("Unity is compiling. Please wait for compilation to finish before building.");
75
+ }
76
+
77
+ if (!ValidateConfigurationAssets(request.Profile))
78
+ {
79
+ return Fail("Configuration assets are not valid. Please configure the Hyper SDK assets correctly.");
80
+ }
81
+
82
+ HyperBuildAssistant.ClearBuildInfo();
83
+ HyperBuildAssistant.ResetOptimizationSummary();
84
+
85
+ BuildSettingsSnapshot settingsSnapshot = CaptureBuildSettingsSnapshot();
86
+
87
+ try
88
+ {
89
+ PrepareBuildOutputDirectory(request.OutputPath, request.CleanOutputFolder);
90
+
91
+ ForceAssetRepack();
92
+
93
+ ApplyProfileSettings(request.Profile);
94
+
95
+ BuildPlayerOptions buildOptions = new BuildPlayerOptions
96
+ {
97
+ scenes = GetEnabledScenes(),
98
+ locationPathName = request.OutputPath,
99
+ target = BuildTarget.WebGL,
100
+ options = BuildOptions.DetailedBuildReport
101
+ };
102
+
103
+ string profileLabel = request.Profile == HyperBuildProfile.Development
104
+ ? "Development"
105
+ : "Release";
106
+
107
+ HyperDebug.Action($"Starting {profileLabel} Build to: {request.OutputPath}");
108
+
109
+ BuildReport report = BuildPipeline.BuildPlayer(buildOptions);
110
+
111
+ bool succeeded = report.summary.result == BuildResult.Succeeded;
112
+
113
+ if (succeeded)
114
+ {
115
+ HyperDebug.LogSuccess($"{profileLabel} build completed successfully");
116
+
117
+ HyperBuildAssistant.UpdateBuildInfo(request.OutputPath, report);
118
+
119
+ if (request.OpenOutputFolder)
120
+ {
121
+ HyperBuildAssistant.OpenBuildOutputFolder(request.OutputPath);
122
+ }
123
+
124
+ return new HyperBuildResult
125
+ {
126
+ Succeeded = true,
127
+ BuildResult = report.summary.result,
128
+ OutputPath = request.OutputPath,
129
+ TotalSizeBytes = (long)report.summary.totalSize,
130
+ Message = $"{profileLabel} build completed successfully."
131
+ };
132
+ }
133
+
134
+ HyperDebug.LogError($"{profileLabel} build failed: {report.summary.result}");
135
+
136
+ HyperBuildAssistant.UpdateBuildInfo(request.OutputPath, null);
137
+
138
+ return new HyperBuildResult
139
+ {
140
+ Succeeded = false,
141
+ BuildResult = report.summary.result,
142
+ OutputPath = request.OutputPath,
143
+ TotalSizeBytes = (long)report.summary.totalSize,
144
+ Message = $"{profileLabel} build failed: {report.summary.result}"
145
+ };
146
+ }
147
+ catch (Exception ex)
148
+ {
149
+ HyperDebug.LogError($"Hyper build failed: {ex.Message}\n{ex.StackTrace}");
150
+
151
+ HyperBuildAssistant.UpdateBuildInfo(request.OutputPath, null);
152
+
153
+ return new HyperBuildResult
154
+ {
155
+ Succeeded = false,
156
+ BuildResult = BuildResult.Failed,
157
+ OutputPath = request.OutputPath,
158
+ Message = ex.Message
159
+ };
160
+ }
161
+ finally
162
+ {
163
+ RestoreBuildSettingsSnapshot(settingsSnapshot);
164
+ }
165
+ }
166
+
167
+ private static HyperBuildResult Fail(string message)
168
+ {
169
+ HyperDebug.LogError(message);
170
+
171
+ return new HyperBuildResult
172
+ {
173
+ Succeeded = false,
174
+ BuildResult = BuildResult.Failed,
175
+ Message = message
176
+ };
177
+ }
178
+
179
+ private static void PrepareBuildOutputDirectory(string outputPath, bool cleanOutputFolder)
180
+ {
181
+ if (!cleanOutputFolder)
182
+ {
183
+ return;
184
+ }
185
+
186
+ if (!Directory.Exists(outputPath))
187
+ {
188
+ return;
189
+ }
190
+
191
+ try
192
+ {
193
+ Directory.Delete(outputPath, true);
194
+
195
+ if (HyperBuildAssistant.IsSDKDeveloper())
196
+ {
197
+ HyperDebug.Log($"Cleaned existing build folder: {outputPath}");
198
+ }
199
+ }
200
+ catch (Exception ex)
201
+ {
202
+ HyperDebug.LogWarning($"Could not clean build folder: {ex.Message}");
203
+ }
204
+ }
205
+
206
+ private static void ApplyProfileSettings(HyperBuildProfile profile)
207
+ {
208
+ switch (profile)
209
+ {
210
+ case HyperBuildProfile.Development:
211
+ SetBuildDefineSymbols(isRelease: false);
212
+ ApplyDevelopmentBuildSettings();
213
+ break;
214
+
215
+ case HyperBuildProfile.Release:
216
+ SetBuildDefineSymbols(isRelease: true);
217
+ HyperBuildAssistant.AddOptimizationSummary("Runtime: Unity debug logger disabled in player (HYPER_RELEASE_BUILD)");
218
+ ApplyReleaseBuildSettings();
219
+ break;
220
+
221
+ default:
222
+ throw new ArgumentOutOfRangeException(nameof(profile), profile, "Unknown Hyper build profile.");
223
+ }
224
+ }
225
+
226
+ private static BuildSettingsSnapshot CaptureBuildSettingsSnapshot()
227
+ {
228
+ var snapshot = new BuildSettingsSnapshot();
229
+
230
+ try
231
+ {
232
+ Type webglType = typeof(PlayerSettings.WebGL);
233
+
234
+ var codeOptProp = webglType.GetProperty("codeOptimization");
235
+ if (codeOptProp != null)
236
+ {
237
+ snapshot.CodeOptimizationValue = codeOptProp.GetValue(null);
238
+ snapshot.HasCodeOptimization = true;
239
+ }
240
+
241
+ var debugSymbolProp = webglType.GetProperty("debugSymbolMode");
242
+ if (debugSymbolProp != null)
243
+ {
244
+ snapshot.DebugSymbolModeValue = debugSymbolProp.GetValue(null);
245
+ snapshot.HasDebugSymbolMode = true;
246
+ }
247
+ }
248
+ catch (Exception ex)
249
+ {
250
+ HyperDebug.LogWarning($"Could not capture code optimization/debug symbols: {ex.Message}");
251
+ }
252
+
253
+ try
254
+ {
255
+ snapshot.ExceptionSupportValue = PlayerSettings.WebGL.exceptionSupport;
256
+ snapshot.HasExceptionSupport = true;
257
+ }
258
+ catch (Exception ex)
259
+ {
260
+ HyperDebug.LogWarning($"Could not capture exception support: {ex.Message}");
261
+ }
262
+
263
+ try
264
+ {
265
+ snapshot.Il2CppCodeGenerationValue = PlayerSettings.GetIl2CppCodeGeneration(NamedBuildTarget.WebGL);
266
+ snapshot.HasIl2CppCodeGeneration = true;
267
+ }
268
+ catch (Exception ex)
269
+ {
270
+ HyperDebug.LogWarning($"Could not capture IL2CPP code generation: {ex.Message}");
271
+ }
272
+
273
+ return snapshot;
274
+ }
275
+
276
+ private static void RestoreBuildSettingsSnapshot(BuildSettingsSnapshot snapshot)
277
+ {
278
+ try
279
+ {
280
+ Type webglType = typeof(PlayerSettings.WebGL);
281
+
282
+ if (snapshot.HasCodeOptimization)
283
+ {
284
+ var codeOptProp = webglType.GetProperty("codeOptimization");
285
+ codeOptProp?.SetValue(null, snapshot.CodeOptimizationValue);
286
+ }
287
+
288
+ if (snapshot.HasDebugSymbolMode)
289
+ {
290
+ var debugSymbolProp = webglType.GetProperty("debugSymbolMode");
291
+ debugSymbolProp?.SetValue(null, snapshot.DebugSymbolModeValue);
292
+ }
293
+ }
294
+ catch (Exception ex)
295
+ {
296
+ HyperDebug.LogWarning($"Could not restore code optimization/debug symbols: {ex.Message}");
297
+ }
298
+
299
+ try
300
+ {
301
+ if (snapshot.HasExceptionSupport)
302
+ {
303
+ PlayerSettings.WebGL.exceptionSupport = snapshot.ExceptionSupportValue;
304
+ }
305
+ }
306
+ catch (Exception ex)
307
+ {
308
+ HyperDebug.LogWarning($"Could not restore exception support: {ex.Message}");
309
+ }
310
+
311
+ try
312
+ {
313
+ if (snapshot.HasIl2CppCodeGeneration)
314
+ {
315
+ PlayerSettings.SetIl2CppCodeGeneration(NamedBuildTarget.WebGL, snapshot.Il2CppCodeGenerationValue);
316
+ }
317
+ }
318
+ catch (Exception ex)
319
+ {
320
+ HyperDebug.LogWarning($"Could not restore IL2CPP code generation: {ex.Message}");
321
+ }
322
+
323
+ AssetDatabase.Refresh();
324
+ }
325
+
326
+ private static void ApplyDevelopmentBuildSettings()
327
+ {
328
+ try
329
+ {
330
+ Type webglType = typeof(PlayerSettings.WebGL);
331
+ var codeOptProp = webglType.GetProperty("codeOptimization");
332
+
333
+ if (codeOptProp != null)
334
+ {
335
+ Type enumType = codeOptProp.PropertyType;
336
+ object shorterBuildValue = Enum.Parse(enumType, "ShorterBuildTime");
337
+ codeOptProp.SetValue(null, shorterBuildValue);
338
+
339
+ HyperBuildAssistant.AddOptimizationSummary("Code Optimization → Shorter Build Time");
340
+
341
+ if (HyperBuildAssistant.IsSDKDeveloper())
342
+ {
343
+ HyperDebug.LogSuccess("Development build: Code Optimization → Shorter Build Time");
344
+ }
345
+ }
346
+ }
347
+ catch (Exception ex)
348
+ {
349
+ HyperDebug.LogWarning($"Could not set Code Optimization: {ex.Message}");
350
+ }
351
+
352
+ try
353
+ {
354
+ Type webglType = typeof(PlayerSettings.WebGL);
355
+ var debugSymbolModeProp = webglType.GetProperty("debugSymbolMode");
356
+
357
+ if (debugSymbolModeProp != null)
358
+ {
359
+ object embeddedValue = Enum.ToObject(debugSymbolModeProp.PropertyType, 2);
360
+ debugSymbolModeProp.SetValue(null, embeddedValue);
361
+
362
+ HyperBuildAssistant.AddOptimizationSummary("Debug Symbols → Embedded");
363
+
364
+ if (HyperBuildAssistant.IsSDKDeveloper())
365
+ {
366
+ HyperDebug.LogSuccess("Development build: Debug Symbols → Embedded");
367
+ }
368
+ }
369
+ }
370
+ catch (Exception ex)
371
+ {
372
+ HyperDebug.LogWarning($"Could not set Debug Symbols: {ex.Message}");
373
+ }
374
+
375
+ try
376
+ {
377
+ PlayerSettings.WebGL.exceptionSupport = WebGLExceptionSupport.FullWithoutStacktrace;
378
+ HyperBuildAssistant.AddOptimizationSummary("Exception Support → Full Without Stacktrace");
379
+
380
+ if (HyperBuildAssistant.IsSDKDeveloper())
381
+ {
382
+ HyperDebug.LogSuccess("Development build: Exception Support → Full Without Stacktrace");
383
+ }
384
+ }
385
+ catch (Exception ex)
386
+ {
387
+ HyperDebug.LogWarning($"Could not set Exception Support: {ex.Message}");
388
+ }
389
+
390
+ HyperBuildAssistant.AddOptimizationSummary("Unity Development Build flag NOT used (keeps Brotli compression)");
391
+ HyperBuildAssistant.AddOptimizationSummary("Using Hyper dev API URL");
392
+
393
+ if (HyperBuildAssistant.IsSDKDeveloper())
394
+ {
395
+ HyperDebug.Log("Development build settings applied: Fast iteration with Brotli compression");
396
+ }
397
+ }
398
+
399
+ private static void ApplyReleaseBuildSettings()
400
+ {
401
+ string currentCodeOpt = "";
402
+
403
+ try
404
+ {
405
+ Type webglType = typeof(PlayerSettings.WebGL);
406
+ var codeOptProp = webglType.GetProperty("codeOptimization");
407
+
408
+ if (codeOptProp != null)
409
+ {
410
+ object value = codeOptProp.GetValue(null);
411
+ if (value != null)
412
+ {
413
+ currentCodeOpt = value.ToString();
414
+ }
415
+ }
416
+ }
417
+ catch (Exception ex)
418
+ {
419
+ HyperDebug.LogWarning($"Could not read current Code Optimization setting: {ex.Message}");
420
+ }
421
+
422
+ bool isShorterBuildTime = !string.IsNullOrEmpty(currentCodeOpt) &&
423
+ currentCodeOpt.Contains("ShorterBuildTime");
424
+
425
+ if (isShorterBuildTime)
426
+ {
427
+ if (HyperBuildAssistant.IsSDKDeveloper())
428
+ {
429
+ HyperDebug.Log("Release build: Respecting developer's 'Shorter Build Time' choice - no Code Optimization changes applied.");
430
+ }
431
+
432
+ return;
433
+ }
434
+
435
+ bool isRuntimePreference = !string.IsNullOrEmpty(currentCodeOpt) &&
436
+ (currentCodeOpt.Contains("Runtime") || currentCodeOpt.Contains("Faster"));
437
+
438
+ bool isDiskPreference = !string.IsNullOrEmpty(currentCodeOpt) &&
439
+ (currentCodeOpt.Contains("DiskSize") || currentCodeOpt.Contains("Disk"));
440
+
441
+ bool wantsDiskSize = isDiskPreference ||
442
+ string.IsNullOrEmpty(currentCodeOpt) ||
443
+ (!isRuntimePreference && !isDiskPreference);
444
+
445
+ try
446
+ {
447
+ Type webglType = typeof(PlayerSettings.WebGL);
448
+ var codeOptProp = webglType.GetProperty("codeOptimization");
449
+
450
+ if (codeOptProp != null)
451
+ {
452
+ Type enumType = codeOptProp.PropertyType;
453
+ string[] enumNames = Enum.GetNames(enumType);
454
+
455
+ string targetValue = wantsDiskSize
456
+ ? Array.IndexOf(enumNames, "DiskSizeLTO") >= 0 ? "DiskSizeLTO" : "DiskSize"
457
+ : Array.IndexOf(enumNames, "FasterRuntimeLTO") >= 0 ? "FasterRuntimeLTO" : "FasterRuntime";
458
+
459
+ object enumValue = Enum.Parse(enumType, targetValue);
460
+ codeOptProp.SetValue(null, enumValue);
461
+
462
+ HyperBuildAssistant.AddOptimizationSummary($"Code Optimization → {targetValue}");
463
+
464
+ if (HyperBuildAssistant.IsSDKDeveloper())
465
+ {
466
+ HyperDebug.LogSuccess($"Release build: Code Optimization → {targetValue}");
467
+ }
468
+ }
469
+ }
470
+ catch (Exception ex)
471
+ {
472
+ HyperDebug.LogWarning($"Could not set Code Optimization: {ex.Message}");
473
+ }
474
+
475
+ try
476
+ {
477
+ if (wantsDiskSize)
478
+ {
479
+ PlayerSettings.SetIl2CppCodeGeneration(NamedBuildTarget.WebGL, Il2CppCodeGeneration.OptimizeSize);
480
+ HyperBuildAssistant.AddOptimizationSummary("IL2CPP Code Generation → Optimize Size");
481
+
482
+ if (HyperBuildAssistant.IsSDKDeveloper())
483
+ {
484
+ HyperDebug.LogSuccess("Release build: IL2CPP Code Generation → Optimize Size");
485
+ }
486
+ }
487
+ else
488
+ {
489
+ PlayerSettings.SetIl2CppCodeGeneration(NamedBuildTarget.WebGL, Il2CppCodeGeneration.OptimizeSpeed);
490
+ HyperBuildAssistant.AddOptimizationSummary("IL2CPP Code Generation → Optimize Speed");
491
+
492
+ if (HyperBuildAssistant.IsSDKDeveloper())
493
+ {
494
+ HyperDebug.LogSuccess("Release build: IL2CPP Code Generation → Optimize Speed");
495
+ }
496
+ }
497
+ }
498
+ catch (Exception)
499
+ {
500
+ HyperDebug.LogWarning("IL2CPP code generation setting not available in this Unity version");
501
+ }
502
+ }
503
+
504
+ private static void SetBuildDefineSymbols(bool isRelease)
505
+ {
506
+ try
507
+ {
508
+ string defines = PlayerSettings.GetScriptingDefineSymbols(NamedBuildTarget.WebGL);
509
+
510
+ bool hasReleaseDefine = HasDefine(defines, ReleaseDefine);
511
+ bool hasDevelopmentDefine = HasDefine(defines, DevelopmentDefine);
512
+
513
+ if (isRelease)
514
+ {
515
+ if (!hasReleaseDefine)
516
+ {
517
+ defines = AddDefine(defines, ReleaseDefine);
518
+ HyperDebug.LogSuccess("Set HYPER_RELEASE_BUILD (production API URL; Unity debug logger off in player)");
519
+ }
520
+
521
+ if (hasDevelopmentDefine)
522
+ {
523
+ defines = RemoveDefine(defines, DevelopmentDefine);
524
+ HyperDebug.LogSuccess("Removed HYPER_DEVELOPMENT_BUILD define symbol for release build");
525
+ }
526
+ }
527
+ else
528
+ {
529
+ if (hasReleaseDefine)
530
+ {
531
+ defines = RemoveDefine(defines, ReleaseDefine);
532
+ HyperDebug.LogSuccess("Removed HYPER_RELEASE_BUILD define symbol for dev API URL");
533
+ }
534
+
535
+ if (!hasDevelopmentDefine)
536
+ {
537
+ defines = AddDefine(defines, DevelopmentDefine);
538
+ HyperDebug.LogSuccess("Set HYPER_DEVELOPMENT_BUILD define symbol for development build");
539
+ }
540
+ }
541
+
542
+ PlayerSettings.SetScriptingDefineSymbols(NamedBuildTarget.WebGL, defines);
543
+ }
544
+ catch (Exception ex)
545
+ {
546
+ HyperDebug.LogWarning($"Could not set Hyper build define symbols: {ex.Message}");
547
+ }
548
+ }
549
+
550
+ private static bool HasDefine(string defines, string targetDefine)
551
+ {
552
+ if (string.IsNullOrWhiteSpace(defines))
553
+ return false;
554
+
555
+ string[] splitDefines = defines.Split(';');
556
+
557
+ foreach (string define in splitDefines)
558
+ {
559
+ if (define.Trim() == targetDefine)
560
+ return true;
561
+ }
562
+
563
+ return false;
564
+ }
565
+
566
+ private static string AddDefine(string defines, string targetDefine)
567
+ {
568
+ if (string.IsNullOrWhiteSpace(defines))
569
+ return targetDefine;
570
+
571
+ if (HasDefine(defines, targetDefine))
572
+ return defines;
573
+
574
+ return $"{defines};{targetDefine}";
575
+ }
576
+
577
+ private static string RemoveDefine(string defines, string targetDefine)
578
+ {
579
+ if (string.IsNullOrWhiteSpace(defines))
580
+ return "";
581
+
582
+ string[] splitDefines = defines.Split(';');
583
+ string cleaned = "";
584
+
585
+ foreach (string define in splitDefines)
586
+ {
587
+ string trimmed = define.Trim();
588
+
589
+ if (string.IsNullOrWhiteSpace(trimmed))
590
+ continue;
591
+
592
+ if (trimmed == targetDefine)
593
+ continue;
594
+
595
+ cleaned = string.IsNullOrEmpty(cleaned)
596
+ ? trimmed
597
+ : $"{cleaned};{trimmed}";
598
+ }
599
+
600
+ return cleaned;
601
+ }
602
+
603
+ private static string[] GetEnabledScenes()
604
+ {
605
+ var scenes = new System.Collections.Generic.List<string>();
606
+
607
+ foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes)
608
+ {
609
+ if (scene.enabled)
610
+ {
611
+ scenes.Add(scene.path);
612
+ }
613
+ }
614
+
615
+ return scenes.ToArray();
616
+ }
617
+
618
+ private static void ForceAssetRepack()
619
+ {
620
+ const string hyperLoaderScenePath = HyperConstants.HYPER_LOADER_SCENE_PATH;
621
+ const string markerPrefix = "__HyperSDK_BuildMarker";
622
+
623
+ if (HyperBuildAssistant.IsSDKDeveloper())
624
+ {
625
+ HyperDebug.Log("ForceAssetRepack() called");
626
+ }
627
+
628
+ try
629
+ {
630
+ Scene hyperLoaderScene = EditorSceneManager.GetSceneByPath(hyperLoaderScenePath);
631
+ bool sceneWasLoaded = hyperLoaderScene.IsValid() && hyperLoaderScene.isLoaded;
632
+
633
+ if (!sceneWasLoaded)
634
+ {
635
+ hyperLoaderScene = EditorSceneManager.OpenScene(hyperLoaderScenePath, OpenSceneMode.Additive);
636
+ }
637
+
638
+ GameObject markerObject = FindMarkerObject(hyperLoaderScene, markerPrefix);
639
+
640
+ if (markerObject == null)
641
+ {
642
+ markerObject = new GameObject(markerPrefix);
643
+
644
+ if (hyperLoaderScene.rootCount > 0)
645
+ {
646
+ markerObject.transform.SetParent(hyperLoaderScene.GetRootGameObjects()[0].transform, false);
647
+ }
648
+
649
+ EditorSceneManager.MoveGameObjectToScene(markerObject, hyperLoaderScene);
650
+ }
651
+
652
+ string newName = $"{markerPrefix}_{DateTime.Now.Ticks}";
653
+ markerObject.name = newName;
654
+
655
+ EditorSceneManager.MarkSceneDirty(hyperLoaderScene);
656
+ EditorSceneManager.SaveScene(hyperLoaderScene);
657
+
658
+ if (HyperBuildAssistant.IsSDKDeveloper())
659
+ {
660
+ HyperDebug.Log($"Renamed build marker to '{newName}'");
661
+ }
662
+
663
+ if (!sceneWasLoaded)
664
+ {
665
+ EditorSceneManager.CloseScene(hyperLoaderScene, true);
666
+ }
667
+ }
668
+ catch (Exception ex)
669
+ {
670
+ HyperDebug.LogWarning($"Could not force asset repack: {ex.Message}");
671
+ }
672
+ }
673
+
674
+ private static GameObject FindMarkerObject(Scene scene, string markerPrefix)
675
+ {
676
+ foreach (GameObject root in scene.GetRootGameObjects())
677
+ {
678
+ Transform marker = FindMarkerRecursive(root.transform, markerPrefix);
679
+
680
+ if (marker != null)
681
+ {
682
+ return marker.gameObject;
683
+ }
684
+ }
685
+
686
+ return null;
687
+ }
688
+
689
+ private static Transform FindMarkerRecursive(Transform parent, string markerPrefix)
690
+ {
691
+ if (parent.name.StartsWith(markerPrefix, StringComparison.Ordinal))
692
+ {
693
+ return parent;
694
+ }
695
+
696
+ foreach (Transform child in parent)
697
+ {
698
+ Transform result = FindMarkerRecursive(child, markerPrefix);
699
+
700
+ if (result != null)
701
+ return result;
702
+ }
703
+
704
+ return null;
705
+ }
706
+
707
+ private static bool LoadConfigurationAssets()
708
+ {
709
+ _gameContentConfig = AssetDatabase.LoadAssetAtPath<HyperGameContentConfig>(
710
+ HyperConstants.GAME_CONTENT_ASSET_PATH);
711
+
712
+ if (_gameContentConfig == null)
713
+ {
714
+ HyperDebug.LogError($"HyperGameContentConfig not found at: {HyperConstants.GAME_CONTENT_ASSET_PATH}");
715
+ return false;
716
+ }
717
+
718
+ _sdkSettings = AssetDatabase.LoadAssetAtPath<HyperSDKSettings>(
719
+ HyperConstants.SETTINGS_ASSET_PATH);
720
+
721
+ if (_sdkSettings == null)
722
+ {
723
+ HyperDebug.LogError($"HyperSDKSettings not found at: {HyperConstants.SETTINGS_ASSET_PATH}");
724
+ return false;
725
+ }
726
+
727
+ return true;
728
+ }
729
+
730
+ private static bool ValidateConfigurationAssets(HyperBuildProfile profile)
731
+ {
732
+ if (!LoadConfigurationAssets())
733
+ {
734
+ return false;
735
+ }
736
+
737
+ if (profile == HyperBuildProfile.Development)
738
+ {
739
+ if (!_gameContentConfig.HasScenesContent)
740
+ {
741
+ HyperDebug.LogError("HyperGameContentConfig is missing scenes content. Development builds require scenes content.");
742
+ return false;
743
+ }
744
+ }
745
+ else if (profile == HyperBuildProfile.Release)
746
+ {
747
+ if (!_gameContentConfig.HasScenesContent)
748
+ {
749
+ HyperDebug.LogError("HyperGameContentConfig is missing scenes content. Release builds require scenes content.");
750
+ return false;
751
+ }
752
+
753
+ if (!_gameContentConfig.HasPosterContent)
754
+ {
755
+ HyperDebug.LogError("HyperGameContentConfig is missing poster content. Release builds require poster content.");
756
+ return false;
757
+ }
758
+ }
759
+
760
+ if (!_sdkSettings.IsConfigured)
761
+ {
762
+ HyperDebug.LogError("HyperSDKSettings is not configured. Please configure at least one platform/orientation flag.");
763
+ return false;
764
+ }
765
+
766
+ return true;
767
+ }
768
+ }
769
+
770
+ public static class HyperBuildCLI
771
+ {
772
+ public static void BuildFromCommandLine()
773
+ {
774
+ string[] args = Environment.GetCommandLineArgs();
775
+
776
+ string profileValue = GetArg(args, "-hyperBuildProfile", "release");
777
+ string outputPath = GetArg(args, "-hyperBuildOutputPath", "");
778
+
779
+ if (string.IsNullOrWhiteSpace(outputPath))
780
+ {
781
+ HyperDebug.LogError("Missing required argument: -hyperBuildOutputPath <path>");
782
+ EditorApplication.Exit(1);
783
+ return;
784
+ }
785
+
786
+ HyperBuildProfile profile;
787
+
788
+ if (profileValue.Equals("development", StringComparison.OrdinalIgnoreCase) ||
789
+ profileValue.Equals("dev", StringComparison.OrdinalIgnoreCase))
790
+ {
791
+ profile = HyperBuildProfile.Development;
792
+ }
793
+ else if (profileValue.Equals("release", StringComparison.OrdinalIgnoreCase) ||
794
+ profileValue.Equals("prod", StringComparison.OrdinalIgnoreCase))
795
+ {
796
+ profile = HyperBuildProfile.Release;
797
+ }
798
+ else
799
+ {
800
+ HyperDebug.LogError($"Invalid -hyperBuildProfile value: {profileValue}. Expected development or release.");
801
+ EditorApplication.Exit(1);
802
+ return;
803
+ }
804
+
805
+ HyperBuildResult result = HyperBuildPipeline.Build(new HyperBuildRequest
806
+ {
807
+ Profile = profile,
808
+ OutputPath = outputPath,
809
+ CleanOutputFolder = true,
810
+ OpenOutputFolder = false,
811
+ IsCliBuild = true
812
+ });
813
+
814
+ if (result.Succeeded)
815
+ {
816
+ HyperDebug.Log($"Hyper build succeeded: {result.OutputPath}");
817
+ EditorApplication.Exit(0);
818
+ }
819
+ else
820
+ {
821
+ HyperDebug.LogError($"Hyper build failed: {result.Message}");
822
+ EditorApplication.Exit(1);
823
+ }
824
+ }
825
+
826
+ private static string GetArg(string[] args, string argName, string fallback)
827
+ {
828
+ for (int i = 0; i < args.Length - 1; i++)
829
+ {
830
+ if (args[i] == argName)
831
+ {
832
+ return args[i + 1];
833
+ }
834
+ }
835
+
836
+ return fallback;
837
+ }
838
+ }
839
+ }
840
+ #endif