EndCore Framework

Player data

The PlayerData table en-core keeps for every character, its fields, the metadata keys, and how new characters are set up.

Every character on an EndCore server has a PlayerData table. It holds who they are, their money, job, group, position and a metadata table with survival stats, XP and state flags. en-core loads it from the database when a character logs in, keeps it valid, sends it to the player's client, and saves it back.

To read or change it from another resource, use the Player API.

Characters and slots

Characters belong to a Rockstar license. One license can own several characters, and en-multicharacter shows the selection screen.

Key in config/server.luaDefaultWhat it does
characters.defaultNumberOfCharacters3Character slots per license
characters.playersNumberOfCharacters{}Per-license override, keyed by the full identifier
lua
-- config/server.lua
characters = {
    playersNumberOfCharacters = {
        ['license:0123456789abcdef'] = 5,
    },
    defaultNumberOfCharacters = 3,
},

PlayerData shape

lua
PlayerData = {
    source    = 1,
    citizenid = 'ENCAB12CD34',
    license   = 'license:...',
    name      = 'John Doe',
    money     = { cash = 500, bank = 1000 },
    charinfo  = {
        firstname = 'John', lastname = 'Doe', birthdate = '1990-01-01',
        gender = 0, nationality = 'USA', phone = '555-0123', account = 'US...',
    },
    job       = { name, label, grade, payment, isboss, onduty, type },
    jobs      = { survivor = 0, scavenger = 1 },
    group     = { id, name, tag, grade, rank, isleader }, -- or nil
    metadata  = { ... },
    position  = { x, y, z, heading },
}
FieldTypeWhat it holds
sourcenumberThe player's server ID while online
citizenidstringThe character's unique ID
licensestringThe Rockstar license that owns the character
namestring"First Last", set from charinfo when the character is created
moneytableOne balance per money type. See Money and cash.
charinfotableIdentity details, below
jobtableThe active job. See Jobs.
jobstableEvery job the character has held, mapped to its grade
grouptable or nilThe character's group summary. Attached at login, not stored on the character row. See Groups.
metadatatableSurvival stats, XP and state flags, below
positiontableThe last saved position and heading

Items are not part of PlayerData. Inventory belongs to en-inventory.

charinfo

KeyDefault if missingNotes
firstname'John'
lastname'Doe'
birthdate'1990-01-01'
gender00 male, 1 female
nationality'USA'
phonegeneratedFrom identifierFormat.phoneNumber()
accountgeneratedFrom identifierFormat.accountNumber()
backstorynoneOptional

Identifiers

Identifier formats are functions in config/server.lua, so you can change them.

