This page covers how other resources read and change a player through en-core. There are two ways in:
- The player object, fetched with
exports['en-core']:GetPlayer(source). It carries the full PlayerData and aFunctionstable of methods. - Per-source exports such as
GetMoney(source, 'cash')orGetPlayerMetadata(source, 'hunger'). They return just one value and are much cheaper to call often.
Exports for groups, XP, survival and content have their own pages: Groups, XP and levels, Survival system and Content registry.
The player object
Player = {
PlayerData = PlayerData, -- see the Player data page
Offline = false, -- true for objects from GetOfflinePlayer
Functions = { ... },
}Every function that changes state calls UpdatePlayerData(), which sends the full PlayerData to that player's client. Unless the player is offline, it also fires a server event encore:server:<event> with (source, ...) and a client event encore:client:<event> with (...). The event names are listed with each function below and on the Events page.
GetPlayer copies the whole object across the export boundary. It is fine for one-off actions, but avoid calling it every frame or inside large loops. Use the lightweight exports further down this page instead.
Player functions
Jobs and duty
| Function | Returns | Notes |
|---|---|---|
SetJob(jobName, grade?, skipUpdate?) | boolean | false if the job or grade does not exist. Resets onduty to the job's defaultDuty, records jobs[jobName] = grade, fires onJobUpdate(job). |
SetDuty(onduty?) | boolean (the new duty state) | Toggles when called with no argument. Fires onDutyUpdate(onduty). |
Money
| Function | Returns | Notes |
|---|---|---|
AddMoney(moneyType, amount, reason?) | boolean | false for an unknown type or an amount of 0 or less after rounding. Fires onMoneyChange(moneyType, amount, 'add', reason, balance). |
RemoveMoney(moneyType, amount, reason?) | boolean | false if it would go below 0 on a protected type, or the player does not carry enough cash item. Action 'remove'. |
SetMoney(moneyType, amount, reason?) | boolean | Action 'set' |
GetMoney(moneyType) | number | When cash is an item, counts the carried item in the inventory and worn backpack |
See Money and cash for the rules.
Metadata
| Function | Returns | Notes |
|---|---|---|
SetMetadata(key, value, save?) | nothing | With save = true the character is saved too. Fires onSetMetaData(key, value). |
SetMetadataBulk(values) | nothing | One client sync, then onSetMetaData fires once per key |
GetMetadata(key) | any |
XP
| Function | Returns | Notes |
|---|---|---|
AddXP(amount, reason?) | boolean | false when offline |
RemoveXP(amount, reason?) | boolean | false when offline |
GetXP() | number | Total XP |
GetLevel() | number |
Survival
| Function | Returns | Notes |
|---|---|---|
AddRadiation(amount, reason?) / RemoveRadiation(amount, reason?) | boolean | false if amount is 0 or less. Clamped. Fires onRadiationChange(newValue, action, reason). |
SetRadiation(amount, reason?) | nothing | Fires onRadiationChange(newValue, 'set', reason) |
GetRadiation() | number | |
AddInfection / RemoveInfection / SetInfection / GetInfection | same as radiation | Fires onInfectionChange |
AddImmunity / RemoveImmunity / GetImmunity | same as radiation | Fires onImmunityChange. There is no SetImmunity. |
SetTemperature(amount, reason?) | nothing | Clamped to 70–120 °F. Fires onTemperatureChange(temp, 'set', reason). |
GetTemperature() | number | |
AddHunger(amount) / RemoveHunger(amount) | boolean | Clamped 0–100. No reason and no dedicated event, only a PlayerData update. |
AddThirst(amount) / RemoveThirst(amount) | boolean | Same as hunger |
For the stat events, the first value is the resulting stat, not the amount that was added.
Inventory
These pass through to the library's inventory interface, which en-inventory implements. Without an inventory running they return nil, 0 or false.
| Function | Returns | Notes |
|---|---|---|
GetItemByName(name) | { name, label, count } or nil | nil when offline or the count is 0 |
GetItemCount(name) | number | |
AddItem(name, count, metadata?) | boolean | |
RemoveItem(name, count, metadata?) | boolean |
Saving and session
| Function | Returns | Notes |
|---|---|---|
UpdatePlayerData() | nothing | Sends encore:client:playerDataUpdate with the full PlayerData. Does nothing when offline. |
Save() | boolean | Reads the ped position on the server (skipping 0, 0, 0) and writes the row |
Logout() | nothing | Same as the Logout export. Does nothing when offline. |
When the QB bridge is active, it also adds Functions.SetGang, which does nothing. See Compatibility bridges.
Server exports
All server exports are called as exports['en-core']:Name(...).
Players and sessions
| Export | Arguments | Returns |
|---|---|---|
GetPlayers() | none | table<source, Player>, the online registry |
GetPlayer(source) | source | Player or nil |
GetPlayerByCitizenId(citizenid) | citizenid | Player or nil (online only) |
GetPlayerByIdentifier(license) | license | Player or nil. Only matches PlayerData.license, despite the name. |
GetOfflinePlayer(citizenid) | citizenid | Player with Offline = true, or nil |
Login(source, citizenid) | source, citizenid | Player or nil, err |
CreateCharacter(source, newData) | source, { charinfo = {...} } | Player or nil, err |
Logout(source, skipSave?) | source, skipSave | nothing |
SaveAllPlayers() | none | number of players saved |
Login checks that the character belongs to the connecting license, attaches the player's group, and fires encore:server:onPlayerLoaded(source, playerData) and encore:client:onPlayerLoaded(playerData). Error codes:
| Error | Meaning |
|---|---|
no_license | The player has no license identifier |
no_citizenid | No citizenid was passed |
character_not_found | No character with that citizenid |
not_your_character | The character belongs to another license |
character_already_online | The character is already in use |
CreateCharacter accepts { charinfo = {...} } or a bare charinfo table. It inserts the row but does not put the character in the world; call Login next. Error codes: no_license, no_slots_available, citizenid_generation_failed, insert_failed.
Logout saves the character (unless skipSave is true), removes it from the registry, and fires encore:server:onPlayerUnload(source, playerData) and encore:client:onPlayerUnload.
Offline players. Changes to an object from GetOfflinePlayer are only written when you call player.Functions.Save().
en-multicharacter is the resource that calls Login, CreateCharacter and DeleteCharacter for you.
Characters
| Export | Arguments | Returns |
|---|---|---|
GetCharacters(license) | license | Array of decoded character rows, oldest first |
GetCharacterSlots(license) | license | number |
DeleteCharacter(citizenid) | citizenid | boolean. Removes the character from its group first (leadership passes on), then deletes the row. |
LicenseOwnsCharacter(citizenid, license) | citizenid, license | boolean |
Never trust a citizenid sent by a client. Check it with LicenseOwnsCharacter against the sender's license before you load, delete or change that character.
Lightweight lookups
These touch only the value you ask for, so they are the right choice for polling and hot paths.
| Export | Arguments | Returns |
|---|---|---|
GetCitizenId(source) | source | string or nil |
IsPlayerLoaded(source) | source | boolean |
GetCharacterName(source) | source | "First Last" or nil |
GetPlayerMetadata(source, key?) | source, key | The value, or the whole metadata table when key is nil |
SetPlayerMetadata(source, key, value) | source, key, value | boolean |
AddMoney(source, moneyType, amount, reason?) | source, moneyType, amount, reason | boolean |
RemoveMoney(source, moneyType, amount, reason?) | source, moneyType, amount, reason | boolean |
GetMoney(source, moneyType) | source, moneyType | number (0 if not loaded) |
SetPlayerMetadata sends only encore:client:onSetMetaData(key, value) to the client and fires encore:server:onSetMetaData(source, key, value). It does not push the whole PlayerData. The value is saved with the character as usual.
Shared data and config
| Export | Returns |
|---|---|
GetJobs() | The job table from shared/jobs.lua |
GetVehicles() | The vehicle table from shared/vehicles.lua |
GetWeapons() | The weapon table from shared/weapons.lua |
GetSharedConfig() | config/shared.lua |
GetServerConfig() | config/server.lua |
GetGroupSettings() | shared/groups.lua |
GetLevels() | shared/levels.lua |
Identifiers and logging
| Export | Arguments | Returns |
|---|---|---|
GetIdentifier(source, idType) | source, 'license' / 'discord' / ... | string or nil. Prefix-anchored, so 'license' never matches license2:. |
GetAllIdentifiers(source) | source | table<type, identifier> |
Log(channel, message) | channel, message | nothing. Prints and posts to the channel's webhook, falling back to default. |
Client exports
| Export | Returns |
|---|---|
GetPlayerData() | The local PlayerData, or nil before login |
IsLoggedIn() | boolean |
GetMetadata(key?) | One value, or the whole metadata table. A stored false is returned correctly. |
GetLevelProgress() | { xp, level, into, needed, max } |
Notify(data) | Wraps encore.notify(data) |
GetVehicles() | The vehicle table |
GetVehiclesByName(name) | A vehicle entry, matched on its display name, case-insensitive |
GetVehiclesByHash(hash) | A vehicle entry |
GetWeapons() / GetWeapon(name) | The weapon table or one weapon |
GetJobs() | The job table |
The client global ENC (with ENC.PlayerData and helpers) is only visible inside en-core's own client scripts. Other resources should use the exports above.
Examples
Pay a player for a sale and promote them:
local player = exports['en-core']:GetPlayer(source)
if not player then return end
if player.Functions.AddMoney('cash', 250, 'Sold scrap') then
player.Functions.SetJob('scavenger', 1)
endCheap checks from a loop:
for _, src in ipairs(GetPlayers()) do
src = tonumber(src)
if exports['en-core']:IsPlayerLoaded(src) then
local hunger = exports['en-core']:GetPlayerMetadata(src, 'hunger')
if hunger and hunger < 10 then
encore.notify(src, { description = 'Your stomach is cramping.', type = 'warning' })
end
end
endCharge by source without fetching the player object:
if not exports['en-core']:RemoveMoney(source, 'bank', 100, 'Repair fee') then
encore.notify(source, { description = 'You cannot afford the repair.', type = 'error' })
endCreate a character and log in, as a character screen would:
local created, err = exports['en-core']:CreateCharacter(source, { charinfo = {
firstname = 'Ada', lastname = 'Reyes', birthdate = '1994-03-02', gender = 1, nationality = 'American',
} })
if not created then
print('create failed: ' .. err)
return
end
local player, loginErr = exports['en-core']:Login(source, created.PlayerData.citizenid)Edit an offline character:
local player = exports['en-core']:GetOfflinePlayer('ENCAB12CD34')
if player then
player.Functions.SetMetadata('radiation', 0)
player.Functions.Save()
endRead data on the client:
local data = exports['en-core']:GetPlayerData()
if data then
print(data.job.label, data.metadata.radiation)
end