tools/engine.js
67 lines · 2254 bytes
1"use strict"
2// Loads the real, unmodified 1MB game into a stubbed browser environment:
3// sprites.js, data.js, then the inline engine script from index.html.
4// Returns the vm context; engine globals (S, R, O, step, build, ...) live in it.
5const fs = require("fs")
6const path = require("path")
7const vm = require("vm")
8
9function load(gameDir) {
10 const html = fs.readFileSync(path.join(gameDir, "index.html"), "utf8")
11 const dataSrc = fs.readFileSync(path.join(gameDir, "data.js"), "utf8")
12 const spriteSrc = fs.readFileSync(path.join(gameDir, "sprites.js"), "utf8")
13
14 // The engine is the inline <script> block that follows the data.js include.
15 const m = html.match(/<script src=data\.js><\/script>\s*<script>([\s\S]*?)<\/script>/)
16 if (!m) {
17 console.error("engine: could not find the inline engine <script> after the data.js include in index.html")
18 process.exit(2)
19 }
20 const engineSrc = m[1]
21
22 // Minimal inert DOM node — enough surface for the engine's load-time render().
23 function el() {
24 return {
25 dataset: {},
26 textContent: "",
27 innerHTML: "",
28 className: "",
29 hidden: false,
30 appendChild() {},
31 onclick: null,
32 classList: { toggle() {} },
33 insertAdjacentHTML() {},
34 insertAdjacentText() {},
35 }
36 }
37
38 const sandbox = {
39 document: {
40 getElementById: () => el(),
41 createElement: () => el(),
42 },
43 addEventListener() {},
44 localStorage: {
45 _mem: Object.create(null),
46 getItem(k) { return k in this._mem ? this._mem[k] : null },
47 setItem(k, v) { this._mem[k] = String(v) },
48 removeItem(k) { delete this._mem[k] },
49 },
50 window: { AudioContext: function () { throw new Error("SFX must not run headless") } },
51 console,
52 }
53 const ctx = vm.createContext(sandbox)
54
55 try {
56 vm.runInContext(spriteSrc, ctx, { filename: "1mb/sprites.js" })
57 vm.runInContext(dataSrc, ctx, { filename: "1mb/data.js" })
58 vm.runInContext(engineSrc, ctx, { filename: "1mb/index.html#engine" })
59 } catch (e) {
60 console.error("engine: game code failed to evaluate headless — improve the stubs in this harness, do not touch the game.")
61 console.error(e && e.stack || e)
62 process.exit(2)
63 }
64 return ctx
65}
66
67module.exports = { load }