2424import  mezz .jei .common .util .ErrorUtil ;
2525import  mezz .jei .common .util .ImmutablePoint2i ;
2626import  mezz .jei .core .collect .ListMultiMap ;
27+ import  mezz .jei .core .util .Pair ;
2728import  mezz .jei .library .gui .ingredients .CycleTicker ;
2829import  mezz .jei .library .gui .recipes .OutputSlotTooltipCallback ;
2930import  mezz .jei .library .gui .recipes .RecipeLayout ;
3536import  java .util .ArrayList ;
3637import  java .util .Arrays ;
3738import  java .util .Collection ;
39+ import  java .util .Comparator ;
3840import  java .util .HashSet ;
3941import  java .util .IntSummaryStatistics ;
4042import  java .util .List ;
@@ -59,6 +61,7 @@ public class RecipeLayoutBuilder<T> implements IRecipeLayoutBuilder, IRecipeExtr
5961	private  int  shapelessY  = -1 ;
6062	private  int  recipeTransferX  = -1 ;
6163	private  int  recipeTransferY  = -1 ;
64+ 	private  int  nextSlotIndex  = 0 ;
6265
6366	public  RecipeLayoutBuilder (IRecipeCategory <T > recipeCategory , T  recipe , IIngredientManager  ingredientManager ) {
6467		this .recipeCategory  = recipeCategory ;
@@ -68,7 +71,7 @@ public RecipeLayoutBuilder(IRecipeCategory<T> recipeCategory, T recipe, IIngredi
6871
6972	@ Override 
7073	public  IRecipeSlotBuilder  addSlot (RecipeIngredientRole  role , int  x , int  y ) {
71- 		RecipeSlotBuilder  slot  = new  RecipeSlotBuilder (ingredientManager , role , x , y );
74+ 		RecipeSlotBuilder  slot  = new  RecipeSlotBuilder (ingredientManager , nextSlotIndex ++,  role , x , y );
7275
7376		if  (role  == RecipeIngredientRole .OUTPUT ) {
7477			addOutputSlotTooltipCallback (slot );
@@ -80,7 +83,7 @@ public IRecipeSlotBuilder addSlot(RecipeIngredientRole role, int x, int y) {
8083
8184	@ Override 
8285	public  IRecipeSlotBuilder  addSlotToWidget (RecipeIngredientRole  role , ISlottedWidgetFactory <?> widgetFactory ) {
83- 		RecipeSlotBuilder  slot  = new  RecipeSlotBuilder (ingredientManager , role , 0 , 0 )
86+ 		RecipeSlotBuilder  slot  = new  RecipeSlotBuilder (ingredientManager , nextSlotIndex ++,  role , 0 , 0 )
8487			.assignToWidgetFactory (widgetFactory );
8588
8689		if  (role  == RecipeIngredientRole .OUTPUT ) {
@@ -186,9 +189,9 @@ public RecipeLayout<T> buildRecipeLayout(
186189		ShapelessIcon  shapelessIcon  = createShapelessIcon (recipeCategory );
187190		ImmutablePoint2i  recipeTransferButtonPosition  = getRecipeTransferButtonPosition (recipeCategory , recipeBorderPadding );
188191
189- 		List <IRecipeSlotDrawable > recipeCategorySlots  = new  ArrayList <>();
190- 		List <IRecipeSlotDrawable > allSlots  = new  ArrayList <>(recipeCategorySlots );
191- 		ListMultiMap <ISlottedWidgetFactory <?>, IRecipeSlotDrawable > widgetSlots  = new  ListMultiMap <>();
192+ 		List <Pair < Integer ,  IRecipeSlotDrawable > > recipeCategorySlots  = new  ArrayList <>();
193+ 		List <Pair < Integer ,  IRecipeSlotDrawable >>  allSlots  = new  ArrayList <>();
194+ 		ListMultiMap <ISlottedWidgetFactory <?>, Pair < Integer ,  IRecipeSlotDrawable > > widgetSlots  = new  ListMultiMap <>();
192195
193196		CycleTicker  cycleTicker  = CycleTicker .createWithRandomOffset ();
194197
@@ -200,7 +203,7 @@ public RecipeLayout<T> buildRecipeLayout(
200203			}
201204			for  (RecipeSlotBuilder  slotBuilder  : linkedSlots ) {
202205				ISlottedWidgetFactory <?> assignedWidget  = slotBuilder .getAssignedWidget ();
203- 				IRecipeSlotDrawable  slotDrawable  = slotBuilder .build (focusMatches , cycleTicker );
206+ 				Pair < Integer ,  IRecipeSlotDrawable >  slotDrawable  = slotBuilder .build (focusMatches , cycleTicker );
204207				if  (assignedWidget  == null ) {
205208					recipeCategorySlots .add (slotDrawable );
206209				} else  {
@@ -214,7 +217,7 @@ public RecipeLayout<T> buildRecipeLayout(
214217		for  (RecipeSlotBuilder  slotBuilder  : slots ) {
215218			if  (!focusLinkedSlots .contains (slotBuilder )) {
216219				ISlottedWidgetFactory <?> assignedWidget  = slotBuilder .getAssignedWidget ();
217- 				IRecipeSlotDrawable  slotDrawable  = slotBuilder .build (focuses , cycleTicker );
220+ 				Pair < Integer ,  IRecipeSlotDrawable >  slotDrawable  = slotBuilder .build (focuses , cycleTicker );
218221				if  (assignedWidget  == null ) {
219222					recipeCategorySlots .add (slotDrawable );
220223				} else  {
@@ -224,11 +227,11 @@ public RecipeLayout<T> buildRecipeLayout(
224227			}
225228		}
226229
227- 		for  (Map .Entry <ISlottedWidgetFactory <?>, List <IRecipeSlotDrawable >> e  : widgetSlots .entrySet ()) {
230+ 		for  (Map .Entry <ISlottedWidgetFactory <?>, List <Pair < Integer ,  IRecipeSlotDrawable > >> e  : widgetSlots .entrySet ()) {
228231			// TODO: breaking change: add a type parameter to IRecipeLayoutBuilder to avoid this cast 
229232			@ SuppressWarnings ("unchecked" )
230233			ISlottedWidgetFactory <T > factory  = (ISlottedWidgetFactory <T >) e .getKey ();
231- 			List <IRecipeSlotDrawable > slots  = e .getValue ();
234+ 			List <IRecipeSlotDrawable > slots  = sortSlots ( e .getValue () );
232235			factory .createWidgetForSlots (this , recipe , slots );
233236		}
234237
@@ -247,8 +250,8 @@ public RecipeLayout<T> buildRecipeLayout(
247250			recipeBorderPadding ,
248251			shapelessIcon ,
249252			recipeTransferButtonPosition ,
250- 			recipeCategorySlots ,
251- 			allSlots ,
253+ 			sortSlots ( recipeCategorySlots ) ,
254+ 			sortSlots ( allSlots ) ,
252255			slottedWidgets ,
253256			widgets ,
254257			inputHandlers ,
@@ -258,6 +261,13 @@ public RecipeLayout<T> buildRecipeLayout(
258261		);
259262	}
260263
264+ 	private  static  List <IRecipeSlotDrawable > sortSlots (List <Pair <Integer , IRecipeSlotDrawable >> indexedSlots ) {
265+ 		return  indexedSlots .stream ()
266+ 			.sorted (Comparator .comparingInt (Pair ::first ))
267+ 			.map (Pair ::second )
268+ 			.toList ();
269+ 	}
270+ 
261271	@ Nullable 
262272	private  ShapelessIcon  createShapelessIcon (IRecipeCategory <?> recipeCategory ) {
263273		if  (!shapeless ) {
0 commit comments