Extending Players

BDSC supports dynamic, runtime-safe extension of player objects with custom data and methods. This lets you build modular logic without touching the core.


Add Data

Adds custom data to the player. Optionally replicated to the client.

Example

player:add_data("stats", { health = 100, stamina = 50 }, true)

Parameters

  • stats – key name for the data entry.

  • { health = 100, stamina = 50 } – table to store.

  • true – replicate to client (optional).


Add Methods

Attach custom methods that can later be executed via run_method.

Example

player:add_method("stats", "get_health", function(self)
    local stats = self:get_data("stats")
    return stats and stats.health or 0
end)

Usage

player:run_method("stats", "get_health")

Update Data

Modify an existing data block and optionally sync it.

Example

local stats = player:get_data("stats")
stats.health = stats.health - 10
player:set_data("stats", stats, true)

Remove Data

Removes a data key.

Example

player:remove_data("job")

Sync Data

Force a sync of all replicated data to the client.

Example

player:sync_data()

Dump All Data

Logs all currently stored player data.

Example

local data = player:get_data()
for k, v in pairs(data) do
    print(k .. ": " .. json.encode(v))
end

Here’s a concise section explaining how the on_save and on_destroy methods work when registered via namespaces:


Lifecycle Hooks

BDSC supports namespace-specific lifecycle methods that automatically run when certain player events occur.

These methods are defined under a specific namespace using add_method and are called internally during key moments in the player's lifecycle.

Supported Hooks

Hook Name
Description

on_save

Called when player:save() is triggered (e.g., on disconnect or manually).

on_destroy

Called when player:destroy() is triggered (e.g., on player drop).

How It Works

When a lifecycle event runs, BDSC will automatically check each namespace for these methods and call them in order.

Example

player:add_method("stats", "on_save", function(self)
    print("Saving stats for player:", self.meta.username)
end)

player:add_method("inventory", "on_destroy", function(self)
    print("Cleaning up inventory for:", self.meta.username)
end)

You do not need to manually call these - BDSC will handle them as long as they are added under a namespace using add_method(namespace, "on_save" | "on_destroy", fn).

Avoid long-running operations inside these hooks — keep them lightweight for stability.


Missing Method Safety

Calling a non-existent method will return nil.

Example

local result = player:run_method("missing")
print("Result:", result or "nil")

No Internal Access

Only the meta table is exposed. All other functionality data, methods, syncing - must be accessed via the public API.

Direct access to _extensions._data, _extensions._methods, or other internals is not possible and never required.


Quick Example

Below is a minimal, self-contained example that demonstrates how to create a player object and extend it externally using basic commands.

This includes:

  • Adding a stats data block

  • Defining custom methods (like get_health)

  • Syncing data to the client

  • Simulating damage

  • Handling save logic

local core = exports.bdsc:import()

-- Create and initialize a new player
RegisterCommand("make", function(src)
    local player = core.create_player(src)
    if not player then print("Failed to create player") return end

    -- Add initial stats
    player:add_data("stats", {
        health = 100,
        stamina = 50
    }, true)

    -- Add method to retrieve health
    player:add_method("stats", "get_health", function(self)
        local stats = self:get_data("stats")
        return stats and stats.health or 0
    end)

    -- Add save lifecycle method
    player:add_method("stats", "on_save", function()
        print("saving player stats")
    end)

    print("Player created and methods attached.")
end, false)

-- Check player health
RegisterCommand("hp", function(src)
    local player = core.get_player(src)
    if not player then print("No player found.") return end

    local hp = player:run_method("stats", "get_health")
    print("Health:", hp)
end, false)

-- Apply damage to the player
RegisterCommand("damage", function(src, args)
    local player = core.get_player(src)
    if not player then print("No player found.") return end

    local amount = tonumber(args[1]) or 10
    local stats = player:get_data("stats")
    stats.health = stats.health - amount

    player:set_data("stats", stats, true)
    print("Damaged player for", amount)
end, false)

Tip: Every player object supports runtime extension. You can safely add new data or methods at any point — even after creation.

Last updated