Skip to main content

Friend System

The Friend System in LiquidBounce allows you to mark players as friends, preventing accidental attacks and identifying them with special markers. The FriendManager handles all friend-related operations.

Overview

The Friend System provides:

Friend Management

Add, remove, and organize friends

Attack Prevention

Optionally prevent attacking friends

Visual Markers

Friends are tagged in-game for easy identification

Aliases

Set custom display names for friends

Friend Manager

The FriendManager is a config-based singleton:
object FriendManager : Config("Friends"), EventListener {
    val friends by list(name, TreeSet<Friend>(), valueType = ValueType.FRIEND)
    private val cancelAttack by boolean("CancelAttack", false)
}
Friends are stored in a TreeSet which keeps them sorted alphabetically by name.

Friend Class

Each friend is represented by a Friend object:
class Friend(val name: String, var alias: String?) : Comparable<Friend> {
    
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false
        other as Friend
        return name == other.name
    }
    
    override fun hashCode(): Int = name.hashCode()
    
    override fun compareTo(other: Friend): Int = 
        this.name.compareTo(other.name)
    
    fun getDefaultName(id: Int): String = "Friend $id"
}

Key Properties

  • name: The friend’s username (immutable, used for equality)
  • alias: Optional custom display name
  • Comparable: Friends are sorted alphabetically
  • Equality: Based solely on username (case-sensitive)

Adding Friends

Add a friend to the list:
val friend = FriendManager.Friend("PlayerName", alias = null)
FriendManager.friends.add(friend)

// Store to config
ConfigSystem.store(FriendManager)
With an alias:
val friend = FriendManager.Friend(
    name = "PlayerName",
    alias = "My Best Friend"
)
FriendManager.friends.add(friend)
ConfigSystem.store(FriendManager)
Friends are automatically deduplicated by username due to the TreeSet and equals() implementation.

Removing Friends

Remove a friend by name:
FriendManager.friends.remove(
    FriendManager.Friend("PlayerName", null)
)
ConfigSystem.store(FriendManager)
The Friend class’s equals() method only checks the name, so you don’t need to know the alias to remove a friend.

Checking Friend Status

By Username

if (FriendManager.isFriend("PlayerName")) {
    // Player is a friend
}

By Entity

if (FriendManager.isFriend(entity)) {
    // Entity is a friend (must be a Player)
}
Implementation:
fun isFriend(name: String): Boolean = 
    friends.contains(Friend(name, null))

fun isFriend(entity: Entity): Boolean = 
    entity is Player && isFriend(entity.gameProfile.name)
Friend checks are case-sensitive and use exact username matching.

Managing Aliases

Set or update a friend’s alias:
val friend = FriendManager.friends.find { it.name == "PlayerName" }
friend?.alias = "New Nickname"
ConfigSystem.store(FriendManager)
Remove an alias:
val friend = FriendManager.friends.find { it.name == "PlayerName" }
friend?.alias = null
ConfigSystem.store(FriendManager)

Attack Prevention

The Friend System can prevent attacking friends:
private val cancelAttack by boolean("CancelAttack", false)

private val onAttack = handler<AttackEntityEvent> {
    if (cancelAttack && isFriend(it.entity)) {
        it.cancelEvent()
    }
}

Usage

Enable attack prevention:
// Through config or settings UI
FriendManager.cancelAttack = true
When enabled:
  • All AttackEntityEvent for friends are cancelled
  • Combat modules will skip friends
  • Manual attacks (clicking) on friends are blocked
This setting is stored in the configuration and persists across sessions.

Friend Tagging

Friends are automatically tagged in-game:
private val tagEntityEvent = handler<TagEntityEvent> {
    if (isFriend(it.entity)) {
        it.assumeFriend()
    }
}
This allows:
  • Visual identification (different name colors, markers)
  • Other modules to recognize friends
  • ESP and other rendering modules to highlight friends differently

Storage and Persistence

Friends are stored through the config system:
init {
    ConfigSystem.root(this)
}
As a root config:
  • Friends are saved to .liquidbounce/friends.json
  • Automatically loaded on client startup
  • Persisted when modified via ConfigSystem.store(FriendManager)

Storage Format

{
  "friends": [
    {
      "name": "Player1",
      "alias": null
    },
    {
      "name": "Player2",
      "alias": "Best Friend"
    }
  ],
  "CancelAttack": true
}

Event Integration

The Friend System listens to two events:
Fired when an entity is being tagged for rendering/identification:
handler<TagEntityEvent> {
    if (isFriend(it.entity)) {
        it.assumeFriend()
    }
}
This ensures friends are visually marked in-game.

Use Cases

Add teammates as friends to prevent combat modules from targeting them:
// Add all team members
teamMembers.forEach { username ->
    FriendManager.friends.add(
        FriendManager.Friend(username, alias = null)
    )
}
ConfigSystem.store(FriendManager)
Combine with attack prevention to create safe interactions:
// Enable attack prevention
FriendManager.cancelAttack = true

// Add allies
FriendManager.friends.add(
    FriendManager.Friend("AllyPlayer", "Ally")
)
Use aliases to add role information:
FriendManager.friends.add(
    FriendManager.Friend("Player1", "Leader")
)
FriendManager.friends.add(
    FriendManager.Friend("Player2", "Support")
)

Module Integration

Modules can check friend status to modify behavior:
// In a combat module
val targetHandler = handler<EntityTargetEvent> {
    if (FriendManager.isFriend(it.entity)) {
        it.excludeFromTargeting()
    }
}

// In an ESP module
val renderHandler = handler<EntityRenderEvent> {
    val color = if (FriendManager.isFriend(it.entity)) {
        Color.GREEN  // Friends in green
    } else {
        Color.RED    // Others in red
    }
    renderBox(it.entity, color)
}

Friend Commands

Friends can be managed via commands:
// Add friend
.friend add PlayerName
.friend add PlayerName "Alias"

// Remove friend
.friend remove PlayerName

// List friends
.friend list

// Clear all
.friend clear

Code References

FriendManager.kt

Complete friend system implementation - line 32
features/misc/FriendManager.kt (81 lines)

Best Practices

1

Validate Usernames

Ensure usernames are valid before adding (1-16 characters, alphanumeric)
2

Store After Modifications

Always call ConfigSystem.store(FriendManager) after adding/removing friends
3

Use Attack Prevention Wisely

Only enable attack prevention when actually needed to avoid confusion
4

Handle Null Aliases

Check for null aliases before displaying to avoid display issues
5

Case Sensitivity

Remember that friend checks are case-sensitive

Build docs developers (and LLMs) love