> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fivenetwork.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Instalação

> Passo a passo para instalar, adaptar ao seu framework e integrar o Five Bennys ao seu sistema de veículos no FiveM.

## Dependências

O Five Bennys usa **oxmysql** para persistência e, por padrão, a base **vRP (Creative Enchanted)** através da camada de framework. A integração com qualquer outra base é feita adaptando apenas os arquivos `server/framework.lua` e `client/framework.lua` — o resto do resource não conhece o seu framework.

<CardGroup cols={2}>
  <Card title="oxmysql" icon="database">
    Dependência obrigatória. Responsável por toda a comunicação com o banco MySQL/MariaDB (`@oxmysql/lib/MySQL.lua`).
  </Card>

  <Card title="vRP / seu framework" icon="puzzle-piece">
    Por padrão usa vRP via Tunnel/Proxy. Para ESX, QBCore, ox\_core ou standalone, adapte a tabela `Framework` nos dois `framework.lua`.
  </Card>
</CardGroup>

<Info>
  O manifesto já declara `@vrp/lib/utils.lua`, `@vrp/config/Global.lua` e as interfaces Tunnel/Proxy. Ao trocar de base, remova/ajuste esses `@vrp` no `fxmanifest.lua` e reescreva o corpo das funções de `Framework`.
</Info>

***

## Estrutura do resource

```text theme={null}
five-bennys/
├── fxmanifest.lua
├── config/
│   ├── config.lua      → identidade, acesso, regras de serviço, oficinas
│   ├── language.lua    → todos os textos e notificações
│   ├── mods.lua        → catálogo de tunagens (categorias, cores, extras)
│   ├── prices.lua      → preço de cada tunagem
│   └── engines.lua     → sons de motor
├── client/
│   ├── framework.lua   → ganchos de client (hud, notify)
│   ├── modules/        → common, customization, mechanic, nui
│   └── client.lua      → comandos, marcadores, sync de tuning
├── server/
│   ├── framework.lua   → camada de adaptação (identidade, permissão, pagamento, db)
│   ├── modules/        → common, database, service, repair
│   └── server.lua      → mecânicos, permissões
└── web/                → interface NUI
```

***

## Banco de dados

A tabela é criada automaticamente na primeira inicialização do resource — a estrutura abaixo serve apenas como referência. Cada tunagem é única por **placa + modelo**.

```sql theme={null}
CREATE TABLE IF NOT EXISTS `core_bennys_tuning` (
    `plate`    VARCHAR(12) NOT NULL,
    `model`    VARCHAR(64) NOT NULL DEFAULT '',
    `passport` INT         NOT NULL DEFAULT 0,
    `custom`   LONGTEXT    NOT NULL,
    PRIMARY KEY (`plate`,`model`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```

<Note>
  Na inicialização, o resource também detecta bancos antigos (com PK só na `plate`) e migra automaticamente a chave primária para `(plate, model)`. Todo o cache de tunagens é carregado em memória (`TuningCache`) para leitura rápida.
</Note>

***

## Instalação do recurso

