1919import net .wurstclient .hack .Hack ;
2020import net .wurstclient .hacks .chestesp .ChestEspGroup ;
2121import net .wurstclient .hacks .chestesp .ChestEspGroupManager ;
22+ import net .wurstclient .chestsearch .ChestManager ;
23+ import net .wurstclient .chestsearch .ChestEntry ;
2224import net .wurstclient .settings .CheckboxSetting ;
2325import net .wurstclient .settings .EspStyleSetting ;
2426import net .wurstclient .settings .SliderSetting ;
2527import net .wurstclient .util .RenderUtils ;
28+ import net .wurstclient .WurstRenderLayers ;
29+ import com .mojang .blaze3d .vertex .VertexConsumer ;
30+ import net .minecraft .client .renderer .MultiBufferSource ;
31+ import net .minecraft .client .renderer .RenderType ;
2632import net .wurstclient .util .chunk .ChunkUtils ;
2733
2834public class ChestEspHack extends Hack implements UpdateListener ,
@@ -49,6 +55,7 @@ public class ChestEspHack extends Hack implements UpdateListener,
4955 false );
5056 private final SliderSetting aboveGroundY = new SliderSetting (
5157 "Set ESP Y limit" , 62 , -65 , 255 , 1 , SliderSetting .ValueDisplay .INTEGER );
58+ private java .util .List <ChestEntry > openedChests = java .util .List .of ();
5259
5360 public ChestEspHack ()
5461 {
@@ -112,6 +119,17 @@ public void onUpdate()
112119 int total = groups .allGroups .stream ().filter (ChestEspGroup ::isEnabled )
113120 .mapToInt (g -> g .getBoxes ().size ()).sum ();
114121 foundCount = Math .min (total , 999 );
122+
123+ // Always load recorded chests from ChestSearch DB so ChestESP can
124+ // mark them even if the ChestSearch UI/hack isn't "enabled".
125+ try
126+ {
127+ ChestManager mgr = new ChestManager ();
128+ openedChests = mgr .all ();
129+ }catch (Throwable ignored )
130+ {
131+ openedChests = java .util .List .of ();
132+ }
115133 }
116134
117135 @ Override
@@ -149,6 +167,192 @@ private void renderBoxes(PoseStack matrixStack)
149167 RenderUtils .drawSolidBoxes (matrixStack , boxes , quadsColor , false );
150168 RenderUtils .drawOutlinedBoxes (matrixStack , boxes , linesColor ,
151169 false );
170+
171+ // If ChestSearch marking is enabled, draw an X through opened
172+ // chests that match entries in the ChestSearch DB
173+ try
174+ {
175+ var csh = net .wurstclient .WurstClient .INSTANCE
176+ .getHax ().chestSearchHack ;
177+ if (csh != null && csh .isMarkOpenedChest ()
178+ && !openedChests .isEmpty ())
179+ {
180+ // base esp line color retained if needed
181+ String curDimFull = MC .level == null ? "overworld"
182+ : MC .level .dimension ().location ().toString ();
183+ String curDim = MC .level == null ? "overworld"
184+ : MC .level .dimension ().location ().getPath ();
185+ for (AABB box : boxes )
186+ {
187+ int boxMinX = (int )Math .floor (box .minX + 1e-6 );
188+ int boxMaxX = (int )Math .floor (box .maxX - 1e-6 );
189+ int boxMinY = (int )Math .floor (box .minY + 1e-6 );
190+ int boxMaxY = (int )Math .floor (box .maxY - 1e-6 );
191+ int boxMinZ = (int )Math .floor (box .minZ + 1e-6 );
192+ int boxMaxZ = (int )Math .floor (box .maxZ - 1e-6 );
193+ boolean matched = false ;
194+ for (ChestEntry e : openedChests )
195+ {
196+ if (e == null || e .dimension == null )
197+ continue ;
198+ // Accept either namespaced ("minecraft:the_nether")
199+ // or
200+ // plain path ("the_nether") dimension identifiers.
201+ String ed = e .dimension ;
202+ if (!(ed .equals (curDimFull ) || ed .equals (curDim )
203+ || ed .endsWith (":" + curDim )))
204+ continue ;
205+ int minX = Math .min (e .x , e .maxX );
206+ int maxX = Math .max (e .x , e .maxX );
207+ int minY = Math .min (e .y , e .maxY );
208+ int maxY = Math .max (e .y , e .maxY );
209+ int minZ = Math .min (e .z , e .maxZ );
210+ int maxZ = Math .max (e .z , e .maxZ );
211+ // check range overlap between the ESP box and
212+ // recorded chest bounds
213+ boolean overlap = boxMinX <= maxX && boxMaxX >= minX
214+ && boxMinY <= maxY && boxMaxY >= minY
215+ && boxMinZ <= maxZ && boxMaxZ >= minZ ;
216+ if (overlap )
217+ {
218+ matched = true ;
219+ break ;
220+ }
221+ }
222+ if (matched )
223+ {
224+ int markColor = csh .getMarkXColorARGB ();
225+ double thickness = csh .getMarkXThickness ();
226+
227+ // Prepare render buffer with custom line width
228+ MultiBufferSource .BufferSource vcp =
229+ RenderUtils .getVCP ();
230+ RenderType layer =
231+ WurstRenderLayers .getLines (false , thickness );
232+ VertexConsumer buffer = vcp .getBuffer (layer );
233+ PoseStack .Pose entry = matrixStack .last ();
234+ Vec3 offset = RenderUtils .getCameraPos ().reverse ();
235+
236+ // Draw plus signs (+) centered on each face of the
237+ // box
238+ double minX = box .minX ;
239+ double maxX = box .maxX ;
240+ double minY = box .minY ;
241+ double maxY = box .maxY ;
242+ double minZ = box .minZ ;
243+ double maxZ = box .maxZ ;
244+ double cx = (minX + maxX ) / 2.0 ;
245+ double cy = (minY + maxY ) / 2.0 ;
246+ double cz = (minZ + maxZ ) / 2.0 ;
247+
248+ double halfX = (maxX - minX ) / 2.0 ;
249+ double halfY = (maxY - minY ) / 2.0 ;
250+ double halfZ = (maxZ - minZ ) / 2.0 ;
251+
252+ // Top face (Y = maxY): lines along X and Z
253+ Vec3 t1 =
254+ new Vec3 (cx - halfX , maxY , cz ).add (offset );
255+ Vec3 t2 =
256+ new Vec3 (cx + halfX , maxY , cz ).add (offset );
257+ Vec3 t3 =
258+ new Vec3 (cx , maxY , cz - halfZ ).add (offset );
259+ Vec3 t4 =
260+ new Vec3 (cx , maxY , cz + halfZ ).add (offset );
261+ RenderUtils .drawLine (entry , buffer , (float )t1 .x ,
262+ (float )t1 .y , (float )t1 .z , (float )t2 .x ,
263+ (float )t2 .y , (float )t2 .z , markColor );
264+ RenderUtils .drawLine (entry , buffer , (float )t3 .x ,
265+ (float )t3 .y , (float )t3 .z , (float )t4 .x ,
266+ (float )t4 .y , (float )t4 .z , markColor );
267+
268+ // Bottom face (Y = minY)
269+ Vec3 b1 =
270+ new Vec3 (cx - halfX , minY , cz ).add (offset );
271+ Vec3 b2 =
272+ new Vec3 (cx + halfX , minY , cz ).add (offset );
273+ Vec3 b3 =
274+ new Vec3 (cx , minY , cz - halfZ ).add (offset );
275+ Vec3 b4 =
276+ new Vec3 (cx , minY , cz + halfZ ).add (offset );
277+ RenderUtils .drawLine (entry , buffer , (float )b1 .x ,
278+ (float )b1 .y , (float )b1 .z , (float )b2 .x ,
279+ (float )b2 .y , (float )b2 .z , markColor );
280+ RenderUtils .drawLine (entry , buffer , (float )b3 .x ,
281+ (float )b3 .y , (float )b3 .z , (float )b4 .x ,
282+ (float )b4 .y , (float )b4 .z , markColor );
283+
284+ // North face (Z = minZ): lines along X and Y
285+ Vec3 n1 =
286+ new Vec3 (cx - halfX , cy , minZ ).add (offset );
287+ Vec3 n2 =
288+ new Vec3 (cx + halfX , cy , minZ ).add (offset );
289+ Vec3 n3 =
290+ new Vec3 (cx , cy - halfY , minZ ).add (offset );
291+ Vec3 n4 =
292+ new Vec3 (cx , cy + halfY , minZ ).add (offset );
293+ RenderUtils .drawLine (entry , buffer , (float )n1 .x ,
294+ (float )n1 .y , (float )n1 .z , (float )n2 .x ,
295+ (float )n2 .y , (float )n2 .z , markColor );
296+ RenderUtils .drawLine (entry , buffer , (float )n3 .x ,
297+ (float )n3 .y , (float )n3 .z , (float )n4 .x ,
298+ (float )n4 .y , (float )n4 .z , markColor );
299+
300+ // South face (Z = maxZ)
301+ Vec3 s1 =
302+ new Vec3 (cx - halfX , cy , maxZ ).add (offset );
303+ Vec3 s2 =
304+ new Vec3 (cx + halfX , cy , maxZ ).add (offset );
305+ Vec3 s3 =
306+ new Vec3 (cx , cy - halfY , maxZ ).add (offset );
307+ Vec3 s4 =
308+ new Vec3 (cx , cy + halfY , maxZ ).add (offset );
309+ RenderUtils .drawLine (entry , buffer , (float )s1 .x ,
310+ (float )s1 .y , (float )s1 .z , (float )s2 .x ,
311+ (float )s2 .y , (float )s2 .z , markColor );
312+ RenderUtils .drawLine (entry , buffer , (float )s3 .x ,
313+ (float )s3 .y , (float )s3 .z , (float )s4 .x ,
314+ (float )s4 .y , (float )s4 .z , markColor );
315+
316+ // West face (X = minX): lines along Z and Y
317+ Vec3 w1 =
318+ new Vec3 (minX , cy , cz - halfZ ).add (offset );
319+ Vec3 w2 =
320+ new Vec3 (minX , cy , cz + halfZ ).add (offset );
321+ Vec3 w3 =
322+ new Vec3 (minX , cy - halfY , cz ).add (offset );
323+ Vec3 w4 =
324+ new Vec3 (minX , cy + halfY , cz ).add (offset );
325+ RenderUtils .drawLine (entry , buffer , (float )w1 .x ,
326+ (float )w1 .y , (float )w1 .z , (float )w2 .x ,
327+ (float )w2 .y , (float )w2 .z , markColor );
328+ RenderUtils .drawLine (entry , buffer , (float )w3 .x ,
329+ (float )w3 .y , (float )w3 .z , (float )w4 .x ,
330+ (float )w4 .y , (float )w4 .z , markColor );
331+
332+ // East face (X = maxX)
333+ Vec3 e1 =
334+ new Vec3 (maxX , cy , cz - halfZ ).add (offset );
335+ Vec3 e2 =
336+ new Vec3 (maxX , cy , cz + halfZ ).add (offset );
337+ Vec3 e3 =
338+ new Vec3 (maxX , cy - halfY , cz ).add (offset );
339+ Vec3 e4 =
340+ new Vec3 (maxX , cy + halfY , cz ).add (offset );
341+ RenderUtils .drawLine (entry , buffer , (float )e1 .x ,
342+ (float )e1 .y , (float )e1 .z , (float )e2 .x ,
343+ (float )e2 .y , (float )e2 .z , markColor );
344+ RenderUtils .drawLine (entry , buffer , (float )e3 .x ,
345+ (float )e3 .y , (float )e3 .z , (float )e4 .x ,
346+ (float )e4 .y , (float )e4 .z , markColor );
347+
348+ vcp .endBatch (layer );
349+ }
350+ }
351+ }
352+ }catch (Throwable ignored )
353+ {
354+ // don't fail rendering if chestsearch isn't available
355+ }
152356 }
153357 }
154358
0 commit comments