77 */
88package net .wurstclient .hacks .spawnradius ;
99
10+ import com .mojang .blaze3d .PrimitiveTopology ;
11+ import com .mojang .blaze3d .vertex .DefaultVertexFormat ;
1012import com .mojang .blaze3d .vertex .PoseStack ;
13+ import com .mojang .blaze3d .vertex .VertexConsumer ;
1114import java .util .ArrayList ;
1215import java .util .List ;
1316import java .lang .reflect .Method ;
17+ import net .minecraft .client .renderer .rendertype .RenderType ;
1418import net .minecraft .core .BlockPos ;
1519import net .minecraft .world .level .BaseSpawner ;
1620import net .minecraft .world .level .block .entity .SpawnerBlockEntity ;
1721import net .minecraft .world .phys .AABB ;
1822import net .minecraft .world .phys .Vec3 ;
1923import net .wurstclient .Category ;
24+ import net .wurstclient .WurstRenderLayers ;
2025import net .wurstclient .hack .Hack ;
2126import net .wurstclient .events .RenderListener ;
2227import net .wurstclient .events .UpdateListener ;
2328import net .wurstclient .nicewurst .NiceWurstModule ;
2429import net .wurstclient .util .BlockUtils ;
30+ import net .wurstclient .util .EasyVertexBuffer ;
31+ import net .wurstclient .util .RegionPos ;
2532import net .wurstclient .util .RenderUtils ;
2633import net .wurstclient .util .chunk .ChunkUtils ;
2734
@@ -55,6 +62,13 @@ public final class SpawnRadiusHack extends Hack
5562
5663 private final List <SpawnerInfo > spawners = new ArrayList <>();
5764
65+ private EasyVertexBuffer buffer ;
66+ private RegionPos bufferRegion = new RegionPos (0 , 0 );
67+ private long bufferSignature ;
68+ private RegionPos pendingRegion = new RegionPos (0 , 0 );
69+ private long pendingSignature ;
70+ private boolean dirty = true ;
71+
5872 public SpawnRadiusHack ()
5973 {
6074 super ("SpawnRadius" );
@@ -74,6 +88,8 @@ protected void onDisable()
7488 EVENTS .remove (UpdateListener .class , this );
7589 EVENTS .remove (RenderListener .class , this );
7690 spawners .clear ();
91+ closeBuffer ();
92+ dirty = true ;
7793 }
7894
7995 @ Override
@@ -98,6 +114,15 @@ public void onUpdate()
98114 spawners
99115 .add (new SpawnerInfo (pos .immutable (), radius , detected ));
100116 });
117+
118+ RegionPos region = RegionPos .of (MC .player .blockPosition ());
119+ long signature = signature (spawners , region );
120+ if (signature != bufferSignature )
121+ {
122+ pendingRegion = region ;
123+ pendingSignature = signature ;
124+ dirty = true ;
125+ }
101126 }
102127
103128 @ Override
@@ -106,37 +131,146 @@ public void onRender(PoseStack matrices, float partialTicks)
106131 if (MC .level == null || spawners .isEmpty ())
107132 return ;
108133
134+ if (NiceWurstModule .isActive ())
135+ {
136+ renderCulled (matrices );
137+ return ;
138+ }
139+
140+ if (dirty || buffer == null )
141+ rebuild ();
142+
143+ if (buffer == null )
144+ return ;
145+
146+ RenderType layer = WurstRenderLayers .getLines (false );
147+ matrices .pushPose ();
148+ RenderUtils .applyRegionalRenderOffset (matrices , bufferRegion );
149+ buffer .draw (matrices , layer , 1 , 1 , 1 , 1 );
150+ matrices .popPose ();
151+ }
152+
153+ private void renderCulled (PoseStack matrices )
154+ {
155+ List <AABB > boxes = new ArrayList <>();
109156 for (SpawnerInfo info : spawners )
110157 {
111158 Vec3 center = Vec3 .atCenterOf (info .pos ()).add (0 , HEIGHT_OFFSET , 0 );
112159 if (!NiceWurstModule .shouldRenderTarget (center ))
113160 continue ;
114161
115- drawCircle (matrices , center , info .radius (), info .detected ());
116- // Draw a simple white ESP box on the spawner block itself
162+ int color = info .detected () ? COLOR_DETECTED : COLOR_IDLE ;
163+ int segments = Math .max (32 , info .radius () * 6 );
164+ RenderUtils .drawCircle (matrices , center , info .radius (), segments ,
165+ color , false );
166+
117167 AABB box = BlockUtils .getBoundingBox (info .pos ());
118168 if (box != null )
119- RenderUtils .drawOutlinedBoxes (matrices ,
120- java .util .Collections .singletonList (box ), SPAWNER_BOX_COLOR ,
121- false );
169+ boxes .add (box );
122170 }
171+
172+ if (!boxes .isEmpty ())
173+ RenderUtils .drawOutlinedBoxes (matrices , boxes , SPAWNER_BOX_COLOR ,
174+ false );
175+ }
176+
177+ private void rebuild ()
178+ {
179+ closeBuffer ();
180+ bufferRegion = pendingRegion ;
181+ bufferSignature = pendingSignature ;
182+ dirty = false ;
183+
184+ if (spawners .isEmpty ())
185+ return ;
186+
187+ List <SpawnerInfo > snapshot = new ArrayList <>(spawners );
188+ RegionPos region = bufferRegion ;
189+ buffer = EasyVertexBuffer .createAndUpload (PrimitiveTopology .LINES ,
190+ DefaultVertexFormat .POSITION_COLOR_NORMAL_LINE_WIDTH , b -> {
191+ for (SpawnerInfo info : snapshot )
192+ buildSpawner (b , info , region );
193+ });
123194 }
124195
125- private static void drawCircle ( PoseStack matrices , Vec3 center , int radius ,
126- boolean detected )
196+ private static void buildSpawner ( VertexConsumer b , SpawnerInfo info ,
197+ RegionPos region )
127198 {
128- int color = detected ? COLOR_DETECTED : COLOR_IDLE ;
199+ int radius = info .radius ();
200+ double cx = info .pos ().getX () + 0.5 - region .x ();
201+ double cy = info .pos ().getY () + 0.5 + HEIGHT_OFFSET ;
202+ double cz = info .pos ().getZ () + 0.5 - region .z ();
203+ int color = info .detected () ? COLOR_DETECTED : COLOR_IDLE ;
204+
129205 int segments = Math .max (32 , radius * 6 );
130206 double step = (Math .PI * 2 ) / segments ;
131- Vec3 prev = center .add (radius , 0 , 0 );
132-
207+ float py = (float )cy ;
208+ float px = (float )(cx + radius );
209+ float pz = (float )cz ;
133210 for (int i = 1 ; i <= segments ; i ++)
134211 {
135212 double angle = i * step ;
136- Vec3 next = center .add (Math .cos (angle ) * radius , 0 ,
137- Math .sin (angle ) * radius );
138- RenderUtils .drawLine (matrices , prev , next , color , false );
139- prev = next ;
213+ float nx = (float )(cx + Math .cos (angle ) * radius );
214+ float nz = (float )(cz + Math .sin (angle ) * radius );
215+ RenderUtils .drawLine (b , px , py , pz , nx , py , nz , color );
216+ px = nx ;
217+ pz = nz ;
218+ }
219+
220+ float x1 = info .pos ().getX () - region .x ();
221+ float x2 = x1 + 1 ;
222+ float y1 = info .pos ().getY ();
223+ float y2 = y1 + 1 ;
224+ float z1 = info .pos ().getZ () - region .z ();
225+ float z2 = z1 + 1 ;
226+ addBoxOutline (b , x1 , y1 , z1 , x2 , y2 , z2 , SPAWNER_BOX_COLOR );
227+ }
228+
229+ private static void addBoxOutline (VertexConsumer b , float x1 , float y1 ,
230+ float z1 , float x2 , float y2 , float z2 , int color )
231+ {
232+ RenderUtils .drawLine (b , x1 , y1 , z1 , x2 , y1 , z1 , color );
233+ RenderUtils .drawLine (b , x2 , y1 , z1 , x2 , y1 , z2 , color );
234+ RenderUtils .drawLine (b , x2 , y1 , z2 , x1 , y1 , z2 , color );
235+ RenderUtils .drawLine (b , x1 , y1 , z2 , x1 , y1 , z1 , color );
236+ RenderUtils .drawLine (b , x1 , y2 , z1 , x2 , y2 , z1 , color );
237+ RenderUtils .drawLine (b , x2 , y2 , z1 , x2 , y2 , z2 , color );
238+ RenderUtils .drawLine (b , x2 , y2 , z2 , x1 , y2 , z2 , color );
239+ RenderUtils .drawLine (b , x1 , y2 , z2 , x1 , y2 , z1 , color );
240+ RenderUtils .drawLine (b , x1 , y1 , z1 , x1 , y2 , z1 , color );
241+ RenderUtils .drawLine (b , x2 , y1 , z1 , x2 , y2 , z1 , color );
242+ RenderUtils .drawLine (b , x2 , y1 , z2 , x2 , y2 , z2 , color );
243+ RenderUtils .drawLine (b , x1 , y1 , z2 , x1 , y2 , z2 , color );
244+ }
245+
246+ /*
247+ * Cheap order-independent hash-combine,
248+ * fingerprints current spawner set to cheaply detect changes since last GPU upload
249+ */
250+ private static long signature (List <SpawnerInfo > list , RegionPos region )
251+ {
252+ long set = 0 ;
253+ for (SpawnerInfo info : list )
254+ {
255+ long h = info .pos ().asLong () * 1099511628211L ; // FNV prime
256+ h ^= info .radius () * 31L ;
257+ h ^= info .detected () ? 0x9E3779B97F4A7C15L : 0L ; // golden-ratio constant
258+ set ^= h ; // XOR accumulate
259+ }
260+
261+ long sig = region .x ();
262+ sig = sig * 31 + region .z ();
263+ sig = sig * 31 + list .size ();
264+ sig = sig * 31 + set ;
265+ return sig ;
266+ }
267+
268+ private void closeBuffer ()
269+ {
270+ if (buffer != null )
271+ {
272+ buffer .close ();
273+ buffer = null ;
140274 }
141275 }
142276
0 commit comments