<Steps>
  <Step title="Copie a pasta do recurso">
    Coloque a pasta `five-bennys` dentro do diretório de recursos do servidor (ex: `resources/[core]/`).
  </Step>

  <Step title="Adapte a camada de framework">
    Ajuste `server/framework.lua` e `client/framework.lua` para o seu framework. Veja a seção [Adaptação de Framework](#adaptação-de-framework).
  </Step>

  <Step title="Configure as oficinas e regras">
    Edite `config/config.lua` (oficinas, permissões, regras de serviço) e, se quiser, os demais arquivos de `config/`. Veja a página de [Configuração](/five-bennys/configuracao).
  </Step>

  <Step title="Integre ao seu sistema de veículos">
    Faça o seu sistema de garagem/spawn reaplicar as tunagens salvas usando os exports do Five Bennys. Veja a seção [Integração com o sistema de veículos](#integração-com-o-sistema-de-veículos).
  </Step>

  <Step title="Adicione à server.cfg">
    Inicie o recurso **depois** do oxmysql e do seu framework.

    ```text theme={null}
    ensure oxmysql
    ensure vrp
    ensure five-bennys
    ```
  </Step>
</Steps>

***

## Adaptação de Framework

Toda a comunicação com a sua base está isolada na tabela `Framework` em `server/framework.lua` (identidade, permissão, veículo, pagamento, banco, notificação) e `client/framework.lua` (hud e notificação). Adapte **apenas o corpo** de cada função.

<AccordionGroup>
  <Accordion title="Identidade (server)" icon="user">
    O resource usa um identificador numérico único por jogador (o "Passport").

    ```lua theme={null}
    Passport = function(source)
        return vRP.Passport(source)                 -- ESX: xPlayer.getIdentifier() · QBCore: citizenid
    end,

    Source = function(Passport)
        return vRP.Source(Passport)                 -- inverso do Passport (id → source)
    end,

    FullName = function(Passport)
        local Identity = vRP.Identity(Passport)
        return Identity and (Identity.Name .. " " .. Identity.Lastname) or nil
    end,

    Avatar = function(Passport)
        local Avatar = exports.vrp:Avatar(Passport)  -- opcional; usado no card do cliente
        return (Avatar ~= "" and Avatar) or false
    end,
    ```
  </Accordion>

  <Accordion title="Permissões (server)" icon="shield">
    Controla quem trabalha em cada oficina (`WorkPermission`), quem acessa (`AccessPermission`) e quem é admin.

    ```lua theme={null}
    HasPermission = function(Passport, Permission)
        if not Passport then return false end
        if not Permission then return true end
        if type(Permission) == "table" then           -- aceita string OU lista de permissões
            for _, Entry in pairs(Permission) do
                if Framework.HasPermission(Passport, Entry) then return true end
            end
            return false
        end
        return vRP.HasPermission(Passport, Permission) and true or false
    end,

    -- Lista os SOURCES online que têm determinada permissão (usada p/ achar mecânicos)
    UsersByPermission = function(Permission)
        local List = {}
        for _, Source in pairs(vRP.NumPermission(Permission)) do
            List[#List + 1] = Source
        end
        return List
    end,
    ```

    <Tip>
      O `/bennys` (admin) usa uma checagem reforçada em `server.lua`: `vRP.HasGroup(Passport, Permission, 2)`. Ajuste `Core.CheckPlayerPermission` se o seu framework não tiver grupos com nível.
    </Tip>
  </Accordion>

  <Accordion title="Veículo (server)" icon="car">
    ```lua theme={null}
    -- Dono da placa (para respeitar Bennys.OnlyOwner e creditar o pagamento)
    PlateOwner = function(Plate)
        return vRP.PassportPlate(Plate)
    end,

    -- Lista de veículos próximos (retorna entity, netId, plate)
    VehicleList = function(Distance)
        return vRP.VehicleList(Distance)
    end,

    -- Jogadores próximos ao mecânico (usado no reparo p/ sincronizar inventory:repairAdmin)
    Players = function(source)
        return vRPclient.Players(source)
    end,
    ```
  </Accordion>

  <Accordion title="Pagamento (server)" icon="money-bill">
    ```lua theme={null}
    -- Cobra o jogador. Deve retornar true em sucesso, false se não tiver saldo.
    TryPayment = function(Passport, Price)
        return vRP.PaymentBank(Passport, Price)      -- ESX: xPlayer.removeAccountMoney('bank', Price)
    end,

    -- Credita o mecânico (porcentagem) e devolve dinheiro em cancelamentos.
    GiveBank = function(Passport, Amount)
        return vRP.GiveBank(Passport, Amount)
    end,
    ```
  </Accordion>

  <Accordion title="Banco de dados (server)" icon="database">
    ```lua theme={null}
    DatabaseReady = function(Callback)
        return MySQL.ready(Callback)
    end,

    Query = function(Sql, Params)
        return MySQL.query.await(Sql, Params or {})
    end,
    ```

    <Info>
      A tabela é criada dentro de `DatabaseReady`, então essas funções precisam estar operacionais antes do primeiro `ensure five-bennys`.
    </Info>
  </Accordion>

  <Accordion title="Notificações (server e client)" icon="bell">
    O resource dispara `Framework.Notify(source, style, content, time)`. Os estilos usados internamente são `sucesso`, `aviso` e `negado`. O evento client `five-bennys:notifyBennys` já normaliza vários apelidos (`verde/success`, `amarelo/info`, `vermelho/error`) para `success` / `warn` / `error` na NUI.

    ```lua theme={null}
    -- server/framework.lua e client/framework.lua
    Notify = function(Source, Style, Content, Time)
        if Source then
            TriggerClientEvent("five-bennys:notifyBennys", Source, Style, Content, Time)
        else
            TriggerEvent("five-bennys:notifyBennys", Style, Content, Time)
        end
    end,
    ```

    Para usar o sistema de notificação do seu servidor, troque o corpo desse evento no client por uma chamada ao seu próprio evento/`lib.notify`.
  </Accordion>

  <Accordion title="Ganchos de client" icon="display">
    Chamados quando o painel abre e fecha — use para esconder/mostrar HUD, por exemplo.

    ```lua theme={null}
    -- client/framework.lua
    Open  = function() TriggerEvent("hud:Active", false) end,   -- painel ABERTO
    Close = function() TriggerEvent("hud:Active", true)  end,   -- painel FECHADO
    ```
  </Accordion>
</AccordionGroup>

***

## Integração com o sistema de veículos

Esta é a integração **essencial**: sozinho, o Five Bennys salva a tunagem por placa, mas quem spawna os veículos (garagem, aluguel, admin) precisa reaplicá-la quando o veículo aparece. Use os exports server-side [`HasTuning`](/five-bennys/api/exports#hastuning) e [`ApplyStoredTuning`](/five-bennys/api/exports#applystoredtuning).

```lua server theme={null}
-- No seu sistema de veículos, logo após criar o veículo em rede:
local entity, networkVehicle = createNetVehicle(plate, model, coords, ...)

if networkVehicle then
    local hasBennys = GetResourceState("five-bennys") == "started"
        and exports["five-bennys"]:HasTuning(plate)

    -- Se o Bennys tem tunagem salva, NÃO aplique os mods antigos do seu sistema —
    -- deixe o Bennys reaplicar a customização completa:
    setupVehicle(networkVehicle, hasBennys and {} or mods, health, damages)

    if hasBennys then
        exports["five-bennys"]:ApplyStoredTuning(networkVehicle, plate)
    end
end
```

<Warning>
  Faça a checagem `GetResourceState("five-bennys") == "started"` antes de chamar os exports, para o seu sistema de veículos continuar funcionando mesmo com o Bennys desligado.
</Warning>

<Tip>
  Para descobrir o **som de motor** salvo de um veículo (ex: reaplicar áudio em outro fluxo), use a função de interface `Core.GetStoredEngineSound(Plate, Model)` do resource. Veja os [Exports](/five-bennys/api/exports).
</Tip>

***

## Migração de tunagens antigas

Se você vinha de uma versão que guardava os mods em `entitydata` (chaves `Mods:passport:model`), o resource registra o comando de console `convertBennys` para migrar tudo em lote para a nova tabela.

```text theme={null}
convertBennys
```

<Note>
  Execute o comando **no console do servidor**. Ele lê `entitydata WHERE dkey LIKE '%Mods%'`, converte cada registro para o novo formato e grava em `core_bennys_tuning`, imprimindo o total de convertidos e falhas.
</Note>
