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)) {
// Copy files loose
copyDir(extractDir, gameDir);
// Auto-inject WASD config for Doom-engine games
injectDoomConfig(extractDir, gameDir);
// Write dosbox.conf (full config, not just autoexec)
// Write js-dos config
Path jsdos = gameDir.resolve(".jsdos");
Files.createDirectories(jsdos);
String relExe = extractDir.relativize(Path.of(mainExe)).toString().replace('/', '\\');
String conf = buildDosboxConf(relExe);
Files.writeString(jsdos.resolve("dosbox.conf"), conf);
Files.writeString(jsdos.resolve("dosbox.conf"), buildDosboxConf(relExe));
Files.write(jsdos.resolve("jsdos.json"), buildJsdosJson(relExe));
bundleFile = ".jsdos/dosbox.conf";
} else {
@@ -210,15 +207,12 @@ public class UploadResource {
Path tmpBundle = Files.createTempDirectory("dostalgia-bundle-");
try {
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");
Files.createDirectories(jsdos);
String relExe = extractDir.relativize(Path.of(mainExe)).toString().replace('/', '\\');
String conf = buildDosboxConf(relExe);
Files.writeString(jsdos.resolve("dosbox.conf"), conf);
Files.writeString(jsdos.resolve("dosbox.conf"), buildDosboxConf(relExe));
Files.write(jsdos.resolve("jsdos.json"), buildJsdosJson(relExe));
// 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) {
// Split into directory and executable components for subdirectory support
String dir = "";
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 parts[] = splitPath(relExe);
String script = (parts[0].isEmpty() ? "" : "cd " + parts[0] + " && ") + parts[1];
String json = "{"
+ "\"autoexec\":{"
+ "\"options\":{\"script\":{\"value\":\"" + escapeJson(script) + "\"}}"
@@ -266,19 +248,10 @@ public class UploadResource {
return json.getBytes(java.nio.charset.StandardCharsets.UTF_8);
}
private String escapeJson(String s) {
return s.replace("\\", "\\\\").replace("\"", "\\\"");
}
private String buildDosboxConf(String relExe) {
// Split into directory and executable components for subdirectory support
String dir = "";
String exe = relExe;
int idx = Math.max(relExe.lastIndexOf('/'), relExe.lastIndexOf('\\'));
if (idx >= 0) {
dir = relExe.substring(0, idx);
exe = relExe.substring(idx + 1);
}
String parts[] = splitPath(relExe);
String dir = parts[0];
String exe = parts[1];
return "[sdl]\n"
+ "autolock=true\n"
@@ -314,80 +287,24 @@ public class UploadResource {
}
/**
* Detect Doom-engine games and inject a DEFAULT.CFG with WASD controls.
* Searches recursively for DOOM.WAD / DOOM2.WAD in source, then writes
* config files to the destination root (where the game will look for them).
* Split a DOS path into directory and filename parts.
* Handles both backslash and forward-slash separators.
* Returns [dir, exe] where dir is empty for root-level files.
*/
private void injectDoomConfig(Path srcDir, Path dstDir) throws IOException {
boolean hasDoom = false;
try (var walk = Files.walk(srcDir)) {
hasDoom = walk.anyMatch(p -> {
String name = p.getFileName().toString().toUpperCase();
return name.equals("DOOM.WAD") || name.equals("DOOM2.WAD");
});
private String[] splitPath(String path) {
int idx = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
if (idx >= 0) {
return new String[]{path.substring(0, idx), path.substring(idx + 1)};
}
if (!hasDoom) {
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");
return new String[]{"", path};
}
/**
* Build a DEFAULT.CFG (Doom engine config) with WASD controls.
* 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);
private String escapeJson(String s) {
return s.replace("\\", "\\\\").replace("\"", "\\\"");
}
// ─── File Utilities ──────────────────────────────────────────
private double dirSizeMB(Path dir) throws IOException {
long[] total = {0};
Files.walkFileTree(dir, new SimpleFileVisitor<>() {