Integrar o CXG-GTFAT a outros recursos
Os arquivos bridge/*.lua são pontos editáveis de adaptação para conectar permissões, persistência, avisos, estações e formatos de aparência. Os patches de menus são alterações manuais para versões específicas; o recurso não modifica outros recursos durante a instalação.
Menus de aparência
Há patches preparados para estes repositórios e revisões:
| Menu | Revisão de origem | Ação adicional |
|---|---|---|
| illenium-appearance | 1b003ec169b15f145d519438ba7c6454bf746f27 | Aplicar o patch Lua de salvamento de componentes. |
| fivem-appearance | b06da32881ed49042909b38a778c10dd9bd9eaed | Aplicar o patch e reconstruir o bundle TypeScript do jogo pelo fluxo build:game. |
| qb-clothing | 8cca4009dd473ab30c30e443ecad50830b816ed7 | Aplicar o patch nos pontos de salvamento da skin e do outfit. |
| esx_skin / skinchanger | fe59ca0bd6da59e2ec6eb4a8d06ece312e96ae7a | O patch é relativo à raiz do repositório esx_core. |
A pasta integrations do pacote contém illenium-appearance.patch, fivem-appearance.patch, qb-clothing.patch e skinchanger.patch. Eles não são aplicados automaticamente. Em um checkout de desenvolvimento do menu, confira o patch correspondente antes de aplicá-lo:
git apply --check /caminho/do-patch-correto.patch
git apply /caminho/do-patch-correto.patch
Se a verificação falhar, pare e adapte a alteração à versão instalada; não force a aplicação. Forks e revisões mais recentes podem ser diferentes. O patch fivem-appearance exige reconstruir o bundle pelo fluxo build:game do próprio menu. Esses patches não certificam todas as versões nem substituem testes no seu servidor.
O salvamento higieniza o decal técnico para impedir que o menu o persista como uma escolha comum do jogador. Menus que mantêm sua própria tabela de aparência devem chamar a higienização no ponto de salvamento. O peso fica separado dos outfits.
Salvar uma aparência própria
O export do cliente SanitizeAppearance retorna uma cópia da aparência. Os formatos incluídos são components, qb e esx:
local appearanceCopy = exports['CXG_GTFAT']:SanitizeAppearance(
ped,
appearance,
'components'
)
GuardarApariencia(appearanceCopy)
GuardarApariencia é uma chamada de exemplo; substitua-a pela função de salvamento do seu menu. components aceita uma matriz de componentes ou um objeto com a propriedade components; cada componente usa component_id, drawable, texture e, opcionalmente, palette. O formato qb usa o campo decals com item e texture; esx usa decals_1 e decals_2. O export retorna uma cópia profunda, preserva os outros campos e não altera temporariamente o ped. Se o adaptador falhar ou o formato não for reconhecido, retorna a cópia sem alterações e registra um diagnóstico.
Registrar um ped de pré-visualização
Se o menu usa um ped de pré-visualização separado do personagem, registre o preview do personagem ativo. Remova o registro antes de excluir a entidade:
local previewPed = ObtenerPreviewActual()
if previewPed and DoesEntityExist(previewPed) then
exports['CXG_GTFAT']:RegisterPreviewPed(previewPed)
end
-- Ao fechar ou cancelar o menu, antes de excluir o ped:
exports['CXG_GTFAT']:UnregisterPreviewPed(previewPed)
EliminarPreview(previewPed)
ObtenerPreviewActual e EliminarPreview são chamadas de exemplo; substitua-as pelas funções do seu menu. Registre somente o preview do personagem ativo, não peds do mundo nem previews de outros personagens. Como alternativa, defina Config.GetPreviewPed para retornar o ped atual ou nil. RefreshAppearance(previewPed) solicita reavaliação de um ped já gerenciado; não ativa Fat por si só.
Exports para recursos do servidor
Os exports do servidor são APIs privilegiadas para outros recursos do servidor. Não os encaminhe diretamente por um evento que possa ser chamado pelo cliente.
local playerSource = source -- ID do jogador no servidor
local kg, err = exports['CXG_GTFAT']:GetWeight(playerSource)
if kg == nil then
print('Peso não confirmado:', err)
end
local appliedKg, setError = exports['CXG_GTFAT']:SetWeight(playerSource, 92.5)
if appliedKg == nil then
print('Não foi possível definir o peso:', setError)
end
local addedKg, addError = exports['CXG_GTFAT']:AddWeight(playerSource, -2.0)
if addedKg == nil then
print('Não foi possível adicionar peso:', addError)
end
local resetKg, resetError = exports['CXG_GTFAT']:ResetWeight(playerSource)
if resetKg == nil then
print('Não foi possível redefinir o peso:', resetError)
end
O argumento source é o ID do jogador no servidor, não um valor enviado pelo cliente. Todos os valores estão em kg. GetWeight retorna o peso ou nil, error. SetWeight e AddWeight retornam o peso aplicado normalizado em kg ou nil, error; SetWeight rejeita valores fora da faixa e arredonda para o incremento mais próximo, arredondando empates para cima. AddWeight permite incrementos negativos. ResetWeight grava defaultKg e também retorna o peso aplicado em kg; não exclui o valor armazenado.
Para abrir a interface de um jogador a partir de outro recurso do servidor:
local playerSource = source -- ID do jogador no servidor
local opened, err = exports['CXG_GTFAT']:OpenWeightUI(playerSource)
if not opened then
print('Não foi possível abrir a balança:', err)
end
É possível passar o ID opcional de uma estação como segundo argumento: OpenWeightUI(source, 'academia'). Sem estação, aplica a política de acesso dos comandos, mesmo se o registro de comandos estiver desativado. O resultado true confirma a autorização e o envio do pedido para abrir, mas não confirma que a interface já foi renderizada no cliente.
Exports do servidor
| Export | Uso |
|---|---|
GetWeight(source) | Retorna kg ou nil, error. |
SetWeight(source, kg) | Define um peso validado e retorna o valor aplicado em kg ou nil, error. |
AddWeight(source, deltaKg) | Soma uma diferença e retorna o valor aplicado em kg ou nil, error. |
ResetWeight(source) | Salva e retorna o peso padrão configurado em kg ou nil, error. |
GetWeightSettings() | Retorna uma cópia dos limites ativos. |
OpenWeightUI(source, stationId?) | Solicita abrir a balança conforme a política aplicável. |
RefreshCharacter(source) | Recarrega identidade e peso após o framework trocar para o personagem desejado. |
ReconcileStorage(source) | Reconcilia o armazenamento após um estado incerto quando o adaptador consegue confirmar gravações anteriores. |
RefreshCharacter é opcional para integrações com vários personagens; chame-o depois que o framework disponibilizar a identidade correta. O recurso não se conecta ao Qbox automaticamente.
Os erros podem 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 ou not_synced. Não considere um erro de armazenamento como peso confirmado nem tente automaticamente outra gravação após storage_timeout ou storage_unknown.
Exports do cliente
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 retorna nil, 'not_synced' até receber o valor confirmado pelo servidor. GetFatStatus(ped?) e GetReservedDecals(ped) oferecem informações de leitura; não comprovam que a geometria foi renderizada. GetReservedDecals pode ajudar a ocultar os decals reservados nos menus. RefreshAppearance(previewPed?) atualiza somente a aparência gerenciada do jogador ou de um preview registrado.
RegisterPreviewPed(ped) e UnregisterPreviewPed(ped) permitem que um menu entregue sua entidade de preview ao seletor. Só o recurso que registrou o ped pode removê-lo. Os previews registrados são limpos quando o recurso proprietário é encerrado.
SanitizeAppearance(ped, appearance, format) retorna uma cópia da aparência; nil, error não indica falha. RegisterPreviewPed e UnregisterPreviewPed retornam true quando a operação é concluída e false quando o ped não pode ser registrado ou removido.
Bridges editáveis
| Arquivo | Adaptação |
|---|---|
bridge/server.lua | CanAccess, identidade, carregamento/salvamento do peso e hooks do servidor. |
bridge/client.lua | Ped de preview, notificações e hooks de alteração do peso/interface. |
bridge/interaction.lua | Registro de estações em um target ou substituição do TextUI. |
bridge/appearance.lua | Leitura/gravação de decals em um formato de aparência próprio. |
Por padrão, CanAccess reconhece somente ace e everyone. Para jobs, groups ou custom, implemente a consulta com a API real do servidor e retorne exatamente true quando conceder acesso. Exceções e outros valores negam o acesso. Os campos de política job, group e custom são dados interpretados pelo adaptador.
Um provedor de armazenamento customizado implementa as assinaturas LoadWeight(characterId, context, done), SaveWeight(characterId, kg, context, done) e, se precisar reconciliar gravações incertas, ReconcileWeight(characterId, context, done). O carregamento chama done(true, kg) (use kg = nil quando não houver valor) ou done(false, 'storage_failed'). O salvamento chama done(true) somente após confirmação ou done(false, 'storage_failed'). A reconciliação chama done(true, true) somente quando nenhuma gravação anterior poderá ser concluída posteriormente; se não puder garantir isso, chame done(false, 'storage_unknown'). Para salvamentos realmente assíncronos, defina AsyncStorage = true; o callback deve concluir em um contexto FiveM que permita espera. A API aguarda até 10 segundos antes de informar timeout. Não tente novamente automaticamente após storage_timeout; primeiro reconcilie com um provedor que garanta que uma gravação anterior não será aplicada depois. Não declare um provedor assíncrono se ele retornar antes de iniciar ou ordenar a gravação.
Os hooks OnWeightChanged, OnCharacterChanged, OnUIOpened, OnUIClosed e Log servem para observar ou registrar alterações. Hooks não concedem acesso nem desfazem operações confirmadas.
Verificações antes de habilitar
Patches e adaptadores precisam ser validados com as versões e os recursos reais do servidor. Antes de liberar a integração aos jogadores:
- Repita a mudança Normal/Fat com personagens freemode masculinos e femininos.
- Com Fat ativo, salve e recarregue a aparência e o outfit. Confirme que o decal técnico não foi salvo como uma escolha comum e que o peso continua separado do outfit.
- Com a persistência por personagem ativada, reinicie o recurso e reconecte. Confirme que o mesmo personagem recupera o peso e que outro personagem não herda esse valor.
- Abra o menu de aparência com um preview registrado e confirme que ele representa o personagem atual. Ao cancelar ou fechar o menu, remova o registro antes de excluir a entidade.
Concluir essas etapas no seu servidor é necessário para validar a combinação específica do menu, framework e roupas. A existência de um patch, por si só, não certifica esses resultados.