v0.7.0: SDL-free wasm worker backend (WebGPU + WebGL2) with on-demand assets
The engine now runs on a plain Web Worker (no SDL, no PROXY_TO_PTHREAD: in a pthread Emscripten proxies every filesystem syscall to the main browser thread, where synchronous XHR - and thus FS.createLazyFile - is forbidden). A page/worker pair transfers an OffscreenCanvas and forwards DOM input; assets load lazily from an embedded manifest, so entering a map fetches only that map and its tiles. Presentation: ra3.webgpu (WebGPU via Emscripten's emdawnwebgpu port, WGSL shaders, the default on wasm) and ra3.wasmgl (WebGL2, GLSL ES). The legacy SDL ra3.webgl backend is removed.
This commit is contained in:
+33
-8
@@ -1,14 +1,16 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Static file server with HTTP Range support, for the OpenRA3 wasm build.
|
||||
|
||||
Emscripten's lazy MEMFS reads assets back as byte ranges, so the server must
|
||||
honour the ``Range`` header -- Python's stdlib ``http.server`` does not.
|
||||
Emscripten's lazy file reads stream assets back as byte ranges, so the server
|
||||
must honour the ``Range`` header -- Python's stdlib ``http.server`` does not.
|
||||
|
||||
python3 apps/web/serve.py --root build/wasm/bin --port 8199
|
||||
# then open http://localhost:8199/openra3.html
|
||||
# then open http://localhost:8199/index.html
|
||||
|
||||
Serve ``--root`` containing ``openra3.html/.js/.wasm``, ``assets.manifest.json``
|
||||
and the extracted ``assets/`` tree (a directory or a junction/symlink to it).
|
||||
Serve ``--root`` containing ``index.html``, ``openra3.js``, ``openra3.wasm``,
|
||||
``openra3.worker.js`` and ``assets.manifest.json``. The lazy asset tree is
|
||||
mounted from ``--assets`` (its files are then fetched from ``/assets/<rel>`` on
|
||||
demand); without ``--assets`` the tree is expected under ``--root`` itself.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
@@ -22,11 +24,27 @@ _RANGE = re.compile(r"bytes=(\d*)-(\d*)$")
|
||||
|
||||
|
||||
class RangeHandler(SimpleHTTPRequestHandler):
|
||||
# SharedArrayBuffer (needed by the pthreads build) requires cross-origin
|
||||
# isolation.
|
||||
# Directory served for ``/assets/...`` (set in main); None means "under root".
|
||||
assets_dir = None
|
||||
|
||||
def translate_path(self, path):
|
||||
if self.assets_dir:
|
||||
prefix = "/assets/"
|
||||
if path == "/assets" or path.startswith(prefix):
|
||||
rel = path[len(prefix):] if path.startswith(prefix) else ""
|
||||
rel = rel.split("?", 1)[0].split("#", 1)[0]
|
||||
parts = [p for p in rel.split("/") if p and p != ".."]
|
||||
return os.path.join(self.assets_dir, *parts)
|
||||
return super().translate_path(path)
|
||||
|
||||
# Cross-origin isolation (kept for SharedArrayBuffer-style features and the
|
||||
# WebGPU/pthread paths). no-store keeps the dev loop honest: a stale
|
||||
# openra3.js/.wasm in the browser cache hides new builds (the worker's
|
||||
# importScripts especially).
|
||||
def end_headers(self):
|
||||
self.send_header("Cross-Origin-Opener-Policy", "same-origin")
|
||||
self.send_header("Cross-Origin-Embedder-Policy", "require-corp")
|
||||
self.send_header("Cache-Control", "no-store, max-age=0")
|
||||
super().end_headers()
|
||||
|
||||
def send_head(self):
|
||||
@@ -86,6 +104,7 @@ class RangeHandler(SimpleHTTPRequestHandler):
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="OpenRA3 wasm dev server")
|
||||
parser.add_argument("--root", default="build/wasm/bin", help="directory to serve")
|
||||
parser.add_argument("--assets", default=None, help="directory served for /assets (the lazy asset tree)")
|
||||
parser.add_argument("--port", type=int, default=8199)
|
||||
parser.add_argument("--bind", default="127.0.0.1")
|
||||
args = parser.parse_args()
|
||||
@@ -93,9 +112,15 @@ def main() -> int:
|
||||
if not os.path.isdir(args.root):
|
||||
print(f"root not found: {args.root}", file=sys.stderr)
|
||||
return 1
|
||||
if args.assets and not os.path.isdir(args.assets):
|
||||
print(f"assets not found: {args.assets}", file=sys.stderr)
|
||||
return 1
|
||||
RangeHandler.assets_dir = os.path.abspath(args.assets) if args.assets else None
|
||||
handler = functools.partial(RangeHandler, directory=args.root)
|
||||
server = ThreadingHTTPServer((args.bind, args.port), handler)
|
||||
print(f"serving {args.root} at http://{args.bind}:{args.port}/openra3.html")
|
||||
print(f"serving {args.root} at http://{args.bind}:{args.port}/index.html")
|
||||
if RangeHandler.assets_dir:
|
||||
print(f" /assets -> {RangeHandler.assets_dir}")
|
||||
try:
|
||||
server.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
|
||||
Reference in New Issue
Block a user