11using System ;
22using System . Collections . Generic ;
3+ using System . Linq ;
4+ using System . Reflection ;
35using SDL2 ;
46using Yafc . Model ;
57
@@ -63,10 +65,18 @@ public static string ExportRequesterChests(string name, IReadOnlyList<(IObjectWi
6365 BlueprintEntity entity = new BlueprintEntity { index = i + 1 , position = { x = ( i * chest . size ) + offset , y = 0 } , name = chest . name } ;
6466 blueprint . blueprint . entities . Add ( entity ) ;
6567
68+ var section = new BlueprintRequestFilterSection {
69+ index = 1 ,
70+ } ;
71+
72+ entity . requestFilters = new BlueprintRequestFilterSections ( ) ;
73+ entity . requestFilters . sections . Add ( section ) ;
74+
75+
6676 for ( int j = 0 ; j < chest . logisticSlotsCount ; j ++ ) {
6777 var ( item , amount ) = goods [ index ++ ] ;
68- BlueprintRequestFilter filter = new BlueprintRequestFilter { index = j + 1 , count = amount , name = item . target . name , quality = item . quality . name , comparator = "=" } ;
69- entity . requestFilters . Add ( filter ) ;
78+ BlueprintRequestFilter filter = new BlueprintRequestFilter { index = j + 1 , count = amount , max_count = amount , name = item . target . name , quality = item . quality . name , comparator = "=" } ;
79+ section . filters . Add ( filter ) ;
7080
7181 if ( index >= goods . Count ) {
7282 break ;
@@ -76,4 +86,112 @@ public static string ExportRequesterChests(string name, IReadOnlyList<(IObjectWi
7686
7787 return ExportBlueprint ( blueprint , copyToClipboard ) ;
7888 }
89+
90+ private class PlacedEntity {
91+ public RecipeRow Recipe { get ; }
92+ public int X { get ; } // Top-left X coordinate
93+ public int Y { get ; } // Top-left Y coordinate
94+
95+ public PlacedEntity ( RecipeRow recipe , int x , int y ) {
96+ Recipe = recipe ;
97+ X = x ;
98+ Y = y ;
99+ }
100+ }
101+
102+ private class LayoutResult {
103+ public int TotalWidth { get ; set ; }
104+ public int TotalHeight { get ; set ; }
105+ public List < PlacedEntity > Placements { get ; set ; } = new ( ) ;
106+ }
107+
108+ public static string ExportRecipiesAsBlueprint ( string name , IEnumerable < RecipeRow > recipies , bool includeFuel , bool copyToClipboard = true ) {
109+ // Sort buildings largest to smallest (by height then width) for better packing
110+ var entities = recipies
111+ . Where ( r => r . entity is not null )
112+ . OrderByDescending ( r => r . entity ! . target . size )
113+ . ToList ( ) ;
114+
115+ // Estimate total area and try square-ish dimensions
116+ int totalArea = entities . Sum ( r => ( r . entity ! . target . width + 1 ) * ( r . entity ! . target . height + 1 ) ) ;
117+ int sideLengthEstimate = ( int ) Math . Ceiling ( Math . Sqrt ( totalArea ) ) ;
118+
119+ // Try increasing row width until it fits all buildings efficiently
120+ int bestWidth = int . MaxValue ;
121+ int bestHeight = int . MaxValue ;
122+ LayoutResult ? bestResult = null ;
123+
124+ for ( int tryWidth = sideLengthEstimate ; tryWidth < sideLengthEstimate * 2 ; tryWidth ++ ) {
125+ int x = 0 , y = 0 , rowHeight = 0 ;
126+ List < PlacedEntity > placed = new ( ) ;
127+
128+ foreach ( var b in entities ) {
129+ if ( x + b . entity ! . target . width > tryWidth ) {
130+ // Move to next row
131+ y += rowHeight + 1 ; // Add 1 for gap
132+ x = 0 ;
133+ rowHeight = 0 ;
134+ }
135+
136+ placed . Add ( new PlacedEntity ( b , x , y ) ) ;
137+ x += b . entity ! . target . width + 1 ; // Add gap
138+ rowHeight = Math . Max ( rowHeight , b . entity ! . target . height ) ;
139+ }
140+
141+ int totalHeight = y + rowHeight ;
142+ int totalWidth = tryWidth ;
143+
144+ // Evaluate how square-like it is
145+ if ( Math . Max ( totalWidth , totalHeight ) < Math . Max ( bestWidth , bestHeight ) ) {
146+ bestResult = new LayoutResult {
147+ TotalWidth = totalWidth ,
148+ TotalHeight = totalHeight ,
149+ Placements = placed
150+ } ;
151+ bestWidth = totalWidth ;
152+ bestHeight = totalHeight ;
153+ }
154+ }
155+
156+ BlueprintString blueprint = new BlueprintString ( name ) ;
157+ int buildingIndex = 0 ;
158+
159+ foreach ( var placement in bestResult ! . Placements ) {
160+ var recipe = placement . Recipe ;
161+
162+ BlueprintEntity entity = new BlueprintEntity {
163+ index = buildingIndex ,
164+ position = { x = placement . X , y = placement . Y } ,
165+ name = recipe . entity ! . target . name ,
166+ } ;
167+
168+ if ( ! recipe . recipe . Is < Mechanics > ( ) ) {
169+ entity . recipe = recipe . recipe . target . name ;
170+ entity . recipe_quality = recipe . recipe . quality . name ;
171+ }
172+
173+ if ( includeFuel && recipe . fuel is not null && ! recipe . fuel . target . isPower ) {
174+ entity . SetFuel ( recipe . fuel . target . name , recipe . fuel . quality . name ) ;
175+ }
176+
177+ var modules = recipe . usedModules . modules ;
178+
179+ if ( modules != null ) {
180+ int idx = 0 ;
181+ foreach ( var ( module , count , beacon ) in modules ) {
182+ if ( ! beacon ) {
183+ BlueprintItem item = new BlueprintItem { id = { name = module . target . name , quality = module . quality . name } } ;
184+ item . items . inInventory . AddRange ( Enumerable . Range ( idx , count ) . Select ( i => new BlueprintInventoryItem { stack = i } ) ) ;
185+ entity . items . Add ( item ) ;
186+ idx += count ;
187+ }
188+ }
189+ }
190+
191+ blueprint . blueprint . entities . Add ( entity ) ;
192+ buildingIndex += 1 ;
193+ }
194+
195+ return ExportBlueprint ( blueprint , copyToClipboard ) ;
196+ }
79197}
0 commit comments