Introspecção
A Camada de Introspecção em Runtime (engine.introspect) fornece visualizações estruturadas e serializáveis em JSON do estado ativo do engine sem globais ou alocações. É a única fonte da verdade consumida pelo Protocolo de Depuração Remota, pelo servidor MCP e pelo Inspector do Studio.
Tipos principais
const engine = @import("engine");
// Uma visualização somente leitura de uma cena carregada entregue ao Inspector pelo host.
const SceneView = engine.introspect.SceneView;
// Tudo o que o Inspector pode ver em um único instante.
const World = engine.introspect.World;
// Um valor tipado para operações de mutação.
const Value = engine.introspect.Value;
Fornecendo um snapshot de World
O host (jogo ou studio) implementa um callback que retorna um World:
fn myWorldProvider(ctx: ?*anyopaque) engine.introspect.World {
const state: *GameState = @ptrCast(@alignCast(ctx));
return .{
.scenes = state.sceneViews(),
.metrics = &state.metrics,
};
}
O callback é chamado na thread de segundo plano do servidor de depuração uma vez por requisição. Ele deve retornar uma visualização somente leitura segura para acesso concorrente — um snapshot de frame é suficiente.
Auxiliares de serialização
// Tira um snapshot de todo o World como JSON (alocando na heap).
const json = try engine.introspect.snapshotJsonAlloc(allocator, world);
defer allocator.free(json);
// Ou transmite em fluxo (stream) diretamente para qualquer std.json.Stringify:
try engine.introspect.writeSnapshot(&jw, world);
// Esquema de todos os tipos de componentes nativos:
try engine.introspect.writeSchema(&jw);
Consultas (livres de alocação)
var indices: [128]usize = undefined;
// Busca por substring do nome:
const count = engine.introspect.findByName(scene.nodes, "Player", &indices);
// Busca por tipo de componente:
const count = engine.introspect.findByComponent(scene.nodes, "Camera", &indices);
// Verifica presença de componente:
const has = engine.introspect.hasComponent(node, "Light");
const ci = engine.introspect.componentIndex(node, "Light"); // ?usize
Métricas
engine.Metrics é o único destino de escrita para todos os subsistemas do engine:
engine.Metrics.recordFrame(dt_seconds); // chama uma vez por frame
engine.Metrics.beginFrame(); // redefine os contadores de renderização por frame
engine.Metrics.draw_calls += 1; // preenchido pelo renderizador
O debug server e o MCP server leem world.metrics para responder às chamadas de metrics e get_metrics.
Mutação
// Define um campo em um componente nativo:
try engine.introspect.setComponentField(node, "Camera", "fov", .{ .number = 90 });
// Define um campo de transform:
try engine.introspect.setTransformField(node, "position.x", .{ .number = 10 });
// Criar / destruir (enfileirado, aplicado no próximo frame):
try engine.introspect.spawnEntity(scene, "NewEnemy");
try engine.introspect.destroyEntity(scene, node_index);
Pelo protocolo, as mutações ficam acessíveis quando o servidor de depuração roda no modo leitura-escrita (allow_write / CLI --rw). O host registra um MutationApplier que o pump da thread principal do servidor invoca, permitindo que as edições sejam aplicadas com segurança ao estado ativo. O Studio conecta isso através de sua pilha de desfazer (undo stack) — consulte a página do Protocolo de Depuração Remota para obter a lista completa de métodos e eventos.