clean: remove all Doom-specific logic, fix path separator in jsdos.json
Build & Deploy / build-and-deploy (push) Successful in 1m5s

Removed:
- injectDoomConfig() — WAD-detection and WASD config injection
- buildDoomDefaultCfg() — Doom config file generator
- All calls to injectDoomConfig in both bundle paths

Fixed:
- buildJsdosJson() now also uses splitPath() helper to handle
  backslash separators (was using lastIndexOf('/') only)
- Extracted shared splitPath() method used by both
  buildJsdosJson and buildDosboxConf

No more game-specific hacks. Just clean config generation.
This commit is contained in:
David Alvarez
2026-05-27 10:48:38 +02:00
parent 596b897df6
commit e7b845e8a1
+22 -105
View File
@@ -83,14 +83,11 @@ public class UploadResource {
if ("sockdrive".equals(bundleType)) { if ("sockdrive".equals(bundleType)) {
// Copy files loose // Copy files loose
copyDir(extractDir, gameDir); copyDir(extractDir, gameDir);
// Auto-inject WASD config for Doom-engine games // Write js-dos config
injectDoomConfig(extractDir, gameDir);
// Write dosbox.conf (full config, not just autoexec)
Path jsdos = gameDir.resolve(".jsdos"); Path jsdos = gameDir.resolve(".jsdos");
Files.createDirectories(jsdos); Files.createDirectories(jsdos);
String relExe = extractDir.relativize(Path.of(mainExe)).toString().replace('/', '\\'); String relExe = extractDir.relativize(Path.of(mainExe)).toString().replace('/', '\\');
String conf = buildDosboxConf(relExe); Files.writeString(jsdos.resolve("dosbox.conf"), buildDosboxConf(relExe));
Files.writeString(jsdos.resolve("dosbox.conf"), conf);
Files.write(jsdos.resolve("jsdos.json"), buildJsdosJson(relExe)); Files.write(jsdos.resolve("jsdos.json"), buildJsdosJson(relExe));
bundleFile = ".jsdos/dosbox.conf"; bundleFile = ".jsdos/dosbox.conf";
} else { } else {
@@ -210,15 +207,12 @@ public class UploadResource {
Path tmpBundle = Files.createTempDirectory("dostalgia-bundle-"); Path tmpBundle = Files.createTempDirectory("dostalgia-bundle-");
try { try {
copyDir(extractDir, tmpBundle); copyDir(extractDir, tmpBundle);
// Auto-inject WASD config for Doom-engine games
injectDoomConfig(extractDir, tmpBundle);
// Create .jsdos config (full config, not just autoexec) // Create .jsdos config
Path jsdos = tmpBundle.resolve(".jsdos"); Path jsdos = tmpBundle.resolve(".jsdos");
Files.createDirectories(jsdos); Files.createDirectories(jsdos);
String relExe = extractDir.relativize(Path.of(mainExe)).toString().replace('/', '\\'); String relExe = extractDir.relativize(Path.of(mainExe)).toString().replace('/', '\\');
String conf = buildDosboxConf(relExe); Files.writeString(jsdos.resolve("dosbox.conf"), buildDosboxConf(relExe));
Files.writeString(jsdos.resolve("dosbox.conf"), conf);
Files.write(jsdos.resolve("jsdos.json"), buildJsdosJson(relExe)); Files.write(jsdos.resolve("jsdos.json"), buildJsdosJson(relExe));
// ZIP it up // ZIP it up
@@ -239,23 +233,11 @@ public class UploadResource {
} }
} }
// ─── File Utilities ────────────────────────────────────────── // ─── Configuration Helpers ───────────────────────────────────
/**
* Build a minimal dosbox.conf with the critical settings for js-dos v8.
* The key setting is usescancodes=true — without it DOSBox doesn't
* translate physical key presses into game input.
*/
private byte[] buildJsdosJson(String relExe) { private byte[] buildJsdosJson(String relExe) {
// Split into directory and executable components for subdirectory support String parts[] = splitPath(relExe);
String dir = ""; String script = (parts[0].isEmpty() ? "" : "cd " + parts[0] + " && ") + parts[1];
String exe = relExe;
int idx = relExe.lastIndexOf('/');
if (idx >= 0) {
dir = relExe.substring(0, idx);
exe = relExe.substring(idx + 1);
}
String script = (dir.isEmpty() ? "" : "cd " + dir + " && ") + exe;
String json = "{" String json = "{"
+ "\"autoexec\":{" + "\"autoexec\":{"
+ "\"options\":{\"script\":{\"value\":\"" + escapeJson(script) + "\"}}" + "\"options\":{\"script\":{\"value\":\"" + escapeJson(script) + "\"}}"
@@ -266,19 +248,10 @@ public class UploadResource {
return json.getBytes(java.nio.charset.StandardCharsets.UTF_8); return json.getBytes(java.nio.charset.StandardCharsets.UTF_8);
} }
private String escapeJson(String s) {
return s.replace("\\", "\\\\").replace("\"", "\\\"");
}
private String buildDosboxConf(String relExe) { private String buildDosboxConf(String relExe) {
// Split into directory and executable components for subdirectory support String parts[] = splitPath(relExe);
String dir = ""; String dir = parts[0];
String exe = relExe; String exe = parts[1];
int idx = Math.max(relExe.lastIndexOf('/'), relExe.lastIndexOf('\\'));
if (idx >= 0) {
dir = relExe.substring(0, idx);
exe = relExe.substring(idx + 1);
}
return "[sdl]\n" return "[sdl]\n"
+ "autolock=true\n" + "autolock=true\n"
@@ -314,80 +287,24 @@ public class UploadResource {
} }
/** /**
* Detect Doom-engine games and inject a DEFAULT.CFG with WASD controls. * Split a DOS path into directory and filename parts.
* Searches recursively for DOOM.WAD / DOOM2.WAD in source, then writes * Handles both backslash and forward-slash separators.
* config files to the destination root (where the game will look for them). * Returns [dir, exe] where dir is empty for root-level files.
*/ */
private void injectDoomConfig(Path srcDir, Path dstDir) throws IOException { private String[] splitPath(String path) {
boolean hasDoom = false; int idx = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
try (var walk = Files.walk(srcDir)) { if (idx >= 0) {
hasDoom = walk.anyMatch(p -> { return new String[]{path.substring(0, idx), path.substring(idx + 1)};
String name = p.getFileName().toString().toUpperCase();
return name.equals("DOOM.WAD") || name.equals("DOOM2.WAD");
});
} }
if (!hasDoom) { return new String[]{"", path};
LOG.info("No Doom WAD found in upload");
return;
}
LOG.info("Doom detected — injecting WASD config");
byte[] cfg = buildDoomDefaultCfg();
Files.write(dstDir.resolve("DEFAULT.CFG"), cfg);
// Doom II also reads DOOM2.CFG (game-specific, takes priority over DEFAULT)
Files.write(dstDir.resolve("DOOM2.CFG"), cfg);
LOG.info("Injected DEFAULT.CFG + DOOM2.CFG with WASD controls");
} }
/** private String escapeJson(String s) {
* Build a DEFAULT.CFG (Doom engine config) with WASD controls. return s.replace("\\", "\\\\").replace("\"", "\\\"");
* Only called when a DOOM.WAD or DOOM2.WAD is detected in the upload.
*
* Key bindings:
* W=forward, S=backward, A=strafe left, D=strafe right
* Arrows=turn, Ctrl=fire, Space=use, Alt=strafe, Shift=run
* Mouse enabled for looking
*/
private byte[] buildDoomDefaultCfg() {
// Use CRLF (\r\n) line endings — Doom's config parser uses fgets()
// which includes \r in the buffer on DOS. Missing \r can cause parsing issues.
String CRLF = "\r\n";
String cfg = ""
+ "mouse_sensitivity\t\t5" + CRLF
+ "sfx_volume\t\t8" + CRLF
+ "music_volume\t\t8" + CRLF
+ "show_messages\t\t1" + CRLF
+ "key_right\t\t77" + CRLF // Right arrow — turn right
+ "key_left\t\t75" + CRLF // Left arrow — turn left
+ "key_up\t\t17" + CRLF // W — forward
+ "key_down\t\t31" + CRLF // S — backward
+ "key_strafeleft\t\t30" + CRLF // A — strafe left
+ "key_straferight\t\t32" + CRLF // D — strafe right
+ "key_fire\t\t29" + CRLF // Ctrl — fire
+ "key_use\t\t57" + CRLF // Space — use/open
+ "key_strafe\t\t56" + CRLF // Alt — strafe (hold)
+ "key_speed\t\t54" + CRLF // Shift — run
+ "use_mouse\t\t1" + CRLF
+ "mouseb_fire\t\t0" + CRLF
+ "mouseb_strafe\t\t1" + CRLF
+ "mouseb_forward\t\t2" + CRLF
+ "use_joystick\t\t0" + CRLF
+ "joyb_fire\t\t0" + CRLF
+ "joyb_strafe\t\t1" + CRLF
+ "joyb_use\t\t3" + CRLF
+ "joyb_speed\t\t2" + CRLF
+ "screenblocks\t\t10" + CRLF
+ "detaillevel\t\t0" + CRLF
+ "showmessages\t\t1" + CRLF
+ "comport\t\t1" + CRLF
+ "snd_channels\t\t3" + CRLF
+ "snd_musicdevice\t\t3" + CRLF
+ "snd_sfxdevice\t\t3" + CRLF
+ "snd_sbport\t\t544" + CRLF
+ "snd_sbirq\t\t7" + CRLF
+ "snd_sbdma\t\t1" + CRLF;
return cfg.getBytes(java.nio.charset.StandardCharsets.US_ASCII);
} }
// ─── File Utilities ──────────────────────────────────────────
private double dirSizeMB(Path dir) throws IOException { private double dirSizeMB(Path dir) throws IOException {
long[] total = {0}; long[] total = {0};
Files.walkFileTree(dir, new SimpleFileVisitor<>() { Files.walkFileTree(dir, new SimpleFileVisitor<>() {