> **Esta página faz parte do roteiro de integração.** Ela detalha a fase 3, quando o jogo é Unity, Godot, sem servidor ou só nativo. Para pôr um jogo no plicflix do zero até ele aparecer no catálogo, siga o roteiro em ordem: https://developers.plicflix.com/docs/COMECE (fases 1 a 8, com quem faz cada passo). Índice para IAs: https://developers.plicflix.com/llms.txt

# Motores e casos especiais

O plicflix abre a **versão web** do seu jogo. O que muda de um motor para
outro é só **como** o jogo fala com o SDK do navegador (`window.Plicflix`). A
troca do token no servidor ([SDK](SDK#4-entrada-o-jogador-já-chega-logado)) é
igual para todos.

| o seu jogo | o caminho |
|---|---|
| JavaScript/TypeScript (Phaser, PixiJS, Three.js, Babylon.js, Construct, PlayCanvas, puro…) | chame `Plicflix.*` direto — [SDK](SDK) |
| **Unity WebGL** | [Unity](#unity-webgl) |
| **Godot 4 (Web)** | [Godot](#godot-4-web) |
| Flutter web | [Flutter web](#flutter-web) |
| outro motor que exporta para a web e fala com JavaScript (Defold, GameMaker HTML5, Bevy/wasm, Emscripten…) | chame as funções do `window.Plicflix` pela ponte JS do motor, ou fale o [protocolo de mensagens](SDK#12-o-protocolo-de-mensagens-sem-o-sdk-em-javascript) |
| **sem servidor** (só arquivos estáticos) | [Jogo sem servidor](#jogo-sem-servidor) |
| só app nativo (Android, iOS, PC), sem versão web | [Ainda não](#jogos-só-nativos) |

## Antes de tudo: exporte sem threads

Unity com "Multithreading" e Godot com "Thread Support" precisam de
`SharedArrayBuffer`, que exige os cabeçalhos COOP/COEP — e eles **não
funcionam** com o jogo dentro de um iframe de outro site (o app do plicflix).
Exporte **sem threads**:
- **Unity:** Player Settings → WebGL → Publishing Settings → *Enable
  Multithreading* desligado (é o padrão).
- **Godot 4.3+:** Exportar → Web → *Thread Support* desligado. (Godot 4.0–4.2
  sempre usa threads na web: use 4.3 ou mais novo.)

## Recarregar a página

Depois da primeira entrada, o token já foi usado: se o jogador recarregar a
página, `entrar` falha. Nesse caso, use a **sessão que o seu servidor já
abriu** (o cookie): peça ao seu servidor "quem sou eu" (ex.: `GET /api/eu`) e
siga. Só mostre erro se não houver sessão. Os exemplos abaixo mostram onde.

## Unity WebGL

Arquivos prontos:
- [`Plicflix.jslib`](/sdk/unity/Plicflix.jslib?baixar=1) → `Assets/Plugins/WebGL/Plicflix.jslib`
- [`Plicflix.cs`](/sdk/unity/Plicflix.cs?baixar=1) → `Assets/Plicflix/Plicflix.cs`

Passos:
1. No seu template WebGL (`Assets/WebGLTemplates/<seu>/index.html`), antes do
   loader do Unity: `<script src="plicflix.js"></script>`, e copie o
   [`plicflix.js`](/sdk/plicflix.js?baixar=1) para a pasta do template.
2. Na primeira cena, crie um GameObject chamado **`Plicflix`** e adicione o
   componente `Plicflix`.
3. No seu código:

```csharp
void Start() {
    if (!Plicflix.I.Dentro) { /* aberto fora do plicflix: o seu login de sempre */ return; }
    Plicflix.I.Progresso(20, "Entrando…");
    Plicflix.I.AoEntrou += json => {               // a resposta do SEU servidor
        // JsonUtility.FromJson<MinhaResposta>(json) …
        Plicflix.I.Pronto();
    };
    Plicflix.I.AoFalhou += erro => StartCoroutine(UsarSessaoOuErro());   // recarregou? a sessão já existe
    Plicflix.I.AoSairDoJogo += terminou => { SalvarProgresso(); terminou(); };
    Plicflix.I.AoPedirIrPara += destinoJson => { /* leve o jogador */ Plicflix.I.FoiPara(true); };
    Plicflix.I.Entrar("/api/plicflix/entrar");     // o seu servidor troca o token
}
IEnumerator UsarSessaoOuErro() {
    using var r = UnityEngine.Networking.UnityWebRequest.Get("/api/eu");   // o cookie vai junto
    yield return r.SendWebRequest();
    if (r.result == UnityEngine.Networking.UnityWebRequest.Result.Success) Plicflix.I.Pronto();
    else Plicflix.I.Erro("Não foi possível entrar. Abra o jogo de novo pelo plicflix.");
}
// a cada troca de cena:
Plicflix.I.Onde("{\"texto\":\"Floresta\",\"area\":\"mundo/floresta\"}");
```

No Editor (fora da web), todas as chamadas são ignoradas e `Dentro` é
`false`: o jogo roda normal.

**O servidor:** o jogo Unity é servido pelo seu servidor web; a rota
`/api/plicflix/entrar` e os cabeçalhos (`frame-ancestors`, cookie) são os do
[SDK](SDK#5-deixar-o-plicflix-abrir-o-seu-jogo). Sem servidor próprio, use
`Plicflix.I.Jogador()` (veja [abaixo](#jogo-sem-servidor)).

## Godot 4 (Web)

Arquivo pronto: [`plicflix.gd`](/sdk/godot/plicflix.gd?baixar=1).

1. **Projeto → Exportar → Web → Head Include:** `<script src="plicflix.js"></script>`,
   e copie o [`plicflix.js`](/sdk/plicflix.js?baixar=1) para a pasta exportada.
2. **Projeto → Configurações do projeto → Autoload:** adicione o `plicflix.gd`
   com o nome **`Plicflix`**.
3. No seu jogo:

```gdscript
func _ready():
    if not Plicflix.dentro():
        return  # fora do plicflix
    Plicflix.progresso(20, "Entrando…")
    Plicflix.ao_sair = func(): salvar_progresso()
    Plicflix.ao_ir_para = func(destino): return levar_ate(destino)   # true/false
    var r = await Plicflix.entrar("/api/plicflix/entrar")           # {} se falhou
    if r.is_empty():
        # recarregou a página? a sessão (cookie) já existe: pergunte ao seu servidor
        # (ex.: HTTPRequest em /api/eu); sem sessão, Plicflix.erro("…") e pare aqui
        pass
    Plicflix.pronto()
    Plicflix.onde({"texto": "Floresta", "area": "mundo/floresta"})
```

Fora da web (`OS.has_feature("web")` falso), tudo é ignorado.

## Flutter web

```dart
import 'dart:js_interop';
import 'dart:js_interop_unsafe';

final plicflix = globalContext['Plicflix'] as JSObject?;
bool get dentro => plicflix?.callMethod<JSBoolean>('dentro'.toJS).toDart ?? false;
void pronto() => plicflix?.callMethod('pronto'.toJS);
void onde(String texto) => plicflix?.callMethod('onde'.toJS, texto.toJS);
Future<void> entrar(String url) async =>
    (plicflix!.callMethod<JSPromise>('entrar'.toJS, url.toJS)).toDart;
```

Carregue o `plicflix.js` no `web/index.html`, antes do `flutter_bootstrap.js`.

## Jogo sem servidor

Se o seu jogo é só arquivos estáticos (sem um servidor seu para guardar a
chave), use `Plicflix.jogador()` no lugar do `Plicflix.entrar`:

```js
if (Plicflix.dentro()) {
  const { jogador } = await Plicflix.jogador();   // { id: "pf_…", nome: "Ana" }
  carregarSave(localStorage.getItem("save:" + jogador.id));
  Plicflix.aoSair(() => localStorage.setItem("save:" + jogador.id, gerarSave()));
  Plicflix.pronto();
}
```

Como funciona: a página troca o token direto na API do plicflix
(`POST https://api.plicflix.com/v1/ingresso/navegador`), sem chave. Só vale se
o pedido vier **da origem cadastrada** do seu jogo. Recarregar a página devolve
o mesmo jogador (fica guardado na aba).

**O limite:** tudo o que roda no navegador pode ser forjado por quem sabe
mexer. Serve para mostrar o nome e guardar progresso local. **Não use** para
moedas, ranking, compras ou qualquer coisa de valor — para isso, um servidor
com a troca normal.

O resto da integração (`frame-ancestors`, `pronto`, `aoSair`, `onde`) é igual.
Hospedagens estáticas: o cabeçalho vai num arquivo de configuração —
Netlify/Cloudflare Pages: `_headers` com
`/*` → `Content-Security-Policy: frame-ancestors 'self' https://plicflix.com`;
Vercel: `headers` no `vercel.json`. (GitHub Pages não deixa mudar cabeçalhos:
não serve.)

## Jogos só nativos

Hoje o plicflix abre jogos pela web (no app do celular, por uma WebView). Um
jogo que só existe como app Android/iOS ou executável de PC **ainda não**
consegue entrar. Se o seu motor exporta para a web (Unity, Godot, Defold,
GameMaker…), exporte e siga esta página. Jogo em nuvem (streaming de vídeo do
jogo rodando num servidor) está nos planos; fale com `suporte@plicflix.com` se
for o seu caso.