FunctionDefault outputNotes
player.identifierFormat.citizenid()ENC plus 8 random letters and digitsRetried against the database up to 25 times until unique
player.identifierFormat.phoneNumber()555-0000 to 555-9999Used when charinfo.phone is missing
player.identifierFormat.accountNumber()US plus 14 digitsUsed when charinfo.account is missing
lua
-- config/server.lua, inside player = { ... }
identifierFormat = {
    citizenid = function()
        local chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
        local out = { 'WL' }
        for i = 1, 8 do
            local n = math.random(#chars)
            out[i + 1] = chars:sub(n, n)
        end
        return table.concat(out)
    end,
    -- phoneNumber and accountNumber as before
},

Existing characters keep their old citizenids. Keep the ID short enough for the citizenid VARCHAR(50) column.

How data is checked on load

Every time a character loads, en-core cleans up its data so other resources can rely on it:

  • Missing charinfo fields get the defaults in the table above.
  • A job that no longer exists in shared/jobs.lua falls back to survivor grade 0. A saved onduty = false is kept.
  • Old gang and gangs data is removed. EndCore uses groups instead.
  • An invalid position is replaced with defaultSpawn.
  • Any metadata key from player.defaultMetadata that is missing is filled in with its default.
  • metadata.level is recalculated from metadata.xp.

Metadata

KeyDefaultNotes
health200Reported by the client every 10 s when it changes, clamped 0–200
armor0Same as health, clamped 0–100
hunger1000–100. Drains every survival tick.
thirst1000–100. Drains every survival tick.
stamina100Stored only; en-core does not simulate it
stress0Stored only; en-core does not simulate it
radiation00–1000 by default (survival.radiation.max)
infection00–100 by default (survival.infection.max)
immunity1000–100 by default (survival.immunity.max)
temperature98.6Body temperature in °F. The setter clamps it to 70–120.
xp0Total XP
levelworked outDerived from xp. See XP and levels.
isdeadfalseSet by the death and revive flow
inlaststandfalseSet by the last stand event
receivedStarterItemsnot settrue after the starter kit is given
cashSyncednot setCash item bookkeeping
cashPendingnot setCash owed as items that did not fit

The survival stats are explained on Survival system, and the cash keys on Money and cash.

Adding your own metadata

Your resources can store their own values in metadata; they are saved with the character. To give every character a default, add the key to player.defaultMetadata. It is filled in on the next load for any character that does not have it yet.

lua
-- config/server.lua, inside player = { ... }
defaultMetadata = {
    health = 200,
    armor = 0,
    hunger = 100,
    thirst = 100,
    stamina = 100,
    stress = 0,
    radiation = 0,
    infection = 0,
    immunity = 100,
    temperature = 98.6,
    xp = 0,
    isdead = false,
    inlaststand = false,
    zombiekills = 0, -- your own key
},

Reading and writing metadata

WhereCallNotes
Server, player objectplayer.Functions.GetMetadata(key)
Server, player objectplayer.Functions.SetMetadata(key, value, save?)Sends the full PlayerData to the client
Server, player objectplayer.Functions.SetMetadataBulk(values)One client update for several keys
Server exportGetPlayerMetadata(source, key?)Cheap. Returns the whole table when key is nil.
Server exportSetPlayerMetadata(source, key, value)Cheap. Sends only the changed key.
Client exportGetMetadata(key?)Returns a stored false correctly

Every write fires encore:server:onSetMetaData(source, key, value) on the server and encore:client:onSetMetaData(key, value) on the client.

New characters

Key in config/shared.luaDefaultWhat it does
defaultSpawnvec4(-258.211, -293.077, 21.6114, 206.0)Where new characters appear, and the fallback for an invalid saved position
defaultMoney{ cash = 500, bank = 1000 }Starting balances
starterItems2 water, 3 bread, 1 radioGiven once per character

Starter items are given when the character loads, through the library's inventory interface. Each entry has a name, an amount and optional metadata, which can be a table or a function(source) that returns one. Once given, metadata.receivedStarterItems is set to true, so the kit is never given twice. If no inventory is running, the kit waits for a later login.

lua
-- config/shared.lua
starterItems = {
    {
        name = 'water',
        amount = 2,
        metadata = function(source)
            return { durability = 100, description = 'Clean water - essential for survival' }
        end,
    },
    { name = 'bandage', amount = 2, metadata = {} },
    { name = 'flashlight', amount = 1, metadata = {} },
},

Items must exist in en-inventory. See Add an item.

On the client

The client gets the full PlayerData on login (encore:client:onPlayerLoaded) and every time a player function changes it (encore:client:playerDataUpdate). Smaller changes arrive as encore:client:onSetMetaData(key, value). The export GetPlayerData() always returns the latest copy.

Examples

Count zombie kills in your own metadata key:

lua
-- server
local function addKill(source)
    local kills = exports['en-core']:GetPlayerMetadata(source, 'zombiekills') or 0
    exports['en-core']:SetPlayerMetadata(source, 'zombiekills', kills + 1)
end

Read a character's identity:

lua
-- server
local player = exports['en-core']:GetPlayer(source)
if player then
    local info = player.PlayerData.charinfo
    print(player.PlayerData.citizenid, info.firstname, info.lastname, info.phone)
end

Show survival stats on the client:

lua
-- client
local data = exports['en-core']:GetPlayerData()
if data then
    local meta = data.metadata
    print(('Hunger %d, thirst %d, radiation %d'):format(meta.hunger, meta.thirst, meta.radiation))
end