mirror of
https://github.com/Ellpeck/PrettyPipes.git
synced 2024-12-22 15:39:22 +01:00
overhaul crafting module modes and add one that splits requests by crafts
closes #231
This commit is contained in:
parent
ddc55003b6
commit
652b3538d2
5 changed files with 61 additions and 44 deletions
|
@ -7,6 +7,7 @@ import de.ellpeck.prettypipes.misc.ItemFilter.IFilteredContainer;
|
|||
import de.ellpeck.prettypipes.pipe.PipeBlockEntity;
|
||||
import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer;
|
||||
import de.ellpeck.prettypipes.pipe.modules.craft.CraftingModuleContainer;
|
||||
import de.ellpeck.prettypipes.pipe.modules.craft.CraftingModuleItem;
|
||||
import de.ellpeck.prettypipes.pipe.modules.modifier.FilterModifierModuleContainer;
|
||||
import de.ellpeck.prettypipes.pipe.modules.modifier.FilterModifierModuleItem;
|
||||
import de.ellpeck.prettypipes.pipe.modules.stacksize.StackSizeModuleItem;
|
||||
|
@ -33,6 +34,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import static de.ellpeck.prettypipes.misc.DirectionSelector.IDirectionContainer;
|
||||
import static de.ellpeck.prettypipes.pipe.modules.craft.CraftingModuleItem.*;
|
||||
|
||||
public record PacketButton(BlockPos pos, int result, List<Integer> data) implements CustomPacketPayload {
|
||||
|
||||
|
@ -95,15 +97,15 @@ public record PacketButton(BlockPos pos, int result, List<Integer> data) impleme
|
|||
if (player.containerMenu instanceof IFilteredContainer filtered)
|
||||
filtered.getFilter().onButtonPacket(filtered, data.getFirst());
|
||||
}),
|
||||
ENSURE_ITEM_ORDER_BUTTON((pos, data, player) -> {
|
||||
INSERTION_TYPE_BUTTON((pos, data, player) -> {
|
||||
if (player.containerMenu instanceof CraftingModuleContainer container) {
|
||||
container.ensureItemOrder = !container.ensureItemOrder;
|
||||
container.insertionType = InsertionType.values()[(container.insertionType.ordinal() + 1) % InsertionType.values().length];
|
||||
container.modified = true;
|
||||
}
|
||||
}),
|
||||
INSERT_SINGLES_BUTTON((pos, data, player) -> {
|
||||
INSERT_UNSTACKED_BUTTON((pos, data, player) -> {
|
||||
if (player.containerMenu instanceof CraftingModuleContainer container) {
|
||||
container.insertSingles = !container.insertSingles;
|
||||
container.insertUnstacked = !container.insertUnstacked;
|
||||
container.modified = true;
|
||||
}
|
||||
}),
|
||||
|
|
|
@ -6,18 +6,15 @@ import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer;
|
|||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.neoforged.neoforge.items.ItemStackHandler;
|
||||
import net.neoforged.neoforge.items.SlotItemHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CraftingModuleContainer extends AbstractPipeContainer<CraftingModuleItem> {
|
||||
|
||||
public ItemStackHandler input;
|
||||
public ItemStackHandler output;
|
||||
public boolean ensureItemOrder;
|
||||
public boolean insertSingles;
|
||||
public boolean emitRedstone;
|
||||
public CraftingModuleItem.InsertionType insertionType;
|
||||
public boolean insertUnstacked;
|
||||
public boolean modified;
|
||||
|
||||
public CraftingModuleContainer(MenuType<?> type, int id, Player player, BlockPos pos, int moduleIndex) {
|
||||
|
@ -27,9 +24,9 @@ public class CraftingModuleContainer extends AbstractPipeContainer<CraftingModul
|
|||
@Override
|
||||
protected void addSlots() {
|
||||
var contents = this.moduleStack.get(CraftingModuleItem.Contents.TYPE);
|
||||
this.ensureItemOrder = contents.ensureItemOrder();
|
||||
this.insertSingles = contents.insertSingles();
|
||||
this.emitRedstone = contents.emitRedstone();
|
||||
this.insertionType = contents.insertionType();
|
||||
this.insertUnstacked = contents.insertUnstacked();
|
||||
|
||||
this.input = Utility.copy(contents.input());
|
||||
for (var i = 0; i < this.input.getSlots(); i++) {
|
||||
|
@ -59,7 +56,7 @@ public class CraftingModuleContainer extends AbstractPipeContainer<CraftingModul
|
|||
public void removed(Player playerIn) {
|
||||
super.removed(playerIn);
|
||||
if (this.modified) {
|
||||
this.moduleStack.set(CraftingModuleItem.Contents.TYPE, new CraftingModuleItem.Contents(this.input, this.output, this.ensureItemOrder, this.insertSingles, this.emitRedstone));
|
||||
this.moduleStack.set(CraftingModuleItem.Contents.TYPE, new CraftingModuleItem.Contents(this.input, this.output, this.emitRedstone, this.insertionType, this.insertUnstacked));
|
||||
this.tile.setChanged();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,11 @@ import net.minecraft.client.gui.GuiGraphics;
|
|||
import net.minecraft.client.gui.components.Button;
|
||||
import net.minecraft.client.gui.components.Tooltip;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class CraftingModuleGui extends AbstractPipeGui<CraftingModuleContainer> {
|
||||
|
@ -28,26 +30,27 @@ public class CraftingModuleGui extends AbstractPipeGui<CraftingModuleContainer>
|
|||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
var cacheText = (Supplier<String>) () -> "info." + PrettyPipes.ID + ".ensure_item_order_" + (this.menu.ensureItemOrder ? "on" : "off");
|
||||
this.addRenderableWidget(Button.builder(Component.translatable(cacheText.get()), button -> {
|
||||
PacketButton.sendAndExecute(this.menu.tile.getBlockPos(), PacketButton.ButtonResult.ENSURE_ITEM_ORDER_BUTTON, List.of());
|
||||
button.setMessage(Component.translatable(cacheText.get()));
|
||||
}).bounds(this.leftPos + this.imageWidth - 7 - 20, this.topPos + 17 + 32 + 18 * 2 + 2, 20, 20).tooltip(
|
||||
Tooltip.create(Component.translatable("info." + PrettyPipes.ID + ".ensure_item_order.description").withStyle(ChatFormatting.GRAY))).build());
|
||||
|
||||
var singleText = (Supplier<String>) () -> "info." + PrettyPipes.ID + ".insert_singles_" + (this.menu.insertSingles ? "on" : "off");
|
||||
this.addRenderableWidget(Button.builder(Component.translatable(singleText.get()), button -> {
|
||||
PacketButton.sendAndExecute(this.menu.tile.getBlockPos(), PacketButton.ButtonResult.INSERT_SINGLES_BUTTON, List.of());
|
||||
button.setMessage(Component.translatable(singleText.get()));
|
||||
}).bounds(this.leftPos + this.imageWidth - 7 - 20 - 22, this.topPos + 17 + 32 + 18 * 2 + 2, 20, 20).tooltip(
|
||||
Tooltip.create(Component.translatable("info." + PrettyPipes.ID + ".insert_singles.description").withStyle(ChatFormatting.GRAY))).build());
|
||||
|
||||
var redstoneText = (Supplier<String>) () -> "info." + PrettyPipes.ID + ".emit_redstone_" + (this.menu.emitRedstone ? "on" : "off");
|
||||
this.addRenderableWidget(Button.builder(Component.translatable(redstoneText.get()), button -> {
|
||||
PacketButton.sendAndExecute(this.menu.tile.getBlockPos(), PacketButton.ButtonResult.EMIT_REDSTONE_BUTTON, List.of());
|
||||
button.setMessage(Component.translatable(redstoneText.get()));
|
||||
}).bounds(this.leftPos + 7, this.topPos + 17 + 32 + 18 * 2 + 2, 20, 20).tooltip(
|
||||
}).bounds(this.leftPos + this.imageWidth - 7 - 20, this.topPos + 17 + 32 + 18 * 2 + 2, 20, 20).tooltip(
|
||||
Tooltip.create(Component.translatable("info." + PrettyPipes.ID + ".emit_redstone.description").withStyle(ChatFormatting.GRAY))).build());
|
||||
var unstackedText = (Supplier<String>) () -> "info." + PrettyPipes.ID + ".insert_unstacked_" + (this.menu.insertUnstacked ? "on" : "off");
|
||||
this.addRenderableWidget(Button.builder(Component.translatable(unstackedText.get()), button -> {
|
||||
PacketButton.sendAndExecute(this.menu.tile.getBlockPos(), PacketButton.ButtonResult.INSERT_UNSTACKED_BUTTON, List.of());
|
||||
button.setMessage(Component.translatable(unstackedText.get()));
|
||||
}).bounds(this.leftPos + this.imageWidth - 7 - 20 - 22, this.topPos + 17 + 32 + 18 * 2 + 2, 20, 20).tooltip(
|
||||
Tooltip.create(Component.translatable("info." + PrettyPipes.ID + ".insert_unstacked.description").withStyle(ChatFormatting.GRAY))).build());
|
||||
|
||||
var insertionTypeText = (Supplier<MutableComponent>) () -> Component.translatable(this.menu.insertionType.translationKey());
|
||||
var insertionTypeTooltip = (Supplier<Tooltip>) () -> Tooltip.create(Component.translatable(this.menu.insertionType.translationKey() + ".description").withStyle(ChatFormatting.GRAY));
|
||||
this.addRenderableWidget(Button.builder(insertionTypeText.get(), button -> {
|
||||
PacketButton.sendAndExecute(this.menu.tile.getBlockPos(), PacketButton.ButtonResult.INSERTION_TYPE_BUTTON, List.of());
|
||||
button.setMessage(insertionTypeText.get());
|
||||
button.setTooltip(insertionTypeTooltip.get());
|
||||
}).bounds(this.leftPos + 7, this.topPos + 17 + 32 + 18 * 2 + 2, 42, 20).tooltip(insertionTypeTooltip.get()).build());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package de.ellpeck.prettypipes.pipe.modules.craft;
|
|||
import com.mojang.datafixers.util.Either;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import de.ellpeck.prettypipes.PrettyPipes;
|
||||
import de.ellpeck.prettypipes.Registry;
|
||||
import de.ellpeck.prettypipes.Utility;
|
||||
import de.ellpeck.prettypipes.items.IModule;
|
||||
|
@ -36,7 +37,7 @@ public class CraftingModuleItem extends ModuleItem {
|
|||
private final int speed;
|
||||
|
||||
public CraftingModuleItem(String name, ModuleTier tier) {
|
||||
super(name, new Properties().component(Contents.TYPE, new Contents(new ItemStackHandler(tier.forTier(1, 4, 9)), new ItemStackHandler(tier.forTier(1, 2, 4)), false, false, false)));
|
||||
super(name, new Properties().component(Contents.TYPE, new Contents(new ItemStackHandler(tier.forTier(1, 4, 9)), new ItemStackHandler(tier.forTier(1, 2, 4)), false, InsertionType.ALL, false)));
|
||||
this.speed = tier.forTier(20, 10, 5);
|
||||
}
|
||||
|
||||
|
@ -87,7 +88,7 @@ public class CraftingModuleItem extends ModuleItem {
|
|||
var dest = tile.getAvailableDestination(Direction.values(), toRequest, true, true);
|
||||
if (dest != null) {
|
||||
// if we're ensuring the correct item order and the item is already on the way, don't do anything yet
|
||||
if (!module.get(Contents.TYPE).ensureItemOrder || craft.travelingIngredients.isEmpty()) {
|
||||
if (module.get(Contents.TYPE).insertionType != InsertionType.PER_ITEM || craft.travelingIngredients.isEmpty()) {
|
||||
var equalityTypes = ItemFilter.getEqualityTypes(tile);
|
||||
var requested = ingredient.map(l -> {
|
||||
// we can ignore the return value here since we're using a lock, so we know that the item is already waiting for us there
|
||||
|
@ -217,15 +218,15 @@ public class CraftingModuleItem extends ModuleItem {
|
|||
|
||||
var leftOfRequest = stack.getCount();
|
||||
var allCrafts = new ArrayList<ActiveCraft>();
|
||||
// if we're ensuring item order, all items for a single recipe should be sent in order first before starting on the next one!
|
||||
for (var c = contents.ensureItemOrder ? toCraft : 1; c > 0; c--) {
|
||||
// if we're inserting individual items or per craft, we need to split up the request into multiple crafts
|
||||
for (var c = contents.insertionType != InsertionType.ALL ? toCraft : 1; c > 0; c--) {
|
||||
var toRequest = new ArrayList<Either<NetworkLock, ItemStack>>();
|
||||
for (var i = 0; i < contents.input.getSlots(); i++) {
|
||||
var in = contents.input.getStackInSlot(i);
|
||||
if (in.isEmpty())
|
||||
continue;
|
||||
var request = in.copy();
|
||||
if (!contents.ensureItemOrder)
|
||||
if (contents.insertionType == InsertionType.ALL)
|
||||
request.setCount(in.getCount() * toCraft);
|
||||
var ret = network.requestLocksAndStartCrafting(tile.getBlockPos(), items, unavailableConsumer, request, CraftingModuleItem.addDependency(dependencyChain, module), equalityTypes);
|
||||
for (var lock : ret.getLeft())
|
||||
|
@ -243,7 +244,7 @@ public class CraftingModuleItem extends ModuleItem {
|
|||
allCrafts.add(dep);
|
||||
}
|
||||
}
|
||||
var crafted = contents.ensureItemOrder ? resultAmount : resultAmount * toCraft;
|
||||
var crafted = contents.insertionType != InsertionType.ALL ? resultAmount : resultAmount * toCraft;
|
||||
// items we started craft dependencies for are ones that will be sent to us (so we're waiting for them immediately!)
|
||||
var activeCraft = new ActiveCraft(tile.getBlockPos(), slot, toRequest, new ArrayList<>(), destPipe, stack.copyWithCount(Math.min(crafted, leftOfRequest)));
|
||||
tile.getActiveCrafts().add(activeCraft);
|
||||
|
@ -272,7 +273,7 @@ public class CraftingModuleItem extends ModuleItem {
|
|||
if (traveling.isEmpty())
|
||||
craft.travelingIngredients.remove(traveling);
|
||||
|
||||
if (contents.insertSingles) {
|
||||
if (contents.insertUnstacked) {
|
||||
var handler = tile.getItemHandler(direction);
|
||||
if (handler != null) {
|
||||
while (!stack.isEmpty()) {
|
||||
|
@ -316,17 +317,28 @@ public class CraftingModuleItem extends ModuleItem {
|
|||
return deps;
|
||||
}
|
||||
|
||||
public record Contents(ItemStackHandler input, ItemStackHandler output, boolean ensureItemOrder, boolean insertSingles, boolean emitRedstone) {
|
||||
public record Contents(ItemStackHandler input, ItemStackHandler output, boolean emitRedstone, InsertionType insertionType, boolean insertUnstacked) {
|
||||
|
||||
public static final Codec<Contents> CODEC = RecordCodecBuilder.create(i -> i.group(
|
||||
Utility.ITEM_STACK_HANDLER_CODEC.fieldOf("input").forGetter(d -> d.input),
|
||||
Utility.ITEM_STACK_HANDLER_CODEC.fieldOf("output").forGetter(d -> d.output),
|
||||
Codec.BOOL.optionalFieldOf("ensure_item_order", false).forGetter(d -> d.ensureItemOrder),
|
||||
Codec.BOOL.optionalFieldOf("insert_singles", false).forGetter(d -> d.insertSingles),
|
||||
Codec.BOOL.optionalFieldOf("emit_redstone", false).forGetter(d -> d.emitRedstone)
|
||||
Codec.BOOL.optionalFieldOf("emit_redstone", false).forGetter(d -> d.emitRedstone),
|
||||
Codec.STRING.xmap(InsertionType::valueOf, InsertionType::name).optionalFieldOf("insertion_type", InsertionType.ALL).forGetter(d -> d.insertionType),
|
||||
Codec.BOOL.optionalFieldOf("insert_unstacked", false).forGetter(d -> d.insertUnstacked)
|
||||
).apply(i, Contents::new));
|
||||
public static final DataComponentType<Contents> TYPE = DataComponentType.<Contents>builder().persistent(Contents.CODEC).cacheEncoding().build();
|
||||
|
||||
}
|
||||
|
||||
public enum InsertionType {
|
||||
|
||||
ALL,
|
||||
PER_ITEM,
|
||||
PER_CRAFT;
|
||||
|
||||
public String translationKey() {
|
||||
return "info." + PrettyPipes.ID + ".insertion_type." + this.name().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -66,15 +66,18 @@
|
|||
"info.prettypipes.blacklist": "\u00A74D",
|
||||
"info.prettypipes.whitelist.description": "Items in filter slots are allowed",
|
||||
"info.prettypipes.blacklist.description": "Items in filter slots are disallowed",
|
||||
"info.prettypipes.insert_singles_on": "\u00A72S",
|
||||
"info.prettypipes.insert_singles_off": "\u00A74\u00A7mS",
|
||||
"info.prettypipes.insert_singles.description": "Whether items should be inserted one at a time, rather than as a stack\n\u00A7oRecommended for use with the Crafter",
|
||||
"info.prettypipes.ensure_item_order_on": "\u00A72O",
|
||||
"info.prettypipes.ensure_item_order_off": "\u00A74\u00A7mO",
|
||||
"info.prettypipes.ensure_item_order.description": "Whether the module should wait for items to be inserted in the order they appear in the input slots\n\u00A7oRecommended for use with the Crafter",
|
||||
"info.prettypipes.insert_unstacked_on": "\u00A72O",
|
||||
"info.prettypipes.insert_unstacked_off": "\u00A74\u00A7mO",
|
||||
"info.prettypipes.insert_unstacked.description": "Whether items should be inserted one at a time, rather than as a stack, causing them to be spread out in some containers\n\u00A7oRecommended for use with the Crafter",
|
||||
"info.prettypipes.emit_redstone_on": "\u00A72R",
|
||||
"info.prettypipes.emit_redstone_off": "\u00A74\u00A7mR",
|
||||
"info.prettypipes.emit_redstone.description": "Whether a redstone signal should be emitted when all crafting items have arrived\nIf the module waits for items to be inserted in order, a redstone signal is emitted for each set of items required for a single craft\n\u00A7oRecommended for use with the Crafter",
|
||||
"info.prettypipes.emit_redstone.description": "Whether a redstone signal should be emitted when all crafting items have arrived\nIf the module is set to insert items individually or per craft, a redstone signal is emitted for each set of items required for a single crafting operation\n\u00A7oRecommended for use with the Crafter",
|
||||
"info.prettypipes.insertion_type.all": "All",
|
||||
"info.prettypipes.insertion_type.all.description": "Causes the module to request all items required for the entire crafting request at once, even if the request consists of multiple crafting operations",
|
||||
"info.prettypipes.insertion_type.per_item": "Singles",
|
||||
"info.prettypipes.insertion_type.per_item.description": "Causes the module to request items individually so that they will be inserted in the order they appear in the input slots\n\u00A7oRecommended for use with the Crafter",
|
||||
"info.prettypipes.insertion_type.per_craft": "Crafts",
|
||||
"info.prettypipes.insertion_type.per_craft.description": "Causes the module to request all items for a single crafting operation at once",
|
||||
"info.prettypipes.shift": "Hold Shift for info",
|
||||
"info.prettypipes.populate": "P",
|
||||
"info.prettypipes.populate.description": "Populate filter slots with items from adjacent inventories",
|
||||
|
|
Loading…
Reference in a new issue