Skip to content

Commit 3673bee

Browse files
committed
Added ChestSearch
1 parent 14ff87d commit 3673bee

19 files changed

+4670
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@ hs_err_pid*
3434
*.pyc
3535

3636
desktop.ini
37+
*.rar

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,18 @@ All credit for the original client goes to Wurst-Imperium and its contributors.
9494

9595
![WayPoints](https://i.imgur.com/Tmp71qs.png) ![Waypoint Manager](https://i.imgur.com/41CKEiO.png) ![Waypoint Editor](https://i.imgur.com/QNCS66B.png)
9696

97+
### Chest Search
98+
- Automatically or manually scan each chest you open and store its contents in a JSON file per server
99+
- Able to detect chest changes that you make, so adding or removing items instantly updates the JSON
100+
- Unable to detect chest changes that other players make
101+
- Able to delete entries
102+
- Visually search all scanned chests for content based on keywords
103+
- Create an ESP highlight of the chest that has your desired item or create a waypoint to track the chest down
104+
- Chests are auto-removed if it has been detected as broken/missing
105+
- Adjustable Waypoint and ESP timeout
106+
- Adjustable ESP and Waypoint colors
107+
108+
![ChestSearch](https://i.imgur.com/o5DYBqR.png)
97109

98110
### Breadcrumbs
99111
- Leaves a line trail behind you (toggle-able/pause-able).

src/main/java/net/wurstclient/WurstInitializer.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
package net.wurstclient;
99

1010
import net.fabricmc.api.ModInitializer;
11+
import net.wurstclient.chestsearch.ChestCleaner;
12+
import net.wurstclient.chestsearch.TargetHighlighter;
13+
import net.wurstclient.events.RenderListener;
1114

1215
public final class WurstInitializer implements ModInitializer
1316
{
@@ -25,6 +28,19 @@ public void onInitialize()
2528
"WurstInitializer.onInitialize() ran twice!");
2629

2730
WurstClient.INSTANCE.initialize();
31+
// Register chest cleaner
32+
try
33+
{
34+
new ChestCleaner().register();
35+
}catch(Throwable ignored)
36+
{}
37+
// Register targeted highlighter
38+
try
39+
{
40+
WurstClient.INSTANCE.getEventManager().add(RenderListener.class,
41+
TargetHighlighter.INSTANCE);
42+
}catch(Throwable ignored)
43+
{}
2844
initialized = true;
2945
}
3046
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright (c) 2014-2025 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.chestsearch;
9+
10+
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
11+
import net.minecraft.client.MinecraftClient;
12+
import net.minecraft.util.math.BlockPos;
13+
import net.wurstclient.WurstClient;
14+
import net.wurstclient.clickgui.screens.ChestSearchScreen;
15+
16+
import java.util.Iterator;
17+
18+
public class ChestCleaner
19+
{
20+
private final ChestManager manager;
21+
private int tickCounter = 0;
22+
23+
public ChestCleaner()
24+
{
25+
// use default manager which reads config for db path
26+
this.manager = new ChestManager();
27+
}
28+
29+
public void register()
30+
{
31+
ClientTickEvents.END_CLIENT_TICK.register(client -> {
32+
try
33+
{
34+
tickCounter++;
35+
if(tickCounter < 100)
36+
return; // check every ~5s (20 ticks/s)
37+
tickCounter = 0;
38+
39+
MinecraftClient mc = WurstClient.MC;
40+
if(mc == null || mc.world == null)
41+
return;
42+
43+
String serverIp = null;
44+
try
45+
{
46+
if(mc.getCurrentServerEntry() != null)
47+
serverIp = mc.getCurrentServerEntry().address;
48+
}catch(Throwable ignored)
49+
{}
50+
String dimension = null;
51+
try
52+
{
53+
dimension = mc.world.getRegistryKey().getValue().toString();
54+
}catch(Throwable ignored)
55+
{}
56+
57+
for(Iterator<net.wurstclient.chestsearch.ChestEntry> it =
58+
manager.all().iterator(); it.hasNext();)
59+
{
60+
net.wurstclient.chestsearch.ChestEntry e = it.next();
61+
if(e.serverIp != null && serverIp != null
62+
&& !e.serverIp.equals(serverIp))
63+
continue;
64+
if(e.dimension != null && dimension != null
65+
&& !e.dimension.equals(dimension))
66+
continue;
67+
try
68+
{
69+
BlockPos pos = e.getMinPos();
70+
boolean chunkLoaded = false;
71+
try
72+
{
73+
@SuppressWarnings("deprecation")
74+
boolean tmp = mc.world.isChunkLoaded(pos);
75+
chunkLoaded = tmp;
76+
}catch(Throwable ignored)
77+
{
78+
try
79+
{
80+
Object cm = mc.world.getChunkManager();
81+
java.lang.reflect.Method m =
82+
cm.getClass().getMethod("isChunkLoaded",
83+
int.class, int.class);
84+
chunkLoaded = Boolean.TRUE.equals(m.invoke(cm,
85+
pos.getX() >> 4, pos.getZ() >> 4));
86+
}catch(Throwable ignored2)
87+
{}
88+
}
89+
if(!chunkLoaded)
90+
continue; // don't delete when chunk is unloaded
91+
var state = mc.world.getBlockState(pos);
92+
boolean containerBlock = state != null && (state
93+
.getBlock() instanceof net.minecraft.block.ChestBlock
94+
|| state
95+
.getBlock() instanceof net.minecraft.block.BarrelBlock
96+
|| state
97+
.getBlock() instanceof net.minecraft.block.ShulkerBoxBlock
98+
|| state
99+
.getBlock() instanceof net.minecraft.block.DecoratedPotBlock);
100+
boolean hasBe = mc.world.getBlockEntity(pos) != null;
101+
if(!hasBe || !containerBlock)
102+
{
103+
ChestSearchScreen.clearDecorations(e.dimension,
104+
pos);
105+
manager.removeChest(e.serverIp, e.dimension,
106+
pos.getX(), pos.getY(), pos.getZ());
107+
}
108+
}catch(Throwable ignored)
109+
{}
110+
}
111+
}catch(Throwable t)
112+
{
113+
t.printStackTrace();
114+
}
115+
});
116+
}
117+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright (c) 2014-2025 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.chestsearch;
9+
10+
import com.google.gson.Gson;
11+
import com.google.gson.GsonBuilder;
12+
13+
import java.io.File;
14+
import java.io.FileReader;
15+
import java.io.FileWriter;
16+
17+
public class ChestConfig
18+
{
19+
public boolean enabled = true;
20+
public boolean storeFullItemNbt = true;
21+
public String dbPath = "config/wurst/chest_database.json";
22+
23+
private final File file;
24+
private final Gson gson = new GsonBuilder().setPrettyPrinting().create();
25+
26+
public ChestConfig(File file)
27+
{
28+
this.file = file;
29+
load();
30+
}
31+
32+
public ChestConfig()
33+
{
34+
this(new File("config/wurst/chest_search.json"));
35+
}
36+
37+
public synchronized void load()
38+
{
39+
try
40+
{
41+
if(!file.exists())
42+
{
43+
file.getParentFile().mkdirs();
44+
save();
45+
return;
46+
}
47+
try(FileReader r = new FileReader(file))
48+
{
49+
ChestConfig c = gson.fromJson(r, ChestConfig.class);
50+
if(c != null)
51+
{
52+
this.enabled = c.enabled;
53+
this.storeFullItemNbt = c.storeFullItemNbt;
54+
this.dbPath = c.dbPath;
55+
}
56+
}
57+
}catch(Exception e)
58+
{
59+
e.printStackTrace();
60+
}
61+
}
62+
63+
public synchronized void save()
64+
{
65+
try(FileWriter w = new FileWriter(file))
66+
{
67+
gson.toJson(this, w);
68+
}catch(Exception e)
69+
{
70+
e.printStackTrace();
71+
}
72+
}
73+
}

0 commit comments

Comments
 (0)