44import java .util .Map ;
55import java .util .Optional ;
66import java .util .Set ;
7+ import java .util .stream .Collectors ;
78import java .util .stream .Stream ;
89import com .google .gson .JsonElement ;
910import com .mojang .serialization .DataResult ;
1011import com .mojang .serialization .JsonOps ;
12+ import dev .compactmods .crafting .api .components .IRecipeComponent ;
13+ import dev .compactmods .crafting .api .components .IRecipeComponents ;
1114import dev .compactmods .crafting .api .field .MiniaturizationFieldSize ;
1215import dev .compactmods .crafting .api .recipe .layers .IRecipeLayer ;
16+ import dev .compactmods .crafting .api .recipe .layers .IRecipeLayerBlocks ;
1317import dev .compactmods .crafting .recipes .MiniaturizationRecipe ;
1418import dev .compactmods .crafting .recipes .blocks .ComponentPositionLookup ;
1519import dev .compactmods .crafting .recipes .blocks .RecipeLayerBlocks ;
1620import dev .compactmods .crafting .recipes .components .CCMiniRecipeComponents ;
1721import dev .compactmods .crafting .recipes .layers .MixedComponentRecipeLayer ;
22+ import dev .compactmods .crafting .recipes .layers .RecipeLayerUtil ;
23+ import dev .compactmods .crafting .server .ServerConfig ;
1824import dev .compactmods .crafting .tests .recipes .util .RecipeTestUtil ;
1925import dev .compactmods .crafting .tests .util .FileHelper ;
2026import dev .compactmods .crafting .tests .world .TestBlockReader ;
2127import dev .compactmods .crafting .util .BlockSpaceUtil ;
28+ import net .minecraft .util .Rotation ;
2229import net .minecraft .util .math .AxisAlignedBB ;
2330import net .minecraft .util .math .BlockPos ;
2431import org .junit .jupiter .api .Assertions ;
2734
2835public class MixedLayerTests {
2936
37+ @ Tag ("minecraft" )
38+ @ org .junit .jupiter .api .BeforeAll
39+ static void BeforeAllTests () {
40+ ServerConfig .RECIPE_REGISTRATION .set (true );
41+ ServerConfig .RECIPE_MATCHING .set (true );
42+ ServerConfig .FIELD_BLOCK_CHANGES .set (true );
43+ }
44+
3045 static MixedComponentRecipeLayer getLayerFromFile (String filename ) {
3146 JsonElement layerJson = FileHelper .INSTANCE .getJsonFromFile (filename );
3247
@@ -76,7 +91,7 @@ void CanCreateLayerInstance() {
7691 @ Tag ("minecraft" )
7792 void remapsUnknownComponents () {
7893 MiniaturizationRecipe recipe = RecipeTestUtil .getRecipeFromFile ("recipes/ender_crystal.json" );
79- if (recipe == null )
94+ if (recipe == null )
8095 Assertions .fail ();
8196
8297 Optional <IRecipeLayer > layer = recipe .getLayer (2 );
@@ -94,8 +109,8 @@ void remapsUnknownComponents() {
94109 @ Test
95110 @ Tag ("minecraft" )
96111 void MixedLayerMatchesWorldInExactMatchScenario () {
97- final TestBlockReader reader = RecipeTestUtil .getBlockReader ("worlds/basic_harness_5x .json" );
98- final CCMiniRecipeComponents components = RecipeTestUtil .getComponentsFromRecipeFile ("worlds/basic_harness_5x .json" );
112+ final TestBlockReader reader = RecipeTestUtil .getBlockReader ("worlds/basic_mixed_medium_iron .json" );
113+ final CCMiniRecipeComponents components = RecipeTestUtil .getComponentsFromRecipeFile ("worlds/basic_mixed_medium_iron .json" );
99114
100115 Assertions .assertNotNull (reader );
101116
@@ -108,4 +123,109 @@ void MixedLayerMatchesWorldInExactMatchScenario() {
108123 final Boolean matched = Assertions .assertDoesNotThrow (() -> layer .matches (components , blocks ));
109124 Assertions .assertTrue (matched , "Expected layer to match; layer did not match." );
110125 }
126+
127+ @ Test
128+ @ Tag ("minecraft" )
129+ void MixedCanFetchAKnownGoodPosition () {
130+ MixedComponentRecipeLayer layer = getLayerFromFile ("layers/mixed/basic.json" );
131+ Assertions .assertNotNull (layer );
132+
133+ Optional <String > spot = layer .getComponentForPosition (BlockPos .ZERO );
134+ Assertions .assertTrue (spot .isPresent ());
135+ Assertions .assertEquals ("I" , spot .get ());
136+ }
137+
138+ @ Test
139+ @ Tag ("minecraft" )
140+ void MixedCanFetchAListOfComponentPositions () {
141+ MixedComponentRecipeLayer layer = getLayerFromFile ("layers/mixed/basic.json" );
142+ Assertions .assertNotNull (layer );
143+
144+ final Stream <BlockPos > g = layer .getPositionsForComponent ("G" );
145+ Assertions .assertNotNull (g );
146+
147+ final Set <BlockPos > positions = g .map (BlockPos ::immutable ).collect (Collectors .toSet ());
148+ Assertions .assertFalse (positions .isEmpty ());
149+ Assertions .assertEquals (15 , positions .size ());
150+ }
151+
152+ @ Test
153+ @ Tag ("minecraft" )
154+ void MixedLayerDeniesMatchIfAllComponentsNotIdentified () {
155+ final TestBlockReader reader = RecipeTestUtil .getBlockReader ("worlds/basic_mixed_medium_iron.json" );
156+ final CCMiniRecipeComponents components = RecipeTestUtil .getComponentsFromRecipeFile ("worlds/basic_mixed_medium_iron.json" );
157+
158+ Assertions .assertNotNull (reader );
159+
160+ // Force that the - component is unregistered; in a real scenario the recipe system would have remapped it
161+ // to an empty component due to it existing in the layer spec. Here, we're testing if a legit component in the world
162+ // did not match.
163+ reader .source .getComponents ().unregisterBlock ("-" );
164+
165+ final RecipeLayerBlocks blocks = RecipeLayerBlocks .create (reader , reader .source , BlockSpaceUtil .getLayerBounds (MiniaturizationFieldSize .MEDIUM , 0 ));
166+
167+ final MixedComponentRecipeLayer layer = getLayerFromFile ("layers/mixed/basic.json" );
168+
169+ final Boolean matched = Assertions .assertDoesNotThrow (() -> layer .matches (components , blocks ));
170+ Assertions .assertFalse (matched , "Expected layer not to match; layer matched anyway." );
171+ }
172+
173+ @ Test
174+ @ Tag ("minecraft" )
175+ void MixedLayerDeniesMatchIfComponentCountDiffers () {
176+ final TestBlockReader reader = RecipeTestUtil .getBlockReader ("worlds/single_layer_medium_filled_G.json" );
177+ final CCMiniRecipeComponents components = RecipeTestUtil .getComponentsFromRecipeFile ("worlds/single_layer_medium_filled_G.json" );
178+ final MixedComponentRecipeLayer layer = getLayerFromFile ("layers/mixed/basic.json" );
179+
180+ Assertions .assertNotNull (reader );
181+
182+ final RecipeLayerBlocks blocks = RecipeLayerBlocks .create (reader , reader .source , BlockSpaceUtil .getLayerBounds (MiniaturizationFieldSize .MEDIUM , 0 ));
183+
184+ final IRecipeComponents readerComponents = reader .source .getComponents ();
185+ final Map <String , IRecipeComponent > allComponents = readerComponents .getAllComponents ();
186+ final int worldCompCount = allComponents .keySet ().size ();
187+
188+ final Set <String > layerComponents = layer .getComponents ();
189+ final int layerCompCount = layerComponents .size ();
190+
191+ Assertions .assertNotEquals (layerCompCount , worldCompCount );
192+
193+ final Boolean matched = Assertions .assertDoesNotThrow (() -> layer .matches (components , blocks ));
194+ Assertions .assertFalse (matched , "Expected layer not to match due to component count mismatch; layer matched anyway." );
195+ }
196+
197+ @ Test
198+ @ Tag ("minecraft" )
199+ void MixedLayerDeniesMatchIfRequiredComponentsMissing () {
200+ String file = "worlds/basic_mixed_medium_redstone.json" ;
201+ final TestBlockReader reader = RecipeTestUtil .getBlockReader (file );
202+ final CCMiniRecipeComponents components = RecipeTestUtil .getComponentsFromRecipeFile (file );
203+
204+ Assertions .assertNotNull (reader );
205+
206+ final RecipeLayerBlocks blocks = RecipeLayerBlocks .create (reader , reader .source , BlockSpaceUtil .getLayerBounds (MiniaturizationFieldSize .MEDIUM , 0 ));
207+
208+ final MixedComponentRecipeLayer layer = getLayerFromFile ("layers/mixed/basic.json" );
209+
210+ final Boolean matched = Assertions .assertDoesNotThrow (() -> layer .matches (components , blocks ));
211+ Assertions .assertFalse (matched , "Expected layer not to match due to missing required components; layer matched anyway." );
212+ }
213+
214+ @ Test
215+ @ Tag ("minecraft" )
216+ void MixedLayerDeniesMatchIfComponentsInWrongPositions () {
217+ String file = "worlds/basic_mixed_medium_iron.json" ;
218+ final TestBlockReader reader = RecipeTestUtil .getBlockReader (file );
219+ final CCMiniRecipeComponents components = RecipeTestUtil .getComponentsFromRecipeFile (file );
220+
221+ Assertions .assertNotNull (reader );
222+
223+ final RecipeLayerBlocks blocks = RecipeLayerBlocks .create (reader , reader .source , BlockSpaceUtil .getLayerBounds (MiniaturizationFieldSize .MEDIUM , 0 ));
224+ final IRecipeLayerBlocks rotated = RecipeLayerUtil .rotate (blocks , Rotation .CLOCKWISE_90 );
225+
226+ final MixedComponentRecipeLayer layer = getLayerFromFile ("layers/mixed/basic.json" );
227+
228+ final Boolean matched = Assertions .assertDoesNotThrow (() -> layer .matches (components , rotated ));
229+ Assertions .assertFalse (matched , "Expected layer not to match due to incorrect positions; layer matched anyway." );
230+ }
111231}
0 commit comments