> ## 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 e configurar o Five Cases no seu servidor FiveM, incluindo a integração de troca de skin com o lb-phone.

## Dependências

Inicie os recursos abaixo antes do Five Cases.

<CardGroup cols={2}>
  <Card title="Base Five (vRP)" icon="cube">
    Framework base. Fornece identidade do jogador e saldo bancário usados na compra. A integração fica isolada em `config/functions.lua`.
  </Card>

  <Card title="Recurso de celular" icon="mobile">
    lb-phone por padrão. O Five Cases chama um export nesse recurso (`Cases.Phone.ExportResource`) pra trocar o modelo do celular pela skin equipada. Pra usar outro celular, implemente o mesmo export lá e troque essa config — veja [Integração com o celular](#integração-com-o-celular).
  </Card>

  <Card title="oxmysql" icon="database">
    Acesso ao banco de dados onde fica o inventário de skins.
  </Card>
</CardGroup>

<Info>
  A tabela `cases_inventory` é criada automaticamente na primeira inicialização. Não é necessário rodar nenhum SQL manual.
</Info>

***

## Instalação do Recurso

<Steps>
  <Step title="Copie a pasta do recurso">
    Coloque a pasta `five-cases` dentro do diretório de recursos do seu servidor.
  </Step>

  <Step title="Informe o token de licença">
    Abra o arquivo `token.lua` na raiz do recurso e substitua pelo token recebido na compra.

    ```lua token.lua theme={null}
    exports('license', function ()
        return 'SEU-TOKEN-AQUI'
    end)
    ```
  </Step>

  <Step title="Ajuste o catálogo e as raridades">
    Edite `config/config.lua` para adicionar, remover ou reprecificar skins. Veja os detalhes na página de [Configuração](/five-cases/configuracao).
  </Step>

  <Step title="Confira a adaptação de framework">
    Se a sua base for diferente da Five Network (vRP), ajuste `config/functions.lua`. Veja a seção [Adaptação de Framework](#adaptação-de-framework) logo abaixo.
  </Step>

  <Step title="Adicione ao server.cfg">
    Inicie o recurso depois das dependências (e depois do seu recurso de celular).

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

<Note>
  O painel é entregue já compilado em `web/dist`, pronto pra uso. Não é necessário nenhum passo de build`web/dist`, pronto pra uso. Não é necessário nenhum passo de build.
</Note>

***

## Integração com o celular

O Five Cases não sabe nada sobre lb-phone, qb-phone, ox\_phone ou qualquer outro — ele só chama um export num resource configurável, sempre que o jogador equipa, desequipa, entra no jogo ou esse resource reinicia com uma skin ativa:

```lua theme={null}
exports[Cases.Phone.ExportResource]:SetCasePhoneSkin(model, offset, rotation, clipDict, clipAnim, frameColor)
```

`Cases.Phone.ExportResource` (em `config/config.lua`) diz **qual resource** recebe essa chamada — por padrão `'lb-phone'`. Pra usar outro celular, troque esse valor e implemente o export `SetCasePhoneSkin` nele, com esta assinatura:

| Parâmetro    | Tipo                      | Descrição                                                                                        |
| ------------ | ------------------------- | ------------------------------------------------------------------------------------------------ |
| `model`      | `string \| number \| nil` | Nome ou hash do modelo da skin. `nil` volta ao celular padrão                                    |
| `offset`     | `vector3`                 | Deslocamento do objeto em relação ao osso da mão                                                 |
| `rotation`   | `vector3`                 | Rotação do objeto                                                                                |
| `clipDict`   | `string?`                 | Dicionário do clipe de animação "idle" tocado no objeto                                          |
| `clipAnim`   | `string?`                 | Nome do clipe tocado no objeto                                                                   |
| `frameColor` | `string?`                 | Cor (hex), opcional — só faz sentido se o seu celular tiver o conceito de "moldura" configurável |

O export precisa, na prática:

<Steps>
  <Step title="Resolver o modelo">
    `model` pode vir como `string` (nome do prop customizado, use `GetHashKey`/`joaat`) ou `number` (hash já resolvido). Cheque `IsModelValid` antes de usar.
  </Step>

  <Step title="Recriar o objeto do celular">
    Se o celular do jogador já estiver visível, apague o objeto atual e crie de novo com o modelo recebido — `CreateObject` + `AttachEntityToEntity` no osso da mão (`GetPedBoneIndex(ped, 28422)`), usando `offset`/`rotation`.
  </Step>

  <Step title="Tocar a animação idle (opcional)">
    Se `clipDict`/`clipAnim` vierem preenchidos, dá pra tocar esse clipe no **objeto** (não no ped) via `PlayEntityAnim`, pra dar uma "respirada" na skin.
  </Step>

  <Step title="Aplicar frameColor (opcional)">
    Se o seu celular tiver uma cor de moldura/tema configurável na UI, repasse `frameColor` pra lá. Se não tiver esse conceito, é seguro ignorar esse parâmetro.
  </Step>

  <Step title="Tratar model = nil">
    Quando `model` vier `nil` (jogador desequipou), volte pro modelo padrão do seu celular e restaure `frameColor` original.
  </Step>
</Steps>

<Note>
  Sem esse export implementado, o painel, a compra e o inventário do Five Cases continuam funcionando normalmente — só a troca visual do celular não terá efeito.
</Note>

### Exemplo pronto: lb-phone

O Five Cases já vem configurado com `Cases.Phone.ExportResource = 'lb-phone'`. Esse export **não existe no lb-phone padrão** — peça esse patch ao suporte se o seu lb-phone ainda não tiver. Uma vez aplicado, a skin troca o modelo do celular e a cor da moldura automaticamente, funcionando com qualquer variação de celular escolhida (iPhone, Samsung, etc.).

<Note>
  A moldura da tela do celular só aceita cor, não a imagem da skin.
</Note>

***

## App no celular

Quer que o jogador também abra a loja direto pelo celular, com um ícone na tela inicial, além do comando `/cases`? Ative em `config/config.lua`:

```lua theme={null}
Cases.Phone.RegisterApp = true
```

<CardGroup cols={2}>
  <Card title="Trocar o ícone" icon="image">
    Edite `Cases.Phone.AppIcon` com a URL da sua própria arte. Vem com um ícone simples por padrão.
  </Card>

  <Card title="Trocar a descrição" icon="text">
    `Cases.Phone.AppDescription` é o texto exibido na ficha do app dentro do celular.
  </Card>
</CardGroup>

<Warning>
  Com o app ativado, o botão **Inspecionar 3D** (visualização de perto, com zoom e rotação) fica disponível só pelo comando `/cases` — não funciona de dentro do app do celular. Comprar, equipar e desequipar funcionam normalmente nos dois.
</Warning>

***

## Adaptação de Framework

Toda a comunicação com o vRP fica concentrada em `config/functions.lua`. O arquivo já vem pronto para a base Five Network (vRP). Caso a sua base use nomes diferentes para essas funções, ajuste apenas o conteúdo delas — mantendo o nome e o retorno esperado — sem tocar em nenhum outro arquivo do recurso.

```lua config/functions.lua theme={null}
Functions = {}

function Functions.GetUserId(source)
    return vRP.getUserId(source)
end

function Functions.GetBankMoney(user_id)
    return vRP.getBankMoney(user_id)
end

function Functions.TryPayment(user_id, price)
    return vRP.PaymentBank(user_id, price)
end

function Functions.FullName(user_id)
    return vRP.FullName(user_id)
end

function Functions.Notify(source, message, kind, title)
    TriggerClientEvent('Notify', source, kind or 'importante', title or 'Five Cases', tostring(message or ''), 5000)
end

function Functions.Log(category, data)
    if GetResourceState('five_logs') == 'started' then
        exports['five_logs']:AddLog(category, data)
    elseif webhooks and webhooks.log then
        webhooks.log(category, data)
    end
end
```

| Função                                 | O que precisa fazer                                                               | Retorno         |
| -------------------------------------- | --------------------------------------------------------------------------------- | --------------- |
| `GetUserId(source)`                    | Resolver o identificador permanente do personagem a partir do `source` da conexão | `number \| nil` |
| `GetBankMoney(user_id)`                | Consultar o saldo bancário do jogador                                             | `number`        |
| `TryPayment(user_id, price)`           | Debitar `price` do saldo bancário, sem debitar nada se o saldo for insuficiente   | `boolean`       |
| `FullName(user_id)`                    | Nome exibido no log de compra                                                     | `string`        |
| `Notify(source, message, kind, title)` | Enviar uma notificação ao jogador                                                 | —               |
| `Log(category, data)`                  | Registrar a compra (ver [Log de compras](#log-de-compras) abaixo)                 | —               |

<Warning>
  Essas são exatamente as funções que quebram quando o Five Cases é instalado em cima de um vRP com nomes diferentes dos usados aqui (por exemplo, `vRP.tryBankPayment` não existe em todo fork de vRP). Teste uma compra logo após instalar — se aparecer "saldo insuficiente" com saldo de sobra, ou erro de `nil` no console, o ajuste é sempre aqui em `config/functions.lua`.
</Warning>

***

## Log de compras

Cada compra chama `Functions.Log('caseOpened', dados)`. Por padrão isso tenta o resource `five_logs`, se estiver rodando, e cai no fallback de `config/webhooks.lua` (um webhook do Discord) caso contrário.

```lua config/webhooks.lua theme={null}
local webhookURLs = {
    caseOpened = "",  -- cole aqui o link do webhook do Discord
    default    = "",
}
```

<Note>
  Deixe o link em branco (`""`) pra desativar o log daquela categoria. Com o `five_logs` rodando, o conteúdo de `config/webhooks.lua` é ignorado.
</Note>
