- Adds Character model with survival needs (hunger, thirst, energy) and state machine - Implements city:tick world ticker for offline progression every minute - Adds city territory expansion and building construction system - Introduces job economy, inventory, and transaction audit trail - Adds social graph (friends, marriage, children) and character chat - Implements admin approval workflow for new registrations - Adds hospital admission system for traffic accidents - Includes comprehensive feature tests and world seeders
8.7 KiB
City10 — Cidadãos Persistentes, Economia Social e Expansão Territorial
Data: 2026-10-18 Status: Aprovado pelo usuário (design + spec + implementação em um ciclo)
1. Objetivo
Cada usuário registrado e aprovado pelo Admin ganha um personagem (Character) próprio na plataforma 3D, capaz de viver como um humano simulado: mover-se, construir e habitar, trabalhar, comer, estudar, comprar/vender, dormir/acordar, fazer amigos, formar família e ter filhos, conversar com outros personagens. O mundo persiste em nuvem sem reiniciar quando alguém entra ou sai, progride continuamente via ticker agendado, e suporta expansão de território e criação de novas cidades.
2. Aprovação de contas e personagem
users.status:pending|active|banned(campo novo;is_activepermanece espelhandostatus === activepara compatibilidade).POST /registercria usuário comopending(sem login no mundo até aprovação; login pendente mostra tela "aguardando aprovação").- Admin: rota
/admin/citizens— listar, aprovar (active), banir (banned). - Ao transitar para
active, cria-seCharacterautomaticamente (factory: nome = first name do usuário, aparência aleatória, spawn no centro decitiesativa). - Usuários existentes com
is_active=truemigram parastatus=active; character é criado sob demanda no primeiro acesso se faltar (lazy-seed).
3. Modelo de dados
cities
id, name, slug, origin_x/z (não usado — bounds), bounds_min_x, bounds_max_x, bounds_min_z, bounds_max_z, is_active, created_at, updated_at
- Seed:
City10com bounds equivalentes ao grid atual (−80..80).
characters
id, user_id (unique), city_id, name, skin, hair, shirt, pos_x, pos_y, pos_z, money (decimal), energy (0-100), hunger (0-100), thirst (0-100), state (awake|sleeping|working|studying|eating), job_id (nullable), house_id (nullable), education (0-100), is_online (boolean), last_tick_at, created_at, updated_at
buildings
id, city_id, owner_character_id, type (house|shop_extension|school|restaurant), name, pos_x, pos_z, width, depth, height, is_complete, build_progress (0-100), created_at, updated_at
relationships
id, character_a_id, character_b_id, type (friend|spouse|parent_child), status (pending|accepted), created_at
parent_child:character_a= filho,character_b= pai/mãe (para filhos NPCs: child pode teruser_idnull via character órfão — na prática filhos sãocharacterssemuser_id).
inventory_items
id, character_id, item (food|water|materials|product), qty, created_at, updated_at (unique character_id+item)
transactions
id, from_character_id, to_character_id (nullable = loja/NPC), store_id (nullable), item, qty, amount, created_at
jobs
id, city_id, store_id (nullable), title, salary, requires_education (0-100), created_at, updated_at
- Seed: Padeiro (Padaria), Mercado, Prefeitura, Escola.
children_npc
Filhos nascem como characters com user_id = NULL, state=awake, idade simulada via created_at + growth_days opcional. Sem login.
4. Ticker de mundo (city:tick)
Comando Artisan agendado a cada 1 minuto (routes/console.php → Schedule::command('city:tick')->everyMinute()):
Para cada character com state != 'dead' (não existe morte):
- Necessidades:
hunger -= 0.5,thirst -= 0.8,energy -= 0.4por tick (proporção ao delta real de tempo desdelast_tick_at, com cap). - Dormindo (
state=sleeping):energy += 15até 100; se energy>=100 →state=awake. - Trabalhando (
state=workingcomjob_id): creditarsalary/30(dia de trabalho ≈ 30 ticks) emmoney; consumir energy extra. - Estudando:
education += 0.5até 100, consome energy. - Fome/sede severas (hunger<=0 ou thirst<=0): energy drena 2× e
stateviraawake(não morre). - IA offline simples: se
is_online=falsee energy<20 e house existe → dormir; se energy>80 e job existe e horário “dia” (tick % 1440 entre 480–1080) → trabalhar; senão awake. - Filhos: characters sem
user_idcomeducationcrescendo automaticamente seage_days < 18*365(simplificado:growth+1/tick até cap de adulto).
city:tick é idempotente por last_tick_at (skip se < 50s).
5. Gameplay (ações do jogador)
Endereços web (sessão) + espelho API Sanctum opcional:
| Ação | Rota | Efeito |
|---|---|---|
| Comer | POST /city/actions/eat |
consome 1 food do inventário; hunger +40 |
| Beber | POST /city/actions/drink |
consome water; thirst +40 |
| Dormir | POST /city/actions/sleep |
state=sleeping (exige casa completa) |
| Acordar | POST /city/actions/wake |
state=awake |
| Trabalhar | POST /city/actions/work |
state=working (exige emprego) |
| Parar trabalho | POST /city/actions/stop-work |
state=awake |
| Estudar | POST /city/actions/study |
state=studying (exige school na cidade) |
| Comprar | POST /city/actions/buy |
store → inventário, money−preço |
| Vender | POST /city/actions/sell |
inventário → money |
| Construir casa | POST /city/actions/build |
valida terreno livre em quadra + materials ≥ 50; cria building build_progress=0 e debita os materials no ato; ticker avança build_progress += 10 por tick até 100 → is_complete=true e vira house_id do dono se ainda não tiver casa |
| Amizade | POST /city/social/friend + accept |
relationship friend pending/accepted |
| Casamento | POST /city/social/marry |
ambos accepted friends → spouse (1 esposo) |
| Filho | POST /city/social/child |
exige casal spouse; cria character NPC criança |
| Chat | POST /city/chat/{character} (estender fluxo existente) |
mensagens persistidas em character_messages (nova tabela simples: id, from, to, body, created_at) |
Validações em Form Requests; autorização via policy/ownership (só o próprio character).
6. Viewer 3D (evolução do existente)
- Rota
GET /cityusa?city=(slug/id; default ativa). /city/dataretorna tambémcharacters(posição, estado, nome, money/needs do próprio),buildings,jobs, bounds da cidade.- Controla character do usuário: WASD grava posição localmente e persiste (throttled POST
/city/actions/position, 1–2 s). - HUD: fome, sede, energia, dinheiro, estado.
- Menu de ações (botões) chamando as rotas de ações; inventário simples.
- Cidadãos (characters com user ou NPC filhos) renderizados como humanoides;
is_onlinedestaca. - Terrenos livres: quadras sem building de casa → painel “Construir aqui” quando próximo.
- Limites da cidade aplicados (clipe nos bounds da cidade ativa).
7. Expansão e multi-cidade
- Admin
POST /admin/citiescria cidade nova (bounds default 160×160) + layout grid gerado no cliente a partir de bounds (estenderCityViewerController::cityLayoutpara usar bounds da cidade, não só stores). - Admin
POST /admin/cities/{city}/expandaumentabounds_max_*em 40 (uma quadra) — limitado a 10 expansões/cidade (colunaexpansions). - Viewer e ticker filtram por
city_id.
8. Persistência em nuvem
- Estado exclusivamente em MariaDB;
city:tickvia cron* * * * * php artisan schedule:rundocumentado no README de deploy. - Entrar/sair não reseta nada; múltiplas sessões simultâneas: posição mais recente vence (
updated_at). - Fila opcional não é obrigatória neste ciclo.
9. LGPD e regras do repo
- Sem dados pessoais em payloads de IA; chat entre characters é dado do usuário (consentimento LGPD já coberto pelos termos).
- Nenhuma remoção de proteção LGPD; CAPTCHA mantido; CSRF; i18n completa (pt_BR/en/es) para TODAS as strings novas.
- PHPDoc em inglês; Pint; testes PHPUnit nos fluxos; licenças registradas em RULES.md se houver dependência nova (não planejado).
10. Testes e critérios de aceite
PHPUnit:
- Registro cria
pending; login pendente bloqueado com mensagem. - Admin aprova →
active+ character criado. - Tick degrada necessidades; dormir recupera energy; trabalhar paga salário; comer/beber funcionam com inventário.
- Comprar/vender alteram money/inventário/transactions.
- Construir valida terreno e materiais; progresso avança no tick.
- Amizade → casamento → filho cria character NPC.
- Expansão de bounds e criação de cidade pelo admin.
Playwright MCP:
- Fluxo completo: register → pending → login vê espera → admin aprova → usuário entra no city com character → HUD necessidades → comer/dormir/trabalhar via UI → construir casa → adicionar amigo (2º usuário) → chat → admin expande território → nova cidade visível.
- Console sem erros; screenshots de evidência; corrigir bugs até limpo.
11. Fora de escopo
Morte permanente, combate, Reverb realtime, OpenRouter obrigatório no tick, moeda fiat real, mobile nativo.