Saltar al contenido
CXGdocs.GUÍAS
Cxg gtfatIntegrar GTFAT con otros recursos
CXG DOCUMENTATION

Integrar GTFAT con otros recursos

Los archivos bridge/*.lua son puntos de adaptación editables para conectar permisos, persistencia, avisos, estaciones y formatos de apariencia. Los parches de menús son cambios manuales a versiones concretas: el recurso no modifica otros recursos al instalarse.

Menús de apariencia

Hay parches preparados para estos repositorios y revisiones:

MenúRevisión de origenAcción adicional
illenium-appearance1b003ec169b15f145d519438ba7c6454bf746f27Aplicar el parche Lua de guardado de componentes.
fivem-appearanceb06da32881ed49042909b38a778c10dd9bd9eaedAplicar el parche y reconstruir el bundle de TypeScript del juego con el flujo build:game.
qb-clothing8cca4009dd473ab30c30e443ecad50830b816ed7Aplicar el parche a los límites de guardado de skin y outfit.
esx_skin / skinchangerfe59ca0bd6da59e2ec6eb4a8d06ece312e96ae7aEl parche está relativo a la raíz del repositorio esx_core.

Los archivos son illenium-appearance.patch, fivem-appearance.patch, qb-clothing.patch y skinchanger.patch en la carpeta integrations del paquete. No se aplican automáticamente. En un checkout de desarrollo del menú, valida el parche correcto antes de aplicarlo:

Código
git apply --check /ruta/al/parche-correcto.patch
git apply /ruta/al/parche-correcto.patch

Si la comprobación falla, detente y adapta el cambio a la versión instalada; no fuerces el parche. Los forks y revisiones más recientes pueden diferir. El parche de fivem-appearance requiere reconstruir el bundle con el flujo build:game según las instrucciones de ese menú. Estos parches no certifican todas las versiones ni equivalen a una prueba en tu servidor.

El guardado sanitiza el decal técnico para que un menú no lo persista como selección ordinaria del jugador. Los menús que conservan su propia tabla de apariencia deben invocar el saneamiento en su punto de guardado. El peso queda separado de los outfits.

Guardar una apariencia propia

El export cliente SanitizeAppearance devuelve una copia de la apariencia. Los formatos incluidos son components, qb y esx:

Código
local appearanceCopy = exports['CXG_GTFAT']:SanitizeAppearance(
    ped,
    appearance,
    'components'
)

GuardarApariencia(appearanceCopy)

GuardarApariencia es una llamada de ejemplo: sustitúyela por la función de guardado de tu menú. components admite un arreglo de componentes o un objeto con la propiedad components; cada componente usa component_id, drawable, texture y opcionalmente palette. El formato qb usa el campo decals con item y texture; esx usa decals_1 y decals_2. El export devuelve una copia profunda y conserva los demás campos sin cambiar temporalmente el ped. Si el adaptador de formato falla o el formato no se reconoce, devuelve la copia sin modificar y registra un diagnóstico.

Registrar un ped de preview

Si el menú usa un ped de previsualización distinto del personaje, registra el preview correspondiente al personaje activo. Retíralo antes de eliminar la entidad:

Código
local previewPed = ObtenerPreviewActual()

if previewPed and DoesEntityExist(previewPed) then
    exports['CXG_GTFAT']:RegisterPreviewPed(previewPed)
end

-- Al cerrar o cancelar el menú, antes de eliminar el ped:
exports['CXG_GTFAT']:UnregisterPreviewPed(previewPed)
EliminarPreview(previewPed)

ObtenerPreviewActual y EliminarPreview son llamadas de ejemplo: reemplázalas por las funciones que gestione tu menú. Registra únicamente el preview del personaje activo, no peds del mundo ni previews de otros personajes. Alternativamente, define Config.GetPreviewPed para devolver el ped actual o nil. RefreshAppearance(previewPed) solicita reevaluar un ped que ya está gestionado; no activa Fat por sí solo.

Exports para recursos de servidor

Los exports de servidor son APIs privilegiadas para otros recursos del servidor. No los reenvíes directamente desde un evento que pueda invocar el cliente.

Código
local playerSource = source -- ID del jugador en el servidor
local kg, err = exports['CXG_GTFAT']:GetWeight(playerSource)
if kg == nil then
    print('No hay un peso confirmado:', err)
end

local appliedKg, setError = exports['CXG_GTFAT']:SetWeight(playerSource, 92.5)
if appliedKg == nil then
    print('No se pudo fijar el peso:', setError)
end

local addedKg, addError = exports['CXG_GTFAT']:AddWeight(playerSource, -2.0)
if addedKg == nil then
    print('No se pudo sumar peso:', addError)
end

local resetKg, resetError = exports['CXG_GTFAT']:ResetWeight(playerSource)
if resetKg == nil then
    print('No se pudo restablecer el peso:', resetError)
end

El argumento source es el ID del jugador en el servidor, no un valor enviado por el cliente. Todos los valores están en kg. GetWeight devuelve el peso o nil, error. SetWeight y AddWeight devuelven el peso aplicado normalizado en kg o nil, error; SetWeight rechaza valores fuera del rango y redondea al paso más cercano, con empates hacia arriba. AddWeight permite incrementos negativos. ResetWeight escribe defaultKg y también devuelve el peso aplicado en kg; no elimina el dato almacenado.

Para abrir la UI a un jugador desde otro recurso de servidor:

Código
local playerSource = source -- ID del jugador en el servidor
local opened, err = exports['CXG_GTFAT']:OpenWeightUI(playerSource)
if not opened then
    print('No se pudo abrir la báscula:', err)
end

Se puede pasar el ID opcional de una estación como segundo argumento: OpenWeightUI(source, 'gimnasio'). Sin estación, aplica la política de acceso de comandos aunque el registro de comandos esté desactivado. El resultado true confirma autorización y envío de la apertura, no que el cliente ya haya renderizado la interfaz.

Exports de servidor

ExportUso
GetWeight(source)Devuelve kg o nil, error.
SetWeight(source, kg)Fija el peso validado y devuelve el peso aplicado en kg o nil, error.
AddWeight(source, deltaKg)Suma un delta y devuelve el peso aplicado en kg o nil, error.
ResetWeight(source)Guarda y devuelve el peso inicial configurado en kg o nil, error.
GetWeightSettings()Devuelve una copia de los límites activos.
OpenWeightUI(source, stationId?)Solicita abrir la báscula con la política correspondiente.
RefreshCharacter(source)Recarga identidad y peso después de que el framework cambie al personaje previsto.
ReconcileStorage(source)Reconcilia el almacenamiento tras un estado incierto, cuando el adaptador puede confirmar escrituras anteriores.

RefreshCharacter es opcional para integraciones de varios personajes; llama al export después de que el framework haya hecho disponible la identidad prevista. El recurso no conecta Qbox automáticamente.

Los errores pueden incluir not_ready, invalid_source, player_unavailable, character_unavailable, invalid_weight, out_of_range, permission_denied, context_denied, busy, storage_failed, storage_timeout, storage_unknown o not_synced. No conviertas un error de almacenamiento en un peso confirmado ni reintentes automáticamente una escritura con resultado storage_timeout o storage_unknown.

Exports de cliente

Código
local kg, err = exports['CXG_GTFAT']:GetWeight()
local settings = exports['CXG_GTFAT']:GetWeightSettings()
local isOpen = exports['CXG_GTFAT']:IsWeightUIOpen()
local closed = exports['CXG_GTFAT']:CloseWeightUI()
local status, statusError = exports['CXG_GTFAT']:GetFatStatus()
local reserved, reservedError = exports['CXG_GTFAT']:GetReservedDecals(PlayerPedId())

GetWeight devuelve nil, 'not_synced' hasta recibir el dato confirmado del servidor. GetFatStatus(ped?) y GetReservedDecals(ped) ofrecen información de lectura; no son prueba de que la geometría se haya renderizado. GetReservedDecals puede servir para ocultar de los menús los decals reservados. RefreshAppearance(previewPed?) solo actualiza la apariencia gestionada del jugador o de un preview registrado.

RegisterPreviewPed(ped) y UnregisterPreviewPed(ped) permiten que un menú entregue su entidad de preview al selector. Solo el recurso que registró el ped puede retirarlo. Al detenerse el recurso propietario, los previews registrados se limpian.

SanitizeAppearance(ped, appearance, format) devuelve una copia de la apariencia; no devuelve nil, error como indicador de fallo. RegisterPreviewPed y UnregisterPreviewPed devuelven true si completan la operación y false si el ped no se puede registrar o retirar.

Bridges editables

ArchivoAdaptación
bridge/server.luaCanAccess, identidad, carga/guardado de peso y hooks del servidor.
bridge/client.luaPed de preview, notificaciones y hooks de cambios de peso/interfaz.
bridge/interaction.luaRegistro de estaciones en un target o reemplazo de TextUI.
bridge/appearance.luaLectura/escritura de decals en un formato de apariencia propio.

Por defecto, CanAccess solo reconoce ace y everyone. Para jobs, groups o custom, implementa la consulta con la API real del servidor y devuelve exactamente true cuando se concede el acceso. Las excepciones y otros valores deniegan. Los campos de policy de job, grupo o custom son datos que interpreta tu adaptador.

Un proveedor de almacenamiento personalizado implementa las firmas LoadWeight(characterId, context, done), SaveWeight(characterId, kg, context, done) y, si necesita reconciliar escrituras inciertas, ReconcileWeight(characterId, context, done). La carga llama done(true, kg) (usa kg = nil si no existe dato) o done(false, 'storage_failed'). El guardado llama done(true) solo tras confirmarse o done(false, 'storage_failed'). La reconciliación llama done(true, true) únicamente cuando ninguna escritura anterior puede completarse más tarde; si no puede garantizarlo, llama done(false, 'storage_unknown'). Para guardados asíncronos reales, marca AsyncStorage = true; el callback debe completar en un contexto FiveM que admita espera. La API permite hasta 10 segundos antes de informar timeout. No reintentes automáticamente tras storage_timeout; primero reconcilia con un proveedor que garantice que una escritura anterior no se aplicará después. No declares asíncrono un proveedor que devuelve antes de iniciar u ordenar la escritura.

Los hooks OnWeightChanged, OnCharacterChanged, OnUIOpened, OnUIClosed y Log sirven para observar o registrar cambios. Los hooks no otorgan acceso ni revierten operaciones confirmadas.

Comprobación antes de habilitarlo

Los parches y adaptadores requieren validación con las versiones y los recursos reales del servidor. Antes de habilitar la integración a jugadores:

  1. Repite el cambio Normal/Fat con un personaje freemode masculino y otro femenino.
  2. Con Fat activo, guarda y vuelve a cargar la apariencia y el outfit. Confirma que el decal técnico no se guarda como una selección ordinaria y que el peso sigue siendo independiente del outfit.
  3. Con persistencia por personaje activada, reinicia el recurso y reconecta. Confirma que el mismo personaje recupera su peso y que otro personaje no hereda ese valor.
  4. Abre el menú de apariencia con un preview registrado y confirma que representa el personaje actual. Al cancelar o cerrar el menú, retíralo antes de borrar la entidad.

Completar estos pasos en tu servidor es necesario para comprobar tu combinación concreta de menú, framework y prendas; la existencia de un parche no certifica por sí sola esos resultados.

CXG · DocumentaciónUna buena base. Infinitas posibilidades.
Integrar GTFAT con otros recursos · cxg-gtfat · CXG Docs