1717
1818package com.lambda.graphics.mc
1919
20+ import com.lambda.Lambda.mc
2021import com.lambda.event.events.RenderEvent
2122import com.lambda.event.events.TickEvent
2223import com.lambda.event.events.WorldEvent
2324import com.lambda.event.listener.SafeListener.Companion.listen
2425import com.lambda.event.listener.SafeListener.Companion.listenConcurrently
25- import com.lambda.graphics.esp.RegionESP
2626import com.lambda.graphics.esp.ShapeScope
2727import com.lambda.module.Module
2828import com.lambda.module.modules.client.StyleEditor
2929import com.lambda.threading.runSafe
3030import com.lambda.util.world.FastVector
3131import com.lambda.util.world.fastVectorOf
32+ import com.mojang.blaze3d.systems.RenderSystem
33+ import net.minecraft.util.math.Vec3d
3234import net.minecraft.world.World
3335import net.minecraft.world.chunk.WorldChunk
36+ import org.joml.Matrix4f
37+ import org.joml.Vector3f
38+ import org.joml.Vector4f
3439import java.util.concurrent.ConcurrentHashMap
3540import java.util.concurrent.ConcurrentLinkedDeque
3641
3742/* *
38- * Region-based chunked ESP system using MC 1.21.11's new render pipeline .
43+ * Chunked ESP system using chunk-origin relative coordinates .
3944 *
4045 * This system:
41- * - Uses region-relative coordinates for precision-safe rendering
42- * - Maintains per-chunk geometry for efficient updates
46+ * - Stores geometry relative to chunk origin (stable, small floats)
47+ * - Only rebuilds when chunks are modified
48+ * - At render time, translates from chunk origin to camera-relative position
4349 *
4450 * @param owner The module that owns this ESP system
4551 * @param name The name of the ESP system
@@ -49,18 +55,23 @@ import java.util.concurrent.ConcurrentLinkedDeque
4955class ChunkedRegionESP (
5056 owner : Module ,
5157 name : String ,
52- depthTest : Boolean = false ,
58+ private val depthTest : Boolean = false ,
5359 private val update : ShapeScope .(World , FastVector ) -> Unit
54- ) : RegionESP(name, depthTest) {
55- private val chunkMap = ConcurrentHashMap <Long , RegionChunk >()
60+ ) {
61+ private val chunkMap = ConcurrentHashMap <Long , ChunkData >()
5662
57- private val WorldChunk .regionChunk
58- get() = chunkMap.getOrPut(getRegionKey(pos.x shl 4 , bottomY, pos.z shl 4 )) {
59- RegionChunk (this )
60- }
63+ private val WorldChunk .chunkKey: Long
64+ get() = getChunkKey(pos.x, pos.z)
65+
66+ private val WorldChunk .chunkData
67+ get() = chunkMap.getOrPut(chunkKey) { ChunkData (this ) }
6168
69+ private val rebuildQueue = ConcurrentLinkedDeque <ChunkData >()
6270 private val uploadQueue = ConcurrentLinkedDeque < () -> Unit > ()
63- private val rebuildQueue = ConcurrentLinkedDeque <RegionChunk >()
71+
72+ private fun getChunkKey (chunkX : Int , chunkZ : Int ): Long {
73+ return (chunkX.toLong() and 0xFFFFFFFFL ) or ((chunkZ.toLong() and 0xFFFFFFFFL ) shl 32 )
74+ }
6475
6576 /* * Mark all tracked chunks for rebuild. */
6677 fun rebuild () {
@@ -76,37 +87,94 @@ class ChunkedRegionESP(
7687 runSafe {
7788 val chunksArray = world.chunkManager.chunks.chunks
7889 (0 until chunksArray.length()).forEach { i ->
79- chunksArray.get(i)?.regionChunk ?.markDirty()
90+ chunksArray.get(i)?.chunkData ?.markDirty()
8091 }
8192 }
8293 }
8394
84- override fun clear () {
95+ fun clear () {
8596 chunkMap.values.forEach { it.close() }
8697 chunkMap.clear()
8798 rebuildQueue.clear()
8899 uploadQueue.clear()
89100 }
90101
102+ fun close () {
103+ clear()
104+ }
105+
106+ /* *
107+ * Render all chunks with camera-relative translation.
108+ */
109+ fun render () {
110+ val cameraPos = mc.gameRenderer?.camera?.pos ? : return
111+
112+ val activeChunks = chunkMap.values.filter { it.renderer.hasData() }
113+ if (activeChunks.isEmpty()) return
114+
115+ val modelViewMatrix = com.lambda.graphics.RenderMain .modelViewMatrix
116+
117+ // Pre-compute all transforms BEFORE starting render passes
118+ val chunkTransforms = activeChunks.map { chunkData ->
119+ // Compute chunk-to-camera offset in double precision
120+ val offsetX = (chunkData.originX - cameraPos.x).toFloat()
121+ val offsetY = (chunkData.originY - cameraPos.y).toFloat()
122+ val offsetZ = (chunkData.originZ - cameraPos.z).toFloat()
123+
124+ val modelView = Matrix4f (modelViewMatrix).translate(offsetX, offsetY, offsetZ)
125+ val dynamicTransform = RenderSystem .getDynamicUniforms()
126+ .write(modelView, Vector4f (1f , 1f , 1f , 1f ), Vector3f (0f , 0f , 0f ), Matrix4f ())
127+
128+ chunkData to dynamicTransform
129+ }
130+
131+ // Render Faces
132+ RegionRenderer .createRenderPass(" ChunkedESP Faces" , depthTest)?.use { pass ->
133+ val pipeline =
134+ if (depthTest) LambdaRenderPipelines .ESP_QUADS
135+ else LambdaRenderPipelines .ESP_QUADS_THROUGH
136+ pass.setPipeline(pipeline)
137+ RenderSystem .bindDefaultUniforms(pass)
138+
139+ chunkTransforms.forEach { (chunkData, transform) ->
140+ pass.setUniform(" DynamicTransforms" , transform)
141+ chunkData.renderer.renderFaces(pass)
142+ }
143+ }
144+
145+ // Render Edges
146+ RegionRenderer .createRenderPass(" ChunkedESP Edges" , depthTest)?.use { pass ->
147+ val pipeline =
148+ if (depthTest) LambdaRenderPipelines .ESP_LINES
149+ else LambdaRenderPipelines .ESP_LINES_THROUGH
150+ pass.setPipeline(pipeline)
151+ RenderSystem .bindDefaultUniforms(pass)
152+
153+ chunkTransforms.forEach { (chunkData, transform) ->
154+ pass.setUniform(" DynamicTransforms" , transform)
155+ chunkData.renderer.renderEdges(pass)
156+ }
157+ }
158+ }
159+
91160 init {
92161 owner.listen<WorldEvent .BlockUpdate .Client > { event ->
93162 val pos = event.pos
94- world.getWorldChunk(pos)?.regionChunk ?.markDirty()
163+ world.getWorldChunk(pos)?.chunkData ?.markDirty()
95164
96165 val xInChunk = pos.x and 15
97166 val zInChunk = pos.z and 15
98167
99- if (xInChunk == 0 ) world.getWorldChunk(pos.west())?.regionChunk ?.markDirty()
100- if (xInChunk == 15 ) world.getWorldChunk(pos.east())?.regionChunk ?.markDirty()
101- if (zInChunk == 0 ) world.getWorldChunk(pos.north())?.regionChunk ?.markDirty()
102- if (zInChunk == 15 ) world.getWorldChunk(pos.south())?.regionChunk ?.markDirty()
168+ if (xInChunk == 0 ) world.getWorldChunk(pos.west())?.chunkData ?.markDirty()
169+ if (xInChunk == 15 ) world.getWorldChunk(pos.east())?.chunkData ?.markDirty()
170+ if (zInChunk == 0 ) world.getWorldChunk(pos.north())?.chunkData ?.markDirty()
171+ if (zInChunk == 15 ) world.getWorldChunk(pos.south())?.chunkData ?.markDirty()
103172 }
104173
105- owner.listen<WorldEvent .ChunkEvent .Load > { event -> event.chunk.regionChunk .markDirty() }
174+ owner.listen<WorldEvent .ChunkEvent .Load > { event -> event.chunk.chunkData .markDirty() }
106175
107176 owner.listen<WorldEvent .ChunkEvent .Unload > {
108- val pos = getRegionKey(it.chunk.pos.x shl 4 , it.chunk.bottomY, it.chunk.pos.z shl 4 )
109- chunkMap.remove(pos)?.close()
177+ chunkMap.remove(it.chunk.chunkKey)?.close()
110178 }
111179
112180 owner.listenConcurrently<TickEvent .Pre > {
@@ -123,10 +191,15 @@ class ChunkedRegionESP(
123191 owner.listen<RenderEvent .Render > { render() }
124192 }
125193
126- /* * Per-chunk rendering data. */
127- private inner class RegionChunk (val chunk : WorldChunk ) {
128- val region = RenderRegion .forChunk(chunk.pos.x, chunk.pos.z, chunk.bottomY)
129- private val key = getRegionKey(chunk.pos.x shl 4 , chunk.bottomY, chunk.pos.z shl 4 )
194+ /* * Per-chunk data with its own renderer and origin. */
195+ private inner class ChunkData (val chunk : WorldChunk ) {
196+ // Chunk origin in world coordinates
197+ val originX: Double = (chunk.pos.x shl 4 ).toDouble()
198+ val originY: Double = chunk.bottomY.toDouble()
199+ val originZ: Double = (chunk.pos.z shl 4 ).toDouble()
200+
201+ // This chunk's own renderer
202+ val renderer = RegionRenderer ()
130203
131204 private var isDirty = false
132205
@@ -137,9 +210,16 @@ class ChunkedRegionESP(
137210 }
138211 }
139212
213+ /* *
214+ * Rebuild geometry relative to chunk origin.
215+ * Coordinates are stored as (worldPos - chunkOrigin).toFloat()
216+ */
140217 fun rebuild () {
141218 if (! isDirty) return
142- val scope = ShapeScope (region)
219+
220+ // Use chunk origin as the "camera" position for relative coords
221+ val chunkOriginVec = Vec3d (originX, originY, originZ)
222+ val scope = ShapeScope (chunkOriginVec)
143223
144224 for (x in chunk.pos.startX.. chunk.pos.endX) {
145225 for (z in chunk.pos.startZ.. chunk.pos.endZ) {
@@ -150,14 +230,13 @@ class ChunkedRegionESP(
150230 }
151231
152232 uploadQueue.add {
153- val renderer = renderers.getOrPut(key) { RegionRenderer (region) }
154233 renderer.upload(scope.builder.collector)
155234 isDirty = false
156235 }
157236 }
158237
159238 fun close () {
160- renderers.remove(key)? .close()
239+ renderer .close()
161240 }
162241 }
163242}
0 commit comments