No description
  • Rust 99.7%
  • Lua 0.3%
Find a file
2026-08-01 09:28:31 +02:00
assets feat: create first mvp 2026-08-01 09:28:31 +02:00
src feat: create first mvp 2026-08-01 09:28:31 +02:00
.gitignore Initial commit 2026-08-01 07:27:59 +00:00
Cargo.toml feat: create first mvp 2026-08-01 09:28:31 +02:00
LICENSE Initial commit 2026-08-01 07:27:59 +00:00
README.md feat: create first mvp 2026-08-01 09:28:31 +02:00

PoC2: Lua como editor → RON como runtime (console-friendly)

Objetivo

Demonstrar um pipeline de conteúdo onde Lua é ferramenta de autoria e RON é o formato de runtime. Designers escrevem scripts .lua imperativos (set_flag, get_flag, move_npc, open_door, close_door); em builds de desenvolvimento (feature lua-editor, ligada por padrão), o jogo compila o .lua para um .ron declarativo no startup e em seguida consome só o .ron. Builds "console" (--no-default-features) não embarcam VM de Lua nenhuma — leem direto o .ron pré-compilado. Outras pessoas podem criar quests/eventos sem mexer no Rust.

Pipeline

level_1.lua ──(lua-editor: compile no startup)──▶ level_1.ron ──▶ WorldState/ECS
                                                  ▲
                             build console lê daqui (sem mlua)
  • Compilador (src/lua_compiler.rs, atrás da feature lua-editor): executa o .lua num sandbox com bindings de captura — cada chamada vira um CompiledAction gravado em ordem; o resultado é serializado em .ron ao lado do fonte.
  • Runtime (src/compiled_script.rs, sempre compilado): lê o .ron, aplica SetFlag direto nas flags e enfileira MoveNpc/OpenDoor/CloseDoor como PendingAction — a mesma fila que action_consumer já drena.
  • get_flag no compilador lê as initial_flags do config.ron + as flags que o próprio script setou (semântica determinística de snapshot).

Build de console (sem Lua)

cargo run -p poc2 --no-default-features

Roda o mesmo cenário de demonstração lendo apenas assets/scripts/level_1.ron (pré-compilado e commitado), sem mlua no binário.

Como rodar

cargo run -p poc2

Aguarde ~30s para build cold (mlua + bevy compilam do zero na primeira vez).

Fluxo principal

  1. ScriptPipelinePlugin (Startup) insere MutableState como Resource
  2. Com lua-editor: lua_compiler::compile_lua_scriptslevel_1.lua, executa no sandbox capturando as chamadas, e (re)escreve level_1.ron
  3. compiled_script::load_compiled_script seeda as flags de config.initial_flags, lê level_1.ron e aplica: flags direto, ações na fila de PendingAction
  4. action_consumer::process_actions (Update) drena a fila e aplica no ECS: move NPCs, abre portas, etc.

Script de exemplo

poc2/assets/scripts/level_1.lua:

set_flag("intro_shown", true)
set_flag("npc_king_dead", true)
move_npc("guide", 10.0, 20.0)
move_npc("Guard", 120.0, 340.0)
open_door("throne_room")

Controles

Nenhum — a demo roda automaticamente no Startup.

O que aparece na tela

Visual (janela 3D aberta)

  • NPC guide — quadrado azul 40×40 px em world (0, 0). Após move_npc("guide", 10, 20) no Lua, vai para (10, 20).
  • NPC Guard — quadrado vermelho 40×40 px em world (100, 300). Após move_npc("Guard", 120, 340), vai para (120, 340).
  • Door throne_room — retângulo verde 60×120 px em world (200, 0). Após open_door("throne_room") no Lua, vira vermelho (perde a colisão via marcador RemoveCollider).
  • HUD — texto Text2d no canto superior esquerdo em world (-550, 320, 1) mostrando flags atuais + actions queue. Fonte 18pt branca. Cada flag muda de cor conforme o valor: verde quando true, cinza quando false — visível em tempo real assim que um script chama set_flag, inclusive para chaves novas que ainda não existiam.

Inspector (devtool, F1)

  • Painel lateral direito (360 px) com 6 seções colapsáveis: Camera / NPCs / Doors / HUD / Initial Flags / Scripts
  • 3 botões no rodapé: Apply (despawn + respawn + reset flags), Save to RON, Reload from RON
  • Pressione F1 para mostrar/ocultar
  • Mouse interage com widgets (DragValue, TextEdit, Checkbox)
  • Sem mouse não dá pra editar valores

Terminal (logs info!)

INFO poc2::script_loader: executing initial script: ".../poc2/assets/scripts/level_1.lua"
INFO poc2::script_loader: initial script executed successfully
INFO poc2::action_consumer: moved NPC guide to (10, 20)
INFO poc2::action_consumer: moved NPC Guard to (120, 340)
INFO poc2::action_consumer: opened door throne_room
INFO poc2::hud: PoC2 HUD is live

Arquitetura

  • poc2/src/main.rs — entry point, spawns NPCs (guide, Guard) e Door (throne_room) do config.ron
  • poc2/src/compiled_script.rsCompiledAction/CompiledScript (serde), applier RON→WorldState, ScriptPipelinePlugin
  • poc2/src/lua_compiler.rs — (feature lua-editor) sandbox + bindings de captura + compile no startup
  • poc2/src/world_state.rsWorldState (HashMap<String, bool> + VecDeque<PendingAction>) e MutableState (Arc<Mutex<WorldState>>)
  • poc2/src/action_consumer.rs — sistema Update que drena actions e aplica no ECS
  • poc2/assets/scripts/level_1.lua — script de autoria (fonte)
  • poc2/assets/scripts/level_1.ron — script compilado (runtime; regenerado pelo lua-editor)

Segurança

lua_compiler::install_sandbox remove funções perigosas (loadfile, dofile, collectgarbage) do ambiente Lua para evitar que scripts de autoria escapem do sandbox. Em builds de produção o problema nem existe: não há VM.

Contratos com outros PoCs

  • Fornece WorldState Resource (flag store + action queue) para poc4, poc6, poc7
  • Fornece MutableState Resource (Arc<Mutex>) para acesso concorrente
  • Define contrato de flags: bridge_fixed, shop_ruined, quest_accepted, intro_shown, npc_king_dead, etc.
  • Define contrato de actions: MoveNpc { id, x, y }, OpenDoor { id }, CloseDoor { id }

Status

Roda limpo | Lua scripts executam | Actions aplicadas com sucesso | Sandbox ativo | Testes unitários em bindings, world_state, action_consumer e lua_state