Skip to content

Commit 2f79525

Browse files
committed
Updated ChestSearch
1 parent 004fd20 commit 2f79525

2 files changed

Lines changed: 208 additions & 1 deletion

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ I did not, nor could I copy their code directly as most are Meteor based mods. S
191191
![WayPoints](https://i.imgur.com/dxFc17N.png) ![Waypoint Manager](https://i.imgur.com/K2xGVqc.png) ![Waypoint Editor](https://i.imgur.com/23i14s1.png)
192192

193193
### Chest Search
194-
- Automatically or manually scan each chest you open and store its contents in a JSON file per server (You can also disable entirely)
194+
- Automatically or manually scan each chest and shulker you open and store its contents in a JSON file per server (You can also disable entirely)
195195
- Able to detect chest changes that you make, so adding or removing items instantly updates the JSON
196196
- Unable to detect chest changes that other players make
197197
- Able to delete entries

src/main/java/net/wurstclient/mixin/ShulkerBoxScreenMixin.java

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,21 @@
1212
import net.minecraft.client.gui.components.Button;
1313
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
1414
import net.minecraft.client.gui.screens.inventory.ShulkerBoxScreen;
15+
import net.minecraft.core.BlockPos;
1516
import net.minecraft.network.chat.Component;
1617
import net.minecraft.world.entity.player.Inventory;
1718
import net.minecraft.world.inventory.ShulkerBoxMenu;
19+
import net.minecraft.world.level.block.ShulkerBoxBlock;
20+
import net.minecraft.world.level.block.entity.BlockEntity;
21+
import net.minecraft.world.level.block.state.BlockState;
22+
import net.minecraft.world.phys.BlockHitResult;
23+
import net.minecraft.world.phys.HitResult;
1824
import net.wurstclient.WurstClient;
25+
import net.wurstclient.chestsearch.ChestConfig;
26+
import net.wurstclient.chestsearch.ChestRecorder;
27+
import net.wurstclient.clickgui.screens.ChestSearchScreen;
1928
import net.wurstclient.hacks.AutoStealHack;
29+
import net.wurstclient.hacks.ChestSearchHack;
2030
import net.wurstclient.hacks.QuickShulkerHack;
2131

2232
@Mixin(ShulkerBoxScreen.class)
@@ -29,6 +39,18 @@ public abstract class ShulkerBoxScreenMixin
2939
@Unique
3040
private final QuickShulkerHack quickShulker =
3141
WurstClient.INSTANCE.getHax().quickShulkerHack;
42+
@Unique
43+
private ChestRecorder chestRecorder;
44+
@Unique
45+
private BlockPos shulkerPos;
46+
@Unique
47+
private BlockPos shulkerClickedPos;
48+
@Unique
49+
private String shulkerServerIp;
50+
@Unique
51+
private String shulkerDimension;
52+
@Unique
53+
private boolean shulkerSnapshotFinalized = false;
3254

3355
private ShulkerBoxScreenMixin(WurstClient wurst, ShulkerBoxMenu handler,
3456
Inventory inventory, Component title)
@@ -95,5 +117,190 @@ public void init()
95117
quickButton.active = !quickShulker.isBusy();
96118
addRenderableWidget(quickButton);
97119
}
120+
121+
try
122+
{
123+
ChestSearchHack chestSearchHack =
124+
WurstClient.INSTANCE.getHax().chestSearchHack;
125+
if(chestSearchHack != null && chestSearchHack.isOffMode())
126+
return;
127+
128+
ChestConfig cfg = new ChestConfig();
129+
if(!cfg.enabled)
130+
return;
131+
132+
this.chestRecorder =
133+
new ChestRecorder(new java.io.File(cfg.dbPath), cfg);
134+
135+
String serverIp = null;
136+
try
137+
{
138+
if(WurstClient.MC != null
139+
&& WurstClient.MC.getCurrentServer() != null)
140+
serverIp = WurstClient.MC.getCurrentServer().ip;
141+
}catch(Throwable ignored)
142+
{}
143+
String dimension = null;
144+
try
145+
{
146+
if(WurstClient.MC != null && WurstClient.MC.level != null)
147+
dimension = WurstClient.MC.level.dimension().identifier()
148+
.toString();
149+
}catch(Throwable ignored)
150+
{}
151+
shulkerServerIp = serverIp;
152+
shulkerDimension = dimension;
153+
154+
shulkerPos = wurst$resolveShulkerPos();
155+
if(shulkerPos == null)
156+
return;
157+
158+
try
159+
{
160+
if(shulkerClickedPos != null)
161+
{
162+
boolean cleared = ChestSearchScreen
163+
.clearDecorations(dimension, shulkerClickedPos);
164+
if(!cleared)
165+
ChestSearchScreen.clearDecorations(dimension,
166+
shulkerPos);
167+
}else
168+
{
169+
ChestSearchScreen.clearDecorations(dimension, shulkerPos);
170+
}
171+
}catch(Throwable ignored)
172+
{}
173+
174+
ChestRecorder.Bounds bounds =
175+
ChestRecorder.Bounds.of(shulkerPos, shulkerPos, null);
176+
chestRecorder.onChestOpened(serverIp, dimension, shulkerPos.getX(),
177+
shulkerPos.getY(), shulkerPos.getZ(), this.menu, 27,
178+
java.util.Collections.emptyList(), bounds);
179+
}catch(Throwable ignored)
180+
{}
181+
}
182+
183+
@Override
184+
public void removed()
185+
{
186+
wurst$finalizeShulkerSnapshot();
187+
super.removed();
188+
}
189+
190+
@Unique
191+
private void wurst$finalizeShulkerSnapshot()
192+
{
193+
if(shulkerSnapshotFinalized)
194+
return;
195+
shulkerSnapshotFinalized = true;
196+
if(chestRecorder == null || shulkerPos == null || this.menu == null)
197+
return;
198+
199+
try
200+
{
201+
int total = this.menu.slots.size();
202+
int window = Math.min(27, total);
203+
java.util.List<Integer> slotOrder =
204+
new java.util.ArrayList<>(window);
205+
java.util.List<net.minecraft.world.item.ItemStack> region =
206+
new java.util.ArrayList<>(window);
207+
boolean any = false;
208+
for(int i = 0; i < window; i++)
209+
{
210+
slotOrder.add(i);
211+
var st = this.menu.slots.get(i).getItem();
212+
region.add(st);
213+
if(st != null && !st.isEmpty())
214+
any = true;
215+
}
216+
if(any && !region.isEmpty())
217+
{
218+
ChestRecorder.Bounds bounds =
219+
ChestRecorder.Bounds.of(shulkerPos, shulkerPos, null);
220+
chestRecorder.recordFromStacksWithSlotOrder(shulkerServerIp,
221+
shulkerDimension, shulkerPos.getX(), shulkerPos.getY(),
222+
shulkerPos.getZ(), region, slotOrder, bounds);
223+
}
224+
}catch(Throwable ignored)
225+
{}
226+
}
227+
228+
@Unique
229+
private BlockPos wurst$resolveShulkerPos()
230+
{
231+
BlockPos resolvedPos = null;
232+
try
233+
{
234+
java.lang.reflect.Method gb =
235+
this.menu.getClass().getMethod("getBlockEntity");
236+
Object be = gb.invoke(this.menu);
237+
if(be instanceof BlockEntity)
238+
resolvedPos = ((BlockEntity)be).getBlockPos();
239+
}catch(Throwable ignored)
240+
{}
241+
242+
if(resolvedPos == null)
243+
{
244+
try
245+
{
246+
Object ctxObj = null;
247+
try
248+
{
249+
java.lang.reflect.Method m =
250+
this.menu.getClass().getMethod("getContext");
251+
ctxObj = m.invoke(this.menu);
252+
}catch(Throwable ignored)
253+
{}
254+
if(ctxObj instanceof net.minecraft.world.inventory.ContainerLevelAccess ctx)
255+
{
256+
BlockPos[] holder = new BlockPos[1];
257+
ctx.execute((world, pos) -> holder[0] = pos);
258+
resolvedPos = holder[0];
259+
}
260+
}catch(Throwable ignored)
261+
{}
262+
}
263+
264+
if(resolvedPos == null)
265+
{
266+
try
267+
{
268+
HitResult hr = WurstClient.MC.hitResult;
269+
if(hr instanceof BlockHitResult bhr)
270+
{
271+
shulkerClickedPos = bhr.getBlockPos();
272+
resolvedPos = shulkerClickedPos;
273+
}
274+
}catch(Throwable ignored)
275+
{}
276+
}
277+
278+
if(resolvedPos == null)
279+
return null;
280+
281+
BlockPos normalized = wurst$normalizeShulkerPos(resolvedPos);
282+
if(shulkerClickedPos == null && resolvedPos != null)
283+
shulkerClickedPos = resolvedPos;
284+
return normalized;
285+
}
286+
287+
@Unique
288+
private BlockPos wurst$normalizeShulkerPos(BlockPos pos)
289+
{
290+
if(pos == null || WurstClient.MC == null
291+
|| WurstClient.MC.level == null)
292+
return pos;
293+
294+
BlockPos current = pos;
295+
BlockState state = WurstClient.MC.level.getBlockState(current);
296+
if(!(state.getBlock() instanceof ShulkerBoxBlock))
297+
{
298+
BlockPos below = current.below();
299+
BlockState belowState = WurstClient.MC.level.getBlockState(below);
300+
if(belowState.getBlock() instanceof ShulkerBoxBlock)
301+
current = below;
302+
}
303+
304+
return current;
98305
}
99306
}

0 commit comments

Comments
 (0)