Skip to content

Commit 8bc487a

Browse files
committed
Added UseItemSpam Hack
1 parent 044624d commit 8bc487a

4 files changed

Lines changed: 349 additions & 4 deletions

File tree

src/main/java/net/wurstclient/hack/HackList.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ public final class HackList implements UpdateListener
289289
public final StepHack stepHack = new StepHack();
290290
public final TemplateToolHack templateToolHack = new TemplateToolHack();
291291
public final ThrowHack throwHack = new ThrowHack();
292+
public final UseItemSpamHack useItemSpamHack = new UseItemSpamHack();
292293
public final TillauraHack tillauraHack = new TillauraHack();
293294
public final TimerHack timerHack = new TimerHack();
294295
public final TargetPlaceHack targetPlaceHack = new TargetPlaceHack();

src/main/java/net/wurstclient/hacks/PearlEspHack.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,8 @@ private void rememberPearlOwnersForEntityId(int ownerId, UUID ownerUuid)
997997
return;
998998

999999
// Walk all known pearl spawn owner ids
1000-
for(Map.Entry<UUID, Integer> entry : pearlSpawnOwnerIds.entrySet())
1000+
for(Map.Entry<UUID, Integer> entry : new ArrayList<>(
1001+
pearlSpawnOwnerIds.entrySet()))
10011002
{
10021003
Integer pearlOwnerId = entry.getValue();
10031004
if(pearlOwnerId == null || pearlOwnerId != ownerId)
@@ -1007,14 +1008,15 @@ private void rememberPearlOwnersForEntityId(int ownerId, UUID ownerUuid)
10071008
}
10081009

