11package  mezz .jei .library .plugins .vanilla .anvil ;
22
3- import  com .google .common .collect .Lists ;
43import  mezz .jei .api .constants .VanillaTypes ;
54import  mezz .jei .api .ingredients .IIngredientHelper ;
65import  mezz .jei .api .recipe .vanilla .IJeiAnvilRecipe ;
2423import  net .minecraft .world .entity .player .Inventory ;
2524import  net .minecraft .world .entity .player .Player ;
2625import  net .minecraft .world .inventory .AnvilMenu ;
26+ import  net .minecraft .world .inventory .Slot ;
2727import  net .minecraft .world .item .Item ;
2828import  net .minecraft .world .item .ItemStack ;
2929import  net .minecraft .world .item .Items ;
3535import  net .minecraft .world .item .enchantment .ItemEnchantments ;
3636import  org .apache .logging .log4j .LogManager ;
3737import  org .apache .logging .log4j .Logger ;
38+ import  org .jetbrains .annotations .Nullable ;
39+ import  org .jetbrains .annotations .Unmodifiable ;
3840
3941import  java .util .List ;
4042import  java .util .Objects ;
4446public  final  class  AnvilRecipeMaker  {
4547	private  static  final  Logger  LOGGER  = LogManager .getLogger ();
4648	private  static  final  ItemStack  ENCHANTED_BOOK  = new  ItemStack (Items .ENCHANTED_BOOK );
49+ 	private  static  @ Nullable  AnvilMenu  ANVIL_MENU  = null ;
4750
4851	private  AnvilRecipeMaker () {
4952	}
@@ -59,20 +62,17 @@ public static List<IJeiAnvilRecipe> getAnvilRecipes(IVanillaRecipeFactory vanill
5962
6063	private  static  final  class  EnchantmentData  {
6164		private  final  Holder <Enchantment > enchantment ;
65+ 		@ Unmodifiable 
6266		private  final  List <ItemStack > enchantedBooks ;
6367
6468		private  EnchantmentData (Holder <Enchantment > enchantment ) {
6569			this .enchantment  = enchantment ;
6670			this .enchantedBooks  = getEnchantedBooks (enchantment );
6771		}
6872
69- 		public  List <ItemStack > getEnchantedBooks (ItemStack  ingredient ) {
70- 			IPlatformItemStackHelper  itemStackHelper  = Services .PLATFORM .getItemStackHelper ();
71- 			var  list  = enchantedBooks .stream ()
72- 				.filter (enchantedBook  -> itemStackHelper .isBookEnchantable (ingredient , enchantedBook ))
73- 				.toList ();
74- 			// avoid using copy of list if it contains the exact same items 
75- 			return  list .size () == enchantedBooks .size () ? enchantedBooks  : list ;
73+ 		@ Unmodifiable 
74+ 		public  List <ItemStack > getEnchantedBooks () {
75+ 			return  enchantedBooks ;
7676		}
7777
7878		private  boolean  canEnchant (IPlatformItemStackHelper  itemStackHelper , ItemStack  ingredient ) {
@@ -120,25 +120,34 @@ private static Stream<IJeiAnvilRecipe> getBookEnchantmentRecipes(
120120		var  ingredientSingletonList  = List .of (ingredient );
121121		return  enchantmentDatas .stream ()
122122			.filter (data  -> data .canEnchant (itemStackHelper , ingredient ))
123- 			.map (data  -> data .getEnchantedBooks (ingredient ))
124- 			.filter (enchantedBooks  -> !enchantedBooks .isEmpty ())
125- 			.map (enchantedBooks  -> {
123+ 			.mapMulti ((data , consumer ) -> {
124+ 				List <ItemStack > enchantedBooks  = data .getEnchantedBooks ();
126125				List <ItemStack > outputs  = getEnchantedIngredients (ingredient , enchantedBooks );
127- 				// All lists given here are immutable, and we want to keep the transforming list from outputs, 
128- 				// so we call the AnvilRecipe constructor directly 
129- 				return  new  AnvilRecipe (ingredientSingletonList , enchantedBooks , outputs , null );
126+ 				if  (outputs .isEmpty ()) {
127+ 					return ;
128+ 				}
129+ 				// All lists given here are immutable, so we call the AnvilRecipe constructor directly 
130+ 				AnvilRecipe  anvilRecipe  = new  AnvilRecipe (ingredientSingletonList , enchantedBooks , outputs , null );
131+ 				consumer .accept (anvilRecipe );
130132			});
131133	}
132134
133135	private  static  List <ItemStack > getEnchantedIngredients (ItemStack  ingredient , List <ItemStack > enchantedBooks ) {
134- 		return  Lists .transform (enchantedBooks , enchantedBook  -> getEnchantedIngredient (ingredient , enchantedBook ));
135- 	}
136- 
137- 	private  static  ItemStack  getEnchantedIngredient (ItemStack  ingredient , ItemStack  enchantedBook ) {
138- 		ItemStack  enchantedIngredient  = ingredient .copy ();
139- 		ItemEnchantments  enchantments  = EnchantmentHelper .getEnchantmentsForCrafting (enchantedBook );
140- 		EnchantmentHelper .setEnchantments (enchantedIngredient , enchantments );
141- 		return  enchantedIngredient ;
136+ 		AnvilMenu  anvilMenu  = getFakeAnvilMenu ();
137+ 		if  (anvilMenu  == null ) {
138+ 			return  List .of ();
139+ 		}
140+ 		return  enchantedBooks .stream ()
141+ 			.map (enchantedBook  -> {
142+ 				AnvilMenu  result  = setAnvilMenu (anvilMenu , ingredient , enchantedBook );
143+ 				if  (result  == null ) {
144+ 					return  ItemStack .EMPTY ;
145+ 				}
146+ 				Slot  resultSlot  = result .slots .get (result .getResultSlot ());
147+ 				return  resultSlot .getItem ();
148+ 			})
149+ 			.filter (i  -> !i .isEmpty ())
150+ 			.toList ();
142151	}
143152
144153	private  static  class  RepairData  {
@@ -312,21 +321,50 @@ private static Stream<IJeiAnvilRecipe> getRepairRecipes(
312321	}
313322
314323	public  static  int  findLevelsCost (ItemStack  leftStack , ItemStack  rightStack ) {
315- 		Player   player  = Minecraft . getInstance (). player ;
316- 		if  (player  == null ) {
324+ 		AnvilMenu   anvilMenu  = getFakeAnvilMenu () ;
325+ 		if  (anvilMenu  == null ) {
317326			return  -1 ;
318327		}
319- 		Inventory  fakeInventory  = new  Inventory (player , new  EntityEquipment ());
328+ 		AnvilMenu  result  = setAnvilMenu (anvilMenu , leftStack , rightStack );
329+ 		if  (result  == null ) {
330+ 			return  -1 ;
331+ 		}
332+ 		return  result .getCost ();
333+ 	}
334+ 
335+ 	@ Nullable 
336+ 	private  static  AnvilMenu  getFakeAnvilMenu () {
337+ 		if  (ANVIL_MENU  == null ) {
338+ 			Player  player  = Minecraft .getInstance ().player ;
339+ 			if  (player  == null ) {
340+ 				return  null ;
341+ 			}
342+ 			Inventory  fakeInventory  = new  Inventory (player , new  EntityEquipment ());
343+ 			ANVIL_MENU  = new  AnvilMenu (0 , fakeInventory );
344+ 			return  ANVIL_MENU ;
345+ 		}
346+ 		return  ANVIL_MENU ;
347+ 	}
348+ 
349+ 	@ Nullable 
350+ 	private  static  AnvilMenu  setAnvilMenu (AnvilMenu  anvilMenu , ItemStack  leftStack , ItemStack  rightStack ) {
320351		try  {
321- 			AnvilMenu  repair  = new  AnvilMenu (0 , fakeInventory );
322- 			repair .slots .get (0 ).set (leftStack );
323- 			repair .slots .get (1 ).set (rightStack );
324- 			return  repair .getCost ();
352+ 			Slot  leftSlot  = anvilMenu .slots .get (0 );
353+ 			Slot  rightSlot  = anvilMenu .slots .get (1 );
354+ 
355+ 			// setting the stack triggers a recalculation of the recipe, so avoid it when possible 
356+ 			if  (leftSlot .getItem () != leftStack ) {
357+ 				leftSlot .set (leftStack );
358+ 			}
359+ 			if  (rightSlot .getItem () != rightStack ) {
360+ 				rightSlot .set (rightStack );
361+ 			}
362+ 			return  anvilMenu ;
325363		} catch  (RuntimeException  e ) {
326364			String  left  = ErrorUtil .getItemStackInfo (leftStack );
327365			String  right  = ErrorUtil .getItemStackInfo (rightStack );
328- 			LOGGER .error ("Could not get  anvil level cost  for: ({} and {})." , left , right , e );
329- 			return  - 1 ;
366+ 			LOGGER .error ("Could not set  anvil recipe  for: ({} and {})." , left , right , e );
367+ 			return  null ;
330368		}
331369	}
332370}
0 commit comments