warning dialog for unsupported groove.exe versions at start and before the first apply of a session (nothing blocked)

This commit is contained in:
MineTec committed 2026-11-07 18:32:42 +01:00
1 parent ff6673af66
commit 932ccf5fc8
6 files changed
+123 -2

No files matched your search

+2 -1
View File
@@ -4,7 +4,8 @@
- **English game version supported.** All exe mods (boot to level, cheats, intro skip, practice - **English game version supported.** All exe mods (boot to level, cheats, intro skip, practice
tools, free camera) and the base patch now also work with the English groove.exe of tools, free camera) and the base patch now also work with the English groove.exe of
2000-10-17; other unknown versions still stop with a clear message. 2000-10-17. With any other version LlamaMod warns at start and before the first Apply (nothing
is blocked); mods that change groove.exe then stop with a clear message.
- **Display diagnostics option renamed and explained.** The cheats option is now called - **Display diagnostics option renamed and explained.** The cheats option is now called
"Troubleshooting: write display diagnostics" and warns that the game switches through every "Troubleshooting: write display diagnostics" and warns that the game switches through every
screen mode of every monitor at start (screens go black for a while). It stays off by default. screen mode of every monitor at start (screens go black for a while). It stays off by default.
+2 -1
View File
@@ -104,7 +104,8 @@ after an update, **Settings → Clear cache** throws it away; active mods are re
**Which versions of the game work?** **Which versions of the game work?**
The German CD (`groove.exe` of 2001-02-12) and the English first release (2000-10-17) are The German CD (`groove.exe` of 2001-02-12) and the English first release (2000-10-17) are
supported, including every mod. With another version the level mods still work, but the mods supported, including every mod. With another version LlamaMod shows a warning at start and before
the first Apply (nothing is blocked); the level mods still work, but the mods
marked *modifies groove.exe* stop with "unknown program version" – the first lines of marked *modifies groove.exe* stop with "unknown program version" – the first lines of
`logs/apply.log` name the version LlamaMod found. Please report it together with that `logs/apply.log` name the version LlamaMod found. Please report it together with that
`groove.exe`, then it can be added. `groove.exe`, then it can be added.
@@ -62,6 +62,7 @@ final class MainFrame extends JFrame {
private boolean crashReported; private boolean crashReported;
private boolean oldWineAccepted; private boolean oldWineAccepted;
private final RecoveryNotice recoveryNotice = new RecoveryNotice(); private final RecoveryNotice recoveryNotice = new RecoveryNotice();
final UnsupportedExeWarning exeWarning = new UnsupportedExeWarning();
private boolean recoveryRunning; private boolean recoveryRunning;
MainFrame(AppState state) { MainFrame(AppState state) {
@@ -223,6 +224,9 @@ final class MainFrame extends JFrame {
showRecovery(state.recovery); showRecovery(state.recovery);
state.recovery = ModManager.Recovery.NONE; state.recovery = ModManager.Recovery.NONE;
} }
if (inst) {
SwingUtilities.invokeLater(() -> exeWarning.atStart(this, state));
}
} }
/** Tells the user once that an interrupted apply was repaired; BUSY is retried later. */ /** Tells the user once that an interrupted apply was repaired; BUSY is retried later. */
@@ -677,6 +677,7 @@ final class ModsPanel extends JPanel {
} }
List<Mod> mods = selected(); List<Mod> mods = selected();
ModManager mm = frame.state.modManager; ModManager mm = frame.state.modManager;
frame.exeWarning.beforeApply(frame, frame.state);
if (!AntivirusDialogs.notice(frame, mm.exeMods(mods), true)) { if (!AntivirusDialogs.notice(frame, mm.exeMods(mods), true)) {
return; return;
} }
@@ -0,0 +1,86 @@
package com.eliasmueller.llamamod.ui;
import com.eliasmueller.llamamod.exe.GameExe;
import com.eliasmueller.llamamod.platform.FileOps;
import com.eliasmueller.llamamod.platform.Integrity;
import java.awt.Component;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.stream.Collectors;
import javax.swing.JOptionPane;
/**
* Warns (never blocks) when the installed groove.exe is not one of the supported builds: once at
* start and once before the first Apply of a session.
*/
final class UnsupportedExeWarning {
private boolean shownAtStart;
private boolean shownAtApply;
private String checkedSha;
private boolean unsupported;
/** The warning text, or null if the build is supported or unknown because nothing is installed. */
static String message(String sha256) {
if (sha256 == null || sha256.isEmpty()) {
return null;
}
for (GameExe.Build b : GameExe.Build.values()) {
if (b.sha256.equalsIgnoreCase(sha256)) {
return null;
}
}
return "You are running an unsupported version of the game. Mods, especially mods that modify"
+ " groove.exe, probably won't work.\n\nSupported are: "
+ Arrays.stream(GameExe.Build.values())
.map(GameExe.Build::toString)
.collect(Collectors.joining(", "))
+ ".";
}
/** SHA-256 of the set-up original groove.exe ("" if not installed or unreadable). */
static String installedSha(AppState state) {
if (!state.cfg.installed()) {
return "";
}
if (!state.cfg.exeSha256.isEmpty()) {
return state.cfg.exeSha256;
}
try {
Path hd = state.paths.originalHd();
Path exe = Files.isDirectory(hd) ? Integrity.find(hd, "groove.exe") : null;
return exe != null && Files.isRegularFile(exe) ? FileOps.sha256(exe) : "";
} catch (IOException e) {
return "";
}
}
private String current(AppState state) {
String sha = installedSha(state);
if (!sha.equals(checkedSha)) {
checkedSha = sha;
unsupported = message(sha) != null;
shownAtStart = false;
shownAtApply = false;
}
return unsupported ? message(sha) : null;
}
void atStart(Component parent, AppState state) {
String m = current(state);
if (m != null && !shownAtStart) {
shownAtStart = true;
JOptionPane.showMessageDialog(parent, m, "Unsupported game version", JOptionPane.WARNING_MESSAGE);
}
}
/** Shows the warning before the first Apply of a session; Apply always continues afterwards. */
void beforeApply(Component parent, AppState state) {
String m = current(state);
if (m != null && !shownAtApply) {
shownAtApply = true;
JOptionPane.showMessageDialog(parent, m, "Unsupported game version", JOptionPane.WARNING_MESSAGE);
}
}
}
@@ -0,0 +1,28 @@
package com.eliasmueller.llamamod.ui;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.eliasmueller.llamamod.exe.GameExe;
import org.junit.jupiter.api.Test;
class UnsupportedExeWarningTest {
@Test
void supportedBuildsAndMissingInstallGiveNoWarning() {
for (GameExe.Build b : GameExe.Build.values()) {
assertNull(UnsupportedExeWarning.message(b.sha256));
assertNull(UnsupportedExeWarning.message(b.sha256.toUpperCase()));
}
assertNull(UnsupportedExeWarning.message(""));
assertNull(UnsupportedExeWarning.message(null));
}
@Test
void otherBuildsAreWarnedAboutAndTheSupportedOnesListed() {
String m = UnsupportedExeWarning.message("00".repeat(32));
assertNotNull(m);
assertTrue(m.startsWith("You are running an unsupported version of the game."), m);
assertTrue(m.contains("German version of 2001-02-12") && m.contains("English version of 2000-10-17"), m);
}
}