feat: SETUP.EXE detection + separate setup .jsdos bundle
Build & Deploy / build-and-deploy (push) Successful in 1m1s
Build & Deploy / build-and-deploy (push) Successful in 1m1s
When a game archive contains SETUP.EXE, INSTALL.EXE, CONFIG.EXE or
CUSTOM.EXE (or .com/.bat variants), the upload now:
- Detects and stores the path in game metadata (setup_exe / has_setup)
- Generates a second .jsdos bundle with SETUP.EXE as autoexec:
- Standard mode: {gameId}.setup.jsdos (full game + setup autoexec)
- Sockdrive mode: .jsdos-setup/ directory alongside .jsdos/
- Both bundles share the same game files; only the autoexec differs
Frontend changes:
- Router strips query params from hash so ?setup=1 doesn't leak into id
- GameDetail shows a "Setup" button between Play and Edit (only when
game.has_setup is true), navigating to /play/{id}?setup=1
- Play.svelte detects ?setup=1, loads setupBundleUrl() instead, and
shows setup-specific overlay text
Persistence is handled automatically by js-dos v8 via the built-in
auto-save mechanism (ci.persist() → browser OPFS), so any config
changes made via SETUP.EXE survive across sessions.
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
<script>
|
||||
import { getGame, bundleUrl } from "../lib/api.js";
|
||||
import { getGame, bundleUrl, setupBundleUrl } from "../lib/api.js";
|
||||
import { push } from "../lib/router.js";
|
||||
|
||||
let { id } = $props();
|
||||
|
||||
// Read query params from the hash — window.location is available after mount
|
||||
let isSetup = $state(false);
|
||||
|
||||
let game = $state(null);
|
||||
let loading = $state(true);
|
||||
let error = $state("");
|
||||
@@ -16,6 +19,8 @@
|
||||
|
||||
async function load() {
|
||||
loading = true;
|
||||
// Detect ?setup=1 from the hash-based URL
|
||||
isSetup = window.location.hash.includes("setup=1");
|
||||
try {
|
||||
game = await getGame(id);
|
||||
} catch (e) {
|
||||
@@ -54,7 +59,7 @@
|
||||
|
||||
// Start the DOS emulator
|
||||
try {
|
||||
const url = bundleUrl(game);
|
||||
const url = isSetup ? setupBundleUrl(game) : bundleUrl(game);
|
||||
if (!url || !window.Dos) throw new Error("Failed to resolve game bundle");
|
||||
dosCI = await window.Dos(dosContainer, { url });
|
||||
running = true;
|
||||
@@ -71,6 +76,10 @@
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
push(`/game/${id}`);
|
||||
}
|
||||
|
||||
$effect(() => { load(); });
|
||||
|
||||
// Auto-start when both game data and the container exist
|
||||
@@ -98,7 +107,9 @@
|
||||
<!-- Top bar: shown when game is loaded -->
|
||||
<div class="play-header" class:active={game}>
|
||||
{#if game}
|
||||
<button class="link-button" onclick={stopEmulator}>← {game.title}</button>
|
||||
<button class="link-button" onclick={stopEmulator}>
|
||||
← {isSetup ? "Back" : game.title}
|
||||
</button>
|
||||
{#if running}
|
||||
<button class="btn stop-btn" onclick={stopEmulator}>⏹ Stop</button>
|
||||
{/if}
|
||||
@@ -119,8 +130,13 @@
|
||||
{:else if booting}
|
||||
<div class="overlay-icon">⚙️</div>
|
||||
<h2>{game?.title || ""}</h2>
|
||||
<p>Starting emulator...</p>
|
||||
<p class="save-hint">💾 Game saves are stored automatically</p>
|
||||
{#if isSetup}
|
||||
<p>Starting setup utility...</p>
|
||||
<p class="save-hint">⚙️ Configure controls, then exit SETUP to save</p>
|
||||
{:else}
|
||||
<p>Starting emulator...</p>
|
||||
<p class="save-hint">💾 Game saves are stored automatically</p>
|
||||
{/if}
|
||||
{:else if error}
|
||||
<div class="overlay-icon">⚠️</div>
|
||||
<h2>Failed to start</h2>
|
||||
|
||||
Reference in New Issue
Block a user