Skip to content

Commit c268735

Browse files
committed
Added the ability to autofill crafting and furnace recipes.
1 parent f47c09d commit c268735

10 files changed

Lines changed: 665 additions & 4 deletions

File tree

src/main/java/turing/tmb/TooltipBuilder.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ public void add(String text) {
1515
lines.add(text);
1616
}
1717

18+
@Override
19+
public void add(int index, String text) {
20+
lines.add(index, text);
21+
}
22+
1823
@Override
1924
public void addAll(Collection<String> text) {
2025
lines.addAll(text);
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
package turing.tmb.api;
22

3+
import net.minecraft.core.data.registry.recipe.RecipeEntryBase;
34
import turing.tmb.api.recipe.IRecipeTranslator;
45

6+
import java.util.List;
7+
58
public interface ISupportsRecipeFilling {
6-
void fillRecipe(IRecipeTranslator<?> recipe);
9+
void fillRecipe(IRecipeTranslator<?> translator, boolean maximum);
10+
11+
List<Class<? extends RecipeEntryBase<?, ?, ?>>> getSupportedRecipes();
712
}

src/main/java/turing/tmb/api/drawable/builder/ITooltipBuilder.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
public interface ITooltipBuilder {
88
void add(String text);
99

10+
void add(int index, String text);
11+
1012
void addAll(Collection<String> text);
1113

1214
void setIngredient(ITypedIngredient<?> ingredient);

src/main/java/turing/tmb/client/ScreenTMBRecipe.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import net.minecraft.client.gui.ButtonElement;
77
import net.minecraft.client.gui.Screen;
88
import net.minecraft.client.gui.TooltipElement;
9+
import net.minecraft.core.data.registry.recipe.RecipeEntryBase;
910
import net.minecraft.core.lang.I18n;
1011
import net.minecraft.core.net.command.TextFormatting;
1112
import net.minecraft.core.sound.SoundCategory;
@@ -331,7 +332,18 @@ public void render(int mx, int my, float partialTick) {
331332
if (list instanceof IngredientList && ((IngredientList) list).itemGroup != null) {
332333
tooltipBuilder.add(TextFormatting.formatted(I18n.getInstance().translateKeyAndFormat("tmb.tooltip.itemGroup", ((IngredientList) list).itemGroup), TextFormatting.LIGHT_GRAY));
333334
}
335+
if(slot.getRole() == RecipeIngredientRole.OUTPUT){
336+
if(parentScreen instanceof ISupportsRecipeFilling){
337+
List<Class<? extends RecipeEntryBase<?, ?, ?>>> supportedRecipes = ((ISupportsRecipeFilling) parentScreen).getSupportedRecipes();
338+
if(supportedRecipes.stream().anyMatch((E)->E.isAssignableFrom(recipe.getOriginal().getClass()))){
339+
String key = ((IKeybinds) mc.gameSettings).toomanyblocks$getKeyFillRecipe().getKeyName();
340+
tooltipBuilder.add(tooltipBuilder.getLines().size()-1, TextFormatting.LIME+I18n.getInstance().translateKeyAndFormat("tmb.tooltip.fillRecipe", key));
341+
}
342+
}
343+
}
334344
}
345+
346+
335347
}
336348
X--;
337349
Y--;
@@ -393,12 +405,13 @@ public void render(int mx, int my, float partialTick) {
393405
}
394406
}
395407

408+
super.render(mx,my,partialTick);
409+
396410
if (!tooltip.isEmpty()) {
397411
GL11.glPushMatrix();
398412
tooltipElement.render(tooltip, mx, my, 8, -8);
399413
GL11.glPopMatrix();
400414
}
401-
super.render(mx,my,partialTick);
402415
}
403416

404417
@SuppressWarnings("unchecked")
@@ -468,7 +481,8 @@ public void keyPressed(char eventCharacter, int eventKey, int mx, int my) {
468481
if (mx >= drawn.getRight().getLeft() && my >= drawn.getRight().getRight() && mx < drawn.getRight().getLeft() + 16 && my < drawn.getRight().getRight() + 16) {
469482
if (recipeIngredient.recipe != null) {
470483
mc.displayScreen(s);
471-
((ISupportsRecipeFilling) s).fillRecipe(recipeIngredient.recipe);
484+
boolean shift = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT);
485+
((ISupportsRecipeFilling) s).fillRecipe(recipeIngredient.recipe,shift);
472486
break;
473487
}
474488
}