10091010
// Also walk pearl identities that have this owner entity id
1010-
for(Map.Entry<UUID, PearlIdentity> entry : pearlIdentities.entrySet())
1011+
for(Map.Entry<UUID, PearlIdentity> entry : new ArrayList<>(
1012+
pearlIdentities.entrySet()))
10111013
{
10121014
PearlIdentity pid = entry.getValue();
10131015
if(pid.ownerEntityId() != null && pid.ownerEntityId() == ownerId)
10141016
{
10151017
UUID pearlUuid = entry.getKey();
1016-
if(!pearlSpawnOwnerIds.containsKey(pearlUuid)
1017-
|| pearlSpawnOwnerIds.get(pearlUuid) != ownerId)
1018+
if(pearlSpawnOwnerIds.containsKey(pearlUuid)
1019+
&& pearlSpawnOwnerIds.get(pearlUuid) == ownerId)
10181020
// Already handled above
10191021
continue;
10201022
rememberPearlOwnerUuid(pearlUuid, ownerUuid);
Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
1+
/*
2+
* Copyright (c) 2014-2026 Wurst-Imperium and contributors.
3+
*
4+
* This source code is subject to the terms of the GNU General Public
5+
* License, version 3. If a copy of the GPL was not distributed with this
6+
* file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt
7+
*/
8+
package net.wurstclient.hacks;
9+
10+
import java.lang.reflect.Field;
11+
import java.lang.reflect.Method;
12+
import java.lang.reflect.Modifier;
13+
import java.util.Locale;
14+
import net.minecraft.core.component.DataComponents;
15+
import net.minecraft.core.registries.BuiltInRegistries;
16+
import net.minecraft.network.protocol.game.ServerboundUseItemPacket;
17+
import net.minecraft.resources.Identifier;
18+
import net.minecraft.world.InteractionHand;
19+
import net.minecraft.world.item.BowItem;
20+
import net.minecraft.world.item.CrossbowItem;
21+
import net.minecraft.world.item.EggItem;
22+
import net.minecraft.world.item.EnderpearlItem;
23+
import net.minecraft.world.item.Item;
24+
import net.minecraft.world.item.ItemStack;
25+
import net.minecraft.world.item.ProjectileWeaponItem;
26+
import net.minecraft.world.item.ShieldItem;
27+
import net.minecraft.world.item.SnowballItem;
28+
import net.minecraft.world.item.ThrowablePotionItem;
29+
import net.minecraft.world.item.component.Consumable;
30+
import net.wurstclient.Category;
31+
import net.wurstclient.SearchTags;
32+
import net.wurstclient.events.UpdateListener;
33+
import net.wurstclient.hack.Hack;
34+
import net.wurstclient.settings.CheckboxSetting;
35+
import net.wurstclient.settings.SliderSetting;
36+
import net.wurstclient.settings.SliderSetting.ValueDisplay;
37+
38+
@SearchTags({"use item spam", "useitemspam", "crossbow machine gun",
39+
"crossbow spam"})
40+
public final class UseItemSpamHack extends Hack implements UpdateListener
41+
{
42+
private final CheckboxSetting crossbow =
43+
new CheckboxSetting("Crossbow", true);
44+
private final CheckboxSetting bow = new CheckboxSetting("Bow", false);
45+
private final CheckboxSetting throwables =
46+
new CheckboxSetting("Throwables", false);
47+
private final CheckboxSetting consumables =
48+
new CheckboxSetting("Consumables", false);
49+
private final CheckboxSetting utilityItems =
50+
new CheckboxSetting("Utility Items", false);
51+
private final CheckboxSetting all = new CheckboxSetting("All", false);
52+
53+
private final SliderSetting delay =
54+
new SliderSetting("Delay", "Ticks between packets.", 0, 0, 20, 1,
55+
ValueDisplay.INTEGER.withSuffix(" ticks"));
56+
57+
private final CheckboxSetting correctSequence = new CheckboxSetting(
58+
"Correct sequence", "Use current prediction sequence.", true);
59+
60+
private final CheckboxSetting requireRightClick = new CheckboxSetting(
61+
"Require right click", "Only repeat while holding use.", true);
62+
63+
private final CheckboxSetting onlyWhenUsingItem =
64+
new CheckboxSetting("Only when using item",
65+
"Only repeat if Minecraft already thinks you are using the item.",
66+
false);
67+
68+
private int timer;
69+
70+
public UseItemSpamHack()
71+
{
72+
super("UseItemSpam");
73+
74+
setCategory(Category.ITEMS);
75+
addSetting(crossbow);
76+
addSetting(bow);
77+
addSetting(throwables);
78+
addSetting(consumables);
79+
addSetting(utilityItems);
80+
addSetting(all);
81+
addSetting(delay);
82+
addSetting(correctSequence);
83+
addSetting(requireRightClick);
84+
addSetting(onlyWhenUsingItem);
85+
}
86+
87+
@Override
88+
protected void onEnable()
89+
{
90+
timer = 0;
91+
EVENTS.add(UpdateListener.class, this);
92+
}
93+
94+
@Override
95+
protected void onDisable()
96+
{
97+
EVENTS.remove(UpdateListener.class, this);
98+
}
99+
100+
@Override
101+
public void onUpdate()
102+
{
103+
if(MC.player == null || MC.level == null || MC.options == null
104+
|| MC.getConnection() == null)
105+
return;
106+
107+
if(requireRightClick.isChecked() && !MC.options.keyUse.isDown())
108+
{
109+
timer = 0;
110+
return;
111+
}
112+
113+
if(delay.getValueI() > 0)
114+
{
115+
if(timer < delay.getValueI())
116+
{
117+
timer++;
118+
return;
119+
}
120+
121+
timer = 0;
122+
}
123+
124+
InteractionHand specialHand = findSpecialHand();
125+
if(specialHand != null)
126+
{
127+
spamSpecialUse(specialHand);
128+
return;
129+
}
130+
131+
InteractionHand genericHand = findGenericMatchingHand();
132+
if(genericHand == null)
133+
return;
134+
135+
if(onlyWhenUsingItem.isChecked() && !isAlreadyUsing(genericHand))
136+
return;
137+
138+
MC.startUseItem();
139+
}
140+
141+
private void spamSpecialUse(InteractionHand hand)
142+
{
143+
ItemStack stack = MC.player.getItemInHand(hand);
144+
if(stack.isEmpty())
145+
return;
146+
147+
if(onlyWhenUsingItem.isChecked() && !isAlreadyUsing(hand))
148+
return;
149+
150+
if(stack.getItem() instanceof CrossbowItem)
151+
{
152+
boolean charged = CrossbowItem.isCharged(stack);
153+
154+
// Help normal crossbows finish their charge/load cycle while the
155+
// key stays held, then fall back to packet spam for the firing
156+
// step.
157+
if(!charged)
158+
{
159+
if(!MC.player.isUsingItem())
160+
{
161+
MC.startUseItem();
162+
return;
163+
}
164+
165+
if(MC.player.getUsedItemHand() == hand && MC.player
166+
.getTicksUsingItem() >= getCrossbowChargeTicks(stack))
167+
{
168+
if(MC.gameMode != null)
169+
MC.gameMode.releaseUsingItem(MC.player);
170+
}
171+
172+
return;
173+
}
174+
}
175+
176+
if(stack.getItem() instanceof BowItem)
177+
{
178+
if(!MC.player.isUsingItem())
179+
{
180+
MC.startUseItem();
181+
return;
182+
}
183+
184+
if(MC.player.getUsedItemHand() == hand && MC.gameMode != null)
185+
{
186+
MC.gameMode.releaseUsingItem(MC.player);
187+
return;
188+
}
189+
}
190+
191+
MC.getConnection().send(new ServerboundUseItemPacket(hand,
192+
getPredictionSequence(), MC.player.getYRot(), MC.player.getXRot()));
193+
}
194+
195+
private int getCrossbowChargeTicks(ItemStack stack)
196+
{
197+
try
198+
{
199+
for(Method method : CrossbowItem.class.getDeclaredMethods())
200+
{
201+
if(!method.getName().equals("getChargeDuration")
202+
|| !Modifier.isStatic(method.getModifiers())
203+
|| method.getReturnType() != int.class)
204+
continue;
205+
206+
method.setAccessible(true);
207+
Class<?>[] params = method.getParameterTypes();
208+
if(params.length == 2 && params[0] == ItemStack.class)
209+
{
210+
Object value = method.invoke(null, stack, MC.player);
211+
if(value instanceof Integer i)
212+
return i;
213+
}
214+
215+
if(params.length == 1 && params[0] == ItemStack.class)
216+
{
217+
Object value = method.invoke(null, stack);
218+
if(value instanceof Integer i)
219+
return i;
220+
}
221+
}
222+
223+
}catch(ReflectiveOperationException ignored)
224+
{}
225+
226+
return 25;
227+
}
228+
229+
private InteractionHand findSpecialHand()
230+
{
231+
ItemStack mainHand = MC.player.getMainHandItem();
232+
if(matchesSpecialType(mainHand))
233+
return InteractionHand.MAIN_HAND;
234+
235+
ItemStack offHand = MC.player.getOffhandItem();
236+
if(matchesSpecialType(offHand))
237+
return InteractionHand.OFF_HAND;
238+
239+
return null;
240+
}
241+
242+
private boolean matchesSpecialType(ItemStack stack)
243+
{
244+
if(stack == null || stack.isEmpty())
245+
return false;
246+
247+
Item item = stack.getItem();
248+
return crossbow.isChecked() && item instanceof CrossbowItem
249+
|| bow.isChecked() && item instanceof BowItem;
250+
}
251+
252+
private InteractionHand findGenericMatchingHand()
253+
{
254+
ItemStack mainHand = MC.player.getMainHandItem();
255+
if(matchesGenericType(mainHand))
256+
return InteractionHand.MAIN_HAND;
257+
258+
ItemStack offHand = MC.player.getOffhandItem();
259+
if(matchesGenericType(offHand))
260+
return InteractionHand.OFF_HAND;
261+
262+
return null;
263+
}
264+
265+
private boolean matchesGenericType(ItemStack stack)
266+
{
267+
if(stack == null || stack.isEmpty())
268+
return false;
269+
270+
if(all.isChecked())
271+
return true;
272+
273+
Item item = stack.getItem();
274+
return throwables.isChecked() && isThrowable(item)
275+
|| consumables.isChecked() && isConsumable(stack)
276+
|| utilityItems.isChecked() && isUtilityItem(item);
277+
}
278+
279+
private boolean isAlreadyUsing(InteractionHand hand)
280+
{
281+
return MC.player.isUsingItem() && MC.player.getUsedItemHand() == hand;
282+
}
283+
284+
private boolean isThrowable(Item item)
285+
{
286+
return item instanceof SnowballItem || item instanceof EggItem
287+
|| item instanceof EnderpearlItem
288+
|| item instanceof ThrowablePotionItem;
289+
}
290+
291+
private boolean isConsumable(ItemStack stack)
292+
{
293+
Consumable consumable = stack.get(DataComponents.CONSUMABLE);
294+
return consumable != null;
295+
}
296+
297+
private boolean isUtilityItem(Item item)
298+
{
299+
if(item instanceof ShieldItem || item instanceof ProjectileWeaponItem
300+
|| item instanceof SnowballItem || item instanceof EggItem
301+
|| item instanceof EnderpearlItem
302+
|| item instanceof ThrowablePotionItem)
303+
return false;
304+
305+
Identifier id = BuiltInRegistries.ITEM.getKey(item);
306+
if(id == null)
307+
return false;
308+
309+
String path = id.getPath().toLowerCase(Locale.ROOT);
310+
return item instanceof ShieldItem || path.contains("bucket")
311+
|| path.contains("spyglass") || path.contains("goat_horn")
312+
|| path.contains("brush") || path.contains("flint_and_steel")
313+
|| path.contains("fire_charge") || path.contains("bundle")
314+
|| path.contains("writable_book") || path.contains("written_book");
315+
}
316+
317+
private int getPredictionSequence()
318+
{
319+
if(!correctSequence.isChecked())
320+
return 0;
321+
322+
try
323+
{
324+
Field handlerField = MC.level.getClass()
325+
.getDeclaredField("blockStatePredictionHandler");
326+
handlerField.setAccessible(true);
327+
Object handler = handlerField.get(MC.level);
328+
if(handler == null)
329+
return 0;
330+
331+
Method currentSequence =
332+
handler.getClass().getMethod("currentSequence");
333+
Object value = currentSequence.invoke(handler);
334+
return value instanceof Integer i ? i : 0;
335+
336+
}catch(ReflectiveOperationException e)
337+
{
338+
return 0;
339+
}
340+
}
341+
}

src/main/resources/assets/wurst/translations/en_us.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,7 @@
597597
"hack.wurst.staffmonitor": "StaffMonitor",
598598
"description.wurst.hack.staffmonitor": "Monitors the tab list for players entering or leaving spectator mode, with optional alerts for hidden staff and visible player entities missing from the tab list.",
599599
"description.wurst.hack.ui-utils": "Adds UI utilities like packet control, chat-in-GUI input, and resource pack bypass tools.",
600+
"description.wurst.hack.useitemspam": "Repeatedly sends use-item packets for selected item types while holding right click. Credit: aisiaiiad (github.com/aisiaiiad).",
600601
"hack.wurst.pearlesp": "PearlESP",
601602
"description.wurst.hack.pearlesp": "Highlights ender pearls thrown by other players, shows predicted landing with a purple box, draws a trajectory line, and highlights when players are holding an ender pearl.",
602603
"hack.wurst.pearldrop": "PearlDrop",

0 commit comments

Comments
 (0)