O engine-kit (opcional)
Esta página é opcional. Tudo aqui é uma forma conveniente de produzir um run conforme; você pode ignorar o kit por completo e enviar um run cru que você escreveu à mão. Recorra ao @caputchin/engine-kit quando preferir escrever lógica de jogo comum e ter o determinismo, o loop de replay e a codificação de trace tratados por você.
O kit reexporta toda a superfície do contrato de replay, então os usuários do kit têm um único ponto de import.
npm install @caputchin/engine-kitA ideia: escreva um reducer, obtenha um run
O movimento central do kit é deixar você expressar seu jogo como um reducer puro: uma função que recebe o estado atual e a entrada de um tick e retorna o próximo estado. Desse reducer mais primitivas determinísticas, o adaptador toRun do kit produz um run(seed, config, trace) que conforma o contrato por construção.
import { defineEngine, toRun, cap } from "@caputchin/engine-kit";
const engine = defineEngine({
setup(seed) {
const rng = cap.rng(seed); // deterministic, seeded RNG
return { score: 0, targets: spawn(rng), rng };
},
tick(state, input) {
// pure: same (state, input) always yields the same next state
return applyInput(state, input);
},
result(state) {
return { passed: state.score >= 3, score: state.score, durationMs: state.elapsed };
},
});
export const run = toRun(engine); // a conforming RunFnPrimitivas determinísticas
O kit te dá as duas coisas que mais frequentemente quebram o determinismo entre runtimes, ambas semeadas e reproduzíveis:
cap.rng(seed)(ecap.rngFromState) - um PRNG semeável. Use-o para cada escolha aleatória em vez deMath.random().cap.math- transcendentais determinísticos (sin,cos, ...) que concordam entre runtimes, em vez dosMathda plataforma que podem não concordar.
Shims opcionais
applyShim()- neutraliza os globais não determinísticos (o relógio,Math.random) para que uma chamada acidental falhe de forma barulhenta no desenvolvimento em vez de divergir silenciosamente no replay.applyDomShim()- um DOM headless mínimo para o caminho de framework, para que um reducer que toca uma pequena superfície de DOM ainda reexecute no isolate sem DOM.
Rode-o localmente antes de publicar
O harness replay do kit roda um trace pela sua engine do mesmo jeito que o servidor vai, e o selfCheck roda uma bateria de casos e reporta qualquer não determinismo antes de você publicar:
import { selfCheck } from "@caputchin/engine-kit";
const report = selfCheck(engine, { cases: myCases });
if (!report.ok) console.error(report.violations);Um selfCheck local limpo é o melhor preditor de que a autoverificação de publicação do marketplace vai passar (é o mesmo padrão de determinismo). O kit também envia uma CLI para rodar isto a partir de scripts do package.json ou da CI.
Codificação de trace
encodeTrace / decodeTrace te dão um formato de trace compacto e versionado para que o fluxo de entrada que seu jogo ativo emite seja exatamente o que seu run decodifica no replay. Usá-los nos dois lados mantém os dois em lockstep.
Quando pular o kit
Pule-o quando você já tem lógica determinística (uma simulação de ponto fixo, um módulo WASM compilado para spec-floats) ou quando seu jogo é simples o bastante para escrever o run à mão ser trivial. A plataforma nunca sabe nem se importa se o kit produziu seu run; ela só carrega e reexecuta o contrato.
Veja também
- O contrato de replay: o
run/ seed / verdict que este kit produz. - Construir um jogo de marketplace: o jogo cuja lógica este kit pode embasar.
- O manifesto caputchin.json: enviar o
runproduzido como o artefato.