EndCore Framework

en-multicharacter

Character selection and creation on a staged scene, with survivor condition cards, server-side validation and a safe spawn.

en-multicharacter is the character selection screen. After a player joins, the screen fades to a staged scene (by default the Sandy Shores motel lot) with a scripted camera and a preview ped.

Players see a card for each survivor: name, birth date, nationality, job, group tag, cash and bank, when they last played, and their condition (health, hunger, thirst, radiation, infection, immunity, dead). They can pick a survivor, create a new one (first and last name, date of birth, gender, nationality) or delete one, optionally confirmed by typing the first name. When en-clothing is running, the preview ped wears the character's saved look. /logout from en-core, or an admin unload, drops the player back into selection.

At a glance

Depends onen-core, en-ui (the creation dialog uses encore.inputDialog)
Optionalen-clothing (preview look), en-loading
Database tablesNone of its own. Characters live in en-core's tables
Config filesconfig.lua
Key bindsNone

How it works

  1. The selector opens automatically 500 ms after NetworkIsSessionStarted().
  2. Once the roster is on screen it fires en-multicharacter:client:opened and calls ShutdownLoadingScreen() and ShutdownLoadingScreenNui(), which closes en-loading.
  3. The number of character slots comes from en-core's GetCharacterSlots(license).
  4. When the player selects or creates a character, en-core logs them in and the client spawns: fade out, stream the scene around the destination, wait for collision (up to 10 seconds), fade in, then fire en-multicharacter:client:spawned.

New characters spawn at Config.newCharacterSpawn, or at en-core's default spawn when that is nil.

Security

  • A server-side "selecting" set gates every callback. A client that is already in the world cannot reopen selection and load a second character.
  • Ownership is re-checked with en-core's LicenseOwnsCharacter before select, delete and look requests.
  • Names, ages and nationalities are validated on the server with Config.validation. Unknown nationalities become 'Unknown'.
  • Character cards leave out metadata and last position, apart from survival condition.

Configuration

config.lua:

KeyDefaultWhat it does
Config.scene.pedvec4(1972.24, 3051.32, 47.21, 152.0)Preview ped position
Config.scene.cameravec3(1970.28, 3048.94, 47.55)Camera position
Config.scene.lookAtvec3(1972.24, 3051.32, 47.45)Camera target
Config.scene.fov42.0Camera field of view
Config.previewPeds[0] = 'mp_m_freemode_01', [1] = 'mp_f_freemode_01'Preview model by stored gender
Config.newCharacterSpawnnilvec4 for new survivors; nil uses en-core's default spawn
Config.confirmDeleteByNametrueRequire typing the first name to delete
Config.validationnameMinLength 2, nameMaxLength 24, namePattern "^[%a][%a%s'%-]*$", minAge 18, maxAge 90Enforced server-side
Config.nationalities32 entries (American ... Unknown)Choices in the creation dialog

Moving the scene and giving new survivors their own spawn:

lua
-- config.lua
Config.scene = {
    ped = vec4(1972.24, 3051.32, 47.21, 152.0),
    camera = vec3(1970.28, 3048.94, 47.55),
    lookAt = vec3(1972.24, 3051.32, 47.45),
    fov = 42.0,
}

Config.newCharacterSpawn = vec4(1853.8, 3689.4, 34.3, 210.0)
Config.validation.minAge = 16

Callbacks

en-multicharacter has no exports or commands. Its UI talks to the server through these encore.callback names:

NameArgumentsReturns
en-multicharacter:getCharacters{ characters, slots }; empty if already logged in
en-multicharacter:selectCharactercitizenid{ ok, position, isNew = false } or { ok = false, error }
en-multicharacter:createCharacter{ firstname, lastname, birthdate = 'YYYY-MM-DD', gender = 0 or 1, nationality }{ ok, position, isNew = true }
en-multicharacter:deleteCharactercitizenid{ ok }
en-multicharacter:getLookcitizeniden-clothing look or nil

Events

EventSidePayload
en-multicharacter:client:openedClient localThe selector is on screen
en-multicharacter:client:spawnedClient localposition = { x, y, z, heading }. The player is placed in the world; run post-spawn logic here

It listens to encore:client:playerUnloaded (reopens the selector), and on the server to encore:server:onPlayerUnload and playerDropped.

Examples

Greet a survivor once they are in the world:

lua
-- client
AddEventHandler('en-multicharacter:client:spawned', function(position)
    local data = exports['en-core']:GetPlayerData()
    encore.notify({ title = 'Welcome back', description = data.charinfo.firstname, type = 'inform' })
end)
Warning

If you replace en-multicharacter with your own selector, it must call ShutdownLoadingScreen() and ShutdownLoadingScreenNui(), or the loading screen never closes.