Skip to main content

Overview

The ClientModule class is the foundation for all modules (hacks) in LiquidBounce. It extends ToggleableValueGroup and implements EventListener, providing a complete framework for creating toggleable features with configuration and event handling. Package: net.ccbluex.liquidbounce.features.module

Class Declaration

open class ClientModule(
    name: String,
    val category: ModuleCategory,
    bind: Int = InputConstants.UNKNOWN.value,
    bindAction: InputBind.BindAction = InputBind.BindAction.TOGGLE,
    state: Boolean = false,
    val notActivatable: Boolean = false,
    val disableActivation: Boolean = notActivatable,
    val disableOnQuit: Boolean = false,
    aliases: List<String> = emptyList(),
    hide: Boolean = false
) : ToggleableValueGroup(null, name, state, aliases = aliases), EventListener

Constructor Parameters

name
String
required
Module name displayed in UI and commands
category
ModuleCategory
required
Module category (Combat, Movement, Player, Render, World, Exploit, Misc, Fun)
bind
Int
default:"InputConstants.UNKNOWN.value"
Default keybind (use GLFW key constants)
bindAction
InputBind.BindAction
default:"TOGGLE"
Binding behavior: TOGGLE, HOLD, or SMART
state
Boolean
default:"false"
Default enabled state
notActivatable
Boolean
default:"false"
If true, module cannot be toggled by user (utility modules)
disableActivation
Boolean
default:"notActivatable"
Prevents module from being enabled
disableOnQuit
Boolean
default:"false"
Auto-disables module when leaving server
aliases
List<String>
default:"emptyList()"
Alternative names for the module
hide
Boolean
default:"false"
Default hidden state (hides from ArrayList)

Properties

running
Boolean
Whether the module is actively running (enabled + in-game)
override val running: Boolean
    get() = super<EventListener>.running && inGame && (enabled || notActivatable)
bind
InputBind
Current keybind configuration
val bind: InputBind
hidden
Boolean
Whether module is hidden from ArrayList
var hidden: Boolean
tag
String?
Optional tag displayed in ArrayList (e.g., mode name)
open val tag: String?
settings
Map<String, Value<*>>
Map of all module settings accessible by name
@ScriptApiRequired
open val settings: Map<String, Value<*>>
baseKey
String
Translation key prefix for this module
override val baseKey: String = "${ConfigSystem.KEY_PREFIX}.module.${name.toLowerCamelCase()}"

Lifecycle Methods

onRegistration

open fun onRegistration()
Called when the module is registered in ModuleManager. Override to perform initialization.

onToggled

final override fun onToggled(state: Boolean): Boolean
Called when module state changes. Handles notifications and events. Do not override - use onEnable()/onDisable() instead.

enabledEffect

open suspend fun enabledEffect()
Launches an async coroutine task when module is enabled. Useful for repeating tasks. Example:
override suspend fun enabledEffect() {
    while (enabled) {
        // Repeating task
        delay(1000)
    }
}

Inherited from ToggleableValueGroup

open fun onEnable()
open fun onDisable()
Override these methods to implement module enable/disable logic.

Methods

tagBy

fun tagBy(setting: Value<*>)
Sets a value to be displayed as the module tag. Example:
val mode by choices("Mode", arrayOf("Speed", "Damage"), "Speed")

init {
    tagBy(mode)
}

message

fun message(key: String, vararg args: Any): MutableComponent
Creates a translated message component for this module.
val msg = message("targetFound", targetName)

verifyFallbackDescription

fun verifyFallbackDescription()
Warns if module is missing translation description. Used during development.

Creating Modules

Basic Module

object ModuleExample : ClientModule(
    name = "Example",
    category = ModuleCategories.MISC
) {
    override fun onEnable() {
        chat("Module enabled!")
    }
    
    override fun onDisable() {
        chat("Module disabled!")
    }
}

Module with Settings

object ModuleFly : ClientModule(
    name = "Fly",
    category = ModuleCategories.MOVEMENT
) {
    val speed by float("Speed", 1.0f, 0.1f..5.0f)
    val mode by choices("Mode", arrayOf("Vanilla", "Damage"), "Vanilla")
    
    override fun onEnable() {
        // Use settings
        player.abilities.mayfly = true
    }
}

Module with Event Handlers

object ModuleAutoJump : ClientModule(
    name = "AutoJump",
    category = ModuleCategories.MOVEMENT
) {
    val tickHandler = handler<GameTickEvent> {
        if (player.onGround) {
            player.jumpFromGround()
        }
    }
}

Module with Modes

object ModuleSpeed : ClientModule(
    name = "Speed",
    category = ModuleCategories.MOVEMENT
) {
    private val modes = choices("Mode", 
        SpeedBHop,
        SpeedStrafe,
        SpeedYPort
    )
    
    object SpeedBHop : ChoiceConfigurable(this, "BHop") {
        val speed by float("Speed", 1.0f, 0.1f..3.0f)
    }
}

Best Practices

  1. Use descriptive names - Module names appear in UI and commands
  2. Set appropriate category - Helps users find your module
  3. Add keybinds for commonly used modules - Improves UX
  4. Use disableOnQuit for modules that shouldn’t persist across sessions
  5. Implement enabledEffect() for background tasks instead of tick handlers
  6. Use tagBy() to show current mode in ArrayList

See Also

Build docs developers (and LLMs) love