From e0bbfcdf8149cbdb1cae7e9fa16e6b6ddbb4e8c0 Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Thu, 21 Aug 2025 20:31:40 -0400 Subject: [PATCH 01/10] shapedsl https://youtu.be/efc7njKAfgo --- .../com/lambda/event/events/RenderEvent.kt | 20 +- .../kotlin/com/lambda/graphics/RenderMain.kt | 16 +- .../lambda/graphics/pipeline/VertexBuilder.kt | 3 - .../graphics/renderer/esp/ChunkedESP.kt | 48 +-- .../graphics/renderer/esp/DynamicAABB.kt | 12 +- .../graphics/renderer/esp/ESPRenderer.kt | 81 ----- .../lambda/graphics/renderer/esp/ShapeDsl.kt | 339 ++++++++++++++++++ .../com/lambda/graphics/renderer/esp/Treed.kt | 79 ++++ .../esp/builders/DynamicESPBuilders.kt | 110 ------ .../esp/builders/StaticESPBuilders.kt | 224 ------------ .../renderer/esp/global/DynamicESP.kt | 22 -- .../graphics/renderer/esp/global/StaticESP.kt | 22 -- .../renderer/esp/impl/DynamicESPRenderer.kt | 22 -- .../renderer/esp/impl/StaticESPRenderer.kt | 22 -- .../construction/result/Drawable.kt | 4 +- .../request/breaking/BreakManager.kt | 14 +- .../module/modules/client/TaskFlowModule.kt | 7 +- .../lambda/module/modules/debug/BlockTest.kt | 8 +- .../lambda/module/modules/debug/RenderTest.kt | 14 +- .../module/modules/movement/BackTrack.kt | 9 +- .../lambda/module/modules/movement/Blink.kt | 6 +- .../module/modules/player/PacketMine.kt | 12 +- .../lambda/module/modules/player/Scaffold.kt | 18 +- .../module/modules/player/WorldEater.kt | 8 +- .../lambda/module/modules/render/BlockESP.kt | 15 +- .../module/modules/render/StorageESP.kt | 57 ++- 26 files changed, 519 insertions(+), 673 deletions(-) delete mode 100644 src/main/kotlin/com/lambda/graphics/renderer/esp/ESPRenderer.kt create mode 100644 src/main/kotlin/com/lambda/graphics/renderer/esp/ShapeDsl.kt create mode 100644 src/main/kotlin/com/lambda/graphics/renderer/esp/Treed.kt delete mode 100644 src/main/kotlin/com/lambda/graphics/renderer/esp/builders/DynamicESPBuilders.kt delete mode 100644 src/main/kotlin/com/lambda/graphics/renderer/esp/builders/StaticESPBuilders.kt delete mode 100644 src/main/kotlin/com/lambda/graphics/renderer/esp/global/DynamicESP.kt delete mode 100644 src/main/kotlin/com/lambda/graphics/renderer/esp/global/StaticESP.kt delete mode 100644 src/main/kotlin/com/lambda/graphics/renderer/esp/impl/DynamicESPRenderer.kt delete mode 100644 src/main/kotlin/com/lambda/graphics/renderer/esp/impl/StaticESPRenderer.kt diff --git a/src/main/kotlin/com/lambda/event/events/RenderEvent.kt b/src/main/kotlin/com/lambda/event/events/RenderEvent.kt index de8dbc6e8..f1c790242 100644 --- a/src/main/kotlin/com/lambda/event/events/RenderEvent.kt +++ b/src/main/kotlin/com/lambda/event/events/RenderEvent.kt @@ -17,22 +17,22 @@ package com.lambda.event.events +import com.lambda.context.SafeContext import com.lambda.event.Event import com.lambda.event.callback.Cancellable import com.lambda.event.callback.ICancellable -import com.lambda.graphics.renderer.esp.global.DynamicESP -import com.lambda.graphics.renderer.esp.global.StaticESP +import com.lambda.event.listener.SafeListener.Companion.listen +import com.lambda.graphics.renderer.esp.ShapeBuilder +import com.lambda.graphics.renderer.esp.Treed -sealed class RenderEvent { - class World : Event +fun Any.onStaticRender(block: SafeContext.(ShapeBuilder) -> Unit) = + listen { block(ShapeBuilder(Treed.staticFaceBuilder, Treed.staticEdgeBuilder)) } - class StaticESP : Event { - val renderer = StaticESP - } +fun Any.onDynamicRender(block: SafeContext.(ShapeBuilder) -> Unit) = + listen { block(ShapeBuilder(Treed.dynamicFaceBuilder, Treed.dynamicEdgeBuilder)) } - class DynamicESP : Event { - val renderer = DynamicESP - } +sealed class RenderEvent { + class World : Event class UpdateTarget : ICancellable by Cancellable() } diff --git a/src/main/kotlin/com/lambda/graphics/RenderMain.kt b/src/main/kotlin/com/lambda/graphics/RenderMain.kt index 1d3b5b20b..43c3cffb5 100644 --- a/src/main/kotlin/com/lambda/graphics/RenderMain.kt +++ b/src/main/kotlin/com/lambda/graphics/RenderMain.kt @@ -25,8 +25,7 @@ import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.graphics.gl.GlStateUtils.setupGL import com.lambda.graphics.gl.Matrices import com.lambda.graphics.gl.Matrices.resetMatrices -import com.lambda.graphics.renderer.esp.global.DynamicESP -import com.lambda.graphics.renderer.esp.global.StaticESP +import com.lambda.graphics.renderer.esp.Treed import com.lambda.util.math.Vec2d import com.mojang.blaze3d.opengl.GlStateManager import com.mojang.blaze3d.systems.RenderSystem @@ -56,21 +55,16 @@ object RenderMain { GlStateManager._glBindFramebuffer(GL_FRAMEBUFFER, prevFramebuffer) + Treed.clear() RenderEvent.World().post() - StaticESP.render() - DynamicESP.render() + Treed.upload() + Treed.render() } } init { listen { - StaticESP.clear() - RenderEvent.StaticESP().post() - StaticESP.upload() - - DynamicESP.clear() - RenderEvent.DynamicESP().post() - DynamicESP.upload() + //Treed.clear() } } } diff --git a/src/main/kotlin/com/lambda/graphics/pipeline/VertexBuilder.kt b/src/main/kotlin/com/lambda/graphics/pipeline/VertexBuilder.kt index 676e27fff..aa4716035 100644 --- a/src/main/kotlin/com/lambda/graphics/pipeline/VertexBuilder.kt +++ b/src/main/kotlin/com/lambda/graphics/pipeline/VertexBuilder.kt @@ -115,9 +115,6 @@ class VertexBuilder( fun collect(vararg indices: Int) = indices - fun use(block: VertexBuilder.() -> Unit) = - apply(block) - /** * Creates a new vertex with specified attributes * @param block Configuration lambda for defining vertex attributes diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt index 7caa5f688..18f2df868 100644 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt +++ b/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt @@ -17,14 +17,14 @@ package com.lambda.graphics.renderer.esp -import com.lambda.event.events.RenderEvent import com.lambda.event.events.TickEvent import com.lambda.event.events.WorldEvent +import com.lambda.event.events.onStaticRender import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.event.listener.SafeListener.Companion.listenConcurrently -import com.lambda.graphics.renderer.esp.impl.StaticESPRenderer import com.lambda.module.modules.client.StyleEditor -import com.lambda.threading.awaitMainThread +import com.lambda.util.world.FastVector +import com.lambda.util.world.fastVectorOf import net.minecraft.util.math.ChunkPos import net.minecraft.world.World import net.minecraft.world.chunk.WorldChunk @@ -33,7 +33,7 @@ import java.util.concurrent.ConcurrentLinkedDeque class ChunkedESP private constructor( owner: Any, - private val update: StaticESPRenderer.(World, Int, Int, Int) -> Unit + private val update: ShapeBuilder.(World, FastVector) -> Unit ) { private val rendererMap = ConcurrentHashMap() private val WorldChunk.renderer @@ -64,12 +64,12 @@ class ChunkedESP private constructor( rendererMap.remove(event.chunk.pos.toLong())?.notifyChunks() } - owner.listenConcurrently { + owner.onStaticRender { builder -> if (++ticks % StyleEditor.updateFrequency == 0) { val polls = minOf(StyleEditor.rebuildsPerTick, rebuildQueue.size) repeat(polls) { - rebuildQueue.poll()?.rebuild() + rebuildQueue.poll()?.rebuild(builder) } ticks = 0 } @@ -84,28 +84,16 @@ class ChunkedESP private constructor( uploadQueue.poll()?.invoke() } } - - owner.listen { - rendererMap.values.forEach { - it.renderer?.render() - } - } } companion object { fun Any.newChunkedESP( - update: StaticESPRenderer.(World, Int, Int, Int) -> Unit - ) = ChunkedESP(this, update) + update: ShapeBuilder.(World, FastVector) -> Unit + ) = ChunkedESP(this@newChunkedESP, update) } private class EspChunk(val chunk: WorldChunk, val owner: ChunkedESP) { - var renderer: StaticESPRenderer? = null - - private val chunkOffsets = listOf(1 to 0, 0 to 1, -1 to 0, 0 to -1) - - val neighbors = chunkOffsets.map { - ChunkPos(chunk.pos.x + it.first, chunk.pos.z + it.second) - }.toTypedArray() + val neighbors = listOf(1 to 0, 0 to 1, -1 to 0, 0 to -1).map { ChunkPos(chunk.pos.x + it.first, chunk.pos.z + it.second) } fun notifyChunks() { neighbors.forEach { @@ -117,24 +105,14 @@ class ChunkedESP private constructor( } } - suspend fun rebuild() { - val newRenderer = awaitMainThread { StaticESPRenderer() } - - iterateChunk { x, y, z -> - owner.update(newRenderer, chunk.world, x, y, z) - } - - owner.uploadQueue.add { - newRenderer.upload() - renderer = newRenderer - } - } + fun rebuild(builder: ShapeBuilder) = + iterateChunk { owner.update(builder, chunk.world, it) } - private fun iterateChunk(block: (Int, Int, Int) -> Unit) = chunk.apply { + inline fun iterateChunk(crossinline block: (FastVector) -> Unit) = chunk.apply { for (x in pos.startX..pos.endX) { for (z in pos.startZ..pos.endZ) { for (y in bottomY..height) { - block(x, y, z) + block(fastVectorOf(x, y, z)) } } } diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/DynamicAABB.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/DynamicAABB.kt index 1b58e7cbf..159b32268 100644 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/DynamicAABB.kt +++ b/src/main/kotlin/com/lambda/graphics/renderer/esp/DynamicAABB.kt @@ -26,6 +26,8 @@ class DynamicAABB { private var prev: Box? = null private var curr: Box? = null + val pair get() = prev?.let { prev -> curr?.let { curr -> prev to curr } } + fun update(box: Box): DynamicAABB { prev = curr ?: box curr = box @@ -38,16 +40,6 @@ class DynamicAABB { curr = null } - fun getBoxPair(): Pair? { - prev?.let { previous -> - curr?.let { current -> - return previous to current - } - } - - return null - } - companion object { val Entity.dynamicBox get() = DynamicAABB().apply { diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/ESPRenderer.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/ESPRenderer.kt deleted file mode 100644 index bf6676636..000000000 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/ESPRenderer.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2025 Lambda - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lambda.graphics.renderer.esp - -import com.lambda.Lambda -import com.lambda.graphics.buffer.vertex.attributes.VertexAttrib -import com.lambda.graphics.buffer.vertex.attributes.VertexMode -import com.lambda.graphics.gl.GlStateUtils -import com.lambda.graphics.pipeline.VertexBuilder -import com.lambda.graphics.pipeline.VertexPipeline -import com.lambda.graphics.shader.Shader -import com.lambda.graphics.shader.Shader.Companion.shader -import com.lambda.module.modules.client.StyleEditor -import com.lambda.util.extension.partialTicks - -open class ESPRenderer(tickedMode: Boolean) { - val shader: Shader - - val faces: VertexPipeline - var faceBuilder: VertexBuilder - - val outlines: VertexPipeline - var outlineBuilder: VertexBuilder - - init { - val mode = if (tickedMode) dynamicMode else staticMode - shader = mode.first - - faces = VertexPipeline(VertexMode.TRIANGLES, mode.second) - faceBuilder = faces.build() - - outlines = VertexPipeline(VertexMode.LINES, mode.second) - outlineBuilder = outlines.build() - } - - fun upload() { - faces.upload(faceBuilder) - outlines.upload(outlineBuilder) - } - - fun render() { - shader.use() - shader["u_TickDelta"] = Lambda.mc.partialTicks - shader["u_CameraPosition"] = Lambda.mc.gameRenderer.camera.pos - - GlStateUtils.withFaceCulling(faces::render) - GlStateUtils.withLineWidth(StyleEditor.outlineWidth, outlines::render) - } - - fun clear() { - faces.clear() - outlines.clear() - faceBuilder = faces.build() - outlineBuilder = outlines.build() - } - - companion object { - private val staticMode = shader( - "renderer/box_static" - ) to VertexAttrib.Group.STATIC_RENDERER - - private val dynamicMode = shader( - "renderer/box_dynamic" - ) to VertexAttrib.Group.DYNAMIC_RENDERER - } -} diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/ShapeDsl.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/ShapeDsl.kt new file mode 100644 index 000000000..35ba1dd02 --- /dev/null +++ b/src/main/kotlin/com/lambda/graphics/renderer/esp/ShapeDsl.kt @@ -0,0 +1,339 @@ +/* + * Copyright 2025 Lambda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lambda.graphics.renderer.esp + +import com.lambda.context.SafeContext +import com.lambda.graphics.pipeline.VertexBuilder +import com.lambda.graphics.renderer.esp.DirectionMask.hasDirection +import com.lambda.util.BlockUtils.blockState +import com.lambda.util.extension.max +import com.lambda.util.extension.min +import com.lambda.util.extension.outlineShape +import net.minecraft.block.BlockState +import net.minecraft.block.entity.BlockEntity +import net.minecraft.entity.Entity +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Box +import net.minecraft.util.shape.VoxelShape +import java.awt.Color + +@DslMarker +annotation class ShapeDsl + +class ShapeBuilder( + val faces: VertexBuilder, + val edges: VertexBuilder, +) { + @ShapeDsl + fun filled( + box : DynamicAABB, + color : Color, + sides : Int = DirectionMask.ALL, + ) = faces.apply { + val boxes = box.pair ?: return@apply + + val pos11 = boxes.first.min + val pos12 = boxes.first.max + val pos21 = boxes.second.min + val pos22 = boxes.second.max + + val blb by lazy { vertex { vec3(pos11.x, pos11.y, pos11.z).vec3(pos21.x, pos21.y, pos21.z).color(color) } } + val blf by lazy { vertex { vec3(pos11.x, pos11.y, pos12.z).vec3(pos21.x, pos21.y, pos22.z).color(color) } } + val brb by lazy { vertex { vec3(pos12.x, pos11.y, pos11.z).vec3(pos22.x, pos21.y, pos21.z).color(color) } } + val brf by lazy { vertex { vec3(pos12.x, pos11.y, pos12.z).vec3(pos22.x, pos21.y, pos22.z).color(color) } } + val tlb by lazy { vertex { vec3(pos11.x, pos12.y, pos11.z).vec3(pos21.x, pos22.y, pos21.z).color(color) } } + val tlf by lazy { vertex { vec3(pos11.x, pos12.y, pos12.z).vec3(pos21.x, pos22.y, pos22.z).color(color) } } + val trb by lazy { vertex { vec3(pos12.x, pos12.y, pos11.z).vec3(pos22.x, pos22.y, pos21.z).color(color) } } + val trf by lazy { vertex { vec3(pos12.x, pos12.y, pos12.z).vec3(pos22.x, pos22.y, pos22.z).color(color) } } + + if (sides.hasDirection(DirectionMask.EAST)) buildQuad(brb, trb, trf, brf) + if (sides.hasDirection(DirectionMask.WEST)) buildQuad(blb, blf, tlf, tlb) + if (sides.hasDirection(DirectionMask.UP)) buildQuad(tlb, tlf, trf, trb) + if (sides.hasDirection(DirectionMask.DOWN)) buildQuad(blb, brb, brf, blf) + if (sides.hasDirection(DirectionMask.SOUTH)) buildQuad(blf, brf, trf, tlf) + if (sides.hasDirection(DirectionMask.NORTH)) buildQuad(blb, tlb, trb, brb) + } + + @ShapeDsl + fun filled( + box : Box, + bottomColor : Color, + topColor : Color = bottomColor, + sides : Int = DirectionMask.ALL + ) = faces.apply { + val pos1 = box.min + val pos2 = box.max + + val blb by lazy { vertex { vec3(pos1.x, pos1.y, pos1.z).color(bottomColor) } } + val blf by lazy { vertex { vec3(pos1.x, pos1.y, pos2.z).color(bottomColor) } } + val brb by lazy { vertex { vec3(pos2.x, pos1.y, pos1.z).color(bottomColor) } } + val brf by lazy { vertex { vec3(pos2.x, pos1.y, pos2.z).color(bottomColor) } } + + val tlb by lazy { vertex { vec3(pos1.x, pos2.y, pos1.z).color(topColor) } } + val tlf by lazy { vertex { vec3(pos1.x, pos2.y, pos2.z).color(topColor) } } + val trb by lazy { vertex { vec3(pos2.x, pos2.y, pos1.z).color(topColor) } } + val trf by lazy { vertex { vec3(pos2.x, pos2.y, pos2.z).color(topColor) } } + + if (sides.hasDirection(DirectionMask.EAST)) buildQuad(brb, trb, trf, brf) + if (sides.hasDirection(DirectionMask.WEST)) buildQuad(blb, blf, tlf, tlb) + if (sides.hasDirection(DirectionMask.UP)) buildQuad(tlb, tlf, trf, trb) + if (sides.hasDirection(DirectionMask.DOWN)) buildQuad(blb, brb, brf, blf) + if (sides.hasDirection(DirectionMask.SOUTH)) buildQuad(blf, brf, trf, tlf) + if (sides.hasDirection(DirectionMask.NORTH)) buildQuad(blb, tlb, trb, brb) + } + + @ShapeDsl + fun SafeContext.filled( + pos : BlockPos, + state : BlockState, + color : Color, + sides : Int = DirectionMask.ALL, + ) = faces.apply { + val shape = state.getOutlineShape(world, pos) + filled(shape, color, sides) + } + + @ShapeDsl + fun SafeContext.filled( + pos : BlockPos, + color : Color, + sides : Int = DirectionMask.ALL, + ) = faces.apply { + val shape = blockState(pos).getOutlineShape(world, pos) + filled(shape, color, sides) + } + + @ShapeDsl + fun SafeContext.filled( + pos : BlockPos, + entity : BlockEntity, + color : Color, + sides : Int = DirectionMask.ALL, + ) { + val shape = outlineShape(entity.cachedState, pos) + filled(shape, color, sides) + } + + @ShapeDsl + fun filled( + shape: VoxelShape, + color: Color, + sides: Int = DirectionMask.ALL, + ) { + shape.boundingBoxes + .forEach { filled(it, color, color, sides) } + } + + @ShapeDsl + fun filled( + box : Box, + color : Color, + sides : Int = DirectionMask.ALL, + ) = filled(box, color, color, sides) + + @ShapeDsl + fun outline( + box : DynamicAABB, + color : Color, + sides : Int = DirectionMask.ALL, + mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, + ) = edges.apply { + val boxes = box.pair ?: return@apply + + val pos11 = boxes.first.min + val pos12 = boxes.first.max + val pos21 = boxes.second.min + val pos22 = boxes.second.max + + val blb by lazy { vertex { vec3(pos11.x, pos11.y, pos11.z).vec3(pos21.x, pos21.y, pos21.z).color(color) } } + val blf by lazy { vertex { vec3(pos11.x, pos11.y, pos12.z).vec3(pos21.x, pos21.y, pos22.z).color(color) } } + val brb by lazy { vertex { vec3(pos12.x, pos11.y, pos11.z).vec3(pos22.x, pos21.y, pos21.z).color(color) } } + val brf by lazy { vertex { vec3(pos12.x, pos11.y, pos12.z).vec3(pos22.x, pos21.y, pos22.z).color(color) } } + val tlb by lazy { vertex { vec3(pos11.x, pos12.y, pos11.z).vec3(pos21.x, pos22.y, pos21.z).color(color) } } + val tlf by lazy { vertex { vec3(pos11.x, pos12.y, pos12.z).vec3(pos21.x, pos22.y, pos22.z).color(color) } } + val trb by lazy { vertex { vec3(pos12.x, pos12.y, pos11.z).vec3(pos22.x, pos22.y, pos21.z).color(color) } } + val trf by lazy { vertex { vec3(pos12.x, pos12.y, pos12.z).vec3(pos22.x, pos22.y, pos22.z).color(color) } } + + val hasEast = sides.hasDirection(DirectionMask.EAST) + val hasWest = sides.hasDirection(DirectionMask.WEST) + val hasUp = sides.hasDirection(DirectionMask.UP) + val hasDown = sides.hasDirection(DirectionMask.DOWN) + val hasSouth = sides.hasDirection(DirectionMask.SOUTH) + val hasNorth = sides.hasDirection(DirectionMask.NORTH) + + if (mode.check(hasUp, hasNorth)) buildLine(tlb, trb) + if (mode.check(hasUp, hasSouth)) buildLine(tlf, trf) + if (mode.check(hasUp, hasWest)) buildLine(tlb, tlf) + if (mode.check(hasUp, hasEast)) buildLine(trf, trb) + + if (mode.check(hasDown, hasNorth)) buildLine(blb, brb) + if (mode.check(hasDown, hasSouth)) buildLine(blf, brf) + if (mode.check(hasDown, hasWest)) buildLine(blb, blf) + if (mode.check(hasDown, hasEast)) buildLine(brb, brf) + + if (mode.check(hasWest, hasNorth)) buildLine(tlb, blb) + if (mode.check(hasNorth, hasEast)) buildLine(trb, brb) + if (mode.check(hasEast, hasSouth)) buildLine(trf, brf) + if (mode.check(hasSouth, hasWest)) buildLine(tlf, blf) + } + + @ShapeDsl + fun outline( + box : Box, + bottomColor : Color, + topColor : Color = bottomColor, + sides : Int = DirectionMask.ALL, + mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, + ) = edges.apply { + val pos1 = box.min + val pos2 = box.max + + val blb by lazy { vertex { vec3(pos1.x, pos1.y, pos1.z).color(bottomColor) } } + val blf by lazy { vertex { vec3(pos1.x, pos1.y, pos2.z).color(bottomColor) } } + val brb by lazy { vertex { vec3(pos2.x, pos1.y, pos1.z).color(bottomColor) } } + val brf by lazy { vertex { vec3(pos2.x, pos1.y, pos2.z).color(bottomColor) } } + val tlb by lazy { vertex { vec3(pos1.x, pos2.y, pos1.z).color(topColor) } } + val tlf by lazy { vertex { vec3(pos1.x, pos2.y, pos2.z).color(topColor) } } + val trb by lazy { vertex { vec3(pos2.x, pos2.y, pos1.z).color(topColor) } } + val trf by lazy { vertex { vec3(pos2.x, pos2.y, pos2.z).color(topColor) } } + + val hasEast = sides.hasDirection(DirectionMask.EAST) + val hasWest = sides.hasDirection(DirectionMask.WEST) + val hasUp = sides.hasDirection(DirectionMask.UP) + val hasDown = sides.hasDirection(DirectionMask.DOWN) + val hasSouth = sides.hasDirection(DirectionMask.SOUTH) + val hasNorth = sides.hasDirection(DirectionMask.NORTH) + + if (mode.check(hasUp, hasNorth)) buildLine(tlb, trb) + if (mode.check(hasUp, hasSouth)) buildLine(tlf, trf) + if (mode.check(hasUp, hasWest)) buildLine(tlb, tlf) + if (mode.check(hasUp, hasEast)) buildLine(trf, trb) + + if (mode.check(hasDown, hasNorth)) buildLine(blb, brb) + if (mode.check(hasDown, hasSouth)) buildLine(blf, brf) + if (mode.check(hasDown, hasWest)) buildLine(blb, blf) + if (mode.check(hasDown, hasEast)) buildLine(brb, brf) + + if (mode.check(hasWest, hasNorth)) buildLine(tlb, blb) + if (mode.check(hasNorth, hasEast)) buildLine(trb, brb) + if (mode.check(hasEast, hasSouth)) buildLine(trf, brf) + if (mode.check(hasSouth, hasWest)) buildLine(tlf, blf) + } + + @ShapeDsl + fun SafeContext.outline( + pos : BlockPos, + state : BlockState, + color : Color, + sides : Int = DirectionMask.ALL, + mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, + ) { + val shape = state.getOutlineShape(world, pos) + outline(shape, color, sides, mode) + } + + @ShapeDsl + fun SafeContext.outline( + pos : BlockPos, + color : Color, + sides : Int = DirectionMask.ALL, + mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, + ) { + val shape = blockState(pos).getOutlineShape(world, pos) + outline(shape, color, sides, mode) + } + + @ShapeDsl + fun SafeContext.outline( + pos : BlockPos, + entity : BlockEntity, + color : Color, + sides : Int = DirectionMask.ALL, + mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, + ) { + val shape = outlineShape(entity.cachedState, pos) + outline(shape, color, sides, mode) + } + + @ShapeDsl + fun outline( + shape : VoxelShape, + color : Color, + sides : Int = DirectionMask.ALL, + mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, + ) { + shape.boundingBoxes + .forEach { outline(it, color, sides, mode) } + } + + @ShapeDsl + fun outline( + box : Box, + color : Color, + sides : Int = DirectionMask.ALL, + mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, + ) { + outline(box, color, color, sides, mode) + } + + @ShapeDsl + fun box( + box : DynamicAABB, + filled : Color, + outline : Color, + sides : Int = DirectionMask.ALL, + mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, + ) { + filled(box, filled, sides) + outline(box, outline, sides, mode) + } + + @ShapeDsl + fun box( + box : Box, + filled : Color, + outline : Color, + sides : Int = DirectionMask.ALL, + mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, + ) { + filled(box, filled, sides) + outline(box, outline, sides, mode) + } + + @ShapeDsl + fun SafeContext.box( + entity : BlockEntity, + color : Color, + sides : Int = DirectionMask.ALL, + mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, + ) { + filled(entity.pos, entity, color, sides) + outline(entity.pos, entity, color, sides, mode) + } + + @ShapeDsl + fun SafeContext.box( + entity : Entity, + color : Color, + sides : Int = DirectionMask.ALL, + mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, + ) { + filled(entity.boundingBox, color, sides) + outline(entity.boundingBox, color, sides, mode) + } +} diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/Treed.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/Treed.kt new file mode 100644 index 000000000..a560c9e96 --- /dev/null +++ b/src/main/kotlin/com/lambda/graphics/renderer/esp/Treed.kt @@ -0,0 +1,79 @@ +/* + * Copyright 2025 Lambda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lambda.graphics.renderer.esp + +import com.lambda.Lambda +import com.lambda.graphics.buffer.vertex.attributes.VertexAttrib +import com.lambda.graphics.buffer.vertex.attributes.VertexMode +import com.lambda.graphics.gl.GlStateUtils +import com.lambda.graphics.pipeline.VertexBuilder +import com.lambda.graphics.pipeline.VertexPipeline +import com.lambda.graphics.shader.Shader.Companion.shader +import com.lambda.module.modules.client.StyleEditor +import com.lambda.util.extension.partialTicks + +object Treed { + val staticShader = shader("renderer/box_static") + val dynamicShader = shader("renderer/box_dynamic") + + val staticFaces = VertexPipeline(VertexMode.TRIANGLES, VertexAttrib.Group.STATIC_RENDERER) + val staticEdges = VertexPipeline(VertexMode.LINES, VertexAttrib.Group.STATIC_RENDERER) + val dynamicFaces = VertexPipeline(VertexMode.TRIANGLES, VertexAttrib.Group.DYNAMIC_RENDERER) + val dynamicEdges = VertexPipeline(VertexMode.LINES, VertexAttrib.Group.DYNAMIC_RENDERER) + + // Vertex builders for shape building + var staticFaceBuilder = VertexBuilder(); private set + var dynamicFaceBuilder = VertexBuilder(); private set + var staticEdgeBuilder = VertexBuilder(); private set + var dynamicEdgeBuilder = VertexBuilder(); private set + + fun upload() { + staticFaces.upload(staticFaceBuilder) + staticEdges.upload(staticEdgeBuilder) + dynamicFaces.upload(dynamicFaceBuilder) + dynamicEdges.upload(dynamicEdgeBuilder) + } + + fun render() { + staticShader.use() + staticShader["u_TickDelta"] = Lambda.mc.partialTicks + staticShader["u_CameraPosition"] = Lambda.mc.gameRenderer.camera.pos + + GlStateUtils.withFaceCulling(staticFaces::render) + GlStateUtils.withLineWidth(StyleEditor.outlineWidth, staticEdges::render) + + dynamicShader.use() + dynamicShader["u_TickDelta"] = Lambda.mc.partialTicks + dynamicShader["u_CameraPosition"] = Lambda.mc.gameRenderer.camera.pos + + GlStateUtils.withFaceCulling(dynamicFaces::render) + GlStateUtils.withLineWidth(StyleEditor.outlineWidth, dynamicEdges::render) + } + + fun clear() { + staticFaces.clear() + staticEdges.clear() + dynamicFaces.clear() + dynamicEdges.clear() + + staticFaceBuilder = VertexBuilder() + staticEdgeBuilder = VertexBuilder() + dynamicFaceBuilder = VertexBuilder() + dynamicEdgeBuilder = VertexBuilder() + } +} diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/builders/DynamicESPBuilders.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/builders/DynamicESPBuilders.kt deleted file mode 100644 index cb0653245..000000000 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/builders/DynamicESPBuilders.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2025 Lambda - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lambda.graphics.renderer.esp.builders - -import com.lambda.graphics.renderer.esp.DirectionMask -import com.lambda.graphics.renderer.esp.DirectionMask.hasDirection -import com.lambda.graphics.renderer.esp.DynamicAABB -import com.lambda.graphics.renderer.esp.impl.DynamicESPRenderer -import com.lambda.util.extension.max -import com.lambda.util.extension.min -import java.awt.Color - -fun DynamicESPRenderer.ofBox( - box: DynamicAABB, - filledColor: Color, - outlineColor: Color, - sides: Int = DirectionMask.ALL, - outlineMode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR -) { - buildFilled(box, filledColor, sides) - buildOutline(box, outlineColor, sides, outlineMode) -} - -fun DynamicESPRenderer.buildFilled( - box: DynamicAABB, - color: Color, - sides: Int = DirectionMask.ALL -) = faceBuilder.use { - val boxes = box.getBoxPair() ?: return@use - val pos11 = boxes.first.min - val pos12 = boxes.first.max - val pos21 = boxes.second.min - val pos22 = boxes.second.max - - val blb by lazy { vertex { vec3(pos11.x, pos11.y, pos11.z).vec3(pos21.x, pos21.y, pos21.z).color(color) } } - val blf by lazy { vertex { vec3(pos11.x, pos11.y, pos12.z).vec3(pos21.x, pos21.y, pos22.z).color(color) } } - val brb by lazy { vertex { vec3(pos12.x, pos11.y, pos11.z).vec3(pos22.x, pos21.y, pos21.z).color(color) } } - val brf by lazy { vertex { vec3(pos12.x, pos11.y, pos12.z).vec3(pos22.x, pos21.y, pos22.z).color(color) } } - val tlb by lazy { vertex { vec3(pos11.x, pos12.y, pos11.z).vec3(pos21.x, pos22.y, pos21.z).color(color) } } - val tlf by lazy { vertex { vec3(pos11.x, pos12.y, pos12.z).vec3(pos21.x, pos22.y, pos22.z).color(color) } } - val trb by lazy { vertex { vec3(pos12.x, pos12.y, pos11.z).vec3(pos22.x, pos22.y, pos21.z).color(color) } } - val trf by lazy { vertex { vec3(pos12.x, pos12.y, pos12.z).vec3(pos22.x, pos22.y, pos22.z).color(color) } } - - if (sides.hasDirection(DirectionMask.EAST)) buildQuad(brb, trb, trf, brf) - if (sides.hasDirection(DirectionMask.WEST)) buildQuad(blb, blf, tlf, tlb) - if (sides.hasDirection(DirectionMask.UP)) buildQuad(tlb, tlf, trf, trb) - if (sides.hasDirection(DirectionMask.DOWN)) buildQuad(blb, brb, brf, blf) - if (sides.hasDirection(DirectionMask.SOUTH)) buildQuad(blf, brf, trf, tlf) - if (sides.hasDirection(DirectionMask.NORTH)) buildQuad(blb, tlb, trb, brb) -} - -fun DynamicESPRenderer.buildOutline( - box: DynamicAABB, - color: Color, - sides: Int = DirectionMask.ALL, - outlineMode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR -) = outlineBuilder.use { - val boxes = box.getBoxPair() ?: return@use - - val pos11 = boxes.first.min - val pos12 = boxes.first.max - val pos21 = boxes.second.min - val pos22 = boxes.second.max - - val blb by lazy { vertex { vec3(pos11.x, pos11.y, pos11.z).vec3(pos21.x, pos21.y, pos21.z).color(color) } } - val blf by lazy { vertex { vec3(pos11.x, pos11.y, pos12.z).vec3(pos21.x, pos21.y, pos22.z).color(color) } } - val brb by lazy { vertex { vec3(pos12.x, pos11.y, pos11.z).vec3(pos22.x, pos21.y, pos21.z).color(color) } } - val brf by lazy { vertex { vec3(pos12.x, pos11.y, pos12.z).vec3(pos22.x, pos21.y, pos22.z).color(color) } } - val tlb by lazy { vertex { vec3(pos11.x, pos12.y, pos11.z).vec3(pos21.x, pos22.y, pos21.z).color(color) } } - val tlf by lazy { vertex { vec3(pos11.x, pos12.y, pos12.z).vec3(pos21.x, pos22.y, pos22.z).color(color) } } - val trb by lazy { vertex { vec3(pos12.x, pos12.y, pos11.z).vec3(pos22.x, pos22.y, pos21.z).color(color) } } - val trf by lazy { vertex { vec3(pos12.x, pos12.y, pos12.z).vec3(pos22.x, pos22.y, pos22.z).color(color) } } - - val hasEast = sides.hasDirection(DirectionMask.EAST) - val hasWest = sides.hasDirection(DirectionMask.WEST) - val hasUp = sides.hasDirection(DirectionMask.UP) - val hasDown = sides.hasDirection(DirectionMask.DOWN) - val hasSouth = sides.hasDirection(DirectionMask.SOUTH) - val hasNorth = sides.hasDirection(DirectionMask.NORTH) - - if (outlineMode.check(hasUp, hasNorth)) buildLine(tlb, trb) - if (outlineMode.check(hasUp, hasSouth)) buildLine(tlf, trf) - if (outlineMode.check(hasUp, hasWest)) buildLine(tlb, tlf) - if (outlineMode.check(hasUp, hasEast)) buildLine(trf, trb) - - if (outlineMode.check(hasDown, hasNorth)) buildLine(blb, brb) - if (outlineMode.check(hasDown, hasSouth)) buildLine(blf, brf) - if (outlineMode.check(hasDown, hasWest)) buildLine(blb, blf) - if (outlineMode.check(hasDown, hasEast)) buildLine(brb, brf) - - if (outlineMode.check(hasWest, hasNorth)) buildLine(tlb, blb) - if (outlineMode.check(hasNorth, hasEast)) buildLine(trb, brb) - if (outlineMode.check(hasEast, hasSouth)) buildLine(trf, brf) - if (outlineMode.check(hasSouth, hasWest)) buildLine(tlf, blf) -} diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/builders/StaticESPBuilders.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/builders/StaticESPBuilders.kt deleted file mode 100644 index d4a733726..000000000 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/builders/StaticESPBuilders.kt +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright 2025 Lambda - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lambda.graphics.renderer.esp.builders - -import com.lambda.graphics.renderer.esp.DirectionMask -import com.lambda.graphics.renderer.esp.DirectionMask.hasDirection -import com.lambda.graphics.renderer.esp.impl.StaticESPRenderer -import com.lambda.threading.runSafe -import com.lambda.util.BlockUtils.blockState -import com.lambda.util.extension.max -import com.lambda.util.extension.min -import net.minecraft.block.BlockState -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Box -import net.minecraft.util.shape.VoxelShape -import java.awt.Color - -fun StaticESPRenderer.ofShape( - pos: BlockPos, - filledColor: Color, - outlineColor: Color, - sides: Int = DirectionMask.ALL, - outlineMode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR -) = runSafe { - val shape = blockState(pos).getOutlineShape(world, pos) - ofShape(pos, shape, filledColor, outlineColor, sides, outlineMode) -} - -fun StaticESPRenderer.ofShape( - pos: BlockPos, - state: BlockState, - filledColor: Color, - outlineColor: Color, - sides: Int = DirectionMask.ALL, - outlineMode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR -) = runSafe { - val shape = state.getOutlineShape(world, pos) - ofShape(pos, shape, filledColor, outlineColor, sides, outlineMode) -} - -fun StaticESPRenderer.ofShape( - pos: BlockPos, - shape: VoxelShape, - filledColor: Color, - outlineColor: Color, - sides: Int = DirectionMask.ALL, - outlineMode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR -) { - shape.boundingBoxes.forEach { - ofBox(it.offset(pos), filledColor, outlineColor, sides, outlineMode) - } -} - -fun StaticESPRenderer.ofBox( - box: Box, - filledColor: Color, - outlineColor: Color, - sides: Int = DirectionMask.ALL, - outlineMode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR -) { - buildFilled(box, filledColor, sides) - buildOutline(box, outlineColor, sides, outlineMode) -} - -fun StaticESPRenderer.buildFilledShape( - pos: BlockPos, - state: BlockState, - color: Color, - sides: Int = DirectionMask.ALL, -) = runSafe { - val shape = state.getOutlineShape(world, pos) - buildFilledShape(shape, color, sides) -} - -fun StaticESPRenderer.buildFilledShape( - pos: BlockPos, - color: Color, - sides: Int = DirectionMask.ALL, -) = runSafe { - val shape = blockState(pos).getOutlineShape(world, pos) - buildFilledShape(shape, color, sides) -} - -fun StaticESPRenderer.buildFilledShape( - shape: VoxelShape, - color: Color, - sides: Int = DirectionMask.ALL, -) { - shape.boundingBoxes - .forEach { buildFilled(it, color, sides) } -} - - -fun StaticESPRenderer.buildFilled( - box: Box, - color: Color, - sides: Int = DirectionMask.ALL -) { - buildFilled(box, color, color, sides) -} - -fun StaticESPRenderer.buildOutlineShape( - pos: BlockPos, - state: BlockState, - color: Color, - sides: Int = DirectionMask.ALL, - outlineMode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR -) = runSafe { - val shape = state.getOutlineShape(world, pos) - buildOutlineShape(shape, color, sides, outlineMode) -} - -fun StaticESPRenderer.buildOutlineShape( - pos: BlockPos, - color: Color, - sides: Int = DirectionMask.ALL, - outlineMode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR -) = runSafe { - val shape = blockState(pos).getOutlineShape(world, pos) - buildOutlineShape(shape, color, sides, outlineMode) -} - -fun StaticESPRenderer.buildOutlineShape( - shape: VoxelShape, - color: Color, - sides: Int = DirectionMask.ALL, - outlineMode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR -) { - shape.boundingBoxes - .forEach { buildOutline(it, color, sides, outlineMode) } -} - -fun StaticESPRenderer.buildOutline( - box: Box, - color: Color, - sides: Int = DirectionMask.ALL, - outlineMode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR -) { - buildOutline(box, color, color, sides, outlineMode) -} - -fun StaticESPRenderer.buildFilled( - box: Box, - colorBottom: Color, - colorTop: Color = colorBottom, - sides: Int = DirectionMask.ALL -) = faceBuilder.use { - val pos1 = box.min - val pos2 = box.max - - val blb by lazy { vertex { vec3(pos1.x, pos1.y, pos1.z).color(colorBottom) } } - val blf by lazy { vertex { vec3(pos1.x, pos1.y, pos2.z).color(colorBottom) } } - val brb by lazy { vertex { vec3(pos2.x, pos1.y, pos1.z).color(colorBottom) } } - val brf by lazy { vertex { vec3(pos2.x, pos1.y, pos2.z).color(colorBottom) } } - - val tlb by lazy { vertex { vec3(pos1.x, pos2.y, pos1.z).color(colorTop) } } - val tlf by lazy { vertex { vec3(pos1.x, pos2.y, pos2.z).color(colorTop) } } - val trb by lazy { vertex { vec3(pos2.x, pos2.y, pos1.z).color(colorTop) } } - val trf by lazy { vertex { vec3(pos2.x, pos2.y, pos2.z).color(colorTop) } } - - if (sides.hasDirection(DirectionMask.EAST)) buildQuad(brb, trb, trf, brf) - if (sides.hasDirection(DirectionMask.WEST)) buildQuad(blb, blf, tlf, tlb) - if (sides.hasDirection(DirectionMask.UP)) buildQuad(tlb, tlf, trf, trb) - if (sides.hasDirection(DirectionMask.DOWN)) buildQuad(blb, brb, brf, blf) - if (sides.hasDirection(DirectionMask.SOUTH)) buildQuad(blf, brf, trf, tlf) - if (sides.hasDirection(DirectionMask.NORTH)) buildQuad(blb, tlb, trb, brb) -} - -fun StaticESPRenderer.buildOutline( - box: Box, - colorBottom: Color, - colorTop: Color = colorBottom, - sides: Int = DirectionMask.ALL, - outlineMode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR -) = outlineBuilder.use { - val pos1 = box.min - val pos2 = box.max - - val blb by lazy { vertex { vec3(pos1.x, pos1.y, pos1.z).color(colorBottom) } } - val blf by lazy { vertex { vec3(pos1.x, pos1.y, pos2.z).color(colorBottom) } } - val brb by lazy { vertex { vec3(pos2.x, pos1.y, pos1.z).color(colorBottom) } } - val brf by lazy { vertex { vec3(pos2.x, pos1.y, pos2.z).color(colorBottom) } } - val tlb by lazy { vertex { vec3(pos1.x, pos2.y, pos1.z).color(colorTop) } } - val tlf by lazy { vertex { vec3(pos1.x, pos2.y, pos2.z).color(colorTop) } } - val trb by lazy { vertex { vec3(pos2.x, pos2.y, pos1.z).color(colorTop) } } - val trf by lazy { vertex { vec3(pos2.x, pos2.y, pos2.z).color(colorTop) } } - - val hasEast = sides.hasDirection(DirectionMask.EAST) - val hasWest = sides.hasDirection(DirectionMask.WEST) - val hasUp = sides.hasDirection(DirectionMask.UP) - val hasDown = sides.hasDirection(DirectionMask.DOWN) - val hasSouth = sides.hasDirection(DirectionMask.SOUTH) - val hasNorth = sides.hasDirection(DirectionMask.NORTH) - - if (outlineMode.check(hasUp, hasNorth)) buildLine(tlb, trb) - if (outlineMode.check(hasUp, hasSouth)) buildLine(tlf, trf) - if (outlineMode.check(hasUp, hasWest)) buildLine(tlb, tlf) - if (outlineMode.check(hasUp, hasEast)) buildLine(trf, trb) - - if (outlineMode.check(hasDown, hasNorth)) buildLine(blb, brb) - if (outlineMode.check(hasDown, hasSouth)) buildLine(blf, brf) - if (outlineMode.check(hasDown, hasWest)) buildLine(blb, blf) - if (outlineMode.check(hasDown, hasEast)) buildLine(brb, brf) - - if (outlineMode.check(hasWest, hasNorth)) buildLine(tlb, blb) - if (outlineMode.check(hasNorth, hasEast)) buildLine(trb, brb) - if (outlineMode.check(hasEast, hasSouth)) buildLine(trf, brf) - if (outlineMode.check(hasSouth, hasWest)) buildLine(tlf, blf) -} diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/global/DynamicESP.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/global/DynamicESP.kt deleted file mode 100644 index cc8758055..000000000 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/global/DynamicESP.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2025 Lambda - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lambda.graphics.renderer.esp.global - -import com.lambda.graphics.renderer.esp.impl.DynamicESPRenderer - -object DynamicESP : DynamicESPRenderer() diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/global/StaticESP.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/global/StaticESP.kt deleted file mode 100644 index 7e0c9b6ce..000000000 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/global/StaticESP.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2025 Lambda - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lambda.graphics.renderer.esp.global - -import com.lambda.graphics.renderer.esp.impl.StaticESPRenderer - -object StaticESP : StaticESPRenderer() diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/DynamicESPRenderer.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/DynamicESPRenderer.kt deleted file mode 100644 index 9ba314bdd..000000000 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/DynamicESPRenderer.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2025 Lambda - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lambda.graphics.renderer.esp.impl - -import com.lambda.graphics.renderer.esp.ESPRenderer - -open class DynamicESPRenderer : ESPRenderer(true) diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/StaticESPRenderer.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/StaticESPRenderer.kt deleted file mode 100644 index d3d48deea..000000000 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/impl/StaticESPRenderer.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2025 Lambda - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lambda.graphics.renderer.esp.impl - -import com.lambda.graphics.renderer.esp.ESPRenderer - -open class StaticESPRenderer : ESPRenderer(false) \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/interaction/construction/result/Drawable.kt b/src/main/kotlin/com/lambda/interaction/construction/result/Drawable.kt index 04b6f84a1..108e56200 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/result/Drawable.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/result/Drawable.kt @@ -20,8 +20,6 @@ package com.lambda.interaction.construction.result import com.lambda.context.SafeContext import com.lambda.graphics.renderer.esp.DirectionMask import com.lambda.graphics.renderer.esp.DirectionMask.include -import com.lambda.graphics.renderer.esp.builders.buildFilled -import com.lambda.graphics.renderer.esp.global.StaticESP import com.lambda.util.BlockUtils.blockState import net.minecraft.block.BlockState import net.minecraft.util.math.BlockPos @@ -34,7 +32,7 @@ interface Drawable { fun SafeContext.buildRenderer() fun SafeContext.withBox(box: Box, color: Color, mask: Int = DirectionMask.ALL) { - StaticESP.buildFilled(box, color, mask) + //StaticESP.filled(box, color, mask) //StaticESP.buildOutline(box, color, mask) } diff --git a/src/main/kotlin/com/lambda/interaction/request/breaking/BreakManager.kt b/src/main/kotlin/com/lambda/interaction/request/breaking/BreakManager.kt index 8765cf276..a0dddecc0 100644 --- a/src/main/kotlin/com/lambda/interaction/request/breaking/BreakManager.kt +++ b/src/main/kotlin/com/lambda/interaction/request/breaking/BreakManager.kt @@ -22,14 +22,12 @@ import com.lambda.event.Event import com.lambda.event.EventFlow.post import com.lambda.event.events.ConnectionEvent import com.lambda.event.events.EntityEvent -import com.lambda.event.events.RenderEvent import com.lambda.event.events.TickEvent import com.lambda.event.events.UpdateManagerEvent import com.lambda.event.events.WorldEvent +import com.lambda.event.events.onStaticRender import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe -import com.lambda.graphics.renderer.esp.builders.buildFilled -import com.lambda.graphics.renderer.esp.builders.buildOutline import com.lambda.interaction.construction.blueprint.Blueprint.Companion.toStructure import com.lambda.interaction.construction.blueprint.StaticBlueprint.Companion.toBlueprint import com.lambda.interaction.construction.context.BreakContext @@ -226,16 +224,16 @@ object BreakManager : RequestHandler( ?.internalOnItemDrop(it.entity) } - listen { event -> + onStaticRender { val activeStack = breakInfos .filterNotNull() - .firstOrNull()?.swapStack ?: return@listen + .firstOrNull()?.swapStack ?: return@onStaticRender breakInfos .filterNotNull() .forEach { info -> val config = info.breakConfig - if (!config.renders) return@listen + if (!config.renders) return@onStaticRender val swapMode = info.breakConfig.swapMode val breakDelta = info.context.cachedState.calcBreakDelta( player, @@ -270,8 +268,8 @@ object BreakManager : RequestHandler( it.offset(info.context.blockPos) }.forEach boxes@ { box -> val interpolated = interpolateBox(box, interpolatedProgress, info.breakConfig) - if (config.fill) event.renderer.buildFilled(interpolated, fillColor) - if (config.outline) event.renderer.buildOutline(interpolated, outlineColor) + if (config.fill) it.filled(interpolated, fillColor) + if (config.outline) it.outline(interpolated, outlineColor) } } } diff --git a/src/main/kotlin/com/lambda/module/modules/client/TaskFlowModule.kt b/src/main/kotlin/com/lambda/module/modules/client/TaskFlowModule.kt index 314657674..ed7f9287f 100644 --- a/src/main/kotlin/com/lambda/module/modules/client/TaskFlowModule.kt +++ b/src/main/kotlin/com/lambda/module/modules/client/TaskFlowModule.kt @@ -23,6 +23,7 @@ import com.lambda.config.groups.InteractionSettings import com.lambda.config.groups.InventorySettings import com.lambda.config.groups.RotationSettings import com.lambda.event.events.RenderEvent +import com.lambda.event.events.onStaticRender import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.construction.result.Drawable import com.lambda.module.Module @@ -58,10 +59,8 @@ object TaskFlowModule : Module( var drawables = listOf() init { - listen { - drawables.toList().forEach { res -> - with(res) { buildRenderer() } - } + onStaticRender { + drawables.forEach { with(it) { buildRenderer() } } } } } diff --git a/src/main/kotlin/com/lambda/module/modules/debug/BlockTest.kt b/src/main/kotlin/com/lambda/module/modules/debug/BlockTest.kt index 223812b68..1a649301c 100644 --- a/src/main/kotlin/com/lambda/module/modules/debug/BlockTest.kt +++ b/src/main/kotlin/com/lambda/module/modules/debug/BlockTest.kt @@ -17,9 +17,7 @@ package com.lambda.module.modules.debug -import com.lambda.event.events.RenderEvent -import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.graphics.renderer.esp.builders.ofBox +import com.lambda.event.events.onStaticRender import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.util.world.blockSearch @@ -49,12 +47,12 @@ object BlockTest : Module( private val outlineColor = Color(100, 150, 255, 51) init { - listen { + onStaticRender { blockSearch(range, step = step) { _, state -> state.isOf(Blocks.DIAMOND_BLOCK) }.forEach { (pos, state) -> state.getOutlineShape(world, pos).boundingBoxes.forEach { box -> - it.renderer.ofBox(box.offset(pos), filledColor, outlineColor) + it.box(box.offset(pos), filledColor, outlineColor) } } } diff --git a/src/main/kotlin/com/lambda/module/modules/debug/RenderTest.kt b/src/main/kotlin/com/lambda/module/modules/debug/RenderTest.kt index 71248fedd..1618c3a6f 100644 --- a/src/main/kotlin/com/lambda/module/modules/debug/RenderTest.kt +++ b/src/main/kotlin/com/lambda/module/modules/debug/RenderTest.kt @@ -17,10 +17,10 @@ package com.lambda.module.modules.debug -import com.lambda.event.events.RenderEvent -import com.lambda.event.listener.SafeListener.Companion.listen +import com.lambda.event.events.onDynamicRender +import com.lambda.event.events.onStaticRender +import com.lambda.graphics.renderer.esp.DirectionMask import com.lambda.graphics.renderer.esp.DynamicAABB.Companion.dynamicBox -import com.lambda.graphics.renderer.esp.builders.ofBox import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.util.math.setAlpha @@ -45,15 +45,15 @@ object RenderTest : Module( private val filledColor = outlineColor.setAlpha(0.2) init { - listen { + onDynamicRender { entitySearch(8.0) .forEach { entity -> - it.renderer.ofBox(entity.dynamicBox, filledColor, outlineColor) + it.box(entity.dynamicBox, filledColor, outlineColor, DirectionMask.ALL, DirectionMask.OutlineMode.AND) } } - listen { - it.renderer.ofBox(Box.of(player.pos, 0.3, 0.3, 0.3), filledColor, outlineColor) + onStaticRender { + it.box(Box.of(player.pos, 0.3, 0.3, 0.3), filledColor, outlineColor) } } } diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BackTrack.kt b/src/main/kotlin/com/lambda/module/modules/movement/BackTrack.kt index a7fc452e3..98f8d6ab2 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BackTrack.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BackTrack.kt @@ -20,11 +20,10 @@ package com.lambda.module.modules.movement import com.lambda.context.SafeContext import com.lambda.event.events.ConnectionEvent import com.lambda.event.events.PacketEvent -import com.lambda.event.events.RenderEvent import com.lambda.event.events.TickEvent +import com.lambda.event.events.onDynamicRender import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.graphics.renderer.esp.DynamicAABB -import com.lambda.graphics.renderer.esp.builders.ofBox import com.lambda.module.Module import com.lambda.module.modules.client.GuiSettings import com.lambda.module.modules.combat.KillAura @@ -111,15 +110,15 @@ object BackTrack : Module( poolPackets() } - listen { - val target = target ?: return@listen + onDynamicRender { + val target = target ?: return@onDynamicRender val c1 = GuiSettings.primaryColor val c2 = Color.RED val p = target.hurtTime / 10.0 val c = lerp(p, c1, c2) - it.renderer.ofBox(box, c.multAlpha(0.3), c.multAlpha(0.8)) + it.box(box, c.multAlpha(0.3), c.multAlpha(0.8)) } listen { event -> diff --git a/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt b/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt index 6b54ed4f4..4b04a8576 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt @@ -20,9 +20,9 @@ package com.lambda.module.modules.movement import com.lambda.context.SafeContext import com.lambda.event.events.PacketEvent import com.lambda.event.events.RenderEvent +import com.lambda.event.events.onDynamicRender import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.graphics.renderer.esp.DynamicAABB -import com.lambda.graphics.renderer.esp.builders.ofBox import com.lambda.module.Module import com.lambda.module.modules.client.GuiSettings import com.lambda.module.modules.combat.KillAura @@ -67,9 +67,9 @@ object Blink : Module( poolPackets() } - listen { event -> + onDynamicRender { val color = GuiSettings.primaryColor - event.renderer.ofBox(box.update(lastBox), color.setAlpha(0.3), color) + it.box(box.update(lastBox), color.setAlpha(0.3), color) } listen { event -> diff --git a/src/main/kotlin/com/lambda/module/modules/player/PacketMine.kt b/src/main/kotlin/com/lambda/module/modules/player/PacketMine.kt index 387418393..c42d2ec79 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/PacketMine.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/PacketMine.kt @@ -24,11 +24,9 @@ import com.lambda.config.groups.InventorySettings import com.lambda.config.groups.RotationSettings import com.lambda.context.SafeContext import com.lambda.event.events.PlayerEvent -import com.lambda.event.events.RenderEvent import com.lambda.event.events.TickEvent +import com.lambda.event.events.onStaticRender import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.graphics.renderer.esp.builders.buildFilled -import com.lambda.graphics.renderer.esp.builders.buildOutline import com.lambda.interaction.construction.blueprint.StaticBlueprint.Companion.toBlueprint import com.lambda.interaction.construction.context.BreakContext import com.lambda.interaction.construction.context.BuildContext @@ -161,8 +159,8 @@ object PacketMine : Module( } } - listen { event -> - if (!renderQueue) return@listen + onStaticRender { + if (!renderQueue) return@onStaticRender queueSorted.forEachIndexed { index, positions -> positions.forEach { pos -> val color = if (dynamicColor) lerp(index / queuePositions.size.toDouble(), startColor, endColor) @@ -173,8 +171,8 @@ object PacketMine : Module( }.map { lerp(renderSize.toDouble(), Box(it.center, it.center), it).offset(pos) } boxes.forEach { box -> - event.renderer.buildFilled(box, color) - event.renderer.buildOutline(box, color.setAlpha(1.0)) + it.filled(box, color) + it.outline(box, color.setAlpha(1.0)) } } } diff --git a/src/main/kotlin/com/lambda/module/modules/player/Scaffold.kt b/src/main/kotlin/com/lambda/module/modules/player/Scaffold.kt index 0541200b7..fe89631c2 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/Scaffold.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/Scaffold.kt @@ -22,12 +22,12 @@ import com.lambda.config.groups.InteractionSettings import com.lambda.config.groups.RotationSettings import com.lambda.context.SafeContext import com.lambda.event.events.MovementEvent -import com.lambda.event.events.RenderEvent import com.lambda.event.events.TickEvent +import com.lambda.event.events.onStaticRender import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.graphics.renderer.esp.DirectionMask import com.lambda.graphics.renderer.esp.DirectionMask.buildSideMesh -import com.lambda.graphics.renderer.esp.builders.ofBox +import com.lambda.graphics.renderer.esp.ShapeBuilder import com.lambda.interaction.blockplace.PlaceFinder.Companion.buildPlaceInfo import com.lambda.interaction.blockplace.PlaceInfo import com.lambda.interaction.blockplace.PlaceInteraction.placeBlock @@ -152,9 +152,7 @@ object Scaffold : Module( updateSneaking() } - listen { event -> - buildRenderer(event) - } + onStaticRender { with(it) { buildRenderer() } } onEnable { placeInfo = null @@ -324,7 +322,7 @@ object Scaffold : Module( if (sneak) sneakTicks = 3 } - private fun buildRenderer(event: RenderEvent.StaticESP) { + private fun ShapeBuilder.buildRenderer() { val c = GuiSettings.primaryColor renderInfo.removeIf { info -> @@ -340,13 +338,7 @@ object Scaffold : Module( val box = Box(info.placedPos) val alpha = transform(seconds, 0.0, 0.5, 1.0, 0.0).coerceIn(0.0, 1.0) - event.renderer.ofBox( - box, - c.multAlpha(0.3 * alpha), - c.multAlpha(alpha), - sides, - DirectionMask.OutlineMode.AND - ) + box(box, c.multAlpha(0.3 * alpha), c.multAlpha(alpha), sides, DirectionMask.OutlineMode.AND) seconds > 1 } diff --git a/src/main/kotlin/com/lambda/module/modules/player/WorldEater.kt b/src/main/kotlin/com/lambda/module/modules/player/WorldEater.kt index a8d6208d2..42a8807e2 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/WorldEater.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/WorldEater.kt @@ -17,9 +17,7 @@ package com.lambda.module.modules.player -import com.lambda.event.events.RenderEvent -import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.graphics.renderer.esp.builders.buildOutline +import com.lambda.event.events.onStaticRender import com.lambda.interaction.construction.blueprint.Blueprint.Companion.toStructure import com.lambda.interaction.construction.blueprint.StaticBlueprint.Companion.toBlueprint import com.lambda.interaction.construction.verify.TargetState @@ -67,9 +65,7 @@ object WorldEater : Module( BaritoneUtils.cancel() } - listen { - it.renderer.buildOutline(Box.enclosing(pos1, pos2), Color.BLUE) - } + onStaticRender { it.outline(Box.enclosing(pos1, pos2), Color.BLUE) } } private fun buildLayer() { diff --git a/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt b/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt index fd68a2504..271363eaa 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt @@ -18,19 +18,17 @@ package com.lambda.module.modules.render import com.lambda.Lambda.mc +import com.lambda.graphics.pipeline.VertexBuilder import com.lambda.graphics.renderer.esp.ChunkedESP.Companion.newChunkedESP import com.lambda.graphics.renderer.esp.DirectionMask import com.lambda.graphics.renderer.esp.DirectionMask.buildSideMesh -import com.lambda.graphics.renderer.esp.builders.buildFilledShape -import com.lambda.graphics.renderer.esp.builders.buildOutlineShape -import com.lambda.graphics.renderer.esp.impl.StaticESPRenderer +import com.lambda.graphics.renderer.esp.ShapeBuilder import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe import com.lambda.util.extension.blockColor import com.lambda.util.extension.getBlockState import com.lambda.util.extension.outlineShape -import com.lambda.util.world.fastVectorOf import com.lambda.util.world.toBlockPos import net.minecraft.block.BlockState import net.minecraft.block.Blocks @@ -71,8 +69,7 @@ object BlockESP : Module( } } - private val esp = newChunkedESP { world, x, y, z -> - val position = fastVectorOf(x, y, z) + private val esp = newChunkedESP { world, position -> val state = world.getBlockState(position) if (state.block !in blocks) return@newChunkedESP @@ -85,7 +82,7 @@ object BlockESP : Module( build(state, position.toBlockPos(), sides) } - private fun StaticESPRenderer.build( + private fun ShapeBuilder.build( state: BlockState, pos: BlockPos, sides: Int, @@ -93,8 +90,8 @@ object BlockESP : Module( val shape = outlineShape(state, pos) val blockColor = blockColor(state, pos) - if (drawFaces) buildFilledShape(shape, if (useBlockColor) blockColor else faceColor, sides) - if (drawOutlines) buildOutlineShape(shape, if (useBlockColor) blockColor else outlineColor, sides, outlineMode) + if (drawFaces) filled(shape, if (useBlockColor) blockColor else faceColor, sides) + if (drawOutlines) outline(shape, if (useBlockColor) blockColor else outlineColor, sides, outlineMode) } private fun rebuildMesh(from: Any, to: Any): Unit = esp.rebuild() diff --git a/src/main/kotlin/com/lambda/module/modules/render/StorageESP.kt b/src/main/kotlin/com/lambda/module/modules/render/StorageESP.kt index 853d0d8b5..60e164121 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/StorageESP.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/StorageESP.kt @@ -18,15 +18,10 @@ package com.lambda.module.modules.render import com.lambda.context.SafeContext -import com.lambda.event.events.RenderEvent -import com.lambda.event.listener.SafeListener.Companion.listen +import com.lambda.event.events.onStaticRender import com.lambda.graphics.renderer.esp.DirectionMask import com.lambda.graphics.renderer.esp.DirectionMask.buildSideMesh -import com.lambda.graphics.renderer.esp.builders.buildFilled -import com.lambda.graphics.renderer.esp.builders.buildFilledShape -import com.lambda.graphics.renderer.esp.builders.buildOutline -import com.lambda.graphics.renderer.esp.builders.buildOutlineShape -import com.lambda.graphics.renderer.esp.impl.StaticESPRenderer +import com.lambda.graphics.renderer.esp.ShapeBuilder import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe @@ -52,7 +47,6 @@ import net.minecraft.entity.Entity import net.minecraft.entity.decoration.ItemFrameEntity import net.minecraft.entity.vehicle.AbstractMinecartEntity import net.minecraft.entity.vehicle.MinecartEntity -import net.minecraft.util.math.BlockPos import java.awt.Color object StorageESP : Module( @@ -64,14 +58,15 @@ object StorageESP : Module( private val distance by setting("Distance", 64.0, 10.0..256.0, 1.0, "Maximum distance for rendering").group(Group.General) /* Render settings */ - private var drawFaces: Boolean by setting("Draw Faces", true, "Draw faces of blocks").onValueSet { _, to -> if (!to) drawOutlines = true }.group(Group.Render) - private var drawOutlines: Boolean by setting("Draw Outlines", true, "Draw outlines of blocks").onValueSet { _, to -> if (!to) drawFaces = true }.group(Group.Render) - private val outlineMode by setting("Outline Mode", DirectionMask.OutlineMode.AND, "Outline mode").group(Group.Render) + private var drawFaces: Boolean by setting("Draw Faces", true, "Draw faces of blocks").onValueSet { _, to -> if (!to) drawEdges = true }.group(Group.Render) + private var drawEdges: Boolean by setting("Draw Edges", true, "Draw edges of blocks").onValueSet { _, to -> if (!to) drawFaces = true }.group(Group.Render) + private val mode by setting("Outline Mode", DirectionMask.OutlineMode.AND, "Outline mode").group(Group.Render) private val mesh by setting("Mesh", true, "Connect similar adjacent blocks").group(Group.Render) /* Color settings */ private val useBlockColor by setting("Use Block Color", true, "Use the color of the block instead").group(Group.Color) - private val alpha by setting("Alpha", 0.3, 0.1..1.0, 0.05).group(Group.Color) + private val facesAlpha by setting("Faces Alpha", 0.3, 0.1..1.0, 0.05).group(Group.Color) + private val edgesAlpha by setting("Edges Alpha", 0.3, 0.1..1.0, 0.05).group(Group.Color) // TODO: // val blockColors by setting("Block Colors", mapOf()) { page == Page.Color && !useBlockColor } @@ -118,15 +113,15 @@ object StorageESP : Module( ) init { - listen { event -> + onStaticRender { builder -> blockEntitySearch(distance) .filter { it::class in entities } - .forEach { event.renderer.build(it, it.pos, excludedSides(it)) } + .forEach { with(builder) { build(it, excludedSides(it)) } } val mineCarts = entitySearch(distance) val itemFrames = entitySearch(distance) (mineCarts + itemFrames) - .forEach { event.renderer.build(it, DirectionMask.ALL) } + .forEach { with(builder) { build(it, DirectionMask.ALL) } } // FixMe: Exclude entity shape sides } } @@ -144,32 +139,32 @@ object StorageESP : Module( } else DirectionMask.ALL } - private fun StaticESPRenderer.build( + private fun ShapeBuilder.build( block: BlockEntity, - pos: BlockPos, sides: Int, ) = runSafe { - val color = if (useBlockColor) { - blockColor(block.cachedState, pos) - } else getBlockEntityColor(block) ?: return@runSafe - val shape = outlineShape(block.cachedState, pos) + val color = + if (useBlockColor) blockColor(block.cachedState, block.pos) + else block.color ?: return@runSafe - if (drawFaces) buildFilledShape(shape, color.setAlpha(alpha), sides) - if (drawOutlines) buildOutlineShape(shape, color, sides, outlineMode) + val shape = outlineShape(block.cachedState, block.pos) + + if (drawFaces) filled(shape, color.setAlpha(facesAlpha), sides) + if (drawEdges) outline(shape, color.setAlpha(edgesAlpha), sides, mode) } - private fun StaticESPRenderer.build( + private fun ShapeBuilder.build( entity: Entity, sides: Int, ) = runSafe { - val color = getEntityColor(entity) ?: return@runSafe + val color = entity.color ?: return@runSafe - if (drawFaces) buildFilled(entity.boundingBox, color.setAlpha(alpha), sides) - if (drawOutlines) buildOutline(entity.boundingBox, color, sides, outlineMode) + if (drawFaces) filled(entity.boundingBox, color.setAlpha(facesAlpha), sides) + if (drawEdges) outline(entity.boundingBox, color.setAlpha(edgesAlpha), sides, mode) } - private fun getBlockEntityColor(block: BlockEntity?) = - when (block) { + private val BlockEntity?.color get() = + when (this) { is BarrelBlockEntity -> barrelColor is BlastFurnaceBlockEntity -> blastFurnaceColor is BrewingStandBlockEntity -> brewingStandColor @@ -184,8 +179,8 @@ object StorageESP : Module( else -> null } - private fun getEntityColor(entity: Entity?) = - when (entity) { + private val Entity?.color get() = + when (this) { is AbstractMinecartEntity -> cartColor is ItemFrameEntity -> itemFrameColor else -> null From 848f1076b01173df9d7fe54bd3c92254b43fec50 Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Sat, 23 Aug 2025 12:23:13 -0400 Subject: [PATCH 02/10] Fixed 3d, 3d classes --- .../com/lambda/event/events/RenderEvent.kt | 8 +-- .../kotlin/com/lambda/graphics/RenderMain.kt | 16 +++-- .../graphics/renderer/esp/ChunkedESP.kt | 67 +++++++++---------- .../lambda/graphics/renderer/esp/ShapeDsl.kt | 4 +- .../com/lambda/graphics/renderer/esp/Treed.kt | 59 +++++++--------- .../module/modules/combat/CrystalAura.kt | 2 +- .../lambda/module/modules/movement/Blink.kt | 2 +- .../module/modules/network/PacketDelay.kt | 2 +- 8 files changed, 75 insertions(+), 85 deletions(-) diff --git a/src/main/kotlin/com/lambda/event/events/RenderEvent.kt b/src/main/kotlin/com/lambda/event/events/RenderEvent.kt index f1c790242..812979bfa 100644 --- a/src/main/kotlin/com/lambda/event/events/RenderEvent.kt +++ b/src/main/kotlin/com/lambda/event/events/RenderEvent.kt @@ -26,13 +26,13 @@ import com.lambda.graphics.renderer.esp.ShapeBuilder import com.lambda.graphics.renderer.esp.Treed fun Any.onStaticRender(block: SafeContext.(ShapeBuilder) -> Unit) = - listen { block(ShapeBuilder(Treed.staticFaceBuilder, Treed.staticEdgeBuilder)) } - + listen { block(ShapeBuilder(Treed.Static.faceBuilder, Treed.Static.edgeBuilder)) } fun Any.onDynamicRender(block: SafeContext.(ShapeBuilder) -> Unit) = - listen { block(ShapeBuilder(Treed.dynamicFaceBuilder, Treed.dynamicEdgeBuilder)) } + listen { block(ShapeBuilder(Treed.Dynamic.faceBuilder, Treed.Dynamic.edgeBuilder)) } sealed class RenderEvent { - class World : Event + object Upload : Event + object Render : Event class UpdateTarget : ICancellable by Cancellable() } diff --git a/src/main/kotlin/com/lambda/graphics/RenderMain.kt b/src/main/kotlin/com/lambda/graphics/RenderMain.kt index 43c3cffb5..3668298f2 100644 --- a/src/main/kotlin/com/lambda/graphics/RenderMain.kt +++ b/src/main/kotlin/com/lambda/graphics/RenderMain.kt @@ -55,16 +55,22 @@ object RenderMain { GlStateManager._glBindFramebuffer(GL_FRAMEBUFFER, prevFramebuffer) - Treed.clear() - RenderEvent.World().post() - Treed.upload() - Treed.render() + Treed.Static.render() + Treed.Dynamic.render() + + RenderEvent.Render.post() } } init { listen { - //Treed.clear() + Treed.Static.clear() + Treed.Dynamic.clear() + + RenderEvent.Upload.post() + + Treed.Static.upload() + Treed.Dynamic.upload() } } } diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt index 18f2df868..ca5c06dc8 100644 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt +++ b/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt @@ -17,11 +17,11 @@ package com.lambda.graphics.renderer.esp +import com.lambda.event.events.RenderEvent import com.lambda.event.events.TickEvent import com.lambda.event.events.WorldEvent import com.lambda.event.events.onStaticRender import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.event.listener.SafeListener.Companion.listenConcurrently import com.lambda.module.modules.client.StyleEditor import com.lambda.util.world.FastVector import com.lambda.util.world.fastVectorOf @@ -37,9 +37,7 @@ class ChunkedESP private constructor( ) { private val rendererMap = ConcurrentHashMap() private val WorldChunk.renderer - get() = rendererMap.getOrPut(pos.toLong()) { - EspChunk(this, this@ChunkedESP) - } + get() = rendererMap.getOrPut(pos.toLong()) { EspChunk(this, this@ChunkedESP) } private val uploadQueue = ConcurrentLinkedDeque<() -> Unit>() private val rebuildQueue = ConcurrentLinkedDeque() @@ -52,38 +50,29 @@ class ChunkedESP private constructor( } init { - listenConcurrently { event -> - world.getWorldChunk(event.pos).renderer.notifyChunks() - } - - listenConcurrently { event -> - event.chunk.renderer.notifyChunks() - } + listen { world.getWorldChunk(it.pos).renderer.notifyChunks() } + listen { it.chunk.renderer.notifyChunks() } + listen { rendererMap.remove(it.chunk.pos.toLong())?.notifyChunks() } - listenConcurrently { event -> - rendererMap.remove(event.chunk.pos.toLong())?.notifyChunks() - } - - owner.onStaticRender { builder -> + owner.onStaticRender { if (++ticks % StyleEditor.updateFrequency == 0) { val polls = minOf(StyleEditor.rebuildsPerTick, rebuildQueue.size) - repeat(polls) { - rebuildQueue.poll()?.rebuild(builder) - } + repeat(polls) { rebuildQueue.poll()?.rebuild() } + ticks = 0 } } - owner.listen { + owner.listen { if (uploadQueue.isEmpty()) return@listen val polls = minOf(StyleEditor.uploadsPerTick, uploadQueue.size) - repeat(polls) { - uploadQueue.poll()?.invoke() - } + repeat(polls) { uploadQueue.poll()?.invoke() } } + + owner.listen { rendererMap.values.forEach { it.renderer.render() } } } companion object { @@ -93,29 +82,35 @@ class ChunkedESP private constructor( } private class EspChunk(val chunk: WorldChunk, val owner: ChunkedESP) { - val neighbors = listOf(1 to 0, 0 to 1, -1 to 0, 0 to -1).map { ChunkPos(chunk.pos.x + it.first, chunk.pos.z + it.second) } + var renderer = Treed(static = true) + private val builder: ShapeBuilder + get() = ShapeBuilder(renderer.faceBuilder, renderer.edgeBuilder) + + val neighbors = listOf(1 to 0, 0 to 1, -1 to 0, 0 to -1) + .map { ChunkPos(chunk.pos.x + it.first, chunk.pos.z + it.second) } fun notifyChunks() { neighbors.forEach { owner.rendererMap[it.toLong()]?.let { - owner.rebuildQueue.apply { - if (!contains(it)) add(it) - } + if (!owner.rebuildQueue.contains(it)) + owner.rebuildQueue.add(it) } } } - fun rebuild(builder: ShapeBuilder) = - iterateChunk { owner.update(builder, chunk.world, it) } + fun rebuild() { + renderer = Treed(static = true) + + chunkIterator { owner.update(builder, chunk.world, it) } - inline fun iterateChunk(crossinline block: (FastVector) -> Unit) = chunk.apply { - for (x in pos.startX..pos.endX) { - for (z in pos.startZ..pos.endZ) { - for (y in bottomY..height) { + owner.uploadQueue.add { renderer.upload() } + } + + inline fun chunkIterator(crossinline block: (FastVector) -> Unit) { + for (x in chunk.pos.startX..chunk.pos.endX) + for (z in chunk.pos.startZ..chunk.pos.endZ) + for (y in chunk.bottomY..chunk.height) block(fastVectorOf(x, y, z)) - } - } - } } } } diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/ShapeDsl.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/ShapeDsl.kt index 35ba1dd02..6fecca9ce 100644 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/ShapeDsl.kt +++ b/src/main/kotlin/com/lambda/graphics/renderer/esp/ShapeDsl.kt @@ -36,8 +36,8 @@ import java.awt.Color annotation class ShapeDsl class ShapeBuilder( - val faces: VertexBuilder, - val edges: VertexBuilder, + val faces: VertexBuilder = VertexBuilder(), + val edges: VertexBuilder = VertexBuilder(), ) { @ShapeDsl fun filled( diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/Treed.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/Treed.kt index a560c9e96..90e96ca44 100644 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/Treed.kt +++ b/src/main/kotlin/com/lambda/graphics/renderer/esp/Treed.kt @@ -27,53 +27,42 @@ import com.lambda.graphics.shader.Shader.Companion.shader import com.lambda.module.modules.client.StyleEditor import com.lambda.util.extension.partialTicks -object Treed { - val staticShader = shader("renderer/box_static") - val dynamicShader = shader("renderer/box_dynamic") +open class Treed(static: Boolean) { + val shader = if (static) staticMode.first else dynamicMode.first - val staticFaces = VertexPipeline(VertexMode.TRIANGLES, VertexAttrib.Group.STATIC_RENDERER) - val staticEdges = VertexPipeline(VertexMode.LINES, VertexAttrib.Group.STATIC_RENDERER) - val dynamicFaces = VertexPipeline(VertexMode.TRIANGLES, VertexAttrib.Group.DYNAMIC_RENDERER) - val dynamicEdges = VertexPipeline(VertexMode.LINES, VertexAttrib.Group.DYNAMIC_RENDERER) + val faces = VertexPipeline(VertexMode.TRIANGLES, if (static) staticMode.second else dynamicMode.second) + val edges = VertexPipeline(VertexMode.LINES, if (static) staticMode.second else dynamicMode.second) - // Vertex builders for shape building - var staticFaceBuilder = VertexBuilder(); private set - var dynamicFaceBuilder = VertexBuilder(); private set - var staticEdgeBuilder = VertexBuilder(); private set - var dynamicEdgeBuilder = VertexBuilder(); private set + var faceBuilder = VertexBuilder(); private set + var edgeBuilder = VertexBuilder(); private set fun upload() { - staticFaces.upload(staticFaceBuilder) - staticEdges.upload(staticEdgeBuilder) - dynamicFaces.upload(dynamicFaceBuilder) - dynamicEdges.upload(dynamicEdgeBuilder) + faces.upload(faceBuilder) + edges.upload(edgeBuilder) } fun render() { - staticShader.use() - staticShader["u_TickDelta"] = Lambda.mc.partialTicks - staticShader["u_CameraPosition"] = Lambda.mc.gameRenderer.camera.pos + shader.use() + shader["u_TickDelta"] = Lambda.mc.partialTicks + shader["u_CameraPosition"] = Lambda.mc.gameRenderer.camera.pos - GlStateUtils.withFaceCulling(staticFaces::render) - GlStateUtils.withLineWidth(StyleEditor.outlineWidth, staticEdges::render) + GlStateUtils.withFaceCulling(faces::render) + GlStateUtils.withLineWidth(StyleEditor.outlineWidth, edges::render) + } - dynamicShader.use() - dynamicShader["u_TickDelta"] = Lambda.mc.partialTicks - dynamicShader["u_CameraPosition"] = Lambda.mc.gameRenderer.camera.pos + fun clear() { + faces.clear() + edges.clear() - GlStateUtils.withFaceCulling(dynamicFaces::render) - GlStateUtils.withLineWidth(StyleEditor.outlineWidth, dynamicEdges::render) + faceBuilder = VertexBuilder() + edgeBuilder = VertexBuilder() } - fun clear() { - staticFaces.clear() - staticEdges.clear() - dynamicFaces.clear() - dynamicEdges.clear() + object Static : Treed(true) + object Dynamic : Treed(false) - staticFaceBuilder = VertexBuilder() - staticEdgeBuilder = VertexBuilder() - dynamicFaceBuilder = VertexBuilder() - dynamicEdgeBuilder = VertexBuilder() + companion object { + private val staticMode = shader("renderer/box_static") to VertexAttrib.Group.STATIC_RENDERER + private val dynamicMode = shader("renderer/box_dynamic") to VertexAttrib.Group.DYNAMIC_RENDERER } } diff --git a/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt b/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt index 9ec6177f2..3d6d2994e 100644 --- a/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt +++ b/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt @@ -180,7 +180,7 @@ object CrystalAura : Module( updatesThisFrame = 0 } - listen { + listen { if (!debug) return@listen Matrices.push { diff --git a/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt b/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt index 4b04a8576..bc9266d99 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt @@ -58,7 +58,7 @@ object Blink : Module( private var lastBox = Box(BlockPos.ORIGIN) init { - listen { + listen { val time = System.currentTimeMillis() if (isActive && time - lastUpdate < delay) return@listen diff --git a/src/main/kotlin/com/lambda/module/modules/network/PacketDelay.kt b/src/main/kotlin/com/lambda/module/modules/network/PacketDelay.kt index 3cf88493f..4d0d3457c 100644 --- a/src/main/kotlin/com/lambda/module/modules/network/PacketDelay.kt +++ b/src/main/kotlin/com/lambda/module/modules/network/PacketDelay.kt @@ -51,7 +51,7 @@ object PacketDelay : Module( private var inboundLastUpdate = 0L init { - listen { + listen { if (mode != Mode.STATIC) return@listen flushPools(System.currentTimeMillis()) From a25d3d6c8931dfa681f5937ec2786cd267209f70 Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Sat, 23 Aug 2025 12:23:24 -0400 Subject: [PATCH 03/10] Added back particles --- .../lambda/module/modules/render/Particles.kt | 51 ++++++++++++++++--- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/render/Particles.kt b/src/main/kotlin/com/lambda/module/modules/render/Particles.kt index 7a7bc021b..d10e76a69 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/Particles.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/Particles.kt @@ -17,11 +17,50 @@ package com.lambda.module.modules.render +import com.lambda.Lambda.mc +import com.lambda.context.SafeContext +import com.lambda.event.events.MovementEvent +import com.lambda.event.events.PlayerEvent +import com.lambda.event.events.RenderEvent +import com.lambda.event.events.TickEvent +import com.lambda.event.listener.SafeListener.Companion.listen +import com.lambda.graphics.buffer.vertex.attributes.VertexAttrib +import com.lambda.graphics.buffer.vertex.attributes.VertexMode +import com.lambda.graphics.gl.GlStateUtils.withBlendFunc +import com.lambda.graphics.gl.GlStateUtils.withDepth +import com.lambda.graphics.gl.Matrices +import com.lambda.graphics.gl.Matrices.buildWorldProjection +import com.lambda.graphics.gl.Matrices.withVertexTransform +import com.lambda.graphics.pipeline.VertexBuilder +import com.lambda.graphics.pipeline.VertexPipeline +import com.lambda.graphics.shader.Shader.Companion.shader +import com.lambda.interaction.request.rotating.Rotation +import com.lambda.module.Module +import com.lambda.module.modules.client.GuiSettings +import com.lambda.module.modules.client.GuiSettings.colorSpeed +import com.lambda.module.tag.ModuleTag +import com.lambda.util.extension.partialTicks +import com.lambda.util.math.DOWN +import com.lambda.util.math.MathUtils.random +import com.lambda.util.math.UP +import com.lambda.util.math.lerp +import com.lambda.util.math.multAlpha +import com.lambda.util.math.plus +import com.lambda.util.math.times +import com.lambda.util.math.transform +import com.lambda.util.player.MovementUtils.moveDelta +import com.lambda.util.world.raycast.InteractionMask +import com.mojang.blaze3d.opengl.GlConst.GL_ONE +import com.mojang.blaze3d.opengl.GlConst.GL_SRC_ALPHA +import net.minecraft.entity.Entity +import net.minecraft.util.math.Vec3d +import kotlin.math.sin + // FixMe: Do not call render stuff in the initialization block -/*object Particles : Module( +object Particles : Module( name = "Particles", description = "Spawns fancy particles", - defaultTags = setOf(ModuleTag.RENDER) + tag = ModuleTag.RENDER, ) { // ToDo: resort, cleanup settings private val duration by setting("Duration", 5.0, 1.0..500.0, 1.0) @@ -52,12 +91,10 @@ package com.lambda.module.modules.render particles.removeIf(Particle::update) } - listen { + listen { // Todo: interpolated tickbased upload? val builder = pipeline.build() - particles.forEach { - it.build(builder) - } + particles.forEach { it.build(builder) } withBlendFunc(GL_SRC_ALPHA, GL_ONE) { shader.use() @@ -182,4 +219,4 @@ package com.lambda.module.modules.render } } } -}*/ +} From b59521af3b449979312e61dd42001913baa92cd1 Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Sat, 23 Aug 2025 16:04:51 -0400 Subject: [PATCH 04/10] BlockESP performance --- src/main/kotlin/com/lambda/Lambda.kt | 7 ++--- .../graphics/renderer/esp/ChunkedESP.kt | 22 +++++++------- .../lambda/module/modules/render/BlockESP.kt | 30 +++++++++---------- .../module/modules/render/StorageESP.kt | 4 +-- .../kotlin/com/lambda/threading/Threading.kt | 3 +- 5 files changed, 31 insertions(+), 35 deletions(-) diff --git a/src/main/kotlin/com/lambda/Lambda.kt b/src/main/kotlin/com/lambda/Lambda.kt index 4c7f6e326..56f624535 100644 --- a/src/main/kotlin/com/lambda/Lambda.kt +++ b/src/main/kotlin/com/lambda/Lambda.kt @@ -72,9 +72,6 @@ object Lambda : ClientModInitializer { .registerTypeAdapter(Text::class.java, Text.Serializer(DynamicRegistryManager.EMPTY)) .create() - override fun onInitializeClient() { - recordRenderCall { - LOG.info("$MOD_NAME $VERSION initialized in ${Loader.initialize()} ms\n") - } - } + override fun onInitializeClient() = + recordRenderCall { LOG.info("$MOD_NAME $VERSION initialized in ${Loader.initialize()} ms\n") } } diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt index ca5c06dc8..1b0859c52 100644 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt +++ b/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt @@ -22,7 +22,9 @@ import com.lambda.event.events.TickEvent import com.lambda.event.events.WorldEvent import com.lambda.event.events.onStaticRender import com.lambda.event.listener.SafeListener.Companion.listen +import com.lambda.event.listener.SafeListener.Companion.listenConcurrently import com.lambda.module.modules.client.StyleEditor +import com.lambda.threading.awaitMainThread import com.lambda.util.world.FastVector import com.lambda.util.world.fastVectorOf import net.minecraft.util.math.ChunkPos @@ -54,7 +56,7 @@ class ChunkedESP private constructor( listen { it.chunk.renderer.notifyChunks() } listen { rendererMap.remove(it.chunk.pos.toLong())?.notifyChunks() } - owner.onStaticRender { + listenConcurrently { if (++ticks % StyleEditor.updateFrequency == 0) { val polls = minOf(StyleEditor.rebuildsPerTick, rebuildQueue.size) @@ -64,8 +66,8 @@ class ChunkedESP private constructor( } } - owner.listen { - if (uploadQueue.isEmpty()) return@listen + owner.onStaticRender { + if (uploadQueue.isEmpty()) return@onStaticRender val polls = minOf(StyleEditor.uploadsPerTick, uploadQueue.size) @@ -98,19 +100,15 @@ class ChunkedESP private constructor( } } - fun rebuild() { - renderer = Treed(static = true) - - chunkIterator { owner.update(builder, chunk.world, it) } - - owner.uploadQueue.add { renderer.upload() } - } + suspend fun rebuild() { + renderer = awaitMainThread { Treed(static = true) } - inline fun chunkIterator(crossinline block: (FastVector) -> Unit) { for (x in chunk.pos.startX..chunk.pos.endX) for (z in chunk.pos.startZ..chunk.pos.endZ) for (y in chunk.bottomY..chunk.height) - block(fastVectorOf(x, y, z)) + owner.update(builder, chunk.world, fastVectorOf(x, y, z)) + + owner.uploadQueue.add { renderer.upload() } } } } diff --git a/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt b/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt index 271363eaa..e17200b4c 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt @@ -18,6 +18,9 @@ package com.lambda.module.modules.render import com.lambda.Lambda.mc +import com.lambda.context.SafeContext +import com.lambda.event.events.TickEvent +import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.graphics.pipeline.VertexBuilder import com.lambda.graphics.renderer.esp.ChunkedESP.Companion.newChunkedESP import com.lambda.graphics.renderer.esp.DirectionMask @@ -26,9 +29,12 @@ import com.lambda.graphics.renderer.esp.ShapeBuilder import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe +import com.lambda.util.Communication.info import com.lambda.util.extension.blockColor import com.lambda.util.extension.getBlockState import com.lambda.util.extension.outlineShape +import com.lambda.util.world.blockSearch +import com.lambda.util.world.distSq import com.lambda.util.world.toBlockPos import net.minecraft.block.BlockState import net.minecraft.block.Blocks @@ -41,17 +47,17 @@ object BlockESP : Module( description = "Render block ESP", tag = ModuleTag.RENDER, ) { - private var drawFaces: Boolean by setting("Draw Faces", true, "Draw faces of blocks").onValueSet(::rebuildMesh).onValueSet { _, to -> if (!to) drawOutlines = true } - private var drawOutlines: Boolean by setting("Draw Outlines", true, "Draw outlines of blocks").onValueSet(::rebuildMesh).onValueSet { _, to -> if (!to) drawFaces = true } - private val mesh by setting("Mesh", true, "Connect similar adjacent blocks").onValueSet(::rebuildMesh) + private var drawFaces: Boolean by setting("Draw Faces", true, "Draw faces of blocks").onValueChange(::rebuildMesh).onValueChange { _, to -> if (!to) drawOutlines = true } + private var drawOutlines: Boolean by setting("Draw Outlines", true, "Draw outlines of blocks").onValueChange(::rebuildMesh).onValueChange { _, to -> if (!to) drawFaces = true } + private val mesh by setting("Mesh", true, "Connect similar adjacent blocks").onValueChange(::rebuildMesh) - private val useBlockColor by setting("Use Block Color", false, "Use the color of the block instead").onValueSet(::rebuildMesh) - private val faceColor by setting("Face Color", Color(100, 150, 255, 51), "Color of the surfaces") { drawFaces && !useBlockColor }.onValueSet(::rebuildMesh) - private val outlineColor by setting("Outline Color", Color(100, 150, 255, 128), "Color of the outlines") { drawOutlines && !useBlockColor }.onValueSet(::rebuildMesh) + private val useBlockColor by setting("Use Block Color", false, "Use the color of the block instead").onValueChange(::rebuildMesh) + private val faceColor by setting("Face Color", Color(100, 150, 255, 51), "Color of the surfaces") { drawFaces && !useBlockColor }.onValueChange(::rebuildMesh) + private val outlineColor by setting("Outline Color", Color(100, 150, 255, 128), "Color of the outlines") { drawOutlines && !useBlockColor }.onValueChange(::rebuildMesh) - private val outlineMode by setting("Outline Mode", DirectionMask.OutlineMode.AND, "Outline mode").onValueSet(::rebuildMesh) + private val outlineMode by setting("Outline Mode", DirectionMask.OutlineMode.AND, "Outline mode").onValueChange(::rebuildMesh) - private val blocks by setting("Blocks", setOf(Blocks.BEDROCK), setOf(Blocks.BEDROCK), "Render blocks").onValueSet(::rebuildMesh) + private val blocks by setting("Blocks", setOf(Blocks.BEDROCK), setOf(Blocks.BEDROCK), "Render blocks").onValueChange(::rebuildMesh) @JvmStatic val barrier by setting("Solid Barrier Block", true, "Render barrier blocks") @@ -63,12 +69,6 @@ object BlockESP : Module( @JvmStatic val model: BlockStateModel get() = mc.bakedModelManager.missingModel - init { - onToggle { - if (barrier) mc.worldRenderer.reload() - } - } - private val esp = newChunkedESP { world, position -> val state = world.getBlockState(position) if (state.block !in blocks) return@newChunkedESP @@ -94,5 +94,5 @@ object BlockESP : Module( if (drawOutlines) outline(shape, if (useBlockColor) blockColor else outlineColor, sides, outlineMode) } - private fun rebuildMesh(from: Any, to: Any): Unit = esp.rebuild() + private fun rebuildMesh(ctx: SafeContext, from: Any, to: Any): Unit = esp.rebuild() } diff --git a/src/main/kotlin/com/lambda/module/modules/render/StorageESP.kt b/src/main/kotlin/com/lambda/module/modules/render/StorageESP.kt index 60e164121..5a8ff3533 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/StorageESP.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/StorageESP.kt @@ -58,8 +58,8 @@ object StorageESP : Module( private val distance by setting("Distance", 64.0, 10.0..256.0, 1.0, "Maximum distance for rendering").group(Group.General) /* Render settings */ - private var drawFaces: Boolean by setting("Draw Faces", true, "Draw faces of blocks").onValueSet { _, to -> if (!to) drawEdges = true }.group(Group.Render) - private var drawEdges: Boolean by setting("Draw Edges", true, "Draw edges of blocks").onValueSet { _, to -> if (!to) drawFaces = true }.group(Group.Render) + private var drawFaces: Boolean by setting("Draw Faces", true, "Draw faces of blocks").onValueChange { _, to -> drawEdges = !to && !drawFaces }.group(Group.Render) + private var drawEdges: Boolean by setting("Draw Edges", true, "Draw edges of blocks").onValueChange { _, to -> drawFaces = !to && !drawEdges }.group(Group.Render) private val mode by setting("Outline Mode", DirectionMask.OutlineMode.AND, "Outline mode").group(Group.Render) private val mesh by setting("Mesh", true, "Connect similar adjacent blocks").group(Group.Render) diff --git a/src/main/kotlin/com/lambda/threading/Threading.kt b/src/main/kotlin/com/lambda/threading/Threading.kt index 08dfab0a2..b08659907 100644 --- a/src/main/kotlin/com/lambda/threading/Threading.kt +++ b/src/main/kotlin/com/lambda/threading/Threading.kt @@ -97,8 +97,9 @@ inline fun runSafeConcurrent(crossinline block: suspend SafeContext.() -> Unit) * * @param block The task to be executed on the game's main thread. */ -inline fun recordRenderCall(crossinline block: () -> Unit) = +inline fun recordRenderCall(crossinline block: () -> Unit) { mc.renderTaskQueue.add { block() } +} /** * Executes a given task on the game's main thread. From 8d3b8778c1d81960d2fc66b57aaaf1156212f1ee Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Sat, 23 Aug 2025 18:18:59 -0400 Subject: [PATCH 05/10] removed neighbor notify --- .../kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt index 1b0859c52..2e284e8fc 100644 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt +++ b/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt @@ -52,11 +52,11 @@ class ChunkedESP private constructor( } init { - listen { world.getWorldChunk(it.pos).renderer.notifyChunks() } + //listen { rebuildQueue.add(rendererMap[ChunkPos.toLong(it.pos)] ?: return@listen) } listen { it.chunk.renderer.notifyChunks() } listen { rendererMap.remove(it.chunk.pos.toLong())?.notifyChunks() } - listenConcurrently { + listenConcurrently { if (++ticks % StyleEditor.updateFrequency == 0) { val polls = minOf(StyleEditor.rebuildsPerTick, rebuildQueue.size) From 1be7135fb7617dfdc5aed07236cf804f8e62e5af Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Sat, 23 Aug 2025 18:26:54 -0400 Subject: [PATCH 06/10] Fixed concurrent vertices access --- src/main/kotlin/com/lambda/graphics/pipeline/VertexBuilder.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/lambda/graphics/pipeline/VertexBuilder.kt b/src/main/kotlin/com/lambda/graphics/pipeline/VertexBuilder.kt index aa4716035..e3346dca1 100644 --- a/src/main/kotlin/com/lambda/graphics/pipeline/VertexBuilder.kt +++ b/src/main/kotlin/com/lambda/graphics/pipeline/VertexBuilder.kt @@ -29,8 +29,8 @@ import org.joml.Vector4d class VertexBuilder( private val direct: VertexPipeline? = null ) { - val vertices by lazy { mutableListOf() } - val indices by lazy { mutableListOf() } + val vertices by lazy(LazyThreadSafetyMode.PUBLICATION) { mutableListOf() } + val indices by lazy(LazyThreadSafetyMode.PUBLICATION) { mutableListOf() } private var verticesCounter = 0 From 6d09bdaa81aadb6e90eab41f94e95c3fc5e6d92f Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Sat, 23 Aug 2025 19:02:09 -0400 Subject: [PATCH 07/10] Faster memory compare --- .../graphics/buffer/DynamicByteBuffer.kt | 11 +++++-- .../graphics/pipeline/PersistentBuffer.kt | 30 +------------------ 2 files changed, 10 insertions(+), 31 deletions(-) diff --git a/src/main/kotlin/com/lambda/graphics/buffer/DynamicByteBuffer.kt b/src/main/kotlin/com/lambda/graphics/buffer/DynamicByteBuffer.kt index 02ec17360..9ee396552 100644 --- a/src/main/kotlin/com/lambda/graphics/buffer/DynamicByteBuffer.kt +++ b/src/main/kotlin/com/lambda/graphics/buffer/DynamicByteBuffer.kt @@ -150,8 +150,8 @@ class DynamicByteBuffer private constructor(initialCapacity: Int) { val offset = position - pointer memCopy(pointer, newPointer, offset) - data = newBuffer + data = newBuffer pointer = newPointer position = newPointer + offset capacity = newCapacity @@ -176,6 +176,13 @@ class DynamicByteBuffer private constructor(initialCapacity: Int) { capacity = newCapacity } + /** + * Returns the relative index of the first mismatch between this and the given buffer, otherwise -1 if no mismatch. + * + * @see [ByteBuffer.mismatch] + */ + fun mismatch(other: DynamicByteBuffer) = data.mismatch(other.data) + companion object { /** * Creates a new DynamicByteBuffer with specified initial capacity @@ -184,4 +191,4 @@ class DynamicByteBuffer private constructor(initialCapacity: Int) { fun dynamicByteBuffer(initialCapacity: Int) = DynamicByteBuffer(initialCapacity) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/lambda/graphics/pipeline/PersistentBuffer.kt b/src/main/kotlin/com/lambda/graphics/pipeline/PersistentBuffer.kt index 351e6ee0a..44ce5014e 100644 --- a/src/main/kotlin/com/lambda/graphics/pipeline/PersistentBuffer.kt +++ b/src/main/kotlin/com/lambda/graphics/pipeline/PersistentBuffer.kt @@ -18,10 +18,8 @@ package com.lambda.graphics.pipeline import com.lambda.graphics.buffer.Buffer.Companion.createPipelineBuffer -import com.lambda.graphics.buffer.DynamicByteBuffer import com.lambda.graphics.buffer.DynamicByteBuffer.Companion.dynamicByteBuffer import com.lambda.graphics.gl.kibibyte -import org.lwjgl.system.MemoryUtil import org.lwjgl.system.MemoryUtil.memCopy /** @@ -64,7 +62,7 @@ class PersistentBuffer( } if (snapshotData > 0 && snapshot.capacity >= byteBuffer.bytesPut) { - if (memcmp(snapshot, byteBuffer, uploadOffset, dataCount)) return + if (snapshot.mismatch(byteBuffer) >= 0) return } glBuffer.update(uploadOffset, dataCount, dataStart) @@ -90,30 +88,4 @@ class PersistentBuffer( } fun use(block: () -> Unit) = glBuffer.bind { block() } - - private fun memcmp(a: DynamicByteBuffer, b: DynamicByteBuffer, position: Long, size: Long): Boolean { - if (a.capacity != b.capacity) return false - - val end = position + size - var head = position - - // Process the aligned bytes in chunks of 8 until we've reached the end - while (head + 8 <= end) { - val first = MemoryUtil.memGetLong(a.pointer + head) - val second = MemoryUtil.memGetLong(b.pointer + head) - if (first != second) return false - - head += 8 - } - - while (head < end) { - val first = MemoryUtil.memGetByte(a.pointer + head) - val second = MemoryUtil.memGetByte(b.pointer + head) - if (first != second) return false - - head++ - } - - return true - } } From 5c60e438dcb68da5fb000e711c1e43fd2b6be075 Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Sun, 7 Sep 2025 15:32:35 -0400 Subject: [PATCH 08/10] Reworked the Drawable --- .../lambda/graphics/renderer/esp/ShapeDsl.kt | 64 +++++++++++++------ .../construction/context/BreakContext.kt | 9 ++- .../context/InteractionContext.kt | 13 ++-- .../construction/context/PlaceContext.kt | 7 +- .../construction/result/BreakResult.kt | 25 ++++---- .../construction/result/BuildResult.kt | 48 ++++++-------- .../construction/result/Drawable.kt | 45 +------------ .../construction/result/InteractResult.kt | 5 +- .../construction/result/PlaceResult.kt | 7 +- .../construction/simulation/Simulation.kt | 5 +- .../module/modules/client/TaskFlowModule.kt | 5 +- 11 files changed, 104 insertions(+), 129 deletions(-) diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/ShapeDsl.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/ShapeDsl.kt index 6fecca9ce..a47e154ec 100644 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/ShapeDsl.kt +++ b/src/main/kotlin/com/lambda/graphics/renderer/esp/ShapeDsl.kt @@ -17,9 +17,9 @@ package com.lambda.graphics.renderer.esp -import com.lambda.context.SafeContext import com.lambda.graphics.pipeline.VertexBuilder import com.lambda.graphics.renderer.esp.DirectionMask.hasDirection +import com.lambda.threading.runSafe import com.lambda.util.BlockUtils.blockState import com.lambda.util.extension.max import com.lambda.util.extension.min @@ -98,33 +98,33 @@ class ShapeBuilder( } @ShapeDsl - fun SafeContext.filled( + fun filled( pos : BlockPos, state : BlockState, color : Color, sides : Int = DirectionMask.ALL, - ) = faces.apply { + ) = runSafe { faces.apply { val shape = state.getOutlineShape(world, pos) filled(shape, color, sides) - } + } } @ShapeDsl - fun SafeContext.filled( + fun filled( pos : BlockPos, color : Color, sides : Int = DirectionMask.ALL, - ) = faces.apply { + ) = runSafe { faces.apply { val shape = blockState(pos).getOutlineShape(world, pos) filled(shape, color, sides) - } + } } @ShapeDsl - fun SafeContext.filled( + fun filled( pos : BlockPos, entity : BlockEntity, color : Color, sides : Int = DirectionMask.ALL, - ) { + ) = runSafe { val shape = outlineShape(entity.cachedState, pos) filled(shape, color, sides) } @@ -236,36 +236,36 @@ class ShapeBuilder( } @ShapeDsl - fun SafeContext.outline( + fun outline( pos : BlockPos, state : BlockState, color : Color, sides : Int = DirectionMask.ALL, mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, - ) { + ) = runSafe { val shape = state.getOutlineShape(world, pos) outline(shape, color, sides, mode) } @ShapeDsl - fun SafeContext.outline( + fun outline( pos : BlockPos, color : Color, sides : Int = DirectionMask.ALL, mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, - ) { + ) = runSafe { val shape = blockState(pos).getOutlineShape(world, pos) outline(shape, color, sides, mode) } @ShapeDsl - fun SafeContext.outline( + fun outline( pos : BlockPos, entity : BlockEntity, color : Color, sides : Int = DirectionMask.ALL, mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, - ) { + ) = runSafe { val shape = outlineShape(entity.cachedState, pos) outline(shape, color, sides, mode) } @@ -291,6 +291,32 @@ class ShapeBuilder( outline(box, color, color, sides, mode) } + @ShapeDsl + fun box( + pos : BlockPos, + state : BlockState, + filled : Color, + outline : Color, + sides : Int = DirectionMask.ALL, + mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, + ) = runSafe { + val shape = state.getOutlineShape(world, pos) + filled(shape, filled, sides) + outline(shape, outline, sides, mode) + } + + @ShapeDsl + fun box( + pos : BlockPos, + filled : Color, + outline : Color, + sides : Int = DirectionMask.ALL, + mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, + ) = runSafe { + filled(pos, filled, sides) + outline(pos, outline, sides, mode) + } + @ShapeDsl fun box( box : DynamicAABB, @@ -316,23 +342,23 @@ class ShapeBuilder( } @ShapeDsl - fun SafeContext.box( + fun box( entity : BlockEntity, color : Color, sides : Int = DirectionMask.ALL, mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, - ) { + ) = runSafe { filled(entity.pos, entity, color, sides) outline(entity.pos, entity, color, sides, mode) } @ShapeDsl - fun SafeContext.box( + fun box( entity : Entity, color : Color, sides : Int = DirectionMask.ALL, mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.OR, - ) { + ) = runSafe { filled(entity.boundingBox, color, sides) outline(entity.boundingBox, color, sides, mode) } diff --git a/src/main/kotlin/com/lambda/interaction/construction/context/BreakContext.kt b/src/main/kotlin/com/lambda/interaction/construction/context/BreakContext.kt index 04cef97b8..9a449a891 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/context/BreakContext.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/context/BreakContext.kt @@ -17,9 +17,9 @@ package com.lambda.interaction.construction.context -import com.lambda.context.SafeContext import com.lambda.graphics.renderer.esp.DirectionMask import com.lambda.graphics.renderer.esp.DirectionMask.exclude +import com.lambda.graphics.renderer.esp.ShapeBuilder import com.lambda.interaction.material.StackSelection import com.lambda.interaction.request.breaking.BreakConfig import com.lambda.interaction.request.breaking.BreakRequest @@ -72,9 +72,8 @@ data class BreakContext( } } - override fun SafeContext.buildRenderer() { - withState(cachedState, blockPos, baseColor, DirectionMask.ALL.exclude(result.side)) - withState(cachedState, blockPos, sideColor, result.side) + override fun ShapeBuilder.buildRenderer() { + box(blockPos, cachedState, baseColor, sideColor, DirectionMask.ALL.exclude(result.side)) } fun requestSwap(breakRequest: BreakRequest, minKeepTicks: Int = 0): Boolean = @@ -83,4 +82,4 @@ data class BreakContext( breakRequest.hotbar, breakRequest.hotbar.keepTicks.coerceAtLeast(minKeepTicks) ).submit(false).done -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/lambda/interaction/construction/context/InteractionContext.kt b/src/main/kotlin/com/lambda/interaction/construction/context/InteractionContext.kt index 33bcb966a..e61351a32 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/context/InteractionContext.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/context/InteractionContext.kt @@ -17,16 +17,14 @@ package com.lambda.interaction.construction.context -import com.lambda.context.SafeContext -import com.lambda.graphics.renderer.esp.DirectionMask -import com.lambda.graphics.renderer.esp.DirectionMask.exclude +import com.lambda.graphics.renderer.esp.DirectionMask.mask +import com.lambda.graphics.renderer.esp.ShapeBuilder import com.lambda.interaction.request.Request.Companion.submit import com.lambda.interaction.request.hotbar.HotbarManager import com.lambda.interaction.request.hotbar.HotbarRequest import com.lambda.interaction.request.interacting.InteractRequest import com.lambda.interaction.request.rotating.RotationRequest import com.lambda.util.BlockUtils -import com.lambda.util.BlockUtils.blockState import net.minecraft.block.BlockState import net.minecraft.util.hit.BlockHitResult import net.minecraft.util.math.BlockPos @@ -61,9 +59,8 @@ class InteractionContext( else -> 1 } - override fun SafeContext.buildRenderer() { - withState(expectedState, blockPos, baseColor, DirectionMask.ALL.exclude(result.side.opposite)) - withState(blockState(result.blockPos), result.blockPos, sideColor, result.side) + override fun ShapeBuilder.buildRenderer() { + box(blockPos, expectedState, baseColor, sideColor, result.side.mask) } fun requestDependencies(request: InteractRequest): Boolean { @@ -71,4 +68,4 @@ class InteractionContext( val validRotation = if (request.rotate) submit(rotation, false).done else true return hotbarRequest.done && validRotation } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/lambda/interaction/construction/context/PlaceContext.kt b/src/main/kotlin/com/lambda/interaction/construction/context/PlaceContext.kt index f25101867..76689dab2 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/context/PlaceContext.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/context/PlaceContext.kt @@ -21,6 +21,8 @@ import com.lambda.Lambda.mc import com.lambda.context.SafeContext import com.lambda.graphics.renderer.esp.DirectionMask import com.lambda.graphics.renderer.esp.DirectionMask.exclude +import com.lambda.graphics.renderer.esp.DirectionMask.mask +import com.lambda.graphics.renderer.esp.ShapeBuilder import com.lambda.interaction.request.Request.Companion.submit import com.lambda.interaction.request.hotbar.HotbarManager import com.lambda.interaction.request.hotbar.HotbarRequest @@ -70,9 +72,8 @@ data class PlaceContext( else -> 1 } - override fun SafeContext.buildRenderer() { - withState(expectedState, blockPos, baseColor, DirectionMask.ALL.exclude(result.side.opposite)) - withState(blockState(result.blockPos), result.blockPos, sideColor, result.side) + override fun ShapeBuilder.buildRenderer() { + box(blockPos, expectedState, baseColor, sideColor, result.side.mask) } fun requestDependencies(request: PlaceRequest): Boolean { diff --git a/src/main/kotlin/com/lambda/interaction/construction/result/BreakResult.kt b/src/main/kotlin/com/lambda/interaction/construction/result/BreakResult.kt index b6f032a47..58092620a 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/result/BreakResult.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/result/BreakResult.kt @@ -19,7 +19,8 @@ package com.lambda.interaction.construction.result import baritone.api.pathing.goals.GoalBlock import baritone.api.pathing.goals.GoalInverted -import com.lambda.context.SafeContext +import com.lambda.graphics.renderer.esp.DirectionMask.mask +import com.lambda.graphics.renderer.esp.ShapeBuilder import com.lambda.interaction.construction.context.BreakContext import com.lambda.interaction.material.StackSelection.Companion.selectStack import com.lambda.interaction.material.container.ContainerManager.transfer @@ -44,7 +45,7 @@ sealed class BreakResult : BuildResult() { ) : Drawable, Contextual, BreakResult() { override val rank = Rank.BREAK_SUCCESS - override fun SafeContext.buildRenderer() { + override fun ShapeBuilder.buildRenderer() { with(context) { buildRenderer() } } @@ -68,8 +69,8 @@ sealed class BreakResult : BuildResult() { override val rank = Rank.BREAK_NOT_EXPOSED private val color = Color(46, 0, 0, 30) - override fun SafeContext.buildRenderer() { - withPos(blockPos, color, side) + override fun ShapeBuilder.buildRenderer() { + box(blockPos, color, color, side.mask) } override fun compareTo(other: ComparableResult): Int { @@ -108,8 +109,8 @@ sealed class BreakResult : BuildResult() { ) } - override fun SafeContext.buildRenderer() { - withPos(blockPos, color) + override fun ShapeBuilder.buildRenderer() { + box(blockPos, color, color) } override fun compareTo(other: ComparableResult): Int { @@ -132,8 +133,8 @@ sealed class BreakResult : BuildResult() { override val rank = Rank.BREAK_SUBMERGE private val color = Color(114, 27, 255, 100) - override fun SafeContext.buildRenderer() { - withPos(blockPos, color) + override fun ShapeBuilder.buildRenderer() { + box(blockPos, color, color) } } @@ -147,8 +148,8 @@ sealed class BreakResult : BuildResult() { override val rank = Rank.BREAK_IS_BLOCKED_BY_FLUID private val color = Color(50, 12, 112, 100) - override fun SafeContext.buildRenderer() { - withPos(blockPos, color) + override fun ShapeBuilder.buildRenderer() { + box(blockPos, color, color) } } @@ -164,8 +165,8 @@ sealed class BreakResult : BuildResult() { override val goal = GoalInverted(GoalBlock(blockPos)) - override fun SafeContext.buildRenderer() { - withPos(blockPos, color) + override fun ShapeBuilder.buildRenderer() { + box(blockPos, color, color) } } } diff --git a/src/main/kotlin/com/lambda/interaction/construction/result/BuildResult.kt b/src/main/kotlin/com/lambda/interaction/construction/result/BuildResult.kt index 5e8d657f9..1712db18c 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/result/BuildResult.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/result/BuildResult.kt @@ -19,7 +19,7 @@ package com.lambda.interaction.construction.result import baritone.api.pathing.goals.GoalBlock import baritone.api.pathing.goals.GoalNear -import com.lambda.context.SafeContext +import com.lambda.graphics.renderer.esp.ShapeBuilder import com.lambda.interaction.construction.context.BuildContext import com.lambda.interaction.material.StackSelection import com.lambda.interaction.material.StackSelection.Companion.select @@ -27,12 +27,10 @@ import com.lambda.interaction.material.container.ContainerManager.transfer import com.lambda.interaction.material.container.MaterialContainer import com.lambda.interaction.material.container.containers.MainHandContainer import com.lambda.interaction.request.inventory.InventoryConfig -import com.lambda.util.BlockUtils.blockState import com.lambda.util.Nameable import net.minecraft.block.BlockState import net.minecraft.item.ItemStack import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Box import net.minecraft.util.math.Direction import net.minecraft.util.math.Vec3d import java.awt.Color @@ -81,8 +79,8 @@ abstract class BuildResult : ComparableResult, Nameable { override val goal = GoalBlock(blockPos) - override fun SafeContext.buildRenderer() { - withBox(Box(blockPos), color) + override fun ShapeBuilder.buildRenderer() { + box(blockPos, color, color) } override fun compareTo(other: ComparableResult): Int { @@ -104,8 +102,8 @@ abstract class BuildResult : ComparableResult, Nameable { override val rank = Rank.BREAK_RESTRICTED private val color = Color(255, 0, 0, 100) - override fun SafeContext.buildRenderer() { - withPos(blockPos, color) + override fun ShapeBuilder.buildRenderer() { + box(blockPos, color, color) } } @@ -122,8 +120,8 @@ abstract class BuildResult : ComparableResult, Nameable { override val rank get() = Rank.BREAK_NO_PERMISSION private val color = Color(255, 0, 0, 100) - override fun SafeContext.buildRenderer() { - withPos(blockPos, color) + override fun ShapeBuilder.buildRenderer() { + box(blockPos, color, color) } } @@ -138,8 +136,8 @@ abstract class BuildResult : ComparableResult, Nameable { override val rank = Rank.OUT_OF_WORLD private val color = Color(3, 148, 252, 100) - override fun SafeContext.buildRenderer() { - withPos(blockPos, color) + override fun ShapeBuilder.buildRenderer() { + box(blockPos, color, color) } } @@ -156,8 +154,8 @@ abstract class BuildResult : ComparableResult, Nameable { override val rank = Rank.UNBREAKABLE private val color = Color(11, 11, 11, 100) - override fun SafeContext.buildRenderer() { - withPos(blockPos, color) + override fun ShapeBuilder.buildRenderer() { + box(blockPos, color, color) } } @@ -176,8 +174,8 @@ abstract class BuildResult : ComparableResult, Nameable { override val rank = Rank.NOT_VISIBLE private val color = Color(46, 0, 0, 80) - override fun SafeContext.buildRenderer() { - withBox(Box(blockPos), color) + override fun ShapeBuilder.buildRenderer() { + box(blockPos, color, color) } override fun compareTo(other: ComparableResult): Int { @@ -215,12 +213,8 @@ abstract class BuildResult : ComparableResult, Nameable { ) } - override fun SafeContext.buildRenderer() { - if (blockState(blockPos).isAir) { - withBox(Box(blockPos), color) - } else { - withPos(blockPos, color) - } + override fun ShapeBuilder.buildRenderer() { + box(blockPos, color, color) } override fun compareTo(other: ComparableResult): Int { @@ -258,12 +252,8 @@ abstract class BuildResult : ComparableResult, Nameable { ) } - override fun SafeContext.buildRenderer() { - if (blockState(blockPos).isAir) { - withBox(Box(blockPos), color) - } else { - withPos(blockPos, color) - } + override fun ShapeBuilder.buildRenderer() { + box(blockPos, color, color) } override fun compareTo(other: ComparableResult): Int { @@ -295,8 +285,8 @@ abstract class BuildResult : ComparableResult, Nameable { override val goal = GoalNear(blockPos, 3) - override fun SafeContext.buildRenderer() { - withPos(blockPos, color) + override fun ShapeBuilder.buildRenderer() { + box(blockPos, color, color) } override fun compareTo(other: ComparableResult): Int { diff --git a/src/main/kotlin/com/lambda/interaction/construction/result/Drawable.kt b/src/main/kotlin/com/lambda/interaction/construction/result/Drawable.kt index 108e56200..84b71901e 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/result/Drawable.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/result/Drawable.kt @@ -17,49 +17,8 @@ package com.lambda.interaction.construction.result -import com.lambda.context.SafeContext -import com.lambda.graphics.renderer.esp.DirectionMask -import com.lambda.graphics.renderer.esp.DirectionMask.include -import com.lambda.util.BlockUtils.blockState -import net.minecraft.block.BlockState -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Box -import net.minecraft.util.math.Direction -import net.minecraft.util.shape.VoxelShape -import java.awt.Color +import com.lambda.graphics.renderer.esp.ShapeBuilder interface Drawable { - fun SafeContext.buildRenderer() - - fun SafeContext.withBox(box: Box, color: Color, mask: Int = DirectionMask.ALL) { - //StaticESP.filled(box, color, mask) - //StaticESP.buildOutline(box, color, mask) - } - - fun SafeContext.withState(blockState: BlockState, blockPos: BlockPos, color: Color, side: Direction) { - withState(blockState, blockPos, color, DirectionMask.NONE.include(side)) - } - - fun SafeContext.withState(blockState: BlockState, blockPos: BlockPos, color: Color, mask: Int = DirectionMask.ALL) { - withShape(blockState.getOutlineShape(world, blockPos), blockPos, color, mask) - } - - fun SafeContext.withPos(blockPos: BlockPos, color: Color, side: Direction) { - withPos(blockPos, color, DirectionMask.NONE.include(side)) - } - - fun SafeContext.withPos(blockPos: BlockPos, color: Color, mask: Int = DirectionMask.ALL) { - val shape = blockState(blockPos).getOutlineShape(world, blockPos) - withShape(shape, blockPos, color, mask) - } - - fun SafeContext.withShape(shape: VoxelShape, offset: BlockPos, color: Color, mask: Int = DirectionMask.ALL) { - if (shape.isEmpty) { - withBox(Box(offset), color, mask) - return - } - shape.boundingBoxes.forEach { box -> - withBox(box.offset(offset), color, mask) - } - } + fun ShapeBuilder.buildRenderer() } diff --git a/src/main/kotlin/com/lambda/interaction/construction/result/InteractResult.kt b/src/main/kotlin/com/lambda/interaction/construction/result/InteractResult.kt index bbfcd5137..e70102e26 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/result/InteractResult.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/result/InteractResult.kt @@ -18,6 +18,7 @@ package com.lambda.interaction.construction.result import com.lambda.context.SafeContext +import com.lambda.graphics.renderer.esp.ShapeBuilder import com.lambda.interaction.construction.context.InteractionContext import net.minecraft.util.math.BlockPos @@ -28,7 +29,7 @@ sealed class InteractResult : BuildResult() { ) : Contextual, Drawable, InteractResult() { override val rank = Rank.INTERACT_SUCCESS - override fun SafeContext.buildRenderer() { + override fun ShapeBuilder.buildRenderer() { with(context) { buildRenderer() } } @@ -38,4 +39,4 @@ sealed class InteractResult : BuildResult() { else -> super.compareTo(other) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/lambda/interaction/construction/result/PlaceResult.kt b/src/main/kotlin/com/lambda/interaction/construction/result/PlaceResult.kt index 6b2dc65a0..067eb08e7 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/result/PlaceResult.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/result/PlaceResult.kt @@ -20,6 +20,7 @@ package com.lambda.interaction.construction.result import baritone.api.pathing.goals.GoalBlock import baritone.api.pathing.goals.GoalInverted import com.lambda.context.SafeContext +import com.lambda.graphics.renderer.esp.ShapeBuilder import com.lambda.interaction.construction.context.PlaceContext import com.lambda.task.tasks.BuildTask.Companion.breakBlock import net.minecraft.block.BlockState @@ -46,7 +47,7 @@ sealed class PlaceResult : BuildResult() { ) : Contextual, Drawable, PlaceResult() { override val rank = Rank.PLACE_SUCCESS - override fun SafeContext.buildRenderer() { + override fun ShapeBuilder.buildRenderer() { with(context) { buildRenderer() } } @@ -77,8 +78,8 @@ sealed class PlaceResult : BuildResult() { override val rank = Rank.PLACE_NO_INTEGRITY private val color = Color(252, 3, 3, 100) - override fun SafeContext.buildRenderer() { - withState(expected, blockPos, color) + override fun ShapeBuilder.buildRenderer() { + box(blockPos, expected, color, color) } } diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/Simulation.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/Simulation.kt index 6e8b1c1fc..5bf40b099 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/Simulation.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/Simulation.kt @@ -20,6 +20,7 @@ package com.lambda.interaction.construction.simulation import com.lambda.config.groups.BuildConfig import com.lambda.config.groups.InteractionConfig import com.lambda.context.SafeContext +import com.lambda.graphics.renderer.esp.ShapeBuilder import com.lambda.interaction.construction.blueprint.Blueprint import com.lambda.interaction.construction.result.BuildResult import com.lambda.interaction.construction.result.Drawable @@ -71,8 +72,8 @@ data class Simulation( .map { PossiblePos(it.key.toBlockPos(), it.value.count { it.rank.ordinal < 4 }) } class PossiblePos(val pos: BlockPos, val interactions: Int) : Drawable { - override fun SafeContext.buildRenderer() { - withBox(Vec3d.ofBottomCenter(pos).playerBox(), Color(0, 255, 0, 50)) + override fun ShapeBuilder.buildRenderer() { + box(Vec3d.ofBottomCenter(pos).playerBox(), Color(0, 255, 0, 50), Color(0, 255, 0, 50)) } } diff --git a/src/main/kotlin/com/lambda/module/modules/client/TaskFlowModule.kt b/src/main/kotlin/com/lambda/module/modules/client/TaskFlowModule.kt index ed7f9287f..944b343fe 100644 --- a/src/main/kotlin/com/lambda/module/modules/client/TaskFlowModule.kt +++ b/src/main/kotlin/com/lambda/module/modules/client/TaskFlowModule.kt @@ -22,9 +22,8 @@ import com.lambda.config.groups.HotbarSettings import com.lambda.config.groups.InteractionSettings import com.lambda.config.groups.InventorySettings import com.lambda.config.groups.RotationSettings -import com.lambda.event.events.RenderEvent import com.lambda.event.events.onStaticRender -import com.lambda.event.listener.SafeListener.Companion.listen +import com.lambda.interaction.construction.result.BuildResult import com.lambda.interaction.construction.result.Drawable import com.lambda.module.Module import com.lambda.module.tag.ModuleTag @@ -60,7 +59,7 @@ object TaskFlowModule : Module( init { onStaticRender { - drawables.forEach { with(it) { buildRenderer() } } + with(it) { drawables.forEach { with(it) { buildRenderer() } } } } } } From 26f379db4b1b80f3ac6e053f725f03f172f8ce1a Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Sun, 7 Sep 2025 15:40:00 -0400 Subject: [PATCH 09/10] Update BreakManager.kt --- .../interaction/request/breaking/BreakManager.kt | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/com/lambda/interaction/request/breaking/BreakManager.kt b/src/main/kotlin/com/lambda/interaction/request/breaking/BreakManager.kt index 7fbdc5699..b57f8ebb3 100644 --- a/src/main/kotlin/com/lambda/interaction/request/breaking/BreakManager.kt +++ b/src/main/kotlin/com/lambda/interaction/request/breaking/BreakManager.kt @@ -22,15 +22,13 @@ import com.lambda.event.Event import com.lambda.event.EventFlow.post import com.lambda.event.events.ConnectionEvent import com.lambda.event.events.EntityEvent -import com.lambda.event.events.RenderEvent import com.lambda.event.events.TickEvent import com.lambda.event.events.UpdateManagerEvent import com.lambda.event.events.WorldEvent +import com.lambda.event.events.onStaticRender import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe import com.lambda.graphics.renderer.esp.DynamicAABB -import com.lambda.graphics.renderer.esp.builders.buildFilled -import com.lambda.graphics.renderer.esp.builders.buildOutline import com.lambda.interaction.construction.blueprint.Blueprint.Companion.toStructure import com.lambda.interaction.construction.blueprint.StaticBlueprint.Companion.toBlueprint import com.lambda.interaction.construction.context.BreakContext @@ -217,16 +215,16 @@ object BreakManager : RequestHandler( ?.internalOnItemDrop(it.entity) } - listen { event -> + onStaticRender { val activeStack = breakInfos .filterNotNull() - .firstOrNull()?.swapStack ?: return@listen + .firstOrNull()?.swapStack ?: return@onStaticRender breakInfos .filterNotNull() .forEach { info -> val config = info.breakConfig - if (!config.renders) return@listen + if (!config.renders) return@onStaticRender val swapMode = info.breakConfig.swapMode val breakDelta = info.context.cachedState.calcBreakDelta( player, @@ -265,8 +263,8 @@ object BreakManager : RequestHandler( val dynamicAABB = DynamicAABB() dynamicAABB.update(interpolatedNow) dynamicAABB.update(interpolatedNext) - if (config.fill) event.renderer.buildFilled(dynamicAABB, fillColor) - if (config.outline) event.renderer.buildOutline(dynamicAABB, outlineColor) + if (config.fill) it.filled(dynamicAABB, fillColor) + if (config.outline) it.outline(dynamicAABB, outlineColor) } } } From 84f4917243b062b5ec59ea515587fb9b9a223547 Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Fri, 3 Oct 2025 14:40:21 -0400 Subject: [PATCH 10/10] I don't remember, have it --- build.gradle.kts | 31 -- .../com/lambda/graphics/buffer/Buffer.kt | 365 +++++------------- .../graphics/buffer/frame/CachedFrame.kt | 82 ---- .../graphics/buffer/frame/FrameBuffer.kt | 150 ------- .../graphics/buffer/pixel/PixelBuffer.kt | 149 ------- .../graphics/buffer/vertex/VertexArray.kt | 30 +- .../buffer/vertex/attributes/VertexAttrib.kt | 16 +- .../graphics/pipeline/PersistentBuffer.kt | 25 +- .../graphics/renderer/gui/TextureRenderer.kt | 85 ---- .../renderer/gui/font/core/LambdaAtlas.kt | 4 +- .../gui/font/sdf/DistanceFieldTexture.kt | 66 ---- .../graphics/texture/AnimatedTexture.kt | 6 +- .../lambda/graphics/texture/TextureOwner.kt | 11 - src/main/kotlin/com/lambda/gui/MenuBar.kt | 5 +- .../kotlin/com/lambda/network/CapeManager.kt | 12 +- 15 files changed, 126 insertions(+), 911 deletions(-) delete mode 100644 src/main/kotlin/com/lambda/graphics/buffer/frame/CachedFrame.kt delete mode 100644 src/main/kotlin/com/lambda/graphics/buffer/frame/FrameBuffer.kt delete mode 100644 src/main/kotlin/com/lambda/graphics/buffer/pixel/PixelBuffer.kt delete mode 100644 src/main/kotlin/com/lambda/graphics/renderer/gui/TextureRenderer.kt delete mode 100644 src/main/kotlin/com/lambda/graphics/renderer/gui/font/sdf/DistanceFieldTexture.kt diff --git a/build.gradle.kts b/build.gradle.kts index ade6f644a..da97c81e1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -211,37 +211,6 @@ tasks { // Forces the task to always run outputs.upToDateWhen { false } } - - // Visual debugger for OpenGL - register("renderDoc") { - // You need renderdoc installed on your system and available in your environment variables in order - // to use this task. - // You can download it from their official website at https://renderdoc.org/ - - val javaHome = Jvm.current().javaHome - val gradle = rootProject.tasks.wrapper.get().jarFile.absolutePath - - val seperator = - if (Os.isFamily(Os.FAMILY_WINDOWS)) ";" else ":" - - commandLine = listOf( - "renderdoccmd", "capture", "--opt-api-validation", "--opt-api-validation-unmute", "--opt-hook-children", "--wait-for-exit", "--working-dir", ".", - "$javaHome/bin/java", - //"-javaagent:${projectDir.resolve("lwjglx-debug-1.0.0.jar")}=t", - //"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005", - "-Dorg.gradle.appname=gradlew", - "-Dorg.gradle.java.home=$javaHome", - "-Dorg.lwjgl.util.Debug=true", - "-Dorg.lwjgl.util.DebugLoader=true", - "-Dorg.lwjgl.util.DebugAllocator=true", - "-Dorg.lwjgl.util.DebugStack=true", - "-Dorg.lwjgl.util.DebugFunctions=true", - "-cp", listOf(projectDir.resolve("lwjgl.jar"), gradle, projectDir.resolve("lwjglx-debug-1.0.0.jar")) - .joinToString(seperator), - "org.gradle.wrapper.GradleWrapperMain", - "runClient", - ) - } } kotlin { diff --git a/src/main/kotlin/com/lambda/graphics/buffer/Buffer.kt b/src/main/kotlin/com/lambda/graphics/buffer/Buffer.kt index b72649506..a03f32e9e 100644 --- a/src/main/kotlin/com/lambda/graphics/buffer/Buffer.kt +++ b/src/main/kotlin/com/lambda/graphics/buffer/Buffer.kt @@ -17,104 +17,12 @@ package com.lambda.graphics.buffer -import org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER -import org.lwjgl.opengl.GL15.GL_DYNAMIC_COPY -import org.lwjgl.opengl.GL15.GL_DYNAMIC_DRAW -import org.lwjgl.opengl.GL15.GL_DYNAMIC_READ -import org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER -import org.lwjgl.opengl.GL15.GL_STATIC_COPY -import org.lwjgl.opengl.GL15.GL_STATIC_DRAW -import org.lwjgl.opengl.GL15.GL_STATIC_READ -import org.lwjgl.opengl.GL15.GL_STREAM_COPY -import org.lwjgl.opengl.GL15.GL_STREAM_DRAW -import org.lwjgl.opengl.GL15.GL_STREAM_READ -import org.lwjgl.opengl.GL15.glBufferSubData -import org.lwjgl.opengl.GL21.GL_PIXEL_PACK_BUFFER -import org.lwjgl.opengl.GL21.GL_PIXEL_UNPACK_BUFFER -import org.lwjgl.opengl.GL30.GL_MAP_FLUSH_EXPLICIT_BIT -import org.lwjgl.opengl.GL30.GL_MAP_INVALIDATE_BUFFER_BIT -import org.lwjgl.opengl.GL30.GL_MAP_INVALIDATE_RANGE_BIT -import org.lwjgl.opengl.GL30.GL_MAP_READ_BIT -import org.lwjgl.opengl.GL30.GL_MAP_UNSYNCHRONIZED_BIT -import org.lwjgl.opengl.GL30.GL_MAP_WRITE_BIT -import org.lwjgl.opengl.GL30.GL_TRANSFORM_FEEDBACK_BUFFER -import org.lwjgl.opengl.GL31.GL_COPY_READ_BUFFER -import org.lwjgl.opengl.GL31.GL_COPY_WRITE_BUFFER -import org.lwjgl.opengl.GL31.GL_TEXTURE_BUFFER -import org.lwjgl.opengl.GL31.GL_UNIFORM_BUFFER -import org.lwjgl.opengl.GL40.GL_DRAW_INDIRECT_BUFFER -import org.lwjgl.opengl.GL42.GL_ATOMIC_COUNTER_BUFFER -import org.lwjgl.opengl.GL43.GL_DISPATCH_INDIRECT_BUFFER -import org.lwjgl.opengl.GL43.GL_SHADER_STORAGE_BUFFER -import org.lwjgl.opengl.GL44.GL_CLIENT_STORAGE_BIT -import org.lwjgl.opengl.GL44.GL_DYNAMIC_STORAGE_BIT -import org.lwjgl.opengl.GL44.GL_MAP_COHERENT_BIT -import org.lwjgl.opengl.GL44.GL_MAP_PERSISTENT_BIT -import org.lwjgl.opengl.GL44.GL_QUERY_BUFFER import org.lwjgl.opengl.GL46.* import java.nio.ByteBuffer -abstract class Buffer( - /** - * Specifies how many buffer must be used - * - * | Number of Buffers | Purpose | - * |-------------------|---------------------------------------------------------------------------------------------------------------| - * | 1 Buffer | Simple operations like storing vertex data, reading from the framebuffer, etc. | - * | 2 Buffers | Increase throughput by not having to explicitly sync memory. | - * | 3 Buffers | If the driver run alongside the CPU and GPU, then each must have their own buffer to avoid stalling. | - */ - val buffers: Int = 1, - - /** - * Edge case to handle vertex arrays - */ - val isVertexArray: Boolean = false, - val validate: Boolean = true -) { - /** - * Specifies how the buffers are used - * - * | Buffer Usage | Description | - * |----------------------------------|-----------------------------------------------------------------| - * | [GL_STREAM_DRAW] | Data is set once and used a few times for drawing. | - * | [GL_STREAM_READ] | Data is set once and used a few times for reading. | - * | [GL_STREAM_COPY] | Data is set once and used a few times for copying. | - * | [GL_STATIC_DRAW] | Data is set once and used many times for drawing. | - * | [GL_STATIC_READ] | Data is set once and used many times for reading. | - * | [GL_STATIC_COPY] | Data is set once and used many times for copying. | - * | [GL_DYNAMIC_DRAW] | Data is modified repeatedly and used many times for drawing. | - * | [GL_DYNAMIC_READ] | Data is modified repeatedly and used many times for reading. | - * | [GL_DYNAMIC_COPY] | Data is modified repeatedly and used many times for copying. | - * - * @see Buffer object - */ - abstract val usage: Int - - /** - * Specifies the target to which the buffer object is bound which must be one - * of the following: - * - * | Buffer Binding Target | Purpose | - * |---------------------------------|--------------------------------------| - * | [GL_ARRAY_BUFFER] | Vertex attributes | - * | [GL_ATOMIC_COUNTER_BUFFER] | Atomic counter storage | - * | [GL_COPY_READ_BUFFER] | Buffer copy source | - * | [GL_COPY_WRITE_BUFFER] | Buffer copy destination | - * | [GL_DISPATCH_INDIRECT_BUFFER] | Indirect compute dispatch commands | - * | [GL_DRAW_INDIRECT_BUFFER] | Indirect command arguments | - * | [GL_ELEMENT_ARRAY_BUFFER] | Vertex array indices | - * | [GL_PIXEL_PACK_BUFFER] | Pixel read target | - * | [GL_PIXEL_UNPACK_BUFFER] | Texture data source | - * | [GL_QUERY_BUFFER] | Query result buffer | - * | [GL_SHADER_STORAGE_BUFFER] | Read-write storage for shaders | - * | [GL_TEXTURE_BUFFER] | Texture data buffer | - * | [GL_TRANSFORM_FEEDBACK_BUFFER] | Transform feedback buffer | - * | [GL_UNIFORM_BUFFER] | Uniform block storage | - * - * @see Buffer object - */ - abstract val target: Int +class Buffer private constructor( + val target: Int, + var buffer: Int, /** * Specifies a combination of access flags indicating the desired @@ -135,29 +43,10 @@ abstract class Buffer( * * @see Buffer object */ - abstract val access: Int - - /** - * Index of the current buffer. - */ - private var index: Int = 0; private set(value) { - if (field == value) return - field = value - id = bufferIds[value] - } - - /** - * ID of the current buffer. - */ - var id: Int = 0; get() { - if (field == 0) field = bufferIds[0] - return field - } private set - - /** - * List of all the buffers. - */ - private val bufferIds = IntArray(buffers) + val access: Int, +) { + fun bind() = glBindBuffer(target, buffer) + fun unbind() = glBindBuffer(target, 0) /** * Execute the [block] in a bound context @@ -165,92 +54,56 @@ abstract class Buffer( fun bind(block: Buffer.() -> Unit) { bind() block(this) - bind(0) + unbind() } /** - * Binds the buffer id to the [target]. - */ - open fun bind(id: Int) = glBindBuffer(target, id) - - /** - * Binds current the buffer [index] to the [target]. - */ - fun bind() = bind(id) - - /** - * Swaps the buffer [index] if [buffers] is greater than 1. - */ - fun swap() { index = (index + 1) % buffers } - - /** - * Update the current buffer without re-allocating. + * Allocates the buffer with the specified data. * - * @throws [IllegalArgumentException] if the target or usage is invalid + * @param data The data to put in the new allocated buffer * - * @see glBufferSubData + * @see glBufferData */ - open fun update(data: ByteBuffer, offset: Long) { - validate() - - bind() - glBufferSubData(target, offset, data) - bind(0) - } + fun allocate(data: ByteBuffer) = + bind { glBufferData(target, data, GL_DYNAMIC_DRAW) } /** - * Update the current buffer without re-allocating. + * Allocates the buffer with the specified size. * - * @throws [IllegalArgumentException] if the target or usage is invalid + * @param data The data to put in the new allocated buffer * - * @see glBufferSubData + * @see glBufferData */ - open fun update(offset: Long, size: Long, data: Long) { - validate() - - bind() - nglBufferSubData(target, offset, size, data) - bind(0) - } + fun allocate(size: Long) = + bind { glBufferData(target, size, GL_DYNAMIC_DRAW) } /** - * Allocates each backing buffer with the specified data. + * Update the current buffer without re-allocating. * - * @param data The data to put in the new allocated buffer * @throws [IllegalArgumentException] if the target or usage is invalid * - * @see glBufferData + * @see glBufferSubData */ - open fun allocate(data: ByteBuffer) { - validate() - - repeat(buffers) { - bind() - glBufferData(target, data, usage) - swap() - } + fun update(offset: Long, data: ByteBuffer) { + check(offset > -1) { "Cannot have negative buffer offsets" } + check(access and GL_DYNAMIC_STORAGE_BIT != 0) { "Buffer contents cannot be modified because the buffer was created without the GL_DYNAMIC_STORAGE_BIT set." } - bind(0) + bind { glBufferSubData(target, offset, data) } } /** - * Allocates memory for each backing buffer of specified size. + * Update the current buffer without re-allocating. * - * @param size The size of the new buffer * @throws [IllegalArgumentException] if the target or usage is invalid * - * @see glBufferData + * @see glBufferSubData */ - open fun allocate(size: Long) { - validate() - - repeat(buffers) { - bind() - glBufferData(target, size.coerceAtLeast(0), usage) - swap() - } + fun update(offset: Long, size: Long, data: Long) { + check(offset > -1) { "Cannot have negative buffer offsets" } + check(size > -1) { "Cannot have negative sized buffers" } + check(access and GL_DYNAMIC_STORAGE_BIT != 0) { "Buffer contents cannot be modified because the buffer was created without the GL_DYNAMIC_STORAGE_BIT set." } - bind(0) + bind { nglBufferSubData(target, offset, size, data) } } /** @@ -265,17 +118,7 @@ abstract class Buffer( * * @see glBufferStorage */ - open fun storage(data: ByteBuffer) { - validate() - - repeat(buffers) { - bind() - glBufferStorage(target, data, access) - swap() - } - - bind(0) - } + fun storage(data: ByteBuffer) = bind { glBufferStorage(target, data, access) } /** * Allocates storage for the buffer object. @@ -290,25 +133,16 @@ abstract class Buffer( * * @see glBufferStorage */ - open fun storage(size: Long) { - validate() - - repeat(buffers) { - bind() - glBufferStorage(target, size.coerceAtLeast(0), access) - swap() - } - - bind(0) + fun storage(size: Long) { + check(size > -1) { "Cannot have negative sized buffers" } + bind { glBufferStorage(target, size, access) } } - // TODO: - // GL_MAP_COHERENT_BIT makes it so changes in the mapped memory are automatically visible to the gpu, no memory barrier and syncing required, but a bit slower - // You still need to swap after each update or you will risk having conflicting reads and writes - // glFlushMappedBufferRange + fun storage(size: Int) = storage(size.toLong()) /** - * Maps a specified region of the buffer's data store into client memory, processes it using the provided lambda, and then unmaps the buffer. + * Maps a specified region of the buffer's data store into client memory, processes it using the provided lambda, and + * then unmaps the buffer. * * If [access] contains the `GL_MAP_PERSISTENT_BIT` flag, the buffer will not be unmapped. * @@ -318,15 +152,12 @@ abstract class Buffer( * * @see Direct memory access */ - open fun map(size: Long, offset: Long, block: (ByteBuffer) -> Unit = {}): ByteBuffer { - validate() - bind() - - check(offset >= 0 || size >= 0) - { "Invalid offset or size parameter offset: $offset size: $size." } + fun map(offset: Long, size: Long, block: (ByteBuffer) -> Unit = {}): ByteBuffer { + check(offset > -1) { "Cannot have negative buffer offsets" } + check(size > -1) { "Cannot have negative sized buffers" } check(offset + size <= glGetBufferParameteri(target, GL_BUFFER_SIZE)) - { "Out of bound (is the buffer initialized?) $size + $offset > ${glGetBufferParameteri(target, GL_BUFFER_SIZE)}." } + { "Segmentation fault Size $size + Offset $offset > Buffer ${glGetBufferParameteri(target, GL_BUFFER_SIZE)}." } check(glGetBufferParameteri(target, GL_BUFFER_MAPPED) == GL_FALSE) { "Buffer is already mapped." } @@ -339,43 +170,58 @@ abstract class Buffer( access and GL_MAP_INVALIDATE_BUFFER_BIT != 0 || access and GL_MAP_UNSYNCHRONIZED_BIT != 0)) || access and GL_MAP_WRITE_BIT != 0 - ) - { "GL_MAP_READ_BIT is set and any of GL_MAP_INVALIDATE_RANGE_BIT, GL_MAP_INVALIDATE_BUFFER_BIT or GL_MAP_UNSYNCHRONIZED_BIT is set." } + ) { "GL_MAP_READ_BIT is set and any of GL_MAP_INVALIDATE_RANGE_BIT, GL_MAP_INVALIDATE_BUFFER_BIT or GL_MAP_UNSYNCHRONIZED_BIT is set." } + + bind() val sharedRegion = glMapBufferRange(target, offset, size, access) - ?: throw IllegalStateException("Failed to map buffer.") + check(sharedRegion != null) { "Could not map the buffer" } block(sharedRegion) - if (access and GL_MAP_PERSISTENT_BIT == 0) { - if (!glUnmapBuffer(target)) - throw IllegalStateException("An unknown error occurred due to GPU memory availability of buffer corruption.") - } + if (access and GL_MAP_PERSISTENT_BIT == 0) + check(glUnmapBuffer(target)) { "An unknown error occurred due to GPU memory availability of buffer corruption." } - bind(0) + unbind() return sharedRegion } /** - * Uploads the specified data to the buffer starting at the given offset. - * - * This abstract function should be implemented to perform the actual data transfer into the buffer. - * - * @param data Data to set in memory - * @param offset The starting offset within the buffer of the range to be mapped + * Indicates modifications to a range of a mapped buffer. + */ + fun flushMappedRange(offset: Long, size: Long) = bind { glFlushMappedBufferRange(target, offset, size) } + + /** + * Copies all or part of one buffer object's data store to the data store of another buffer object. */ - abstract fun upload(data: ByteBuffer, offset: Long) + // fun copy(dst: Buffer, readOffset: Long, writeOffset: Long, size: Long) {} - private fun validate() { - if (!validate) return + /** + * Deletes the buffer object and creates a new one + */ + fun orphan() { + delete() + create() + } - check(usage in GL_STREAM_DRAW..GL_DYNAMIC_COPY) - { "Usage is invalid, refer to the documentation table." } + /** + * Deletes the buffer and mark all allocated data as free + */ + fun delete() { + glDeleteBuffers(buffer) + buffer = -69 + } - check(target in bindingCheckMappings) - { "Target is invalid, refer to the documentation table." } + /** + * Creates a new buffer + */ + fun create() { + check(buffer == -69) { "Cannot create a new buffer if the previous one is not deleted" } + buffer = glGenBuffers() + } + init { check(access and GL_MAP_COHERENT_BIT == 0 || access and GL_MAP_PERSISTENT_BIT != 0) { "GL_MAP_COHERENT_BIT requires GL_MAP_PERSISTENT_BIT flag." } @@ -383,52 +229,15 @@ abstract class Buffer( { "GL_MAP_PERSISTENT_BIT requires GL_MAP_READ_BIT or GL_MAP_WRITE_BIT." } } - init { - check(buffers > 0) { "Cannot generate less than one buffer" } - - if (isVertexArray) glGenVertexArrays(bufferIds) // If there are more than 1 buffer you should expect undefined behavior, this is not the way to do it - else glGenBuffers(bufferIds) - } - companion object { - val bindingCheckMappings = mapOf( - GL_ARRAY_BUFFER to GL_ARRAY_BUFFER_BINDING, - GL_ATOMIC_COUNTER_BUFFER to GL_ATOMIC_COUNTER_BUFFER_BINDING, - GL_COPY_READ_BUFFER_BINDING to GL_COPY_READ_BUFFER_BINDING, - GL_COPY_WRITE_BUFFER_BINDING to GL_COPY_WRITE_BUFFER_BINDING, - GL_DISPATCH_INDIRECT_BUFFER to GL_DISPATCH_INDIRECT_BUFFER_BINDING, - GL_DRAW_INDIRECT_BUFFER to GL_DRAW_INDIRECT_BUFFER_BINDING, - GL_ELEMENT_ARRAY_BUFFER to GL_ELEMENT_ARRAY_BUFFER_BINDING, - GL_PIXEL_PACK_BUFFER to GL_PIXEL_PACK_BUFFER_BINDING, - GL_PIXEL_UNPACK_BUFFER to GL_PIXEL_UNPACK_BUFFER_BINDING, - GL_QUERY_BUFFER to GL_QUERY_BUFFER_BINDING, - GL_SHADER_STORAGE_BUFFER to GL_SHADER_STORAGE_BUFFER_BINDING, - GL_TEXTURE_BUFFER to GL_TEXTURE_BUFFER_BINDING, - GL_TRANSFORM_FEEDBACK_BUFFER to GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, - GL_UNIFORM_BUFFER to GL_UNIFORM_BUFFER_BINDING, - ) - - @JvmField - var lastIbo = 0 - var prevIbo = 0 - - fun createPipelineBuffer(bufferTarget: Int) = object : Buffer(buffers = 1, validate = false) { - override val target: Int = bufferTarget - - override val usage: Int = GL_STATIC_DRAW - override val access: Int = GL_MAP_WRITE_BIT - - override fun bind(id: Int) { - if (bufferTarget != GL_ELEMENT_ARRAY_BUFFER) { - super.bind(id) - return - } - - if (id != 0) prevIbo = lastIbo - super.bind(if (id != 0) id else prevIbo) - } - - override fun upload(data: ByteBuffer, offset: Long) = throw UnsupportedOperationException() - } + /** + * Creates a buffer. + * + * If no [buffer] is provided, one will be created. + * + * @see [Buffer.access] + */ + fun create(target: Int, access: Int, buffer: Int = glGenBuffers(), block: Buffer.() -> Unit = {}) = + Buffer(target, buffer, access).apply { block() } } } diff --git a/src/main/kotlin/com/lambda/graphics/buffer/frame/CachedFrame.kt b/src/main/kotlin/com/lambda/graphics/buffer/frame/CachedFrame.kt deleted file mode 100644 index e7ad8030a..000000000 --- a/src/main/kotlin/com/lambda/graphics/buffer/frame/CachedFrame.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2025 Lambda - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lambda.graphics.buffer.frame - -import com.lambda.Lambda.mc -import com.lambda.graphics.RenderMain -import com.lambda.graphics.gl.Matrices -import org.joml.Matrix4f -import org.lwjgl.opengl.GL11C.glViewport - -/** - * A class that handles a cached frame, encapsulating a framebuffer with a specified width and height. - * It provides methods for binding the framebuffer texture and writing to the framebuffer with custom rendering operations. - * - * @param width The width of the framebuffer. - * @param height The height of the framebuffer. - */ -class CachedFrame(val width: Int, val height: Int) { - - // The framebuffer associated with this cached frame - private val frameBuffer = FrameBuffer(width, height) - - /** - * Binds the color texture of the framebuffer to a specified texture slot. - * - * @param slot The texture slot to bind the color texture to. Defaults to slot 0. - */ - fun bind(slot: Int = 0) = frameBuffer.bindColorTexture(slot) - - /** - * Executes custom drawing operations on the framebuffer. - * - * The method temporarily modifies the view and projection matrices, the viewport, - * and then restores them after the block is executed. - * - * @param block A block of code that performs custom drawing operations on the framebuffer. - */ - fun write(block: () -> Unit): CachedFrame { - frameBuffer.write { - // Save the current viewmodel matrix - Matrices.push() - // Set the viewmodel matrix to translate the scene away - Matrices.peek().set(Matrix4f().translate(0f, 0f, -3000f)) - - // Save the previous projection matrix and set a custom orthographic projection - val prevProj = Matrix4f(RenderMain.projectionMatrix) - RenderMain.projectionMatrix.setOrtho(0f, width.toFloat(), height.toFloat(), 0f, 1000f, 21000f) - - // Resize the viewport to match the framebuffer's dimensions - glViewport(0, 0, width, height) - - // Execute the drawing operations defined in the block - block() - - // Restore the previous viewport dimensions - glViewport(0, 0, mc.framebuffer.viewportWidth, mc.framebuffer.viewportHeight) - - // Restore the previous projection matrix - RenderMain.projectionMatrix.set(prevProj) - - // Restore the previous viewmodel matrix - Matrices.pop() - } - - return this - } -} diff --git a/src/main/kotlin/com/lambda/graphics/buffer/frame/FrameBuffer.kt b/src/main/kotlin/com/lambda/graphics/buffer/frame/FrameBuffer.kt deleted file mode 100644 index 02294dd53..000000000 --- a/src/main/kotlin/com/lambda/graphics/buffer/frame/FrameBuffer.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2025 Lambda - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lambda.graphics.buffer.frame - -import com.lambda.Lambda.mc -import com.lambda.graphics.buffer.vertex.attributes.VertexAttrib -import com.lambda.graphics.buffer.vertex.attributes.VertexMode -import com.lambda.graphics.pipeline.VertexPipeline -import com.lambda.graphics.texture.TextureUtils -import com.mojang.blaze3d.systems.RenderSystem -import net.minecraft.client.gl.GlBackend -import net.minecraft.client.texture.GlTexture -import org.lwjgl.opengl.GL12C.GL_CLAMP_TO_EDGE -import org.lwjgl.opengl.GL30C.GL_COLOR_ATTACHMENT0 -import org.lwjgl.opengl.GL30C.GL_COLOR_BUFFER_BIT -import org.lwjgl.opengl.GL30C.GL_DEPTH_ATTACHMENT -import org.lwjgl.opengl.GL30C.GL_DEPTH_BUFFER_BIT -import org.lwjgl.opengl.GL30C.GL_DEPTH_COMPONENT -import org.lwjgl.opengl.GL30C.GL_DEPTH_COMPONENT32F -import org.lwjgl.opengl.GL30C.GL_FLOAT -import org.lwjgl.opengl.GL30C.GL_FRAMEBUFFER -import org.lwjgl.opengl.GL30C.GL_FRAMEBUFFER_COMPLETE -import org.lwjgl.opengl.GL30C.GL_LINEAR -import org.lwjgl.opengl.GL30C.GL_RGBA -import org.lwjgl.opengl.GL30C.GL_TEXTURE_2D -import org.lwjgl.opengl.GL30C.GL_TEXTURE_MAG_FILTER -import org.lwjgl.opengl.GL30C.GL_TEXTURE_MIN_FILTER -import org.lwjgl.opengl.GL30C.GL_TEXTURE_WRAP_S -import org.lwjgl.opengl.GL30C.GL_TEXTURE_WRAP_T -import org.lwjgl.opengl.GL30C.GL_UNSIGNED_BYTE -import org.lwjgl.opengl.GL30C.glBindFramebuffer -import org.lwjgl.opengl.GL30C.glCheckFramebufferStatus -import org.lwjgl.opengl.GL30C.glClear -import org.lwjgl.opengl.GL30C.glClearColor -import org.lwjgl.opengl.GL30C.glClearDepth -import org.lwjgl.opengl.GL30C.glFramebufferTexture2D -import org.lwjgl.opengl.GL30C.glGenFramebuffers -import org.lwjgl.opengl.GL30C.glGenTextures -import org.lwjgl.opengl.GL30C.glTexImage2D -import org.lwjgl.opengl.GL30C.glTexParameteri -import java.nio.IntBuffer - -open class FrameBuffer( - var width: Int = 1, - var height: Int = 1, - private val depth: Boolean = false -) { - val fbo = glGenFramebuffers() - - val colorAttachment = glGenTextures() - val depthAttachment by lazy(::glGenTextures) - - private val clearMask = if (!depth) GL_COLOR_BUFFER_BIT - else GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT - - private var lastWidth = -1 - private var lastHeight = -1 - - open fun write(block: () -> Unit): FrameBuffer { - glBindFramebuffer(GL_FRAMEBUFFER, fbo) - - update() - block() - - glBindFramebuffer(GL_FRAMEBUFFER, 0) - return this - } - - fun bind() { - glBindFramebuffer(GL_FRAMEBUFFER, fbo) - } - - fun updateScreenSized() { - width = mc.framebuffer.viewportWidth - height = mc.framebuffer.viewportHeight - update() - } - - fun update() { - if (width == lastWidth && height == lastHeight) { - glClear(clearMask) - return - } - - lastWidth = width - lastHeight = height - - setupBufferTexture(colorAttachment) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null as IntBuffer?) - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorAttachment, 0) - - if (depth) { - setupBufferTexture(depthAttachment) - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null as IntBuffer?) - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthAttachment, 0) - } - - glClearColor(0f, 0f, 0f, 0f) - glClearDepth(1.0) - - glClear(clearMask) - - val fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER) - - check(fboStatus == GL_FRAMEBUFFER_COMPLETE) { "Framebuffer not complete: $fboStatus" } - } - - open fun bindColorTexture(slot: Int = 0): FrameBuffer { - TextureUtils.bindTexture(colorAttachment, slot) - return this - } - - open fun bindDepthTexture(slot: Int = 0): FrameBuffer { - check(depth) { - "Cannot bind depth texture of a non-depth framebuffer" - } - - TextureUtils.bindTexture(depthAttachment, slot) - return this - } - - companion object { - val pipeline = VertexPipeline(VertexMode.TRIANGLES, VertexAttrib.Group.POS_UV) - private var lastFrameBuffer: Int? = null - - private fun setupBufferTexture(id: Int) { - TextureUtils.bindTexture(id) - TextureUtils.setupTexture(GL_LINEAR, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) - } - } -} diff --git a/src/main/kotlin/com/lambda/graphics/buffer/pixel/PixelBuffer.kt b/src/main/kotlin/com/lambda/graphics/buffer/pixel/PixelBuffer.kt deleted file mode 100644 index d7d383401..000000000 --- a/src/main/kotlin/com/lambda/graphics/buffer/pixel/PixelBuffer.kt +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2025 Lambda - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lambda.graphics.buffer.pixel - -import com.lambda.graphics.buffer.Buffer -import com.lambda.graphics.texture.Texture -import com.lambda.util.math.MathUtils.toInt -import org.lwjgl.opengl.GL45C.GL_ALPHA -import org.lwjgl.opengl.GL45C.GL_BGR -import org.lwjgl.opengl.GL45C.GL_BGRA -import org.lwjgl.opengl.GL45C.GL_BLUE -import org.lwjgl.opengl.GL45C.GL_DYNAMIC_STORAGE_BIT -import org.lwjgl.opengl.GL45C.GL_GREEN -import org.lwjgl.opengl.GL45C.GL_LINEAR -import org.lwjgl.opengl.GL45C.GL_MAP_COHERENT_BIT -import org.lwjgl.opengl.GL45C.GL_MAP_PERSISTENT_BIT -import org.lwjgl.opengl.GL45C.GL_MAP_WRITE_BIT -import org.lwjgl.opengl.GL45C.GL_PIXEL_UNPACK_BUFFER -import org.lwjgl.opengl.GL45C.GL_RED -import org.lwjgl.opengl.GL45C.GL_RG -import org.lwjgl.opengl.GL45C.GL_RGB -import org.lwjgl.opengl.GL45C.GL_RGBA -import org.lwjgl.opengl.GL45C.GL_STATIC_DRAW -import org.lwjgl.opengl.GL45C.GL_TEXTURE_2D -import org.lwjgl.opengl.GL45C.GL_TEXTURE_MAG_FILTER -import org.lwjgl.opengl.GL45C.GL_TEXTURE_MIN_FILTER -import org.lwjgl.opengl.GL45C.GL_UNSIGNED_BYTE -import org.lwjgl.opengl.GL45C.glBindTexture -import org.lwjgl.opengl.GL45C.glTexImage2D -import org.lwjgl.opengl.GL45C.glTexParameteri -import org.lwjgl.opengl.GL45C.glTexSubImage2D -import java.nio.ByteBuffer - -/** - * Represents a Pixel Buffer Object (PBO) that facilitates asynchronous data transfer to the GPU. - * - * Every function that performs a pixel transfer operation can use buffer objects instead of client memory. - * Functions that perform an upload operation, a pixel unpack, will use the buffer object bound to the target GL_PIXEL_UNPACK_BUFFER. - * If a buffer is bound, then the pointer value that those functions take is not a pointer, but an offset from the beginning of that buffer. - * - * Asynchronous should only be used for medium-size blocks of data being updated one time or less per frame - * Persistent should only be used for streaming operations with large blocks of data updated once or more per frame - * - * @property texture The [Texture] instance to use - * @property asynchronous Whether to use 2 buffers or not - * @property persistent Whether to map a block in memory to upload or not - * - * @see Pixel buffer object - */ -class PixelBuffer( - private val texture: Texture, - private val asynchronous: Boolean = false, - private val persistent: Boolean = false, -) : Buffer(buffers = asynchronous.toInt() + 1) { - override val usage = GL_STATIC_DRAW - override val target = GL_PIXEL_UNPACK_BUFFER - override val access = - if (persistent) GL_MAP_WRITE_BIT or GL_DYNAMIC_STORAGE_BIT or GL_MAP_PERSISTENT_BIT or GL_MAP_COHERENT_BIT - else GL_MAP_WRITE_BIT or GL_DYNAMIC_STORAGE_BIT - - private val channels = channelMapping[texture.format] - ?: throw IllegalArgumentException("Invalid image format, expected OpenGL format, got ${texture.format} instead") - private val size = texture.width * texture.height * channels * 1L - // private var sharedRegion: ByteBuffer? = null - - override fun upload(data: ByteBuffer, offset: Long) { - if (!asynchronous) { - glBindTexture(GL_TEXTURE_2D, texture.id) - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture.width, texture.height, texture.format, GL_UNSIGNED_BYTE, data) - glBindTexture(GL_TEXTURE_2D, 0) - return - } - - bind() - glBindTexture(GL_TEXTURE_2D, texture.id) - - // Copy pixels from PBO to texture object - // Use offset instead of pointer - glTexSubImage2D( - GL_TEXTURE_2D, // Target - 0, // Mipmap level - 0, 0, // x and y offset - texture.width, // Width of the texture - texture.height, // Height of the texture - texture.format, // Format of your texture (depends on your data) - GL_UNSIGNED_BYTE, // Type (depends on your data) - 0, // PBO offset (for asynchronous transfer) - ) - - swap() - bind() - - // if (persistent) data.putTo(sharedRegion) - // else update(data, offset) - update(data, offset) - - bind(0) - } - - init { - if (!texture.initialized) throw IllegalStateException("Cannot use uninitialized textures for pixel buffers") - - // We can't call the texture's bind method because the animated texture updates the - // data when binding the texture, causing a null pointer exception due to the animated - // texture object not being initialized - glBindTexture(GL_TEXTURE_2D, texture.id) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0, texture.format, GL_UNSIGNED_BYTE, 0) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - - storage(size) - - // bind() - // sharedRegion = if (persistent) map(size, 0) else null - // bind(0) - } - - companion object { - /** - * Returns how many channels are used for each image format - */ - private val channelMapping = mapOf( - GL_RED to 1, - GL_GREEN to 1, - GL_BLUE to 1, - GL_ALPHA to 1, - GL_RG to 2, - GL_RGB to 3, - GL_BGR to 3, - GL_RGBA to 4, - GL_BGRA to 4, - ) - } -} diff --git a/src/main/kotlin/com/lambda/graphics/buffer/vertex/VertexArray.kt b/src/main/kotlin/com/lambda/graphics/buffer/vertex/VertexArray.kt index 518d4d8b3..a0a5db567 100644 --- a/src/main/kotlin/com/lambda/graphics/buffer/vertex/VertexArray.kt +++ b/src/main/kotlin/com/lambda/graphics/buffer/vertex/VertexArray.kt @@ -17,23 +17,19 @@ package com.lambda.graphics.buffer.vertex -import com.lambda.graphics.buffer.Buffer import com.lambda.graphics.buffer.vertex.attributes.VertexAttrib import com.lambda.graphics.buffer.vertex.attributes.VertexMode import com.lambda.graphics.pipeline.PersistentBuffer import org.lwjgl.opengl.GL30C.GL_UNSIGNED_INT import org.lwjgl.opengl.GL30C.glBindVertexArray +import org.lwjgl.opengl.GL30C.glGenVertexArrays import org.lwjgl.opengl.GL32C.glDrawElementsBaseVertex -import java.nio.ByteBuffer class VertexArray( private val vertexMode: VertexMode, private val attributes: VertexAttrib.Group -) : Buffer(isVertexArray = true) { - override val usage: Int = -1 - override val target: Int = -1 - override val access: Int = -1 - +) { + private val vao = glGenVertexArrays() private var linkedVBO: PersistentBuffer? = null fun renderIndices( @@ -50,7 +46,8 @@ class VertexArray( indicesSize: Long, indicesPointer: Long, verticesOffset: Long - ) = bind { + ) { + glBindVertexArray(vao) glDrawElementsBaseVertex( vertexMode.mode, indicesSize.toInt() / Int.SIZE_BYTES, @@ -58,21 +55,14 @@ class VertexArray( indicesPointer, verticesOffset.toInt() / attributes.stride, ) + glBindVertexArray(0) } - fun linkVbo(vbo: PersistentBuffer, block: VertexArray.() -> Unit = { }) { + fun linkVbo(vbo: PersistentBuffer) { linkedVBO = vbo - bind { - vbo.use { - attributes.link() - block(this@VertexArray) - } - } + glBindVertexArray(vao) + vbo.buffer.bind { attributes.link() } + glBindVertexArray(0) } - - override fun map(size: Long, offset: Long, block: (ByteBuffer) -> Unit) = throw UnsupportedOperationException() - override fun upload(data: ByteBuffer, offset: Long) = throw UnsupportedOperationException() - - override fun bind(id: Int) = glBindVertexArray(id) } diff --git a/src/main/kotlin/com/lambda/graphics/buffer/vertex/attributes/VertexAttrib.kt b/src/main/kotlin/com/lambda/graphics/buffer/vertex/attributes/VertexAttrib.kt index d8ae2f4f6..e1bde0196 100644 --- a/src/main/kotlin/com/lambda/graphics/buffer/vertex/attributes/VertexAttrib.kt +++ b/src/main/kotlin/com/lambda/graphics/buffer/vertex/attributes/VertexAttrib.kt @@ -64,23 +64,11 @@ sealed class VertexAttrib( @Suppress("ClassName") open class Group(vararg val attributes: VertexAttrib) { - object POS_UV : Group( - Vec2, Vec2 - ) - // GUI object FONT : Group( Vec3, Vec2, Color ) - object RECT : Group( - Vec3, Vec2, Color - ) - - object RECT_OUTLINE : Group( - Vec3, Vec2, Float, Color - ) - // WORLD object DYNAMIC_RENDERER : Group( Vec3, Vec3, Color @@ -94,9 +82,7 @@ sealed class VertexAttrib( Vec3, Vec2, Color ) - val stride = attributes.sumOf { attribute -> - attribute.size - } + val stride = attributes.sumOf { it.size } fun link() { attributes.foldIndexed(0L) { index, pointer, attrib -> diff --git a/src/main/kotlin/com/lambda/graphics/pipeline/PersistentBuffer.kt b/src/main/kotlin/com/lambda/graphics/pipeline/PersistentBuffer.kt index 44ce5014e..e449894e6 100644 --- a/src/main/kotlin/com/lambda/graphics/pipeline/PersistentBuffer.kt +++ b/src/main/kotlin/com/lambda/graphics/pipeline/PersistentBuffer.kt @@ -17,32 +17,38 @@ package com.lambda.graphics.pipeline -import com.lambda.graphics.buffer.Buffer.Companion.createPipelineBuffer +import com.lambda.graphics.buffer.Buffer import com.lambda.graphics.buffer.DynamicByteBuffer.Companion.dynamicByteBuffer import com.lambda.graphics.gl.kibibyte +import com.lambda.graphics.gl.megabyte +import com.lambda.gui.dsl.ImStorageDsl.storage +import com.lambda.util.collections.updatableLazy +import org.lwjgl.opengl.GL30.GL_MAP_WRITE_BIT +import org.lwjgl.opengl.GL44.GL_DYNAMIC_STORAGE_BIT import org.lwjgl.system.MemoryUtil.memCopy /** * Represents a persistent dynamic coherent buffer for fast opengl rendering purposes */ class PersistentBuffer( - target: Int, stride: Int, initialSize: Int = 1.kibibyte + target: Int, stride: Int, initialSize: Int = 64.kibibyte, ) { /** * Resizable byte buffer that stores all data used last frame */ val byteBuffer = dynamicByteBuffer(stride * initialSize) + /** + * Represents a OpenGl Object that store unformatted memory + */ + val buffer = Buffer.create(target, GL_MAP_WRITE_BIT or GL_DYNAMIC_STORAGE_BIT) { allocate(byteBuffer.capacity.toLong()) } + /** * Data that has passed through the buffer within previous frame */ private val snapshot = dynamicByteBuffer(1) private var snapshotData = 0L - /** - * Represents a gpu-side buffer - */ - val glBuffer = createPipelineBuffer(target) private var glSize = 0 var uploadOffset = 0L @@ -54,8 +60,7 @@ class PersistentBuffer( if (glSize != byteBuffer.capacity) { glSize = byteBuffer.capacity - - glBuffer.allocate(byteBuffer.data) + buffer.allocate(byteBuffer.data) snapshot.realloc(byteBuffer.capacity) snapshotData = 0 return @@ -65,7 +70,7 @@ class PersistentBuffer( if (snapshot.mismatch(byteBuffer) >= 0) return } - glBuffer.update(uploadOffset, dataCount, dataStart) + buffer.update(uploadOffset, dataCount, dataStart) } fun end() { @@ -86,6 +91,4 @@ class PersistentBuffer( uploadOffset = 0 snapshotData = 0 } - - fun use(block: () -> Unit) = glBuffer.bind { block() } } diff --git a/src/main/kotlin/com/lambda/graphics/renderer/gui/TextureRenderer.kt b/src/main/kotlin/com/lambda/graphics/renderer/gui/TextureRenderer.kt deleted file mode 100644 index c2d468133..000000000 --- a/src/main/kotlin/com/lambda/graphics/renderer/gui/TextureRenderer.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2025 Lambda - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lambda.graphics.renderer.gui - -import com.lambda.graphics.RenderMain -import com.lambda.graphics.buffer.vertex.attributes.VertexAttrib -import com.lambda.graphics.buffer.vertex.attributes.VertexMode -import com.lambda.graphics.pipeline.VertexPipeline -import com.lambda.graphics.shader.Shader.Companion.shader -import com.lambda.graphics.texture.Texture -import com.lambda.module.modules.client.GuiSettings -import com.lambda.module.modules.client.GuiSettings.primaryColor -import com.lambda.module.modules.client.GuiSettings.secondaryColor -import com.lambda.util.math.Rect -import com.lambda.util.math.Vec2d -import org.lwjgl.glfw.GLFW.glfwGetTime - -object TextureRenderer { - private val pipeline = VertexPipeline(VertexMode.TRIANGLES, VertexAttrib.Group.POS_UV) - - private val mainShader = shader("pos_tex") - private val coloredShader = shader("pos_tex_shady") - - fun drawTexture(texture: Texture, rect: Rect) { - texture.bind() - mainShader.use() - - drawInternal(rect) - } - - fun drawTextureShaded(texture: Texture, rect: Rect) { - texture.bind() - coloredShader.use() - - coloredShader["u_Shade"] = 1.0 - coloredShader["u_ShadeTime"] = glfwGetTime() * GuiSettings.colorSpeed * 5.0 - coloredShader["u_ShadeColor1"] = primaryColor - coloredShader["u_ShadeColor2"] = secondaryColor - - coloredShader["u_ShadeSize"] = RenderMain.screenSize / Vec2d(GuiSettings.colorWidth, GuiSettings.colorHeight) - - drawInternal(rect) - } - - fun drawInternal(rect: Rect) { - val pos1 = rect.leftTop - val pos2 = rect.rightBottom - - pipeline.immediate { - buildQuad( - vertex { - vec2(pos1.x, pos1.y) - vec2(0.0, 0.0) - }, - vertex { - vec2(pos1.x, pos2.y) - vec2(0.0, 1.0) - }, - vertex { - vec2(pos2.x, pos2.y) - vec2(1.0, 1.0) - }, - vertex { - vec2(pos2.x, pos1.y) - vec2(1.0, 0.0) - } - ) - } - } -} diff --git a/src/main/kotlin/com/lambda/graphics/renderer/gui/font/core/LambdaAtlas.kt b/src/main/kotlin/com/lambda/graphics/renderer/gui/font/core/LambdaAtlas.kt index 8093dc5a8..bc4004394 100644 --- a/src/main/kotlin/com/lambda/graphics/renderer/gui/font/core/LambdaAtlas.kt +++ b/src/main/kotlin/com/lambda/graphics/renderer/gui/font/core/LambdaAtlas.kt @@ -19,7 +19,7 @@ package com.lambda.graphics.renderer.gui.font.core import com.google.common.math.IntMath import com.lambda.core.Loadable -import com.lambda.graphics.texture.TextureOwner.uploadField +import com.lambda.graphics.texture.TextureOwner.upload import com.lambda.threading.runGameScheduled import com.lambda.util.math.Vec2d import com.lambda.util.stream @@ -206,7 +206,7 @@ object LambdaAtlas : Loadable { val str = "Loaded ${bufferPool.size} fonts" // avoid race condition runGameScheduled { - bufferPool.forEach { (owner, image) -> owner.uploadField(image) } + bufferPool.forEach { (owner, image) -> owner.upload(image) } bufferPool.clear() } diff --git a/src/main/kotlin/com/lambda/graphics/renderer/gui/font/sdf/DistanceFieldTexture.kt b/src/main/kotlin/com/lambda/graphics/renderer/gui/font/sdf/DistanceFieldTexture.kt deleted file mode 100644 index 65e78d2f1..000000000 --- a/src/main/kotlin/com/lambda/graphics/renderer/gui/font/sdf/DistanceFieldTexture.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2025 Lambda - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lambda.graphics.renderer.gui.font.sdf - -import com.lambda.graphics.buffer.frame.CachedFrame -import com.lambda.graphics.buffer.frame.FrameBuffer -import com.lambda.graphics.shader.Shader.Companion.shader -import com.lambda.graphics.texture.Texture -import com.lambda.util.math.Vec2d -import java.awt.image.BufferedImage - -/** - * A class that represents a distance field texture, which is created by rendering a given texture - * onto a framebuffer with specific shader operations. - * - * The texture is used to create a signed distance field (SDF) for rendering operations. - * - * @param image Image data to upload - */ -class DistanceFieldTexture(image: BufferedImage) : Texture(image, levels = 0) { - private val shader = shader("post/sdf") - - private val frame = CachedFrame(width, height).write { - FrameBuffer.pipeline.immediate { - val (pos1, pos2) = Vec2d.ZERO to Vec2d(width, height) - - buildQuad( - vertex { - vec2(pos1.x, pos1.y).vec2(0.0, 1.0) - }, - vertex { - vec2(pos1.x, pos2.y).vec2(0.0, 0.0) - }, - vertex { - vec2(pos2.x, pos2.y).vec2(1.0, 0.0) - }, - vertex { - vec2(pos2.x, pos1.y).vec2(1.0, 1.0) - } - ) - - shader.use() - shader["u_TexelSize"] = Vec2d.ONE / pos2 - super.bind(0) - } - } - - override fun bind(slot: Int) { - frame.bind(slot) - } -} diff --git a/src/main/kotlin/com/lambda/graphics/texture/AnimatedTexture.kt b/src/main/kotlin/com/lambda/graphics/texture/AnimatedTexture.kt index 95e69350f..3590dff00 100644 --- a/src/main/kotlin/com/lambda/graphics/texture/AnimatedTexture.kt +++ b/src/main/kotlin/com/lambda/graphics/texture/AnimatedTexture.kt @@ -17,7 +17,6 @@ package com.lambda.graphics.texture -import com.lambda.graphics.buffer.pixel.PixelBuffer import com.lambda.util.LambdaResource import com.lambda.util.stream import org.lwjgl.BufferUtils @@ -26,7 +25,6 @@ import java.nio.ByteBuffer class AnimatedTexture(path: LambdaResource) : Texture(image = null) { - private val pbo: PixelBuffer private val gif: ByteBuffer // Do NOT free this pointer private val frameDurations: IntArray // Array of frame duration milliseconds as ints val channels: Int @@ -51,7 +49,7 @@ class AnimatedTexture(path: LambdaResource) : Texture(image = null) { .position(blockSize * currentFrame) .limit(blockSize * (currentFrame + 1)) - pbo.upload(slice, offset = 0) + update(slice, width, height) gif.clear() currentFrame = (currentFrame + 1) % frames @@ -85,7 +83,5 @@ class AnimatedTexture(path: LambdaResource) : Texture(image = null) { frameDurations = IntArray(frames) pDelays.getIntBuffer(frames).get(frameDurations) - - pbo = PixelBuffer(this@AnimatedTexture) } } diff --git a/src/main/kotlin/com/lambda/graphics/texture/TextureOwner.kt b/src/main/kotlin/com/lambda/graphics/texture/TextureOwner.kt index 75e9adbb6..b568a45f1 100644 --- a/src/main/kotlin/com/lambda/graphics/texture/TextureOwner.kt +++ b/src/main/kotlin/com/lambda/graphics/texture/TextureOwner.kt @@ -17,7 +17,6 @@ package com.lambda.graphics.texture -import com.lambda.graphics.renderer.gui.font.sdf.DistanceFieldTexture import com.lambda.util.readImage import java.awt.image.BufferedImage @@ -93,16 +92,6 @@ object TextureOwner { textureMap.computeIfAbsent(this@upload) { mutableListOf() }.add(it) } - /** - * Uploads a distance field texture from image data and associates it with the object - * Distance field textures are commonly used for rendering fonts. - * - * @param data The image data as a [BufferedImage] to create the distance field texture - * @return The created distance field texture object - */ - fun Any.uploadField(data: BufferedImage) = - DistanceFieldTexture(data).also { textureMap.computeIfAbsent(this@uploadField) { mutableListOf() }.add(it) } - /** * Uploads a GIF and associates it with the object as an animated texture * diff --git a/src/main/kotlin/com/lambda/gui/MenuBar.kt b/src/main/kotlin/com/lambda/gui/MenuBar.kt index 21888de84..7cb3c529f 100644 --- a/src/main/kotlin/com/lambda/gui/MenuBar.kt +++ b/src/main/kotlin/com/lambda/gui/MenuBar.kt @@ -41,12 +41,9 @@ import imgui.ImGui.closeCurrentPopup import imgui.flag.ImGuiCol import imgui.flag.ImGuiStyleVar import imgui.flag.ImGuiWindowFlags -import imgui.type.ImString import net.fabricmc.loader.api.FabricLoader -import net.minecraft.client.Keyboard import net.minecraft.util.Util import net.minecraft.world.GameMode -import java.nio.file.Path import java.util.Locale object MenuBar { @@ -450,4 +447,4 @@ object MenuBar { } } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/lambda/network/CapeManager.kt b/src/main/kotlin/com/lambda/network/CapeManager.kt index dd8412894..99a549fed 100644 --- a/src/main/kotlin/com/lambda/network/CapeManager.kt +++ b/src/main/kotlin/com/lambda/network/CapeManager.kt @@ -23,7 +23,6 @@ import com.lambda.context.SafeContext import com.lambda.core.Loadable import com.lambda.event.events.WorldEvent import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.graphics.texture.TextureUtils import com.lambda.module.modules.client.Network.cdn import com.lambda.network.api.v1.endpoints.getCape import com.lambda.network.api.v1.endpoints.getCapes @@ -39,8 +38,10 @@ import com.lambda.util.FolderRegister.capes import com.lambda.util.StringUtils.asIdentifier import com.lambda.util.extension.resolveFile import kotlinx.coroutines.runBlocking +import net.minecraft.client.texture.NativeImage import net.minecraft.client.texture.NativeImage.read import net.minecraft.client.texture.NativeImageBackedTexture +import org.lwjgl.BufferUtils import java.util.* import java.util.concurrent.ConcurrentHashMap import kotlin.concurrent.fixedRateTimer @@ -100,7 +101,14 @@ object CapeManager : ConcurrentHashMap(), Loadable { .downloadIfNotPresent(cape.url).getOrNull() ?.readBytes() ?: return@runIO - mc.textureManager.registerTexture(cape.id.asIdentifier, NativeImageBackedTexture({ cape.id }, TextureUtils.readImage(bytes))) + val buffer = BufferUtils + .createByteBuffer(bytes.size) + .put(bytes) + .flip() + + val image = read(NativeImage.Format.RGBA, buffer) + + mc.textureManager.registerTexture(cape.id.asIdentifier, NativeImageBackedTexture({ cape.id }, image)) put(uuid, cape.id) }.invokeOnCompletion { block(it) }