src/main/java/turing/tmb/client/TMBRenderer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ public static void mouseClicked(int mouseX, int mouseY, int width, int height, M
143143
if (currentFavouritePage > favouritePages) currentFavouritePage = 0;
144144
}
145145

146+
if(search == null) return;
146147
search.mouseClicked(mouseX, mouseY, 1);
147148
}
148149

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package turing.tmb.mixin.client;
2+
3+
import net.minecraft.client.gui.container.ScreenContainerAbstract;
4+
import net.minecraft.client.gui.container.ScreenCrafting;
5+
import net.minecraft.client.gui.guidebook.SlotGuidebook;
6+
import net.minecraft.client.gui.guidebook.crafting.RecipePageCrafting;
7+
import net.minecraft.client.gui.guidebook.crafting.displays.RecipeDisplayAdapter;
8+
import net.minecraft.core.data.registry.recipe.RecipeEntryBase;
9+
import net.minecraft.core.data.registry.recipe.RecipeSymbol;
10+
import net.minecraft.core.data.registry.recipe.entry.RecipeEntryCraftingShaped;
11+
import net.minecraft.core.data.registry.recipe.entry.RecipeEntryCraftingShapeless;
12+
import net.minecraft.core.item.ItemStack;
13+
import net.minecraft.core.player.inventory.menu.MenuAbstract;
14+
import net.minecraft.core.player.inventory.slot.Slot;
15+
import net.minecraft.core.util.collection.Pair;
16+
import org.spongepowered.asm.mixin.Mixin;
17+
import turing.tmb.TMB;
18+
import turing.tmb.api.ISupportsRecipeFilling;
19+
import turing.tmb.api.recipe.IRecipeTranslator;
20+
import turing.tmb.util.InventoryWrapper;
21+
22+
import java.util.ArrayList;
23+
import java.util.Arrays;
24+
import java.util.List;
25+
import java.util.stream.Collectors;
26+
27+
@Mixin(value = ScreenCrafting.class, remap = false)
28+
public abstract class ScreenCraftingMixin extends ScreenContainerAbstract implements ISupportsRecipeFilling {
29+
private ScreenCraftingMixin(MenuAbstract container) {
30+
super(container);
31+
}
32+
33+
@Override
34+
public void fillRecipe(IRecipeTranslator<?> translator, boolean maximum) {
35+
InventoryWrapper w = new InventoryWrapper(mc.thePlayer.inventory);
36+
for (Slot slot : inventorySlots.slots) {
37+
if(slot.hasItem() && slot.index > 0 && slot.index < 10){
38+
mc.thePlayer.inventory.insertItem(slot.getItemStack(), false);
39+
slot.set(null);
40+
}
41+
}
42+
if (translator.getOriginal() instanceof RecipeEntryCraftingShaped) {
43+
RecipeEntryCraftingShaped recipe = (RecipeEntryCraftingShaped) translator.getOriginal();
44+
List<RecipeSymbol> list = Arrays.stream(recipe.getInput()).collect(Collectors.toList());
45+
Pair<Boolean, List<ItemStack>> pair = w.containsRecipe(list);
46+
if(pair.getLeft()){
47+
List<ItemStack> materials = pair.getRight();
48+
RecipeDisplayAdapter<RecipeEntryCraftingShaped> adapter = (RecipeDisplayAdapter<RecipeEntryCraftingShaped>) RecipePageCrafting.recipeToDisplayAdapterMap.get(RecipeEntryCraftingShaped.class);
49+
List<SlotGuidebook> slots = adapter.getSlots(recipe, 0, 0, 0);
50+
51+
int maxAmount = materials.stream().mapToInt(stack -> stack.stackSize).min().orElse(0);
52+
53+
for (int i = 0; i < maxAmount; i++) {
54+
for (SlotGuidebook slot : slots) {
55+
if (slot.symbol == null && slot.item == null) continue;
56+
for (ItemStack material : materials) {
57+
List<ItemStack> resolved = new ArrayList<>();
58+
if (slot.symbol != null) {
59+
resolved = slot.symbol.resolve();
60+
} else if (slot.item != null) {
61+
resolved.add(slot.item);
62+
}
63+
Pair<Boolean, ItemStack> contains = InventoryWrapper.listContains(resolved, material, ItemStack::isItemEqual, true);
64+
if (contains.getLeft()) {
65+
ItemStack recipeStack = contains.getRight();
66+
ItemStack removedStack = w.removeUntil(recipeStack.itemID, recipeStack.getMetadata(), recipeStack.stackSize, recipeStack.getData(), false, false);
67+
if(removedStack == null) continue;
68+
if (inventorySlots.slots.get(slot.index + 1).getItemStack() == null) {
69+
inventorySlots.slots.get(slot.index + 1).set(removedStack);
70+
} else if (removedStack.isItemEqual(inventorySlots.slots.get(slot.index + 1).getItemStack())) {
71+
inventorySlots.slots.get(slot.index + 1).getItemStack().stackSize += removedStack.stackSize;
72+
}
73+
}
74+
}
75+
}
76+
}
77+
}
78+
79+
}
80+
if(translator.getOriginal() instanceof RecipeEntryCraftingShapeless) {
81+
RecipeEntryCraftingShapeless recipe = (RecipeEntryCraftingShapeless) translator.getOriginal();
82+
List<RecipeSymbol> list = new ArrayList<>(recipe.getInput());
83+
Pair<Boolean, List<ItemStack>> pair = w.containsRecipe(list);
84+
if(pair.getLeft()){
85+
List<ItemStack> materials = pair.getRight();
86+
RecipeDisplayAdapter<RecipeEntryCraftingShapeless> adapter = (RecipeDisplayAdapter<RecipeEntryCraftingShapeless>) RecipePageCrafting.recipeToDisplayAdapterMap.get(RecipeEntryCraftingShapeless.class);
87+
List<SlotGuidebook> slots = adapter.getSlots(recipe, 0, 0, 0);
88+
89+
int maxAmount = materials.stream().mapToInt(stack -> stack.stackSize).min().orElse(0);
90+
91+
for (int i = 0; i < maxAmount; i++) {
92+
for (SlotGuidebook slot : slots) {
93+
if (slot.symbol == null && slot.item == null) continue;
94+
List<ItemStack> resolved = new ArrayList<>();
95+
if (slot.symbol != null) {
96+
resolved = slot.symbol.resolve();
97+
} else {
98+
resolved.add(slot.item);
99+
}
100+
for (ItemStack material : materials) {
101+
Pair<Boolean, ItemStack> contains = InventoryWrapper.listContains(resolved, material, ItemStack::isItemEqual, true);
102+
if (contains.getLeft()) {
103+
ItemStack recipeStack = contains.getRight();
104+
ItemStack removedStack = w.removeUntil(recipeStack.itemID, recipeStack.getMetadata(), recipeStack.stackSize, recipeStack.getData(), false, false);
105+
if(removedStack == null) continue;
106+
if (inventorySlots.slots.get(slot.index + 1).getItemStack() == null) {
107+
inventorySlots.slots.get(slot.index + 1).set(removedStack);
108+
} else if (removedStack.isItemEqual(inventorySlots.slots.get(slot.index + 1).getItemStack())) {
109+
inventorySlots.slots.get(slot.index + 1).getItemStack().stackSize += removedStack.stackSize;
110+
}
111+
}
112+
}
113+
}
114+
}
115+
}
116+
}
117+
}
118+
119+
@Override
120+
public List<Class<? extends RecipeEntryBase<?, ?, ?>>> getSupportedRecipes() {
121+
ArrayList<Class<? extends RecipeEntryBase<?, ?, ?>>> list = new ArrayList<>();
122+
list.add(RecipeEntryCraftingShaped.class);
123+
list.add(RecipeEntryCraftingShapeless.class);
124+
return list;
125+
}
126+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package turing.tmb.mixin.client;
2+
3+
import net.minecraft.client.gui.container.ScreenContainerAbstract;
4+
import net.minecraft.client.gui.container.ScreenFurnace;
5+
import net.minecraft.client.gui.guidebook.SlotGuidebook;
6+
import net.minecraft.client.gui.guidebook.crafting.RecipePageCrafting;
7+
import net.minecraft.client.gui.guidebook.crafting.displays.RecipeDisplayAdapter;
8+
import net.minecraft.core.block.entity.TileEntityFurnace;
9+
import net.minecraft.core.data.registry.recipe.RecipeEntryBase;
10+
import net.minecraft.core.data.registry.recipe.RecipeSymbol;
11+
import net.minecraft.core.data.registry.recipe.entry.RecipeEntryBlastFurnace;
12+
import net.minecraft.core.data.registry.recipe.entry.RecipeEntryCraftingShaped;
13+
import net.minecraft.core.data.registry.recipe.entry.RecipeEntryCraftingShapeless;
14+
import net.minecraft.core.data.registry.recipe.entry.RecipeEntryFurnace;
15+
import net.minecraft.core.item.ItemStack;
16+
import net.minecraft.core.player.inventory.menu.MenuAbstract;
17+
import net.minecraft.core.player.inventory.slot.Slot;
18+
import net.minecraft.core.util.collection.Pair;
19+
import org.spongepowered.asm.mixin.Final;
20+
import org.spongepowered.asm.mixin.Mixin;
21+
import org.spongepowered.asm.mixin.Shadow;
22+
import turing.tmb.api.ISupportsRecipeFilling;
23+
import turing.tmb.api.recipe.IRecipeTranslator;
24+
import turing.tmb.util.InventoryWrapper;
25+
26+
import java.util.ArrayList;
27+
import java.util.Arrays;
28+
import java.util.List;
29+
import java.util.stream.Collectors;
30+
31+
@Mixin(value = ScreenFurnace.class, remap = false)
32+
public abstract class ScreenFurnaceMixin extends ScreenContainerAbstract implements ISupportsRecipeFilling {
33+
@Shadow
34+
@Final
35+
private TileEntityFurnace furnaceInventory;
36+
37+
public ScreenFurnaceMixin(MenuAbstract container) {
38+
super(container);
39+
}
40+
41+
@Override
42+
public void fillRecipe(IRecipeTranslator<?> translator, boolean maximum) {
43+
InventoryWrapper w = new InventoryWrapper(mc.thePlayer.inventory);
44+
for (Slot slot : inventorySlots.slots) {
45+
if(slot.hasItem() && slot.index == 0){
46+
mc.thePlayer.inventory.insertItem(slot.getItemStack(), false);
47+
slot.set(null);
48+
}
49+
}
50+
51+
if (translator.getOriginal() instanceof RecipeEntryFurnace) {
52+
RecipeEntryFurnace recipe = (RecipeEntryFurnace) translator.getOriginal();
53+
List<RecipeSymbol> list = new ArrayList<>();
54+
list.add(recipe.getInput());
55+
Pair<Boolean, List<ItemStack>> pair = w.containsRecipe(list);
56+
if(pair.getLeft()){
57+
List<ItemStack> materials = pair.getRight();
58+
List<ItemStack> resolved = recipe.getInput().resolve();
59+
Pair<Boolean, ItemStack> contains = InventoryWrapper.listContains(resolved, materials.get(0), ItemStack::isItemEqual, true);
60+
if(contains.getLeft()){
61+
ItemStack recipeStack = contains.getRight();
62+
int amount = recipeStack.stackSize;
63+
if(maximum){
64+
amount = materials.get(0).stackSize / recipeStack.stackSize;
65+
}
66+
ItemStack removedStack = w.removeUntil(recipeStack.itemID, recipeStack.getMetadata(), amount, recipeStack.getData(), false, false);
67+
inventorySlots.slots.get(0).set(removedStack);
68+
}
69+
}
70+
}
71+
72+
if (translator.getOriginal() instanceof RecipeEntryBlastFurnace) {
73+
RecipeEntryBlastFurnace recipe = (RecipeEntryBlastFurnace) translator.getOriginal();
74+
List<RecipeSymbol> list = new ArrayList<>();
75+
list.add(recipe.getInput());
76+
Pair<Boolean, List<ItemStack>> pair = w.containsRecipe(list);
77+
if(pair.getLeft()){
78+
List<ItemStack> materials = pair.getRight();
79+
List<ItemStack> resolved = recipe.getInput().resolve();
80+
Pair<Boolean, ItemStack> contains = InventoryWrapper.listContains(resolved, materials.get(0), ItemStack::isItemEqual, true);
81+
if(contains.getLeft()){
82+
ItemStack recipeStack = contains.getRight();
83+
int amount = recipeStack.stackSize;
84+
if(maximum){
85+
amount = materials.get(0).stackSize / recipeStack.stackSize;
86+
}
87+
ItemStack removedStack = w.removeUntil(recipeStack.itemID, recipeStack.getMetadata(), amount, recipeStack.getData(), false, false);
88+
inventorySlots.slots.get(0).set(removedStack);
89+
}
90+
}
91+
}
92+
}
93+
94+
@Override
95+
public List<Class<? extends RecipeEntryBase<?, ?, ?>>> getSupportedRecipes() {
96+
ArrayList<Class<? extends RecipeEntryBase<?, ?, ?>>> list = new ArrayList<>();
97+
if(furnaceInventory instanceof TileEntityFurnace){
98+
list.add(RecipeEntryFurnace.class);
99+
} else {
100+
list.add(RecipeEntryBlastFurnace.class);
101+
}
102+
return list;
103+
}
104+
}

0 commit comments

Comments
 (0)