@@ -15,6 +15,26 @@ private List<Button> GetTopLevelMainMenuButtons()
1515 return items ;
1616 }
1717
18+ GameObject preferredRoot = FindTopLevelMainMenuButtonContainer ( root ) ?? root ;
19+ Button [ ] buttons = preferredRoot . GetComponentsInChildren < Button > ( includeInactive : false ) ;
20+ for ( int i = 0 ; i < buttons . Length ; i ++ )
21+ {
22+ Button button = buttons [ i ] ;
23+ if ( button == null || ! button . gameObject . activeInHierarchy || ! button . interactable )
24+ {
25+ continue ;
26+ }
27+
28+ items . Add ( button ) ;
29+ }
30+
31+ items . Sort ( CompareVerticalMenuButtons ) ;
32+ LogTopLevelMainMenuButtons ( preferredRoot == root ? "dynamic-root" : "dynamic-button-container" , items ) ;
33+ if ( items . Count > 0 )
34+ {
35+ return items ;
36+ }
37+
1838 string [ ] labels = new string [ ]
1939 {
2040 "New" ,
@@ -35,9 +55,131 @@ private List<Button> GetTopLevelMainMenuButtons()
3555 }
3656 }
3757
58+ LogTopLevelMainMenuButtons ( "fallback" , items ) ;
3859 return items ;
3960 }
4061
62+ private static GameObject FindTopLevelMainMenuButtonContainer ( GameObject root )
63+ {
64+ if ( root == null )
65+ {
66+ return null ;
67+ }
68+
69+ Transform [ ] transforms = root . GetComponentsInChildren < Transform > ( includeInactive : false ) ;
70+ for ( int i = 0 ; i < transforms . Length ; i ++ )
71+ {
72+ Transform candidate = transforms [ i ] ;
73+ if ( candidate == null || candidate . gameObject == null )
74+ {
75+ continue ;
76+ }
77+
78+ if ( string . Equals ( candidate . name , "ButtonContainer" , StringComparison . OrdinalIgnoreCase ) )
79+ {
80+ return candidate . gameObject ;
81+ }
82+ }
83+
84+ return null ;
85+ }
86+
87+ private void LogTopLevelMainMenuButtons ( string source , List < Button > items )
88+ {
89+ if ( items == null )
90+ {
91+ log ( "Top-level main menu discovery source=" + source + " returned null." ) ;
92+ return ;
93+ }
94+
95+ log ( "Top-level main menu discovery source=" + source + " count=" + items . Count + "." ) ;
96+ for ( int i = 0 ; i < items . Count ; i ++ )
97+ {
98+ log ( "Top-level main menu item " + i + ": " + DescribeTopLevelMainMenuButtonForLog ( items [ i ] ) ) ;
99+ }
100+ }
101+
102+ private string DescribeTopLevelMainMenuButtonForLog ( Button button )
103+ {
104+ if ( button == null )
105+ {
106+ return "null" ;
107+ }
108+
109+ ConsoleUIItem consoleItem = GetConsoleItemForComponent ( button ) ;
110+ Transform transform = button . transform ;
111+ Vector3 position = transform . position ;
112+ string label = GetComponentLabel ( button ) ;
113+ string objectName = button . gameObject . name ;
114+ string parentName = transform . parent != null ? transform . parent . name : "none" ;
115+ string consoleItemName = consoleItem != null ? consoleItem . gameObject . name : "none" ;
116+ string consoleItemType = consoleItem != null ? consoleItem . GetType ( ) . Name : "none" ;
117+ string localizeTerm = GetPrimaryLocalizationTerm ( button . gameObject ) ;
118+ return "label=" + SafeLogValue ( label )
119+ + ", object=" + SafeLogValue ( objectName )
120+ + ", parent=" + SafeLogValue ( parentName )
121+ + ", type=" + button . GetType ( ) . Name
122+ + ", consoleItem=" + SafeLogValue ( consoleItemName )
123+ + ", consoleItemType=" + SafeLogValue ( consoleItemType )
124+ + ", localize=" + SafeLogValue ( localizeTerm )
125+ + ", pos=(" + position . x . ToString ( "F1" ) + "," + position . y . ToString ( "F1" ) + "," + position . z . ToString ( "F1" ) + ")" ;
126+ }
127+
128+ private static string SafeLogValue ( string value )
129+ {
130+ return string . IsNullOrEmpty ( value ) ? "<empty>" : value ;
131+ }
132+
133+ private static string GetPrimaryLocalizationTerm ( GameObject obj )
134+ {
135+ if ( obj == null )
136+ {
137+ return string . Empty ;
138+ }
139+
140+ I2 . Loc . Localize localize = obj . GetComponent < I2 . Loc . Localize > ( ) ?? obj . GetComponentInChildren < I2 . Loc . Localize > ( includeInactive : false ) ;
141+ return localize != null ? CleanText ( localize . Term ) : string . Empty ;
142+ }
143+
144+ private static int CompareVerticalMenuButtons ( Button left , Button right )
145+ {
146+ if ( left == null && right == null )
147+ {
148+ return 0 ;
149+ }
150+
151+ if ( left == null )
152+ {
153+ return 1 ;
154+ }
155+
156+ if ( right == null )
157+ {
158+ return - 1 ;
159+ }
160+
161+ Vector3 leftPosition = left . transform . position ;
162+ Vector3 rightPosition = right . transform . position ;
163+ float yDelta = Mathf . Abs ( leftPosition . y - rightPosition . y ) ;
164+ if ( yDelta > 0.5f )
165+ {
166+ return rightPosition . y . CompareTo ( leftPosition . y ) ;
167+ }
168+
169+ float xDelta = Mathf . Abs ( leftPosition . x - rightPosition . x ) ;
170+ if ( xDelta > 0.5f )
171+ {
172+ return leftPosition . x . CompareTo ( rightPosition . x ) ;
173+ }
174+
175+ return string . Compare ( GetStableMenuButtonName ( left ) , GetStableMenuButtonName ( right ) , StringComparison . OrdinalIgnoreCase ) ;
176+ }
177+
178+ private static string GetStableMenuButtonName ( Button button )
179+ {
180+ return button != null ? button . gameObject . name : string . Empty ;
181+ }
182+
41183 private List < Button > GetChooseModeButtons ( )
42184 {
43185 List < Button > buttons = new List < Button > ( ) ;
0 commit comments