Skip to content

Commit

Permalink
Trigger crafting jobs from JEI by Ctrl-clicking recipes
Browse files Browse the repository at this point in the history
  • Loading branch information
rubensworks committed Oct 16, 2024
1 parent 554563f commit d4680d7
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 13 deletions.
6 changes: 3 additions & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
mod_version=1.0.0
minecraft_version=1.19.2
forge_version=43.0.8
cyclopscore_version=1.18.0-294
cyclopscore_version=1.19.4-495
release_type=release
fingerprint=bd0353b3e8a2810d60dd584e256e364bc3bedd44

integrateddynamics_version=1.19.2-1.15.2-518
integratedterminals_version=1.19.2-1.4.6-270
integrateddynamics_version=1.19.2-1.22.0-726
integratedterminals_version=1.19.2-1.5.1-385
commoncapabilities_version=1.19.2-2.9.0-88
curios_version=1.19.2-5.1.1.0
jei_version=1.19.2-forge:11.5.2.1007
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package org.cyclops.integratedterminalscompat.modcompat.jei;

import com.mojang.blaze3d.vertex.PoseStack;
import mezz.jei.api.gui.ingredient.IRecipeSlotView;
import mezz.jei.api.gui.ingredient.IRecipeSlotsView;
import mezz.jei.api.recipe.transfer.IRecipeTransferError;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Component;
import org.cyclops.cyclopscore.helper.Helpers;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
* A transfer error object that changes appearance based on presence of storage and craftable items.
* @author rubensworks
*/
public class RecipeTransferErrorColored implements IRecipeTransferError {

public static final int SLOT_COLOR_MISSING = Helpers.RGBAToInt(255, 0, 0, 100);
public static final int SLOT_COLOR_CRAFTABLE = Helpers.RGBAToInt(0, 0, 255, 100);

public static final int HIGHLIGHT_COLOR_FAIL = Helpers.RGBAToInt(255, 0, 0, 100);
public static final int HIGHLIGHT_COLOR_CRAFTABLE = Helpers.RGBAToInt(0, 0, 255, 100);
public static final int HIGHLIGHT_COLOR_CRAFTABLE_PARTIAL = Helpers.RGBAToInt(255, 125, 0, 100);

private final List<Component> message = new ArrayList<>();
private final Collection<IRecipeSlotView> slotsMissing;
private final Collection<IRecipeSlotView> slotsCraftable;
private final int color;

public RecipeTransferErrorColored(Collection<IRecipeSlotView> slotsMissing, Collection<IRecipeSlotView> slotsCraftable) {
this.message.add(Component.translatable("jei.tooltip.transfer"));
this.slotsMissing = slotsMissing;
this.slotsCraftable = slotsCraftable;
if (slotsMissing.isEmpty()) {
// Missing items, but they are all craftable
this.message.add(Component.translatable("gui.integratedterminalscompat.terminal_storage.jei.transfer.craftable").withStyle(ChatFormatting.RED));
this.message.add(Component.translatable("gui.integratedterminalscompat.terminal_storage.jei.transfer.craft.info").withStyle(ChatFormatting.ITALIC));
this.color = HIGHLIGHT_COLOR_CRAFTABLE;
} else if (!slotsCraftable.isEmpty()) {
// Missing items, but only some of them are craftable
this.message.add(Component.translatable("gui.integratedterminalscompat.terminal_storage.jei.transfer.craftable_partial").withStyle(ChatFormatting.RED));
this.message.add(Component.translatable("gui.integratedterminalscompat.terminal_storage.jei.transfer.craft.info").withStyle(ChatFormatting.ITALIC));
this.color = HIGHLIGHT_COLOR_CRAFTABLE_PARTIAL;
} else {
// Missing items, and none are craftable
this.message.add(Component.translatable("gui.integratedterminalscompat.terminal_storage.jei.transfer.missing").withStyle(ChatFormatting.ITALIC));
this.color = HIGHLIGHT_COLOR_FAIL;
}
}

@Override
public Type getType() {
return this.slotsCraftable.isEmpty() ? Type.USER_FACING : Type.COSMETIC;
}

@Override
public int getButtonHighlightColor() {
return this.color;
}

@Override
public void showError(PoseStack poseStack, int mouseX, int mouseY, IRecipeSlotsView recipeSlotsView, int recipeX, int recipeY) {
Minecraft.getInstance().screen.renderComponentTooltip(poseStack, this.message, mouseX, mouseY);
poseStack.pushPose();
poseStack.translate(recipeX, recipeY, 0.0);
for (IRecipeSlotView slot : this.slotsMissing) {
slot.drawHighlight(poseStack, SLOT_COLOR_MISSING);
}
for (IRecipeSlotView slot : this.slotsCraftable) {
slot.drawHighlight(poseStack, SLOT_COLOR_CRAFTABLE);
}
poseStack.popPose();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import mezz.jei.api.recipe.transfer.IRecipeTransferError;
import mezz.jei.api.recipe.transfer.IRecipeTransferHandler;
import mezz.jei.api.recipe.transfer.IRecipeTransferHandlerHelper;
import net.minecraft.network.chat.Component;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.inventory.Slot;
Expand All @@ -35,6 +35,7 @@
import org.cyclops.integratedterminals.inventory.container.ContainerTerminalStorageBase;
import org.cyclops.integratedterminalscompat.IntegratedTerminalsCompat;
import org.cyclops.integratedterminalscompat.modcompat.jei.JEIIntegratedTerminalsConfig;
import org.cyclops.integratedterminalscompat.modcompat.jei.RecipeTransferErrorColored;
import org.cyclops.integratedterminalscompat.network.packet.TerminalStorageIngredientItemStackCraftingGridSetRecipe;

import javax.annotation.Nullable;
Expand Down Expand Up @@ -163,7 +164,7 @@ public IRecipeTransferError transferRecipe(T container, CraftingRecipe recipe, I

IntegratedTerminalsCompat._instance.getPacketHandler().sendToServer(
new TerminalStorageIngredientItemStackCraftingGridSetRecipe(container.getSelectedTab(),
container.getSelectedChannel(), maxTransfer, slottedIngredientsFromPlayer, slottedIngredientsFromStorage));
container.getSelectedChannel(), maxTransfer, slottedIngredientsFromPlayer, slottedIngredientsFromStorage, AbstractContainerScreen.hasControlDown()));
return null;
}
}
Expand Down Expand Up @@ -191,18 +192,26 @@ private Optional<IRecipeTransferError> getMissingItems(T container, CraftingReci
List<TerminalStorageTabIngredientComponentClient.InstanceWithMetadata<ItemStack>> unfilteredIngredients = tabClient
.getUnfilteredIngredientsView(container.getSelectedChannel());
IIngredientCollectionMutable<ItemStack, Integer> hayStack = IngredientCollectionHelpers.createCollapsedCollection(IngredientComponent.ITEMSTACK);
IIngredientCollectionMutable<ItemStack, Integer> hayStackCraftable = IngredientCollectionHelpers.createCollapsedCollection(IngredientComponent.ITEMSTACK);
hayStack.addAll(unfilteredIngredients
.stream()
.filter(i -> i.getCraftingOption() == null)
.map(TerminalStorageTabIngredientComponentClient.InstanceWithMetadata::getInstance)
.collect(Collectors.toList()));
hayStackCraftable.addAll(unfilteredIngredients
.stream()
.filter(i -> i.getCraftingOption() != null)
.map(TerminalStorageTabIngredientComponentClient.InstanceWithMetadata::getInstance)
.collect(Collectors.toList()));

List<IRecipeSlotView> slotsMissingItems = Lists.newArrayList();
List<IRecipeSlotView> slotsMissingCraftableItems = Lists.newArrayList();
for (IRecipeSlotView slotView : recipeLayout.getSlotViews()) {
if (!slotView.isEmpty() && slotView.getRole() == RecipeIngredientRole.INPUT) {
ITypedIngredient<?> typedIngredient = slotView.getAllIngredients().findFirst().get();
if (typedIngredient.getType() == VanillaTypes.ITEM_STACK) {
boolean found = false;
boolean craftable = false;
for (ItemStack itemStack : ((Stream<ITypedIngredient<ItemStack>>) (Stream) slotView.getAllIngredients())
.map(ITypedIngredient::getIngredient)
.collect(Collectors.toSet())) {
Expand All @@ -228,18 +237,26 @@ private Optional<IRecipeTransferError> getMissingItems(T container, CraftingReci
found = true;
break;
}

// Also check if this item could be craftable
if (hayStackCraftable.contains(itemStack, matchCondition)) {
craftable = true;
}
}
if (!found) {
slotsMissingItems.add(slotView);
if (craftable) {
slotsMissingCraftableItems.add(slotView);
} else {
slotsMissingItems.add(slotView);
}
}
}
}
}

previousChangeId = tabClient.getLastChangeId();
if (!slotsMissingItems.isEmpty()) {
Component message = Component.translatable("jei.tooltip.error.recipe.transfer.missing");
return Optional.of(recipeTransferHandlerHelper.createUserErrorForMissingSlots(message, slotsMissingItems));
if (!slotsMissingItems.isEmpty() || !slotsMissingCraftableItems.isEmpty()) {
return Optional.of(new RecipeTransferErrorColored(slotsMissingItems, slotsMissingCraftableItems));
}

return Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import net.minecraft.world.entity.player.Player;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.level.Level;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
Expand All @@ -18,11 +18,17 @@
import org.cyclops.cyclopscore.network.CodecField;
import org.cyclops.cyclopscore.network.PacketCodec;
import org.cyclops.integratedterminals.api.terminalstorage.ITerminalStorageTabCommon;
import org.cyclops.integratedterminals.api.terminalstorage.crafting.CraftingJobStartException;
import org.cyclops.integratedterminals.api.terminalstorage.crafting.ITerminalCraftingOption;
import org.cyclops.integratedterminals.api.terminalstorage.crafting.ITerminalCraftingPlan;
import org.cyclops.integratedterminals.api.terminalstorage.crafting.ITerminalStorageTabIngredientCraftingHandler;
import org.cyclops.integratedterminals.core.terminalstorage.TerminalStorageTabIngredientComponentItemStackCraftingCommon;
import org.cyclops.integratedterminals.core.terminalstorage.TerminalStorageTabIngredientComponentServer;
import org.cyclops.integratedterminals.core.terminalstorage.crafting.TerminalStorageTabIngredientCraftingHandlers;
import org.cyclops.integratedterminals.inventory.container.ContainerTerminalStorageBase;
import org.cyclops.integratedterminals.network.packet.TerminalStorageIngredientItemStackCraftingGridClear;

import java.util.Collection;
import java.util.List;
import java.util.Map;

Expand All @@ -41,19 +47,23 @@ public class TerminalStorageIngredientItemStackCraftingGridSetRecipe extends Pac
private boolean maxTransfer;
private Map<Integer, Pair<ItemStack, Integer>> slottedIngredientsFromPlayer;
private Map<Integer, List<Pair<ItemStack, Integer>>> slottedIngredientsFromStorage;
@CodecField
private boolean triggerCraftingJobs;

public TerminalStorageIngredientItemStackCraftingGridSetRecipe() {

}

public TerminalStorageIngredientItemStackCraftingGridSetRecipe(String tabId, int channel, boolean maxTransfer,
Map<Integer, Pair<ItemStack, Integer>> slottedIngredientsFromPlayer,
Map<Integer, List<Pair<ItemStack, Integer>>> slottedIngredientsFromStorage) {
Map<Integer, List<Pair<ItemStack, Integer>>> slottedIngredientsFromStorage,
boolean triggerCraftingJobs) {
this.tabId = tabId;
this.channel = channel;
this.maxTransfer = maxTransfer;
this.slottedIngredientsFromPlayer = slottedIngredientsFromPlayer;
this.slottedIngredientsFromStorage = slottedIngredientsFromStorage;
this.triggerCraftingJobs = triggerCraftingJobs;
}

@Override
Expand Down Expand Up @@ -160,6 +170,31 @@ public void actionServer(Level world, ServerPlayer player) {
}
if (!extracted.isEmpty()) {
slot.set(extracted);
} else if (this.triggerCraftingJobs) {
// Trigger crafting job if enabled
boolean startedJob = false;
for (ITerminalStorageTabIngredientCraftingHandler handler : TerminalStorageTabIngredientCraftingHandlers.REGISTRY.getHandlers()) {
for (Pair<ItemStack, Integer> stackEntry : entry.getValue()) {
for (ITerminalCraftingOption<ItemStack> craftingOption : (Collection<ITerminalCraftingOption<ItemStack>>) handler.getCraftingOptionsWithOutput(tabServerCrafting, channel, stackEntry.getLeft(), stackEntry.getRight())) {
ITerminalCraftingPlan craftingPlan = handler.calculateCraftingPlan(tabServerCrafting.getNetwork(), channel, craftingOption, 1);
if (craftingPlan.getStatus().isValid()) {
try {
handler.startCraftingJob(tabServerCrafting.getNetwork(), channel, craftingPlan, player);
startedJob = true;
break;
} catch (CraftingJobStartException e) {
// Ignore jobs that could not start
}
}
}
if (startedJob) {
break;
}
}
if (startedJob) {
break;
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"_comment": "Gui",
"gui.integratedterminalscompat.terminal_storage.craftinggrid.jeisync": "JEI Search Sync",
"gui.integratedterminalscompat.terminal_storage.craftinggrid.jeisync.info": "Synchronize search box with JEI."
"gui.integratedterminalscompat.terminal_storage.craftinggrid.jeisync.info": "Synchronize search box with JEI.",
"gui.integratedterminalscompat.terminal_storage.jei.transfer.craftable": "Auto-craftable items",
"gui.integratedterminalscompat.terminal_storage.jei.transfer.craftable_partial": "Partially auto-craftable items",
"gui.integratedterminalscompat.terminal_storage.jei.transfer.missing": "Missing items",
"gui.integratedterminalscompat.terminal_storage.jei.transfer.craft.info": "Ctrl+click to trigger auto-crafting"
}

0 comments on commit d4680d7

Please sign in to comment.