feat(city): add airports, ATC agent, luminous signs, and AI model fallback chain

- Add two airports (north/south) with full geometry: runways, taxiways,
  aprons, terminals, hangars, stands, and helipads; walkable airport
  grounds extend beyond city bounds.
- Introduce ATC AI agent ("Torre de Controle City10") using AI_ATC_MODEL
  to generate takeoff clearances; includes dispatch endpoint with
  30-second cooldown and deterministic fallback on failure.
- Implement AI model fallback chain: preferred model → AI_FALLBACK_MODEL
  before failing, applied in ChatController and PersonTalkController.
- Add luminous sign labels (letreiros) for plazas, beach, food, hospital,
  school, city hall, and airports with day/night glow.
- Fix city presence cache: compute is_me per viewer instead of baking
  into shared per-second cache to prevent cross-user flag leakage.
- Add tests: AirportTest, CityPresenceTest, SignLabelsTest, and
  PersonTalkTest fallback model retry scenario.
This commit is contained in:
2026-10-31 22:06:18 -03:00
parent a12807492f
commit e7498e1566
26 changed files with 2226 additions and 108 deletions
+30 -4
View File
@@ -46,7 +46,7 @@ O visualizador `/city` carrega o mundo completo em tempo real:
- **Cidade de 72 quarteirões** (grade 9 × 8 de blocos de 40 m; bounds
`−120..160 × −120..120`), com rio e ponte a oeste, extensão rodoviária ao
norte, hospital, escola, prefeitura e casas de jogadores.
sul, hospital, escola, prefeitura e casas de jogadores.
- **Trânsito**: carros, motos, bikes e ônibus com tráfego à direita, loop por
quarteirão e **semáforos por cruzamento** (fases NS/EW com amarelos e
all-red; veículos param na linha de parada **antes** das faixas).
@@ -63,6 +63,19 @@ O visualizador `/city` carrega o mundo completo em tempo real:
e bola em arremesso, barracas de comidas, cadeiras e guarda-sóis**.
O jogador pode **relaxar na areia** (tecla `E` → `POST /city/actions/beach`),
recuperando energia/saúde por tick até o máximo.
- **Dois aeroportos** derivados dos bounds (pavimento + sinalização de
pista com designadores, taxiways com eixo amarelo, pátio de embarque com
posições de estacionamento de aeronaves, terminal com pontes articuladas,
hangars, torre de controle e helipista): **7 aeronaves de 7 companhias**
(jato comercial, jato regional, monomotor e helicóptero) executam o ciclo
completo *taxi → decolagem → cruíse sobre a cidade → aproximação → pouso
→ taxi → gate*, com contagem de decolagens/pousos em `stats().flights`.
- **Torre de controle com IA**: o agente `atc` "Torre de Controle City10"
(modelo `AI_ATC_MODEL`, `poolside/laguna-xs-2.1:free`) gera clearances de
decolagem a cada decolagem (`POST /city/airport/dispatch`, cooldown de
30 s) numa **cadeia de modelos** `AI_ATC_MODEL` → default →
`AI_FALLBACK_MODEL` (`xiaomi/mimo-v2.6-flash`), com texto determinístico
quando tudo falha; o clearance mais recente aparece como aviso "✈ ...".
- **Agentes vivos**: prefeito itinerante, lojistas nas lojas, pedestres com
rotas, mais trens (passagem de nível com barreiras), ônibus/trem
embarcáveis, avião e barcos no rio.
@@ -163,6 +176,14 @@ AI_MODELS=deepseek/deepseek-v4-flash-0731,nvidia/nemotron-3.5-lightning:free,liq
# Override por personagem: "nome ou id=modelo" separado por vírgula.
AI_CHARACTER_MODELS=
# AI_ATC_MODEL: default model of the control-tower agent (airport
# clearances: takeoff authorizations). Must be allow-listed.
AI_ATC_MODEL=poolside/laguna-xs-2.1:free
# AI_FALLBACK_MODEL: tried when the preferred model of a call fails
# (owner-approved paid model with near-zero cost).
AI_FALLBACK_MODEL=xiaomi/mimo-v2.6-flash
```
### 4. Banco de dados
@@ -274,6 +295,8 @@ Todas exigem login + termos aceitos.
| POST/GET | `/city/chat/{agent}` (+`/stream`) | Conversa com NPC (envio + SSE de resposta) |
| POST/GET | `/city/messages/{character}` | Mensagens assíncronas entre personagens |
| POST | `/city/social/{verb}` · GET `/city/social/inbox` | Amizade, casamento, filho, inbox |
| GET | `/city/airport` | Sites dos aeroportos, torre (ATC) e clearance atual |
| POST | `/city/airport/dispatch` | Pede um clearance de decolagem à torre (cooldown 30 s) |
| GET/POST | `/city/market` (`/buy`, `/sell`) | Mercado |
| GET/PUT | `/city/customize` | Personalização do personagem |
@@ -281,9 +304,11 @@ Todas exigem login + termos aceitos.
## Modelos de IA Permitidos
Somente os modelos **gratuitos** abaixo podem ser usados (validado no backend
em `config/ai.php`; os quatro últimos foram verificados ao vivo no catálogo do
OpenRouter):
Somente os modelos abaixo podem ser usados (validado no backend em
`config/ai.php`; os quatro últimos foram verificados ao vivo no catálogo do
OpenRouter). Exceção aprovada pelo responsável: `xiaomi/mimo-v2.6-flash`
(pago, custo mínimo ~1,4e-7/token, verificado ao vivo) — usado como
**fallback** de todas as cadeias de chamada:
```
poolside/laguna-m.1:free cohere/north-mini-code:free
@@ -297,6 +322,7 @@ poolside/laguna-xs-2.1:free inclusionai/ling-3.0-flash-vl:free
qwen/qwen3.7-flash:free
deepseek/deepseek-v4-flash-0731 nvidia/nemotron-3.5-lightning:free
liquid/lfm-2.5-2.6b:free openrouter/free
xiaomi/mimo-v2.6-flash (fallback — ver nota acima)
```
---