Skip to content

Commit 624bed4

Browse files
authored
Refactor AutoReplenish (MeteorDevelopment#5307)
- clean up the code - fix unstackables not getting replenished (mostly)
1 parent bf4cd6b commit 624bed4

File tree

3 files changed

+71
-94
lines changed

3 files changed

+71
-94
lines changed

src/main/java/meteordevelopment/meteorclient/mixin/ItemStackAccessor.java

Lines changed: 0 additions & 19 deletions
This file was deleted.

src/main/java/meteordevelopment/meteorclient/systems/modules/player/AutoReplenish.java

Lines changed: 71 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,26 @@
66
package meteordevelopment.meteorclient.systems.modules.player;
77

88
import meteordevelopment.meteorclient.events.world.TickEvent;
9-
import meteordevelopment.meteorclient.mixin.ItemStackAccessor;
109
import meteordevelopment.meteorclient.settings.*;
1110
import meteordevelopment.meteorclient.systems.modules.Categories;
1211
import meteordevelopment.meteorclient.systems.modules.Module;
1312
import meteordevelopment.meteorclient.systems.modules.Modules;
1413
import meteordevelopment.meteorclient.systems.modules.combat.AutoTotem;
1514
import meteordevelopment.meteorclient.utils.player.InvUtils;
16-
import meteordevelopment.meteorclient.utils.player.SlotUtils;
1715
import meteordevelopment.orbit.EventHandler;
1816
import net.minecraft.item.Item;
1917
import net.minecraft.item.ItemStack;
2018
import net.minecraft.item.Items;
2119

20+
import java.util.Arrays;
2221
import java.util.List;
2322

2423
public class AutoReplenish extends Module {
2524
private final SettingGroup sgGeneral = settings.getDefaultGroup();
2625

27-
private final Setting<Integer> threshold = sgGeneral.add(new IntSetting.Builder()
28-
.name("threshold")
29-
.description("The threshold of items left this actives at.")
26+
private final Setting<Integer> minCount = sgGeneral.add(new IntSetting.Builder()
27+
.name("min-count")
28+
.description("Replenish a slot when it reaches this item count.")
3029
.defaultValue(8)
3130
.min(1)
3231
.sliderRange(1, 63)
@@ -35,47 +34,59 @@ public class AutoReplenish extends Module {
3534

3635
private final Setting<Integer> tickDelay = sgGeneral.add(new IntSetting.Builder()
3736
.name("delay")
38-
.description("The tick delay to replenish your hotbar.")
37+
.description("How long in ticks to wait between replenishing your hotbar.")
3938
.defaultValue(1)
4039
.min(0)
4140
.build()
4241
);
4342

4443
private final Setting<Boolean> offhand = sgGeneral.add(new BoolSetting.Builder()
4544
.name("offhand")
46-
.description("Whether or not to refill your offhand with items.")
45+
.description("Whether or not to replenish items in your offhand.")
4746
.defaultValue(true)
4847
.build()
4948
);
5049

5150
private final Setting<Boolean> unstackable = sgGeneral.add(new BoolSetting.Builder()
5251
.name("unstackable")
53-
.description("Replenishes unstackable items.")
52+
.description("Replenish unstackable items.")
5453
.defaultValue(true)
5554
.build()
5655
);
5756

57+
private final Setting<Boolean> sameEnchants = sgGeneral.add(new BoolSetting.Builder()
58+
.name("same-enchants")
59+
.description("Only replace unstackables with items that have the same enchants.")
60+
.defaultValue(true)
61+
.visible(unstackable::get)
62+
.build()
63+
);
64+
5865
private final Setting<Boolean> searchHotbar = sgGeneral.add(new BoolSetting.Builder()
5966
.name("search-hotbar")
60-
.description("Uses items in your hotbar to replenish if they are the only ones left.")
61-
.defaultValue(true)
67+
.description("Combine stacks in your hotbar/offhand as a last resort.")
68+
.defaultValue(false)
6269
.build()
6370
);
6471

6572
private final Setting<List<Item>> excludedItems = sgGeneral.add(new ItemListSetting.Builder()
6673
.name("excluded-items")
67-
.description("Items that WILL NOT replenish.")
74+
.description("Items that won't be replenished.")
6875
.build()
6976
);
7077

78+
/**
79+
* Represents the items the player had last tick. Indices 0-8 represent the
80+
* hotbar from left to right, index 9 represents the player's offhand
81+
*/
7182
private final ItemStack[] items = new ItemStack[10];
7283
private boolean prevHadOpenScreen;
7384
private int tickDelayLeft;
7485

7586
public AutoReplenish() {
7687
super(Categories.Player, "auto-replenish", "Automatically refills items in your hotbar, main hand, or offhand.");
7788

78-
for (int i = 0; i < items.length; i++) items[i] = new ItemStack(Items.AIR);
89+
Arrays.fill(items, Items.AIR.getDefaultStack());
7990
}
8091

8192
@Override
@@ -94,97 +105,83 @@ private void onTick(TickEvent.Pre event) {
94105
prevHadOpenScreen = mc.currentScreen != null;
95106
if (mc.player.currentScreenHandler.getStacks().size() != 46 || mc.currentScreen != null) return;
96107

97-
if (tickDelayLeft <= 0) {
98-
tickDelayLeft = tickDelay.get();
99-
100-
// Hotbar
101-
for (int i = 0; i < 9; i++) {
102-
ItemStack stack = mc.player.getInventory().getStack(i);
103-
checkSlot(i, stack);
104-
}
108+
if (tickDelayLeft > 0) {
109+
tickDelayLeft--;
110+
return;
111+
}
105112

106-
// Offhand
107-
if (offhand.get() && !Modules.get().get(AutoTotem.class).isLocked()) {
108-
ItemStack stack = mc.player.getOffHandStack();
109-
checkSlot(SlotUtils.OFFHAND, stack);
110-
}
113+
// Hotbar
114+
for (int i = 0; i < 9; i++) {
115+
ItemStack stack = mc.player.getInventory().getStack(i);
116+
checkSlot(i, stack);
111117
}
112-
else {
113-
tickDelayLeft--;
118+
119+
// Offhand
120+
if (offhand.get() && !Modules.get().get(AutoTotem.class).isLocked()) {
121+
ItemStack stack = mc.player.getOffHandStack();
122+
checkSlot(9, stack);
114123
}
124+
125+
tickDelayLeft = tickDelay.get();
115126
}
116127

117128
private void checkSlot(int slot, ItemStack stack) {
118-
ItemStack prevStack = getItem(slot);
129+
ItemStack prevStack = items[slot];
130+
items[slot] = stack.copy();
119131

120-
// Stackable items 1
121-
if (!stack.isEmpty() && stack.isStackable() && !excludedItems.get().contains(stack.getItem())) {
122-
if (stack.getCount() <= threshold.get()) {
123-
addSlots(slot, findItem(stack, slot, threshold.get() - stack.getCount() + 1));
124-
}
132+
if (excludedItems.get().contains(stack.getItem())) return;
133+
if (excludedItems.get().contains(prevStack.getItem())) return;
134+
135+
int fromSlot = -1;
136+
137+
// If there are still items left in the stack, but it just crossed the threshold
138+
if (stack.isStackable() && !stack.isEmpty() && stack.getCount() <= minCount.get()) {
139+
fromSlot = findItem(stack, slot, minCount.get() - stack.getCount() + 1);
125140
}
126141

127-
if (stack.isEmpty() && !prevStack.isEmpty() && !excludedItems.get().contains(prevStack.getItem())) {
128-
// Stackable items 2
129-
if (prevStack.isStackable()) {
130-
addSlots(slot, findItem(prevStack, slot, threshold.get() - stack.getCount() + 1));
131-
}
132-
// Unstackable items
133-
else {
134-
if (unstackable.get()) {
135-
addSlots(slot, findItem(prevStack, slot, 1));
136-
}
137-
}
142+
// If the stack just went from above the threshold to empty in a single tick
143+
// this can happen if the threshold is set low enough while using modules that
144+
// place many blocks per tick, like surround or holefiller
145+
if (prevStack.isStackable() && stack.isEmpty() && !prevStack.isEmpty()) {
146+
fromSlot = findItem(prevStack, slot, minCount.get() - stack.getCount() + 1);
138147
}
139148

140-
setItem(slot, stack);
149+
// Unstackable items
150+
if (unstackable.get() && !prevStack.isStackable() && stack.isEmpty() && !prevStack.isEmpty()) {
151+
fromSlot = findItem(prevStack, slot, 1);
152+
}
153+
154+
InvUtils.move().from(fromSlot).to(slot);
141155
}
142156

143-
private int findItem(ItemStack itemStack, int excludedSlot, int goodEnoughCount) {
157+
private int findItem(ItemStack lookForStack, int excludedSlot, int goodEnoughCount) {
144158
int slot = -1;
145159
int count = 0;
146160

147161
for (int i = mc.player.getInventory().size() - 2; i >= (searchHotbar.get() ? 0 : 9); i--) {
162+
if (i == excludedSlot) continue;
163+
148164
ItemStack stack = mc.player.getInventory().getStack(i);
165+
if (stack.getItem() != lookForStack.getItem()) continue;
166+
167+
if (sameEnchants.get() && !stack.getEnchantments().equals(lookForStack.getEnchantments())) continue;
149168

150-
if (i != excludedSlot && stack.getItem() == itemStack.getItem() && ItemStack.areItemsAndComponentsEqual(itemStack, stack)) {
151-
if (stack.getCount() > count) {
152-
slot = i;
153-
count = stack.getCount();
169+
if (stack.getCount() > count) {
170+
slot = i;
171+
count = stack.getCount();
154172

155-
if (count >= goodEnoughCount) break;
156-
}
173+
if (count >= goodEnoughCount) break;
157174
}
158175
}
159176

160177
return slot;
161178
}
162179

163-
private void addSlots(int to, int from) {
164-
InvUtils.move().from(from).to(to);
165-
}
166-
167180
private void fillItems() {
168181
for (int i = 0; i < 9; i++) {
169-
setItem(i, mc.player.getInventory().getStack(i));
182+
items[i] = mc.player.getInventory().getStack(i).copy();
170183
}
171184

172-
setItem(SlotUtils.OFFHAND, mc.player.getOffHandStack());
173-
}
174-
175-
private ItemStack getItem(int slot) {
176-
if (slot == SlotUtils.OFFHAND) slot = 9;
177-
178-
return items[slot];
179-
}
180-
181-
private void setItem(int slot, ItemStack stack) {
182-
if (slot == SlotUtils.OFFHAND) slot = 9;
183-
184-
ItemStack s = items[slot];
185-
((ItemStackAccessor) (Object) s).setItem(stack.getItem());
186-
s.setCount(stack.getCount());
187-
s.applyComponentsFrom(stack.getComponents());
188-
if (stack.isEmpty()) ((ItemStackAccessor) (Object) s).setItem(Items.AIR);
185+
items[9] = mc.player.getOffHandStack().copy();
189186
}
190187
}

src/main/resources/meteor-client.mixins.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@
113113
"ItemGroupsMixin",
114114
"ItemMixin",
115115
"ItemRendererMixin",
116-
"ItemStackAccessor",
117116
"ItemStackMixin",
118117
"JukeboxPlayableComponentMixin",
119118
"KeyBindingAccessor",

0 commit comments

Comments
 (0)