Skip to content

Player Interaction Library

Player-to-player and entity interaction management system for the Lilia framework.


Overview

The player interaction library provides comprehensive functionality for managing player interactions and actions within the Lilia framework. It handles the creation, registration, and execution of various interaction types including player-to-player interactions, entity interactions, and personal actions. The library operates on both server and client sides, with the server managing interaction registration and validation, while the client handles UI display and user input. It includes range checking, timed actions, and network synchronization to ensure consistent interaction behavior across all clients. The library supports both immediate and delayed actions with progress indicators, making it suitable for complex interaction systems like money transfers, voice changes, and other gameplay mechanics.


lia.playerinteract.isWithinRange(client, entity, customRange)

Check if a client is within a usable range of an entity.

Before running interaction logic or building interaction menus.

Parameters:

Player client The player attempting the interaction.

Entity entity Target entity to test.

number customRange optional Optional override distance in Hammer units (default 100).

Returns:

boolean true if both are valid and distance is within range.

Example Usage:

    -- Validate a timed hack action before starting the progress bar.
    local function tryHackDoor(client, door)
        if not lia.playerinteract.isWithinRange(client, door, 96) then
            client:notifyLocalized("tooFarAway")
            return
        end
        client:setAction("@hackingDoor", 5, function()
            if IsValid(door) then door:Fire("Unlock") end
        end)
    end

lia.playerinteract.getInteractions(client)

Collect interaction options for the entity the player is aiming at.

When opening the interaction menu (TAB keybind) to populate entries.

Parameters:

Player client optional Player to use for trace; defaults to LocalPlayer on client.

Returns:

table Map of interaction name → data filtered for the target.

Example Usage:

    -- Server: send only valid interactions for the traced entity.
    net.Receive("liaRequestInteractOptions", function(_, ply)
        local interactions = lia.playerinteract.getInteractions(ply)
        local categorized = lia.playerinteract.getCategorizedOptions(interactions)
        lia.net.writeBigTable(ply, "liaInteractionOptions", categorized)
    end)

lia.playerinteract.getActions(client)

Gather personal actions that do not require a target entity.

When opening the personal actions menu (G keybind).

Parameters:

Player client optional Player to evaluate; defaults to LocalPlayer on client.

Returns:

table Map of action name → data available for this player.

Example Usage:

    -- Filter actions for a character sheet panel.
    local actions = lia.playerinteract.getActions(ply)
    for name, data in pairs(actions) do
        if name:find("changeTo") then
            -- add a voice toggle button
        end
    end

lia.playerinteract.getCategorizedOptions(options)

Transform option map into a categorized, ordered list for UI display.

Before rendering interaction/action menus that use category headers.

Parameters:

table options Map of name → option entry (expects `opt.category`).

Returns:

table Array containing category rows followed by option entries.

Example Usage:

    -- Build an options array with headers for a custom menu.
    local options = lia.playerinteract.getCategorizedOptions(interactions)
    local panel = vgui.Create("liaOptionsPanel")
    panel:Populate(options)

lia.playerinteract.addInteraction(name, data)

Register a targeted interaction and ensure timed actions wrap onRun.

Server startup or dynamically when new context interactions are added.

Parameters:

string name Unique interaction key.

table data Fields: `onRun`, `shouldShow`, `range`, `target`, `category`,

Example Usage:

    lia.playerinteract.addInteraction("zipTie", {
        target = "player",
        range = 96,
        category = "categoryRestraint",
        timeToComplete = 4,
        actionText = "@tying",
        targetActionText = "@beingTied",
        shouldShow = function(client, target)
            return target:IsPlayer() and not target:getNetVar("ziptied")
        end,
        onRun = function(client, target)
            target:setNetVar("ziptied", true)
        end
    })

lia.playerinteract.addAction(name, data)

Register a self-action (no target) and auto-wrap timed executions.

Server startup or dynamically to add personal actions/emotes.

Parameters:

string name Unique action key.

table data Fields similar to interactions but no target differentiation.

Example Usage:

    lia.playerinteract.addAction("wave", {
        category = "categoryEmotes",
        timeToComplete = 1,
        actionText = "@gesturing",
        onRun = function(client)
            client:DoAnimation(ACT_GMOD_GESTURE_WAVE)
        end
    })

lia.playerinteract.sync(client)

Push registered interactions/actions and categories to clients.

After definitions change or when a player joins to keep menus current.

Parameters:

Player client optional Send to one player if provided; otherwise broadcast in batches.

Example Usage:

    if lia.playerinteract.hasChanges() then
        lia.playerinteract.sync() -- broadcast updates
    end

lia.playerinteract.hasChanges()

Determine if interaction/action definitions changed since last sync.

Prior to syncing to avoid unnecessary network traffic.

Returns:

boolean true when counts differ from the last broadcast.

Example Usage:

    if lia.playerinteract.hasChanges() then
        lia.playerinteract.sync()
    end

lia.playerinteract.openMenu(options, isInteraction, titleText, closeKey, netMsg, preFiltered)

Open the interaction or personal action menu on the client.

After receiving options from the server or when keybind handlers fire.

Parameters:

table options Array of option entries plus category rows.

boolean isInteraction true for interaction mode; false for personal actions.

string titleText optional Optional menu title override.

number closeKey optional Optional key code to close the menu.

string netMsg optional Net message name to send selections with.

boolean preFiltered optional If true, options are already filtered for target/range visibility.

Returns:

Panel|nil The created menu panel.

Example Usage:

    net.Receive("liaSendInteractOptions", function()
        local data = lia.net.readBigTable()
        local categorized = lia.playerinteract.getCategorizedOptions(data)
        lia.playerinteract.openMenu(categorized, true, L("interactionMenu"))
    end)