1111import java .util .stream .IntStream ;
1212
1313import net .minecraft .client .gui .screen .ingame .HandledScreen ;
14+ import net .minecraft .item .Item ;
1415import net .minecraft .screen .slot .Slot ;
1516import net .minecraft .screen .slot .SlotActionType ;
1617import net .wurstclient .Category ;
@@ -35,6 +36,10 @@ public final class AutoStealHack extends Hack
3536 private final CheckboxSetting reverseSteal =
3637 new CheckboxSetting ("Reverse steal order" , false );
3738
39+ private final CheckboxSetting stealStoreSame = new CheckboxSetting (
40+ "Steal/Store same" ,
41+ "Only move exact matching item types present in the source." , false );
42+
3843 private Thread thread ;
3944
4045 public AutoStealHack ()
@@ -44,6 +49,7 @@ public AutoStealHack()
4449 addSetting (buttons );
4550 addSetting (delay );
4651 addSetting (reverseSteal );
52+ addSetting (stealStoreSame );
4753 }
4854
4955 public void steal (HandledScreen <?> screen , int rows )
@@ -76,12 +82,72 @@ private void shiftClickSlots(HandledScreen<?> screen, int from, int to,
7682 if (reverseSteal .isChecked () && steal )
7783 slots = slots .reversed ();
7884
85+ java .util .Set <Item > inventoryTypes = null ;
86+ java .util .Set <Item > chestTypes = null ;
87+ if (stealStoreSame .isChecked ())
88+ {
89+ if (steal )
90+ {
91+ // Try to read player inventory item types directly from the UI
92+ // The chest UI has `rows * 9` chest slots first; the player
93+ // inventory follows and is commonly 36 slots (27 main + 9
94+ // hotbar).
95+ int rows = to / 9 ; // when stealing `to` equals rows*9
96+ int invStart = rows * 9 ;
97+ int invEnd = Math .min (invStart + 36 ,
98+ screen .getScreenHandler ().slots .size ());
99+ java .util .Set <Item > typesFromUI = new java .util .HashSet <>();
100+ for (int i = invStart ; i < invEnd ; i ++)
101+ {
102+ Slot s = screen .getScreenHandler ().slots .get (i );
103+ if (!s .getStack ().isEmpty ())
104+ typesFromUI .add (s .getStack ().getItem ());
105+ }
106+ if (!typesFromUI .isEmpty ())
107+ inventoryTypes = typesFromUI ;
108+ else
109+ {
110+ // Fallback to previous UI-reflection attempt, then to
111+ // player
112+ // inventory via reflection if necessary
113+ inventoryTypes = getInventoryItemTypesUI (screen );
114+ if (inventoryTypes == null )
115+ inventoryTypes = getInventoryItemTypes ();
116+ }
117+ }else
118+ {
119+ chestTypes = new java .util .HashSet <>();
120+ for (int i = 0 ; i < from ; i ++)
121+ {
122+ Slot s = screen .getScreenHandler ().slots .get (i );
123+ if (!s .getStack ().isEmpty ())
124+ chestTypes .add (s .getStack ().getItem ());
125+ }
126+ }
127+ }
128+
79129 for (Slot slot : slots )
80130 try
81131 {
82132 if (slot .getStack ().isEmpty ())
83133 continue ;
84134
135+ // Exact-type filtering (Steal/Store same)
136+ if (stealStoreSame .isChecked ())
137+ {
138+ net .minecraft .item .Item item = slot .getStack ().getItem ();
139+ if (steal )
140+ {
141+ if (inventoryTypes != null
142+ && !inventoryTypes .contains (item ))
143+ continue ;
144+ }else
145+ {
146+ if (chestTypes != null && !chestTypes .contains (item ))
147+ continue ;
148+ }
149+ }
150+
85151 Thread .sleep (delay .getValueI ());
86152
87153 if (MC .currentScreen == null )
@@ -97,6 +163,107 @@ private void shiftClickSlots(HandledScreen<?> screen, int from, int to,
97163 }
98164 }
99165
166+ private java .util .Set <Item > getInventoryItemTypes ()
167+ {
168+ java .util .Set <Item > types = new java .util .HashSet <>();
169+ try
170+ {
171+ Object invObj = MC .player .getClass ().getMethod ("getInventory" )
172+ .invoke (MC .player );
173+ // First attempt: read the primary 'main' list from the inventory
174+ Object main =
175+ invObj .getClass ().getDeclaredField ("main" ).get (invObj );
176+ if (main instanceof java .util .List )
177+ {
178+ for (Object o : (java .util .List <?>)main )
179+ {
180+ if (o instanceof net .minecraft .item .ItemStack )
181+ {
182+ net .minecraft .item .ItemStack stack =
183+ (net .minecraft .item .ItemStack )o ;
184+ if (stack != null && !stack .isEmpty ())
185+ types .add (stack .getItem ());
186+ }
187+ }
188+ }
189+ // If we couldn't collect any items, try alternative inventory
190+ // structures via reflection
191+ if (types .isEmpty ())
192+ {
193+ for (java .lang .reflect .Field f : invObj .getClass ()
194+ .getDeclaredFields ())
195+ {
196+ if (java .util .List .class .isAssignableFrom (f .getType ()))
197+ {
198+ f .setAccessible (true );
199+ Object listObj = f .get (invObj );
200+ if (listObj instanceof java .util .List )
201+ {
202+ for (Object obj : (java .util .List <?>)listObj )
203+ {
204+ if (obj instanceof net .minecraft .item .ItemStack )
205+ {
206+ net .minecraft .item .ItemStack st =
207+ (net .minecraft .item .ItemStack )obj ;
208+ if (st != null && !st .isEmpty ())
209+ types .add (st .getItem ());
210+ }
211+ }
212+ }
213+ }
214+ }
215+ }
216+ }catch (Exception ignored )
217+ {
218+ // Ignore and return whatever we could collect
219+ }
220+ return types .isEmpty () ? null : types ;
221+ }
222+
223+ private java .util .Set <Item > getInventoryItemTypesUI (HandledScreen <?> screen )
224+ {
225+ java .util .Set <Item > types = new java .util .HashSet <>();
226+ try
227+ {
228+ // Access the chest inventory directly from the screen handler
229+ Object chestInventory = screen .getScreenHandler ().getClass ()
230+ .getMethod ("getInventory" ).invoke (screen .getScreenHandler ());
231+
232+ // Try to read the 'stacks' field directly, which should contain
233+ // the items visible in the player's chest GUI
234+ Object stacksObj = chestInventory .getClass ()
235+ .getDeclaredField ("stacks" ).get (chestInventory );
236+ if (stacksObj instanceof java .util .List )
237+ {
238+ for (Object o : (java .util .List <?>)stacksObj )
239+ {
240+ if (o instanceof net .minecraft .item .ItemStack )
241+ {
242+ net .minecraft .item .ItemStack stack =
243+ (net .minecraft .item .ItemStack )o ;
244+ if (stack != null && !stack .isEmpty ())
245+ types .add (stack .getItem ());
246+ }
247+ }
248+ }
249+ // Fallback: scan the typical 36-item UI region if the stacks field
250+ // is inaccessible or empty
251+ if (types .isEmpty ())
252+ {
253+ for (int i = 27 ; i < 63 ; i ++)
254+ {
255+ Slot s = screen .getScreenHandler ().slots .get (i );
256+ if (!s .getStack ().isEmpty ())
257+ types .add (s .getStack ().getItem ());
258+ }
259+ }
260+ }catch (Exception ignored )
261+ {
262+ // Ignore and fallback to the regular inventory scan
263+ }
264+ return types .isEmpty () ? null : types ;
265+ }
266+
100267 public boolean areButtonsVisible ()
101268 {
102269 return buttons .isChecked ();
0 commit comments