Flujo y eventos
Flujo general
sequenceDiagram
participant P as Jugador
participant L as Loadingscreen
participant C as Client
participant S as Server
participant DB as MySQL
P->>L: Conecta
L-->>L: Barra de progreso (eventos FiveM)
L->>C: Carga completa → ShutdownLoadingScreen
C->>C: spawnmanager:setAutoSpawn(false)
C->>P: Muestra Menú Principal (NUI)
P->>C: Click "JUGAR"
C->>S: getCharacters
S->>DB: SELECT * FROM fiverank_intro_characters
DB-->>S: rows
S-->>C: Lista de slots (5)
C->>P: Char select + preview ped
P->>C: Selecciona slot
C->>S: selectCharacter(slot)
S->>DB: UPDATE last_played
S-->>C: { character, position }
C->>C: Cinematic.run() — descenso desde el cielo
C->>P: Control del personaje
Eventos del servidor
Llamados por el cliente
| Evento | Payload | Qué hace |
|---|---|---|
fiverank_intro:server:getCharacters | — | Devuelve los 5 slots del jugador |
fiverank_intro:server:createCharacter | {slot, firstname, lastname, dob, gender, nationality} | Crea/sobrescribe un slot |
fiverank_intro:server:deleteCharacter | slot:int | Borra un slot |
fiverank_intro:server:selectCharacter | slot:int | Marca el slot como activo y devuelve sus datos |
fiverank_intro:server:savePosition | slot, {x,y,z,h} | Guarda posición actual (auto cada 30 s) |
Disparados por el servidor
| Evento | Payload |
|---|---|
fiverank_intro:client:receiveCharacters | slots[] |
fiverank_intro:client:createResult | {ok, error?} |
fiverank_intro:client:deleteResult | {ok, slot} |
fiverank_intro:client:selectResult | {ok, character} |
Engancharse desde otros scripts
"El jugador acaba de entrar al mundo"
Al terminar la cinemática, FR Intro dispara el evento estándar de FiveM:
-- En cualquier client script:
AddEventHandler('playerSpawned', function()
print('El jugador completó la cinemática y tiene el control')
end)
Saber qué personaje eligió
-- client side
RegisterNetEvent('fiverank_intro:client:selectResult', function(res)
if res.ok then
print('Slot elegido:', res.character.slot)
print('Nombre:', res.character.firstname, res.character.lastname)
print('Modelo:', res.character.pedModel)
end
end)
Forzar abrir el menú de nuevo (ej. comando /cambiarpersonaje)
Esto no viene de caja, pero es trivial añadirlo en client/main.lua:
RegisterCommand('cambiarpersonaje', function()
TriggerServerEvent('fiverank_intro:server:getCharacters')
CharSelect.show(nil)
SendNUIMessage({ action = 'show', screen = 'charselect' })
SetNuiFocus(true, true)
end)
Persistencia
- Cada 30 segundos el cliente envía la posición actual al servidor.
- Se guarda en
fiverank_intro_characters.positioncomo JSON. - La próxima vez que el jugador entre a ese slot, la cinemática terminará en esas coordenadas.
Si quieres desactivar el auto-save y manejarlo tú, comenta el CreateThread al final de client/main.lua.
Integración con ESX / QBCore / qbx
FR Intro no reemplaza la lógica de personajes de tu framework. Guarda metadatos paralelos (slot, nombre cosmético, last_played, position) para controlar el flujo de entrada.
Si quieres que cada slot esté ligado a un citizenid (QB) o identifier (ESX)
específico, edita server/main.lua → selectCharacter:
RegisterNetEvent('fiverank_intro:server:selectCharacter', function(slot)
local src = source
-- ... existing code ...
if res.ok then
-- Carga el personaje en tu framework:
if Framework.name == 'qb' then
Framework.core.Player.Login(src, row.citizenid)
elseif Framework.name == 'esx' then
-- xPlayer.set('character', row.citizenid) etc.
end
end
end)
(Necesitarás añadir una columna citizenid a la tabla.)