Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/CCBlueX/LiquidBounce/llms.txt

Use this file to discover all available pages before exploring further.

Overview

LiquidBounce provides extensive rendering utilities for drawing 2D overlays, 3D world objects, and managing render state.

Core Rendering Packages

  • net.ccbluex.liquidbounce.render - Core rendering engine
  • net.ccbluex.liquidbounce.utils.render - Rendering utilities and extensions

3D World Rendering

usePoseStack

Borrows a pose stack from the pool for transformations.
inline fun <T> usePoseStack(block: PoseStack.() -> T): T
Example:
usePoseStack {
    translate(x, y, z)
    scale(2.0f, 2.0f, 2.0f)
    // Render at transformed position
}

withPush

Pushes the pose stack, executes a block, then pops.
inline fun PoseStack.withPush(block: PoseStack.() -> Unit)
Example:
matrices.withPush {
    translate(0.5, 0.5, 0.5)
    // Transformation only applies within this block
}

DrawMode

Controls how geometry is submitted:
  • IMMEDIATE - Draw immediately
  • BATCH - Collect and draw in batch
enum class DrawMode {
    IMMEDIATE,
    BATCH
}

Rendering Context

WorldRenderEnvironment

Provides context for world rendering:
val renderHandler = handler<WorldRenderEvent> { event ->
    val env = event.worldRenderEnvironment
    
    env.withPush {
        // Your rendering code
    }
}

Common Rendering Utilities

Render Boxes

// Draw a box outline
fun drawBox(box: AABB, color: Color4b) {
    // Box rendering
}

// Draw filled box
fun drawFilledBox(box: AABB, color: Color4b) {
    // Filled box rendering
}

Render Lines

// Draw a line between two points
fun drawLine(
    from: Vec3,
    to: Vec3,
    color: Color4b,
    lineWidth: Float = 2.0f
)

Render Text in World

// Render text at world position
fun renderTextAtPosition(
    text: String,
    pos: Vec3,
    scale: Float = 1.0f
)

Rendering Events

WorldRenderEvent

Fired during world rendering.
val renderHandler = handler<WorldRenderEvent> { event ->
    // Draw ESP boxes, tracers, etc.
    for (entity in world.entities) {
        if (entity.shouldBeAttacked()) {
            drawBox(entity.boundingBox, Color4b(255, 0, 0, 100))
        }
    }
}

OverlayRenderEvent

Fired during overlay rendering (2D HUD).
val overlayHandler = handler<OverlayRenderEvent> { event ->
    // Draw 2D elements on screen
}

ScreenRenderEvent

Fired when rendering GUI screens.

Rendering Primitives

Color4b

Represents RGBA color.
val red = Color4b(255, 0, 0, 255)
val transparentBlue = Color4b(0, 0, 255, 100)

// From hex
val color = Color4b.fromHex(0xFF0000FF)

Vec3f

3D vector for positions and directions.
val position = Vec3f(x, y, z)

Batch Rendering

For performance, batch similar draw calls:
val batchCollector = BatchCollector()

// Collect draws
for (entity in entities) {
    batchCollector.draw(entity.box, color)
}

// Render all at once
batchCollector.flush()

Shader Usage

ClientShaders

Access built-in shaders:
ClientShaders.POSITION_COLOR
ClientShaders.POSITION_COLOR_TEXTURE

Custom Rendering Pipeline

val pipeline = RenderPipeline(
    vertexFormat = VertexFormat.POSITION_COLOR,
    mode = VertexFormat.Mode.QUADS
)

Rendering Examples

ESP Box Rendering

val espHandler = handler<WorldRenderEvent> { event ->
    val env = event.worldRenderEnvironment
    
    for (entity in world.entities) {
        if (!entity.shouldBeAttacked()) continue
        
        val box = entity.boundingBox
        val color = if (entity.isPlayer) {
            Color4b(255, 0, 0, 100)  // Red for players
        } else {
            Color4b(0, 255, 0, 100)  // Green for mobs
        }
        
        env.drawBox(box, color)
    }
}

Tracer Rendering

