Skip to content

Commit 2ffbf56

Browse files
DeepTransfer (#1)
1 parent ae97ee0 commit 2ffbf56

14 files changed

Lines changed: 957 additions & 0 deletions

build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ dependencies {
205205

206206
annotationProcessor 'org.spongepowered:mixin:0.8.5:processor'
207207

208+
implementation fg.deobf("curse.maven:aea-aee-1466886:7803688")
209+
210+
implementation fg.deobf("curse.maven:extended-crafting-268387:6880322")
211+
208212
implementation fg.deobf("curse.maven:cucumber-272335:7180783")
209213

210214
implementation fg.deobf("curse.maven:jei-238222:7391695")
@@ -224,6 +228,8 @@ dependencies {
224228
implementation fg.deobf("curse.maven:sophisticated-backpacks-422301:7455143")
225229
implementation fg.deobf("curse.maven:sophisticated-core-618298:7552278")
226230

231+
implementation fg.deobf("curse.maven:mouse-tweaks-60089:5338457")
232+
227233
implementation fg.deobf("curse.maven:jade-324717:6271651")
228234
}
229235

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
package com.ref.extendedpick.integration.jei;
2+
3+
import com.ref.extendedpick.api.IDeepSearchProvider;
4+
import com.ref.extendedpick.api.IPlayerInventoryAccess;
5+
import java.util.ArrayList;
6+
import java.util.Arrays;
7+
import java.util.Collection;
8+
import java.util.List;
9+
import java.util.function.Supplier;
10+
import mezz.jei.common.transfer.BasicRecipeTransferHandlerServer;
11+
import mezz.jei.common.transfer.TransferOperation;
12+
import net.minecraft.network.FriendlyByteBuf;
13+
import net.minecraft.server.level.ServerPlayer;
14+
import net.minecraft.world.inventory.AbstractContainerMenu;
15+
import net.minecraft.world.inventory.Slot;
16+
import net.minecraft.world.item.ItemStack;
17+
import net.minecraftforge.network.NetworkEvent;
18+
19+
public class DeepRecipeTransferPacket {
20+
21+
private final Collection<TransferOperation> normalOperations;
22+
private final Collection<Integer> craftingSlotIndices;
23+
private final Collection<Integer> inventorySlotIndices;
24+
private final boolean maxTransfer;
25+
private final boolean requireCompleteSets;
26+
private final Collection<DeepTransferData> deepTransfers;
27+
28+
public DeepRecipeTransferPacket(
29+
Collection<TransferOperation> normalOperations,
30+
Collection<Integer> craftingSlotIndices,
31+
Collection<Integer> inventorySlotIndices,
32+
boolean maxTransfer,
33+
boolean requireCompleteSets,
34+
Collection<DeepTransferData> deepTransfers) {
35+
this.normalOperations = normalOperations;
36+
this.craftingSlotIndices = craftingSlotIndices;
37+
this.inventorySlotIndices = inventorySlotIndices;
38+
this.maxTransfer = maxTransfer;
39+
this.requireCompleteSets = requireCompleteSets;
40+
this.deepTransfers = deepTransfers;
41+
}
42+
43+
public void encode(FriendlyByteBuf buf) {
44+
buf.writeVarInt(normalOperations.size());
45+
for (TransferOperation op : normalOperations) {
46+
op.writePacketData(buf);
47+
}
48+
49+
buf.writeVarInt(craftingSlotIndices.size());
50+
craftingSlotIndices.forEach(buf::writeVarInt);
51+
52+
buf.writeVarInt(inventorySlotIndices.size());
53+
inventorySlotIndices.forEach(buf::writeVarInt);
54+
55+
buf.writeBoolean(maxTransfer);
56+
buf.writeBoolean(requireCompleteSets);
57+
58+
buf.writeVarInt(deepTransfers.size());
59+
for (DeepTransferData dt : deepTransfers) {
60+
dt.write(buf);
61+
}
62+
}
63+
64+
public static DeepRecipeTransferPacket decode(FriendlyByteBuf buf) {
65+
int opSize = buf.readVarInt();
66+
List<TransferOperation> ops = new ArrayList<>();
67+
for (int i = 0; i < opSize; i++) {
68+
ops.add(new TransferOperation(buf.readVarInt(), buf.readVarInt()));
69+
}
70+
71+
int craftSize = buf.readVarInt();
72+
List<Integer> crafts = new ArrayList<>();
73+
for (int i = 0; i < craftSize; i++) {
74+
crafts.add(buf.readVarInt());
75+
}
76+
77+
int invSize = buf.readVarInt();
78+
List<Integer> invs = new ArrayList<>();
79+
for (int i = 0; i < invSize; i++) {
80+
invs.add(buf.readVarInt());
81+
}
82+
83+
boolean maxTransfer = buf.readBoolean();
84+
boolean requireCompleteSets = buf.readBoolean();
85+
86+
int dtSize = buf.readVarInt();
87+
List<DeepTransferData> dts = new ArrayList<>();
88+
for (int i = 0; i < dtSize; i++) {
89+
dts.add(DeepTransferData.read(buf));
90+
}
91+
92+
return new DeepRecipeTransferPacket(ops, crafts, invs, maxTransfer, requireCompleteSets, dts);
93+
}
94+
95+
public static void handle(DeepRecipeTransferPacket msg, Supplier<NetworkEvent.Context> ctx) {
96+
ctx.get()
97+
.enqueueWork(
98+
() -> {
99+
ServerPlayer player = ctx.get().getSender();
100+
if (player == null) return;
101+
transfer(msg, player);
102+
});
103+
ctx.get().setPacketHandled(true);
104+
}
105+
106+
private static void transfer(DeepRecipeTransferPacket msg, ServerPlayer player) {
107+
AbstractContainerMenu container = player.containerMenu;
108+
List<Slot> craftingSlots = msg.craftingSlotIndices.stream().map(container::getSlot).toList();
109+
List<Slot> inventorySlots = msg.inventorySlotIndices.stream().map(container::getSlot).toList();
110+
111+
int jeiTransferredSets;
112+
boolean hasNormalOps = !msg.normalOperations.isEmpty();
113+
114+
if (hasNormalOps) {
115+
BasicRecipeTransferHandlerServer.setItems(
116+
player,
117+
msg.normalOperations.stream().toList(),
118+
craftingSlots,
119+
inventorySlots,
120+
msg.maxTransfer,
121+
msg.requireCompleteSets);
122+
123+
jeiTransferredSets = Integer.MAX_VALUE;
124+
for (TransferOperation op : msg.normalOperations) {
125+
Slot craftSlot = op.craftingSlot(container);
126+
ItemStack stack = craftSlot.getItem();
127+
if (stack.isEmpty()) {
128+
jeiTransferredSets = 0;
129+
break;
130+
}
131+
jeiTransferredSets = Math.min(jeiTransferredSets, stack.getCount());
132+
}
133+
134+
if (jeiTransferredSets == 0 && msg.requireCompleteSets) {
135+
return;
136+
}
137+
} else {
138+
clearCraftingGridToInventory(player, craftingSlots);
139+
jeiTransferredSets = msg.maxTransfer ? 64 : 1;
140+
}
141+
142+
if (msg.deepTransfers.isEmpty()) {
143+
return;
144+
}
145+
int successfulDeepSets = 0;
146+
ItemStack[] accumulatedDeepItems = new ItemStack[msg.deepTransfers.size()];
147+
Arrays.fill(accumulatedDeepItems, ItemStack.EMPTY);
148+
149+
int targetLoops = Math.min(jeiTransferredSets, msg.maxTransfer ? 64 : 1);
150+
151+
for (int i = 0; i < targetLoops; i++) {
152+
boolean setComplete = true;
153+
ItemStack[] currentSet = new ItemStack[msg.deepTransfers.size()];
154+
int opIndex = 0;
155+
156+
for (DeepTransferData deepOp : msg.deepTransfers) {
157+
ItemStack pulled = extractExactOne(player, deepOp);
158+
if (pulled.isEmpty()) {
159+
setComplete = false;
160+
break;
161+
}
162+
currentSet[opIndex++] = pulled;
163+
}
164+
165+
if (setComplete) {
166+
boolean maxStackReached = false;
167+
for (int j = 0; j < msg.deepTransfers.size(); j++) {
168+
ItemStack acc = accumulatedDeepItems[j];
169+
if (!acc.isEmpty() && acc.getCount() >= acc.getMaxStackSize()) {
170+
maxStackReached = true;
171+
break;
172+
}
173+
}
174+
175+
if (maxStackReached) {
176+
for (int j = 0; j < msg.deepTransfers.size(); j++) {
177+
player.getInventory().placeItemBackInInventory(currentSet[j]);
178+
}
179+
break;
180+
}
181+
182+
successfulDeepSets++;
183+
for (int j = 0; j < msg.deepTransfers.size(); j++) {
184+
if (accumulatedDeepItems[j].isEmpty()) {
185+
accumulatedDeepItems[j] = currentSet[j];
186+
} else {
187+
accumulatedDeepItems[j].grow(1);
188+
}
189+
}
190+
} else {
191+
192+
for (int j = 0; j < opIndex; j++) {
193+
player.getInventory().placeItemBackInInventory(currentSet[j]);
194+
}
195+
break;
196+
}
197+
}
198+
199+
if (successfulDeepSets == 0 && msg.requireCompleteSets) {
200+
if (hasNormalOps) {
201+
clearCraftingGridToInventory(player, craftingSlots);
202+
}
203+
return;
204+
}
205+
206+
if (hasNormalOps && successfulDeepSets < jeiTransferredSets) {
207+
for (TransferOperation op : msg.normalOperations) {
208+
Slot craftSlot = op.craftingSlot(container);
209+
ItemStack stack = craftSlot.getItem();
210+
if (stack.getCount() > successfulDeepSets) {
211+
int excess = stack.getCount() - successfulDeepSets;
212+
ItemStack remainder = craftSlot.safeTake(excess, excess, player);
213+
player.getInventory().placeItemBackInInventory(remainder);
214+
}
215+
}
216+
}
217+
218+
int opIndex = 0;
219+
for (DeepTransferData deepOp : msg.deepTransfers) {
220+
Slot craftSlot = container.getSlot(deepOp.craftingSlotIndex());
221+
ItemStack toInsert = accumulatedDeepItems[opIndex++];
222+
if (!toInsert.isEmpty()) {
223+
if (craftSlot.getItem().isEmpty()) {
224+
craftSlot.set(toInsert);
225+
} else if (ItemStack.isSameItemSameTags(craftSlot.getItem(), toInsert)) {
226+
craftSlot.getItem().grow(toInsert.getCount());
227+
}
228+
}
229+
}
230+
231+
container.broadcastChanges();
232+
}
233+
234+
private static void clearCraftingGridToInventory(ServerPlayer player, List<Slot> craftingSlots) {
235+
for (Slot craftingSlot : craftingSlots) {
236+
ItemStack item = craftingSlot.getItem();
237+
if (item.isEmpty()) {
238+
continue;
239+
}
240+
int count = item.getCount();
241+
ItemStack remainder = craftingSlot.safeTake(count, count, player);
242+
player.getInventory().placeItemBackInInventory(remainder);
243+
}
244+
}
245+
246+
public static ItemStack extractExactOne(ServerPlayer player, DeepTransferData deepOp) {
247+
ItemStack[] extractedRef = new ItemStack[] {ItemStack.EMPTY};
248+
249+
IPlayerInventoryAccess.findStacks(
250+
player,
251+
(containerItem, context) -> {
252+
if (!extractedRef[0].isEmpty() || containerItem.isEmpty()) {
253+
return;
254+
}
255+
256+
IDeepSearchProvider<?> provider = IDeepSearchProvider.getProvider(containerItem);
257+
if (provider != null) {
258+
provider.forEachItem(
259+
containerItem,
260+
indexed -> {
261+
for (ItemStack validTarget : deepOp.validItems()) {
262+
if (ItemStack.isSameItemSameTags(validTarget, indexed.stack())) {
263+
ItemStack extracted =
264+
provider.invokeExtract(player, containerItem, indexed.index(), 1, false);
265+
if (!extracted.isEmpty()) {
266+
extractedRef[0] = extracted;
267+
return false;
268+
}
269+
}
270+
}
271+
return true;
272+
});
273+
}
274+
});
275+
return extractedRef[0];
276+
}
277+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.ref.extendedpick.integration.jei;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import net.minecraft.network.FriendlyByteBuf;
6+
import net.minecraft.world.item.ItemStack;
7+
8+
public record DeepTransferData(int craftingSlotIndex, List<ItemStack> validItems) {
9+
10+
public void write(FriendlyByteBuf buf) {
11+
buf.writeVarInt(craftingSlotIndex);
12+
buf.writeVarInt(validItems.size());
13+
for (ItemStack stack : validItems) {
14+
buf.writeItem(stack);
15+
}
16+
}
17+
18+
public static DeepTransferData read(FriendlyByteBuf buf) {
19+
int craftingSlotIndex = buf.readVarInt();
20+
int size = buf.readVarInt();
21+
List<ItemStack> validItems = new ArrayList<>(size);
22+
for (int i = 0; i < size; i++) {
23+
validItems.add(buf.readItem());
24+
}
25+
return new DeepTransferData(craftingSlotIndex, validItems);
26+
}
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.ref.extendedpick.integration.jei;
2+
3+
import net.minecraft.world.item.ItemStack;
4+
5+
public class DeepTransferItemRecord {
6+
private final ItemStack stack;
7+
private int remaining;
8+
9+
public DeepTransferItemRecord(ItemStack stack) {
10+
this.stack = stack;
11+
this.remaining = stack.getCount();
12+
}
13+
14+
public ItemStack getStack() {
15+
return stack;
16+
}
17+
18+
public int getRemaining() {
19+
return remaining;
20+
}
21+
22+
public void consume() {
23+
if (this.remaining > 0) {
24+
this.remaining--;
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)