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.
Blink is a powerful feature that allows you to queue network packets and release them later, creating the appearance of lag or enabling advanced movement techniques.
Overview
The BlinkManager (features/blink/BlinkManager.kt:75) intercepts network packets and stores them in a queue instead of sending them immediately. When flushed, all queued packets are sent at once.
How It Works
Packet Queueing
Intercept Packets
The PacketEvent handler intercepts all packets (BlinkManager.kt:125)
Check Action
Fires BlinkPacketEvent to determine if the packet should be queued
Queue or Pass
Based on the action, the packet is either queued or allowed through
Store Snapshot
Queued packets are stored with origin and timestamp
Packet Queue
val packetQueue: ConcurrentLinkedQueue < PacketSnapshot > = Queues. newConcurrentLinkedQueue ()
Each snapshot contains:
data class PacketSnapshot (
val packet: Packet <*>,
val origin: TransferOrigin , // INCOMING or OUTGOING
val timestamp: Long
)
Blink Actions
The BlinkPacketEvent returns one of three actions:
enum class Action ( val priority: Int ) {
FLUSH ( 0 ), // Send all queued packets
PASS ( 1 ), // Let this packet through
QUEUE ( 2 ), // Queue this packet
}
Actions are prioritized by their value, with FLUSH taking precedence (BlinkManager.kt:289-293).
Packet Filtering
Certain packets are never queued:
Always Passed
Connection packets (ClientIntentionPacket, ServerboundStatusRequestPacket, ServerboundPingRequestPacket)
Chat messages (ServerboundChatPacket, ClientboundSystemChatPacket, ServerboundChatCommandPacket)
Implementation (BlinkManager.kt:145-154):
when (packet) {
is ClientIntentionPacket, is ServerboundStatusRequestPacket,
is ServerboundPingRequestPacket -> {
return @handler
}
is ServerboundChatPacket, is ClientboundSystemChatPacket,
is ServerboundChatCommandPacket -> {
return @handler
}
}
Auto-Flush Triggers
Some packets trigger automatic flush:
Teleport : ClientboundPlayerPositionPacket
Disconnect : ClientboundDisconnectPacket
Death : ClientboundSetHealthPacket with health ≤ 0
This prevents desyncs and ensures game-critical packets are processed (BlinkManager.kt:157-171).
Ignored Packets
Player hurt sounds are ignored to reduce queue spam:
is ClientboundSoundPacket if packet.sound. value () == SoundEvents.PLAYER_HURT -> {
return @handler
}
Flushing Packets
By Origin
Flush all packets from a specific origin:
BlinkManager. flush (TransferOrigin.OUTGOING) // Send queued outgoing packets
BlinkManager. flush (TransferOrigin.INCOMING) // Process queued incoming packets
By Condition
Flush packets matching a condition:
BlinkManager. flush { snapshot ->
snapshot.timestamp < someTimestamp
}
By Count
Flush a specific number of movement packets:
BlinkManager. flush (count = 10 ) // Flush first 10 movement packets
Implementation (BlinkManager.kt:233-254):
fun flush (count: Int ) {
var counter = 0
with (packetQueue. iterator ()) {
while ( hasNext ()) {
val snapshot = next ()
val packet = snapshot.packet
if (packet is ServerboundMovePlayerPacket && packet.hasPos) {
counter += 1
}
flushSnapshot (snapshot)
remove ()
if (counter >= count) {
break
}
}
}
}
Canceling Blink
Cancel blink and teleport to the first queued position:
This:
Teleports player to first queued position
Flushes all non-movement packets
Discards movement packets
Clears the queue
Implementation (BlinkManager.kt:256-268):
fun cancel () {
positions. firstOrNull ()?. let { pos ->
player. setPos (pos)
}
for (snapshot in packetQueue) {
when (snapshot.packet) {
is ServerboundMovePlayerPacket -> continue
else -> flushSnapshot (snapshot)
}
}
packetQueue. clear ()
}
Position Tracking
Get queued player positions:
val positions = BlinkManager.positions
This extracts positions from queued ServerboundMovePlayerPackets (BlinkManager.kt:78-82):
val positions
get () = packetQueue
. map { snapshot -> snapshot.packet }
. filterIsInstance < ServerboundMovePlayerPacket > { it.hasPos }
. map { Vec3 (it.x, it.y, it.z) }
Lag Detection
val isLagging = BlinkManager.isLagging
Returns true if there are queued packets (BlinkManager.kt:84-85).
Packet Rewriting
Modify queued packets before flushing:
BlinkManager. rewrite < ServerboundMovePlayerPacket > { packet ->
// Modify packet
packet.x += 1.0
}
This uses inline reified generics to filter and modify packets (BlinkManager.kt:275-277).
Time-Based Flushing
Check if packets have been queued longer than a delay:
if (BlinkManager. isAboveTime ( 1000L )) {
// Packets have been queued for >1 second
BlinkManager. flush (TransferOrigin.OUTGOING)
}
Implementation (BlinkManager.kt:270-273):
fun isAboveTime (delay: Long ): Boolean {
val entryPacketTime = (packetQueue. firstOrNull ()?.timestamp ?: return false )
return System. currentTimeMillis () - entryPacketTime >= delay
}
Visual Feedback
ESP Modes
Blink includes multiple ESP modes for visualization:
Box - Draws a box at the blink position
Model - Renders a player model
Wireframe - Shows wireframe rendering
None - No visualization
Modes are configured via:
private val espMode = modes ( this , "Esp" , 2 ) {
arrayOf (
BlinkEspBox (it, :: getEspData ),
BlinkEspModel (it, getEspData = :: getEspData ),
BlinkEspWireframe (it, :: getEspData ),
BlinkEspNone (it),
)
}
Line Trail
Draws a line showing the blink path:
private val lineColor by color ( "Line" , Color4b.LIQUID_BOUNCE)
private val renderHandler = handler < WorldRenderEvent > { event ->
val matrixStack = event.matrixStack
if (lineColor.a > 0 ) {
renderEnvironmentForWorld (matrixStack) {
drawLineStrip (
argb = lineColor.argb,
positions = positions. mapToArray { Vec3f ( relativeToCamera (it)) },
)
}
}
}
Event Handlers
Auto-Flush Handlers
Blink automatically attempts to flush based on game events:
// Flush outgoing packets each render frame
private val flushHandler = handler < GameRenderTaskQueueEvent > {
if ( fireEvent ( null , TransferOrigin.OUTGOING) == Action.FLUSH) {
flush (TransferOrigin.OUTGOING)
}
}
// Flush incoming packets each tick
private val flushReceiveHandler = handler < TickPacketProcessEvent > {
if ( fireEvent ( null , TransferOrigin.INCOMING) == Action.FLUSH) {
flush (TransferOrigin.INCOMING)
}
}
World Change Handler
Clears packets on disconnect:
private val worldChangeHandler = handler < WorldChangeEvent > { event ->
if (event.world == null ) {
packetQueue. clear ()
}
}
Use Cases
Lag Switch
Simulate lag to confuse opponents:
// Queue packets for 2 seconds
if (BlinkManager. isAboveTime ( 2000 )) {
BlinkManager. flush (TransferOrigin.OUTGOING)
}
Advanced Movement
Queue movement packets and release them to teleport:
// Move while blinking
// Then flush to appear to teleport
BlinkManager. flush (TransferOrigin.OUTGOING)
Desync
Create client-server position desync:
// Cancel to snap back to first position
BlinkManager. cancel ()
Gradual Flush
Flush packets gradually:
// Flush 5 movement packets per tick
BlinkManager. flush (count = 5 )
Best Practices
Blink automatically clears on world change. Don’t manually clear unless needed.
Don’t prevent auto-flush for teleport/death packets - this can cause severe desyncs.
Large queues can cause lag spikes when flushed. Consider periodic partial flushes.
When in doubt, use cancel() instead of flush() to prevent invalid game states.
Configuration
Blink is configured as a ValueGroup:
object BlinkManager : EventListener , ValueGroup ( "BlinkManager" )
This allows it to be toggled and configured through the client’s module system.