val tracerHandler = handler<WorldRenderEvent> { event ->
    val env = event.worldRenderEnvironment
    val eyePos = player.eyePosition
    
    for (entity in world.entities) {
        if (!entity.shouldBeAttacked()) continue
        
        val targetPos = entity.position()
        
        env.drawLine(
            from = eyePos,
            to = targetPos,
            color = Color4b(255, 255, 255, 200),
            lineWidth = 2.0f
        )
    }
}

Name Tags

val nameTagHandler = handler<WorldRenderEvent> { event ->
    val env = event.worldRenderEnvironment
    
    for (entity in world.entities) {
        val namePos = entity.position().add(0.0, entity.bbHeight + 0.3, 0.0)
        
        env.renderTextAtPosition(
            text = entity.name.string,
            pos = namePos,
            scale = 0.02f
        )
    }
}

Block ESP

val blockEspHandler = handler<WorldRenderEvent> { event ->
    val env = event.worldRenderEnvironment
    val searchRadius = 50
    
    for (x in -searchRadius..searchRadius) {
        for (y in -searchRadius..searchRadius) {
            for (z in -searchRadius..searchRadius) {
                val pos = player.blockPosition().offset(x, y, z)
                val block = world.getBlockState(pos).block
                
                if (block == Blocks.DIAMOND_ORE) {
                    val box = AABB.ofSize(pos.center(), 1.0, 1.0, 1.0)
                    env.drawFilledBox(box, Color4b(0, 255, 255, 50))
                    env.drawBox(box, Color4b(0, 255, 255, 200))
                }
            }
        }
    }
}

Custom Shapes

val customShapeHandler = handler<WorldRenderEvent> { event ->
    val env = event.worldRenderEnvironment
    
    env.withPush {
        translate(player.x, player.y, player.z)
        
        // Draw circle on ground
        val radius = 3.0
        val segments = 32
        
        for (i in 0 until segments) {
            val angle1 = (i.toDouble() / segments) * 2 * Math.PI
            val angle2 = ((i + 1).toDouble() / segments) * 2 * Math.PI
            
            val x1 = cos(angle1) * radius
            val z1 = sin(angle1) * radius
            val x2 = cos(angle2) * radius
            val z2 = sin(angle2) * radius
            
            drawLine(
                Vec3(x1, 0.0, z1),
                Vec3(x2, 0.0, z2),
                Color4b(255, 255, 0, 255)
            )
        }
    }
}

2D Overlay Rendering

Screen Coordinates

val overlayHandler = handler<OverlayRenderEvent> { event ->
    val screenWidth = mc.window.guiScaledWidth
    val screenHeight = mc.window.guiScaledHeight
    
    // Draw at screen position
    drawText(
        text = "LiquidBounce",
        x = 5f,
        y = 5f
    )
}

Render Statistics

val statsHandler = handler<OverlayRenderEvent> { event ->
    val stats = listOf(
        "FPS: ${mc.fps}",
        "Position: ${player.blockPosition()}",
        "Speed: ${getSpeed()}"
    )
    
    stats.forEachIndexed { index, stat ->
        drawText(
            text = stat,
            x = 5f,
            y = 5f + (index * 10f)
        )
    }
}

World to Screen Conversion

Convert 3D world positions to 2D screen coordinates:
fun worldToScreen(worldPos: Vec3): Vec2? {
    // Projection logic
    // Returns null if position is behind camera
}

Performance Tips

Use batch rendering for multiple objects with the same render state to improve performance.
Avoid creating new objects in render handlers - reuse objects or use object pools.
Rendering happens on the render thread - don’t perform game logic in render handlers.

Best Practices

  1. Use appropriate events - WorldRenderEvent for 3D, OverlayRenderEvent for 2D
  2. Batch similar draws - Reduce state changes
  3. Reuse resources - Don’t create new buffers every frame
  4. Cull invisible objects - Don’t render what’s not visible
  5. Use appropriate precision - Float for most rendering, Double for positions

Common Utilities

Distance Checks

fun shouldRender(entity: Entity): Boolean {
    val distance = player.distanceTo(entity)
    return distance <= renderDistance
}

Frustum Culling

fun isInView(box: AABB): Boolean {
    // Check if box is in camera frustum
}

See Also