11package com .github .gtexpert .gtmt .integration .chisel .metatileentities ;
22
3+ import java .util .ArrayList ;
4+ import java .util .Collections ;
5+ import java .util .HashMap ;
6+ import java .util .List ;
7+ import java .util .Map ;
38import java .util .function .Function ;
49import java .util .function .Supplier ;
510
11+ import net .minecraft .item .Item ;
12+ import net .minecraft .item .ItemStack ;
613import net .minecraft .util .ResourceLocation ;
14+ import net .minecraftforge .items .IItemHandlerModifiable ;
715
816import gregtech .api .GTValues ;
917import gregtech .api .capability .IEnergyContainer ;
18+ import gregtech .api .capability .IMultipleTankHandler ;
1019import gregtech .api .metatileentity .MetaTileEntity ;
1120import gregtech .api .metatileentity .SimpleMachineMetaTileEntity ;
1221import gregtech .api .metatileentity .interfaces .IGregTechTileEntity ;
22+ import gregtech .api .recipes .Recipe ;
1323import gregtech .api .recipes .RecipeMap ;
24+ import gregtech .api .recipes .ingredients .GTRecipeInput ;
1425import gregtech .client .renderer .ICubeRenderer ;
1526
1627import com .github .gtexpert .gtmt .api .capability .SingleblockRecipeLogicNoCache ;
@@ -32,9 +43,60 @@ public MetaTileEntity createMetaTileEntity(IGregTechTileEntity tileEntity) {
3243
3344 private static class AutoChiselRecipeLogic extends SingleblockRecipeLogicNoCache {
3445
46+ // Shared across all AutoChisel instances — built once from the recipe map on first use.
47+ private static volatile Map <Item , List <Recipe >> inputIndex ;
48+ private static final Object INDEX_LOCK = new Object ();
49+
3550 public AutoChiselRecipeLogic (MetaTileEntity tileEntity , RecipeMap <?> recipeMap ,
3651 Supplier <IEnergyContainer > energyContainer ) {
3752 super (tileEntity , recipeMap , energyContainer );
3853 }
54+
55+ @ Override
56+ protected Recipe findRecipe (long maxVoltage , IItemHandlerModifiable inputs ,
57+ IMultipleTankHandler fluidInputs ) {
58+ Map <Item , List <Recipe >> idx = inputIndex ;
59+ if (idx == null ) {
60+ synchronized (INDEX_LOCK ) {
61+ idx = inputIndex ;
62+ if (idx == null ) {
63+ inputIndex = idx = buildIndex (getRecipeMap ());
64+ }
65+ }
66+ }
67+
68+ for (int i = 0 ; i < inputs .getSlots (); i ++) {
69+ ItemStack stack = inputs .getStackInSlot (i );
70+ if (stack .isEmpty ()) continue ;
71+
72+ List <Recipe > candidates = idx .get (stack .getItem ());
73+ if (candidates == null ) return null ;
74+
75+ for (Recipe recipe : candidates ) {
76+ if (recipe .getEUt () <= maxVoltage &&
77+ recipe .matches (false , inputs , fluidInputs )) {
78+ return recipe ;
79+ }
80+ }
81+ return null ; // primary slot found but no match — stop scanning
82+ }
83+ return null ;
84+ }
85+
86+ private static Map <Item , List <Recipe >> buildIndex (RecipeMap <?> recipeMap ) {
87+ Map <Item , List <Recipe >> idx = new HashMap <>();
88+ for (Recipe recipe : recipeMap .getRecipeList ()) {
89+ for (GTRecipeInput input : recipe .getInputs ()) {
90+ if (input .isNonConsumable ()) continue ;
91+ for (ItemStack match : input .getInputStacks ()) {
92+ idx .computeIfAbsent (match .getItem (), k -> new ArrayList <>()).add (recipe );
93+ }
94+ break ; // index by first consumable input only
95+ }
96+ }
97+ // Wrap lists as unmodifiable to prevent accidental mutation
98+ idx .replaceAll ((k , v ) -> Collections .unmodifiableList (v ));
99+ return Collections .unmodifiableMap (idx );
100+ }
39101 }
40102}
0 commit comments