@@ -65,11 +65,13 @@ private static void BuildPlayer(string defaultBuildPath, bool setupForAltTester
6565 // PlayerSettings, AltTester runtime scripts may be excluded from the build
6666 // (leading to missing-script errors and no AltTester server listening).
6767 // For AltTester builds, temporarily mirror the current Standalone define
68- // symbols onto the BuildProfile's scripting defines .
68+ // symbols onto the BuildProfile.
6969 string [ ] originalProfileDefines = Array . Empty < string > ( ) ;
70+ string [ ] originalProfilePlayerSettingsLines = Array . Empty < string > ( ) ;
7071 if ( setupForAltTester )
7172 {
7273 originalProfileDefines = GetBuildProfileDefines ( buildProfile ) ;
74+ originalProfilePlayerSettingsLines = GetBuildProfilePlayerSettingsLines ( buildProfile ) ;
7375
7476 // Capture the current Standalone define symbols after SetupAltTester()
7577 // has added AltTester + IMMUTABLE_E2E_TESTING.
@@ -83,6 +85,13 @@ private static void BuildPlayer(string defaultBuildPath, bool setupForAltTester
8385
8486 SetBuildProfileDefines ( buildProfile , MergeDefines ( originalProfileDefines , desired ) ) ;
8587 Debug . Log ( $ "Applied { desired . Length } define symbols to BuildProfile for AltTester build.") ;
88+
89+ // IMPORTANT: macOS Profile stores Standalone define symbols inside m_PlayerSettingsYaml.
90+ // If we don't patch that block, the build may still run with only the profile's defines
91+ // (e.g. VUPLEX_STANDALONE), resulting in missing AltTester runtime scripts.
92+ var patchedLines = WithStandaloneDefineSymbols ( originalProfilePlayerSettingsLines , desired ) ;
93+ SetBuildProfilePlayerSettingsLines ( buildProfile , patchedLines ) ;
94+ Debug . Log ( "Patched BuildProfile PlayerSettings define symbols for AltTester build." ) ;
8695 }
8796
8897 BuildPlayerWithProfileOptions options = new BuildPlayerWithProfileOptions
@@ -111,6 +120,7 @@ private static void BuildPlayer(string defaultBuildPath, bool setupForAltTester
111120 {
112121 // Restore original profile defines to avoid dirtying the repo locally.
113122 SetBuildProfileDefines ( buildProfile , originalProfileDefines ) ;
123+ SetBuildProfilePlayerSettingsLines ( buildProfile , originalProfilePlayerSettingsLines ) ;
114124 }
115125
116126 if ( setupForAltTester )
@@ -218,6 +228,133 @@ private static string[] GetBuildProfileDefines(BuildProfile buildProfile)
218228 return list . ToArray ( ) ;
219229 }
220230
231+ private static string [ ] GetBuildProfilePlayerSettingsLines ( BuildProfile buildProfile )
232+ {
233+ var so = new SerializedObject ( buildProfile ) ;
234+ var prop = so . FindProperty ( "m_PlayerSettingsYaml.m_Settings" ) ;
235+ if ( prop == null || ! prop . isArray ) return Array . Empty < string > ( ) ;
236+ var list = new List < string > ( prop . arraySize ) ;
237+ for ( int i = 0 ; i < prop . arraySize ; i ++ )
238+ {
239+ var el = prop . GetArrayElementAtIndex ( i ) ;
240+ var lineProp = el ? . FindPropertyRelative ( "line" ) ;
241+ if ( lineProp != null )
242+ {
243+ list . Add ( lineProp . stringValue ) ;
244+ }
245+ }
246+ return list . ToArray ( ) ;
247+ }
248+
249+ private static void SetBuildProfilePlayerSettingsLines ( BuildProfile buildProfile , IEnumerable < string > lines )
250+ {
251+ var so = new SerializedObject ( buildProfile ) ;
252+ var prop = so . FindProperty ( "m_PlayerSettingsYaml.m_Settings" ) ;
253+ if ( prop == null || ! prop . isArray )
254+ {
255+ Debug . LogWarning ( "BuildProfile does not expose m_PlayerSettingsYaml.m_Settings; cannot patch player settings YAML." ) ;
256+ return ;
257+ }
258+
259+ prop . ClearArray ( ) ;
260+ int idx = 0 ;
261+ if ( lines != null )
262+ {
263+ foreach ( var l in lines )
264+ {
265+ prop . InsertArrayElementAtIndex ( idx ) ;
266+ var el = prop . GetArrayElementAtIndex ( idx ) ;
267+ var lineProp = el . FindPropertyRelative ( "line" ) ;
268+ if ( lineProp != null )
269+ {
270+ lineProp . stringValue = l ?? string . Empty ;
271+ }
272+ idx ++ ;
273+ }
274+ }
275+
276+ so . ApplyModifiedPropertiesWithoutUndo ( ) ;
277+ EditorUtility . SetDirty ( buildProfile ) ;
278+ AssetDatabase . SaveAssets ( ) ;
279+ }
280+
281+ private static string [ ] WithStandaloneDefineSymbols ( string [ ] originalLines , IEnumerable < string > desiredDefines )
282+ {
283+ // We patch the YAML lines:
284+ // | scriptingDefineSymbols:
285+ // | Standalone: <defines>
286+ //
287+ // Preserve existing Standalone defines (e.g. VUPLEX_STANDALONE) and append our desired ones.
288+ var lines = ( originalLines ?? Array . Empty < string > ( ) ) . ToList ( ) ;
289+ if ( lines . Count == 0 )
290+ {
291+ // Unexpected, but still handle it.
292+ lines . Add ( "| PlayerSettings:" ) ;
293+ }
294+
295+ int symbolsIdx = lines . FindIndex ( l => l != null && l . TrimEnd ( ) == "| scriptingDefineSymbols:" ) ;
296+ if ( symbolsIdx < 0 )
297+ {
298+ // Append a minimal block near the end.
299+ lines . Add ( "| scriptingDefineSymbols:" ) ;
300+ lines . Add ( "| Standalone: " + string . Join ( ";" , desiredDefines ?? Array . Empty < string > ( ) ) ) ;
301+ return lines . ToArray ( ) ;
302+ }
303+
304+ int standaloneIdx = - 1 ;
305+ for ( int i = symbolsIdx + 1 ; i < Math . Min ( symbolsIdx + 10 , lines . Count ) ; i ++ )
306+ {
307+ var l = lines [ i ] ?? "" ;
308+ if ( l . TrimStart ( ) . StartsWith ( "| Standalone:" ) )
309+ {
310+ standaloneIdx = i ;
311+ break ;
312+ }
313+ // Stop if we hit another top-level key
314+ if ( l . StartsWith ( "| " ) && ! l . StartsWith ( "| " ) )
315+ {
316+ break ;
317+ }
318+ }
319+
320+ string existing = "" ;
321+ if ( standaloneIdx >= 0 )
322+ {
323+ var l = lines [ standaloneIdx ] ?? "" ;
324+ existing = l . Substring ( l . IndexOf ( ":" ) + 1 ) . Trim ( ) ;
325+ }
326+
327+ var merged = new HashSet < string > ( StringComparer . Ordinal ) ;
328+ foreach ( var d in ( existing ?? "" ) . Split ( new [ ] { ';' } , StringSplitOptions . RemoveEmptyEntries ) )
329+ {
330+ merged . Add ( d . Trim ( ) ) ;
331+ }
332+ if ( desiredDefines != null )
333+ {
334+ foreach ( var d in desiredDefines )
335+ {
336+ if ( ! string . IsNullOrEmpty ( d ) )
337+ {
338+ merged . Add ( d . Trim ( ) ) ;
339+ }
340+ }
341+ }
342+
343+ string mergedStr = string . Join ( ";" , merged . Where ( s => ! string . IsNullOrEmpty ( s ) ) ) ;
344+ string newLine = "| Standalone: " + mergedStr ;
345+
346+ if ( standaloneIdx >= 0 )
347+ {
348+ lines [ standaloneIdx ] = newLine ;
349+ }
350+ else
351+ {
352+ lines . Insert ( symbolsIdx + 1 , newLine ) ;
353+ }
354+
355+ return lines . ToArray ( ) ;
356+ }
357+
221358 private static string [ ] MergeDefines ( IEnumerable < string > a , IEnumerable < string > b )
222359 {
223360 var set = new HashSet < string > ( StringComparer . Ordinal ) ;
0 commit comments