Skip to content

Commit 652b353

Browse files
committed
overhaul crafting module modes and add one that splits requests by crafts
closes #231
1 parent ddc5500 commit 652b353

File tree

5 files changed

+61
-44
lines changed

5 files changed

+61
-44
lines changed

src/main/java/de/ellpeck/prettypipes/packets/PacketButton.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import de.ellpeck.prettypipes.pipe.PipeBlockEntity;
88
import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer;
99
import de.ellpeck.prettypipes.pipe.modules.craft.CraftingModuleContainer;
10+
import de.ellpeck.prettypipes.pipe.modules.craft.CraftingModuleItem;
1011
import de.ellpeck.prettypipes.pipe.modules.modifier.FilterModifierModuleContainer;
1112
import de.ellpeck.prettypipes.pipe.modules.modifier.FilterModifierModuleItem;
1213
import de.ellpeck.prettypipes.pipe.modules.stacksize.StackSizeModuleItem;
@@ -33,6 +34,7 @@
3334
import java.util.List;
3435

3536
import static de.ellpeck.prettypipes.misc.DirectionSelector.IDirectionContainer;
37+
import static de.ellpeck.prettypipes.pipe.modules.craft.CraftingModuleItem.*;
3638

3739
public record PacketButton(BlockPos pos, int result, List<Integer> data) implements CustomPacketPayload {
3840

@@ -95,15 +97,15 @@ public boolean shouldTriggerClientSideContainerClosingOnOpen() {
9597
if (player.containerMenu instanceof IFilteredContainer filtered)
9698
filtered.getFilter().onButtonPacket(filtered, data.getFirst());
9799
}),
98-
ENSURE_ITEM_ORDER_BUTTON((pos, data, player) -> {
100+
INSERTION_TYPE_BUTTON((pos, data, player) -> {
99101
if (player.containerMenu instanceof CraftingModuleContainer container) {
100-
container.ensureItemOrder = !container.ensureItemOrder;
102+
container.insertionType = InsertionType.values()[(container.insertionType.ordinal() + 1) % InsertionType.values().length];
101103
container.modified = true;
102104
}
103105
}),
104-
INSERT_SINGLES_BUTTON((pos, data, player) -> {
106+
INSERT_UNSTACKED_BUTTON((pos, data, player) -> {
105107
if (player.containerMenu instanceof CraftingModuleContainer container) {
106-
container.insertSingles = !container.insertSingles;
108+
container.insertUnstacked = !container.insertUnstacked;
107109
container.modified = true;
108110
}
109111
}),

src/main/java/de/ellpeck/prettypipes/pipe/modules/craft/CraftingModuleContainer.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,15 @@
66
import net.minecraft.core.BlockPos;
77
import net.minecraft.world.entity.player.Player;
88
import net.minecraft.world.inventory.MenuType;
9-
import net.minecraft.world.item.ItemStack;
109
import net.neoforged.neoforge.items.ItemStackHandler;
11-
import net.neoforged.neoforge.items.SlotItemHandler;
12-
import org.jetbrains.annotations.NotNull;
1310

1411
public class CraftingModuleContainer extends AbstractPipeContainer<CraftingModuleItem> {
1512

1613
public ItemStackHandler input;
1714
public ItemStackHandler output;
18-
public boolean ensureItemOrder;
19-
public boolean insertSingles;
2015
public boolean emitRedstone;
16+
public CraftingModuleItem.InsertionType insertionType;
17+
public boolean insertUnstacked;
2118
public boolean modified;
2219

2320
public CraftingModuleContainer(MenuType<?> type, int id, Player player, BlockPos pos, int moduleIndex) {
@@ -27,9 +24,9 @@ public CraftingModuleContainer(MenuType<?> type, int id, Player player, BlockPos
2724
@Override
2825
protected void addSlots() {
2926
var contents = this.moduleStack.get(CraftingModuleItem.Contents.TYPE);
30-
this.ensureItemOrder = contents.ensureItemOrder();
31-
this.insertSingles = contents.insertSingles();
3227
this.emitRedstone = contents.emitRedstone();
28+
this.insertionType = contents.insertionType();
29+
this.insertUnstacked = contents.insertUnstacked();
3330

3431
this.input = Utility.copy(contents.input());
3532
for (var i = 0; i < this.input.getSlots(); i++) {
@@ -59,7 +56,7 @@ public void setChanged() {
5956
public void removed(Player playerIn) {
6057
super.removed(playerIn);
6158
if (this.modified) {
62-
this.moduleStack.set(CraftingModuleItem.Contents.TYPE, new CraftingModuleItem.Contents(this.input, this.output, this.ensureItemOrder, this.insertSingles, this.emitRedstone));
59+
this.moduleStack.set(CraftingModuleItem.Contents.TYPE, new CraftingModuleItem.Contents(this.input, this.output, this.emitRedstone, this.insertionType, this.insertUnstacked));
6360
this.tile.setChanged();
6461
}
6562
}

src/main/java/de/ellpeck/prettypipes/pipe/modules/craft/CraftingModuleGui.java

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
import net.minecraft.client.gui.components.Button;
99
import net.minecraft.client.gui.components.Tooltip;
1010
import net.minecraft.network.chat.Component;
11+
import net.minecraft.network.chat.MutableComponent;
1112
import net.minecraft.world.entity.player.Inventory;
1213

1314
import java.util.List;
15+
import java.util.Locale;
1416
import java.util.function.Supplier;
1517

1618
public class CraftingModuleGui extends AbstractPipeGui<CraftingModuleContainer> {
@@ -28,26 +30,27 @@ protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, in
2830
@Override
2931
protected void init() {
3032
super.init();
31-
var cacheText = (Supplier<String>) () -> "info." + PrettyPipes.ID + ".ensure_item_order_" + (this.menu.ensureItemOrder ? "on" : "off");
32-
this.addRenderableWidget(Button.builder(Component.translatable(cacheText.get()), button -> {
33-
PacketButton.sendAndExecute(this.menu.tile.getBlockPos(), PacketButton.ButtonResult.ENSURE_ITEM_ORDER_BUTTON, List.of());
34-
button.setMessage(Component.translatable(cacheText.get()));
35-
}).bounds(this.leftPos + this.imageWidth - 7 - 20, this.topPos + 17 + 32 + 18 * 2 + 2, 20, 20).tooltip(
36-
Tooltip.create(Component.translatable("info." + PrettyPipes.ID + ".ensure_item_order.description").withStyle(ChatFormatting.GRAY))).build());
37-
38-
var singleText = (Supplier<String>) () -> "info." + PrettyPipes.ID + ".insert_singles_" + (this.menu.insertSingles ? "on" : "off");
39-
this.addRenderableWidget(Button.builder(Component.translatable(singleText.get()), button -> {
40-
PacketButton.sendAndExecute(this.menu.tile.getBlockPos(), PacketButton.ButtonResult.INSERT_SINGLES_BUTTON, List.of());
41-
button.setMessage(Component.translatable(singleText.get()));
42-
}).bounds(this.leftPos + this.imageWidth - 7 - 20 - 22, this.topPos + 17 + 32 + 18 * 2 + 2, 20, 20).tooltip(
43-
Tooltip.create(Component.translatable("info." + PrettyPipes.ID + ".insert_singles.description").withStyle(ChatFormatting.GRAY))).build());
4433

4534
var redstoneText = (Supplier<String>) () -> "info." + PrettyPipes.ID + ".emit_redstone_" + (this.menu.emitRedstone ? "on" : "off");
4635
this.addRenderableWidget(Button.builder(Component.translatable(redstoneText.get()), button -> {
4736
PacketButton.sendAndExecute(this.menu.tile.getBlockPos(), PacketButton.ButtonResult.EMIT_REDSTONE_BUTTON, List.of());
4837
button.setMessage(Component.translatable(redstoneText.get()));
49-
}).bounds(this.leftPos + 7, this.topPos + 17 + 32 + 18 * 2 + 2, 20, 20).tooltip(
38+
}).bounds(this.leftPos + this.imageWidth - 7 - 20, this.topPos + 17 + 32 + 18 * 2 + 2, 20, 20).tooltip(
5039
Tooltip.create(Component.translatable("info." + PrettyPipes.ID + ".emit_redstone.description").withStyle(ChatFormatting.GRAY))).build());
40+
var unstackedText = (Supplier<String>) () -> "info." + PrettyPipes.ID + ".insert_unstacked_" + (this.menu.insertUnstacked ? "on" : "off");
41+
this.addRenderableWidget(Button.builder(Component.translatable(unstackedText.get()), button -> {
42+
PacketButton.sendAndExecute(this.menu.tile.getBlockPos(), PacketButton.ButtonResult.INSERT_UNSTACKED_BUTTON, List.of());
43+
button.setMessage(Component.translatable(unstackedText.get()));
44+
}).bounds(this.leftPos + this.imageWidth - 7 - 20 - 22, this.topPos + 17 + 32 + 18 * 2 + 2, 20, 20).tooltip(
45+
Tooltip.create(Component.translatable("info." + PrettyPipes.ID + ".insert_unstacked.description").withStyle(ChatFormatting.GRAY))).build());
46+
47+
var insertionTypeText = (Supplier<MutableComponent>) () -> Component.translatable(this.menu.insertionType.translationKey());
48+
var insertionTypeTooltip = (Supplier<Tooltip>) () -> Tooltip.create(Component.translatable(this.menu.insertionType.translationKey() + ".description").withStyle(ChatFormatting.GRAY));
49+
this.addRenderableWidget(Button.builder(insertionTypeText.get(), button -> {
50+
PacketButton.sendAndExecute(this.menu.tile.getBlockPos(), PacketButton.ButtonResult.INSERTION_TYPE_BUTTON, List.of());
51+
button.setMessage(insertionTypeText.get());
52+
button.setTooltip(insertionTypeTooltip.get());
53+
}).bounds(this.leftPos + 7, this.topPos + 17 + 32 + 18 * 2 + 2, 42, 20).tooltip(insertionTypeTooltip.get()).build());
5154
}
5255

5356
}

src/main/java/de/ellpeck/prettypipes/pipe/modules/craft/CraftingModuleItem.java

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.mojang.datafixers.util.Either;
44
import com.mojang.serialization.Codec;
55
import com.mojang.serialization.codecs.RecordCodecBuilder;
6+
import de.ellpeck.prettypipes.PrettyPipes;
67
import de.ellpeck.prettypipes.Registry;
78
import de.ellpeck.prettypipes.Utility;
89
import de.ellpeck.prettypipes.items.IModule;
@@ -36,7 +37,7 @@ public class CraftingModuleItem extends ModuleItem {
3637
private final int speed;
3738

3839
public CraftingModuleItem(String name, ModuleTier tier) {
39-
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)));
40+
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)));
4041
this.speed = tier.forTier(20, 10, 5);
4142
}
4243

@@ -87,7 +88,7 @@ public void tick(ItemStack module, PipeBlockEntity tile) {
8788
var dest = tile.getAvailableDestination(Direction.values(), toRequest, true, true);
8889
if (dest != null) {
8990
// if we're ensuring the correct item order and the item is already on the way, don't do anything yet
90-
if (!module.get(Contents.TYPE).ensureItemOrder || craft.travelingIngredients.isEmpty()) {
91+
if (module.get(Contents.TYPE).insertionType != InsertionType.PER_ITEM || craft.travelingIngredients.isEmpty()) {
9192
var equalityTypes = ItemFilter.getEqualityTypes(tile);
9293
var requested = ingredient.map(l -> {
9394
// 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 Pair<ItemStack, Collection<ActiveCraft>> craft(ItemStack module, PipeBloc
217218

218219
var leftOfRequest = stack.getCount();
219220
var allCrafts = new ArrayList<ActiveCraft>();
220-
// if we're ensuring item order, all items for a single recipe should be sent in order first before starting on the next one!
221-
for (var c = contents.ensureItemOrder ? toCraft : 1; c > 0; c--) {
221+
// if we're inserting individual items or per craft, we need to split up the request into multiple crafts
222+
for (var c = contents.insertionType != InsertionType.ALL ? toCraft : 1; c > 0; c--) {
222223
var toRequest = new ArrayList<Either<NetworkLock, ItemStack>>();
223224
for (var i = 0; i < contents.input.getSlots(); i++) {
224225
var in = contents.input.getStackInSlot(i);
225226
if (in.isEmpty())
226227
continue;
227228
var request = in.copy();
228-
if (!contents.ensureItemOrder)
229+
if (contents.insertionType == InsertionType.ALL)
229230
request.setCount(in.getCount() * toCraft);
230231
var ret = network.requestLocksAndStartCrafting(tile.getBlockPos(), items, unavailableConsumer, request, CraftingModuleItem.addDependency(dependencyChain, module), equalityTypes);
231232
for (var lock : ret.getLeft())
@@ -243,7 +244,7 @@ public Pair<ItemStack, Collection<ActiveCraft>> craft(ItemStack module, PipeBloc
243244
allCrafts.add(dep);
244245
}
245246
}
246-
var crafted = contents.ensureItemOrder ? resultAmount : resultAmount * toCraft;
247+
var crafted = contents.insertionType != InsertionType.ALL ? resultAmount : resultAmount * toCraft;
247248
// items we started craft dependencies for are ones that will be sent to us (so we're waiting for them immediately!)
248249
var activeCraft = new ActiveCraft(tile.getBlockPos(), slot, toRequest, new ArrayList<>(), destPipe, stack.copyWithCount(Math.min(crafted, leftOfRequest)));
249250
tile.getActiveCrafts().add(activeCraft);
@@ -272,7 +273,7 @@ public ItemStack store(ItemStack module, PipeBlockEntity tile, ItemStack stack,
272273
if (traveling.isEmpty())
273274
craft.travelingIngredients.remove(traveling);
274275

275-
if (contents.insertSingles) {
276+
if (contents.insertUnstacked) {
276277
var handler = tile.getItemHandler(direction);
277278
if (handler != null) {
278279
while (!stack.isEmpty()) {
@@ -316,17 +317,28 @@ private static Stack<ItemStack> addDependency(Stack<ItemStack> deps, ItemStack m
316317
return deps;
317318
}
318319

319-
public record Contents(ItemStackHandler input, ItemStackHandler output, boolean ensureItemOrder, boolean insertSingles, boolean emitRedstone) {
320+
public record Contents(ItemStackHandler input, ItemStackHandler output, boolean emitRedstone, InsertionType insertionType, boolean insertUnstacked) {
320321

321322
public static final Codec<Contents> CODEC = RecordCodecBuilder.create(i -> i.group(
322323
Utility.ITEM_STACK_HANDLER_CODEC.fieldOf("input").forGetter(d -> d.input),
323324
Utility.ITEM_STACK_HANDLER_CODEC.fieldOf("output").forGetter(d -> d.output),
324-
Codec.BOOL.optionalFieldOf("ensure_item_order", false).forGetter(d -> d.ensureItemOrder),
325-
Codec.BOOL.optionalFieldOf("insert_singles", false).forGetter(d -> d.insertSingles),
326-
Codec.BOOL.optionalFieldOf("emit_redstone", false).forGetter(d -> d.emitRedstone)
325+
Codec.BOOL.optionalFieldOf("emit_redstone", false).forGetter(d -> d.emitRedstone),
326+
Codec.STRING.xmap(InsertionType::valueOf, InsertionType::name).optionalFieldOf("insertion_type", InsertionType.ALL).forGetter(d -> d.insertionType),
327+
Codec.BOOL.optionalFieldOf("insert_unstacked", false).forGetter(d -> d.insertUnstacked)
327328
).apply(i, Contents::new));
328329
public static final DataComponentType<Contents> TYPE = DataComponentType.<Contents>builder().persistent(Contents.CODEC).cacheEncoding().build();
329330

330331
}
331332

333+
public enum InsertionType {
334+
335+
ALL,
336+
PER_ITEM,
337+
PER_CRAFT;
338+
339+
public String translationKey() {
340+
return "info." + PrettyPipes.ID + ".insertion_type." + this.name().toLowerCase(Locale.ROOT);
341+
}
342+
}
343+
332344
}

src/main/resources/assets/prettypipes/lang/en_us.json

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,18 @@
6666
"info.prettypipes.blacklist": "\u00A74D",
6767
"info.prettypipes.whitelist.description": "Items in filter slots are allowed",
6868
"info.prettypipes.blacklist.description": "Items in filter slots are disallowed",
69-
"info.prettypipes.insert_singles_on": "\u00A72S",
70-
"info.prettypipes.insert_singles_off": "\u00A74\u00A7mS",
71-
"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",
72-
"info.prettypipes.ensure_item_order_on": "\u00A72O",
73-
"info.prettypipes.ensure_item_order_off": "\u00A74\u00A7mO",
74-
"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",
69+
"info.prettypipes.insert_unstacked_on": "\u00A72O",
70+
"info.prettypipes.insert_unstacked_off": "\u00A74\u00A7mO",
71+
"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",
7572
"info.prettypipes.emit_redstone_on": "\u00A72R",
7673
"info.prettypipes.emit_redstone_off": "\u00A74\u00A7mR",
77-
"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",
74+
"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",
75+
"info.prettypipes.insertion_type.all": "All",
76+
"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",
77+
"info.prettypipes.insertion_type.per_item": "Singles",
78+
"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",
79+
"info.prettypipes.insertion_type.per_craft": "Crafts",
80+
"info.prettypipes.insertion_type.per_craft.description": "Causes the module to request all items for a single crafting operation at once",
7881
"info.prettypipes.shift": "Hold Shift for info",
7982
"info.prettypipes.populate": "P",
8083
"info.prettypipes.populate.description": "Populate filter slots with items from adjacent inventories",

0 commit comments

Comments
 (0)