@@ -42,31 +42,13 @@ public EngineSequencedAssemblyProvider(PackOutput output) {
4242 public CompletableFuture <?> run (CachedOutput cache ) {
4343 List <CompletableFuture <?>> futures = new ArrayList <>();
4444
45- // Material-dependent recipes
46- for (MaterialLevel mat : MaterialLevel .values ()) {
47- for (EnginePartType type : EnginePartType .values ()) {
48- if (!type .isMaterialDependent ()) continue ;
49-
50- try {
51- JsonObject json = buildRecipe (type , mat );
52- Path path = recipePath (type , mat );
53- futures .add (saveJson (cache , json , path ));
54- } catch (Exception e ) {
55- throw new RuntimeException ("Failed generating recipe for " + type .name () + " at " + mat .key (), e );
56- }
57- }
58- }
59-
60- // Non-material recipes
6145 for (EnginePartType type : EnginePartType .values ()) {
62- if (type .isMaterialDependent ()) continue ;
63-
64- try {
65- JsonObject json = buildRecipe (type , null );
66- Path path = recipePath (type , null );
67- futures .add (saveJson (cache , json , path ));
68- } catch (Exception e ) {
69- throw new RuntimeException ("Failed generating static recipe for " + type .name (), e );
46+ type .applicableMaterials ()
47+ .map (mat -> scheduleRecipe (cache , type , mat ))
48+ .forEach (futures ::add );
49+
50+ if (!type .isMaterialDependent ()) {
51+ futures .add (scheduleRecipe (cache , type , null ));
7052 }
7153 }
7254
@@ -81,35 +63,20 @@ private JsonObject buildRecipe(EnginePartType type, MaterialLevel mat) {
8163 EngineSAJson .Builder b = EngineSAJson .builder ()
8264 .loops (type .loops ());
8365
84- // --------------------------------------------------------------------
85- // Material-dependent recipes
86- // --------------------------------------------------------------------
87- if (type .isMaterialDependent () && mat != null ) {
66+ if (type .isMaterialDependent ()) {
67+ if (mat == null ) {
68+ throw new IllegalArgumentException ("Material-dependent recipe requires material level for " + type .name ());
69+ }
70+
8871 // Add proper ingredient with materialLevel in custom data
8972 b .blueprintIngredient (mat .level ());
90-
91- // Result item — same name as the recipe file
92- String partName = type .recipeSubPath ()
93- .substring (type .recipeSubPath ().lastIndexOf ('/' ) + 1 );
94- b .result (getResultItemId (type , mat ));
95-
96- // Transitional item naming rules
97- b .transitionalItem (getTransitionalItemId (type , mat ));
98-
99-
100- // --------------------------------------------------------------------
101- // Non-material recipes (engine, duplicate_blueprint)
102- // --------------------------------------------------------------------
10373 } else {
104- b .result ("creatingspace:" + type .recipeSubPath ());
105- b .transitionalItem ("creatingspace:engine_blueprint" );
106-
107- // simple ingredient reference to avoid {}
108- JsonObject ing = new JsonObject ();
109- ing .addProperty ("item" , "creatingspace:engine_blueprint" );
110- b .rawIngredient (ing );
74+ b .rawIngredient (EngineSAJson .Builder .itemIngredient ("creatingspace:engine_blueprint" ));
11175 }
11276
77+ b .result (type .resultItemId (mat ));
78+ b .transitionalItem (type .transitionalItemId (mat ));
79+
11380 // --------------------------------------------------------------------
11481 // Extra data & sequence definition
11582 // --------------------------------------------------------------------
@@ -128,15 +95,16 @@ private JsonObject buildRecipe(EnginePartType type, MaterialLevel mat) {
12895 // ------------------------------------------------------------------------
12996
13097 private Path recipePath (EnginePartType type , MaterialLevel mat ) {
131- StringBuilder sb = new StringBuilder ("data/creatingspace/recipe/" );
132- sb .append (type .baseFolder ()).append ("/" );
133-
134- if (type .isMaterialDependent () && mat != null ) {
135- sb .append (mat .folderName ()).append ("/" );
98+ Path base = Path .of ("data" , "creatingspace" , "recipe" , type .baseFolder ());
99+ if (type .isMaterialDependent ()) {
100+ if (mat == null ) {
101+ throw new IllegalArgumentException ("Material-dependent recipe requires material level for " + type .name ());
102+ }
103+ base = base .resolve (mat .folderName ());
136104 }
137105
138- sb . append (type .recipeSubPath ()). append ( ".json" );
139- return output .getOutputFolder ().resolve (Path . of ( sb . toString ()) );
106+ Path file = Path . of (type .recipeSubPath () + ".json" );
107+ return output .getOutputFolder ().resolve (base ). resolve ( file );
140108 }
141109
142110 // ------------------------------------------------------------------------
@@ -148,40 +116,17 @@ private static CompletableFuture<?> saveJson(CachedOutput cache, JsonObject json
148116 return DataProvider .saveStable (cache , GSON .toJsonTree (json ), path );
149117 }
150118
151- private static String getResultItemId (EnginePartType part , MaterialLevel mat ) {
152- // These parts always produce generic item IDs (no material prefix)
153- return switch (part ) {
154- case COMBUSTION_CHAMBER -> "creatingspace:combustion_chamber" ;
155- case BELL_NOZZLE -> "creatingspace:bell_nozzle" ;
156- case AEROSPIKE_PLUG -> "creatingspace:aerospike_plug" ;
157- case FUEL_RICH_STAGED_CYCLE , FULL_FLOW_STAGED_CYCLE , OPEN_CYCLE , OX_RICH_STAGED_CYCLE -> "creatingspace:power_pack" ;
158- case DUPLICATE_BLUEPRINT -> "creatingspace:duplicate_blueprint" ;
159- case ENGINE -> "creatingspace:engine" ;
160- default -> mat .itemId (
161- part .recipeSubPath ().substring (part .recipeSubPath ().lastIndexOf ('/' ) + 1 )
162- );
163- };
164- }
165-
166- private static String getTransitionalItemId (EnginePartType type , MaterialLevel mat ) {
167- return switch (type ) {
168- // Exhaust pack members all use a shared transitional
169- case COMBUSTION_CHAMBER -> "creatingspace:incomplete_combustion_chamber" ;
170- case BELL_NOZZLE -> "creatingspace:incomplete_bell_nozzle" ;
171- case AEROSPIKE_PLUG -> "creatingspace:incomplete_aerospike_plug" ;
172- case FUEL_RICH_STAGED_CYCLE , FULL_FLOW_STAGED_CYCLE , OPEN_CYCLE , OX_RICH_STAGED_CYCLE -> "creatingspace:incomplete_power_pack" ;
173- case DUPLICATE_BLUEPRINT -> "creatingspace:engine_blueprint" ;
174- case ENGINE -> "creatingspace:engine_blueprint" ;
175-
176- // Default material-dependent transitional logic
177- default -> {
178- String partName = type .recipeSubPath ()
179- .substring (type .recipeSubPath ().lastIndexOf ('/' ) + 1 );
180- if (partName .equals ("injector_grid" ) || partName .equals ("turbine" ))
181- yield EngineSAJson .Builder .incompleteMaterialItemId (mat , partName );
182- yield EngineSAJson .Builder .incompleteItemId (partName );
183- }
184- };
119+ private CompletableFuture <?> scheduleRecipe (CachedOutput cache , EnginePartType type , MaterialLevel mat ) {
120+ try {
121+ JsonObject json = buildRecipe (type , mat );
122+ Path path = recipePath (type , mat );
123+ return saveJson (cache , json , path );
124+ } catch (Exception e ) {
125+ String context = type .isMaterialDependent ()
126+ ? " at " + (mat != null ? mat .key () : "<missing material>" )
127+ : " (static)" ;
128+ throw new RuntimeException ("Failed generating recipe for " + type .name () + context , e );
129+ }
185130 }
186131
187132 @ Override
0 commit comments