Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/scripts/publish-screenshots.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
# URLs) in a PR comment and in the job summary.
#
# Leaves the normalized screenshots in screenshots-publish/ for the comment
# step: <sha>/mc-<version>-survival.png and <sha>/mc-<version>-title.png.
# step: <sha>/mc-<version>-survival.png, <sha>/mc-<version>-title.png,
# <sha>/mc-<version>-mods.png and <sha>/mc-<version>-settings.png.
#
# Required env: GITHUB_TOKEN, GITHUB_REPOSITORY, GITHUB_RUN_ID, GITHUB_SHA
set -euo pipefail
Expand Down Expand Up @@ -34,7 +35,7 @@ mkdir -p "$PUBLISH"

for dir in shots/*/; do
mc="$(basename "$dir")"
for kind in survival-world title-screen; do
for kind in survival-world title-screen mods-menu settings; do
src="$(find "$dir" -name "*betterhud-$kind.png" -print -quit)"
if [ -n "$src" ]; then
cp "$src" "$PUBLISH/mc-$mc-${kind%%-*}.png"
Expand Down
20 changes: 12 additions & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ jobs:
- name: check survival world screenshot was taken
run: test -n "$(find launchtest/run/screenshots -name '*betterhud-survival-world.png' -print -quit 2>/dev/null)"

- name: check settings screen screenshot was taken
run: test -n "$(find launchtest/run/screenshots -name '*betterhud-settings.png' -print -quit 2>/dev/null)"

- name: upload screenshots
# Consumed by the screenshot-report job below.
if: always()
Expand Down Expand Up @@ -155,13 +158,14 @@ jobs:
const dir = `screenshots-publish/${context.sha}`;
const base = `https://raw.githubusercontent.com/${context.repo.owner}/${context.repo.repo}/ci-screenshots/${context.sha}`;

const cells = versions.map(v => {
const file = `mc-${v}-survival.png`;
const ok = fs.existsSync(`${dir}/${file}`);
return ok
? `<td align="center"><b>${v}</b><br><a href="${base}/${file}"><img src="${base}/${file}" width="200" alt="BetterHUD on Minecraft ${v}"></a></td>`
: `<td align="center"><b>${v}</b><br>❌ no screenshot</td>`;
});
const shot = (v, kind, what) => {
const file = `mc-${v}-${kind}.png`;
return fs.existsSync(`${dir}/${file}`)
? `<a href="${base}/${file}"><img src="${base}/${file}" width="200" alt="${what} on Minecraft ${v}"></a>`
: `❌ no ${kind} screenshot`;
};
const cells = versions.map(v =>
`<td align="center"><b>${v}</b><br>${shot(v, 'survival', 'BetterHUD')}<br>${shot(v, 'settings', 'BetterHUD settings')}</td>`);
let rows = '';
for (let i = 0; i < cells.length; i += 4) {
rows += `<tr>${cells.slice(i, i + 4).join('')}</tr>\n`;
Expand All @@ -170,7 +174,7 @@ jobs:
const marker = '<!-- betterhud-launch-screenshots -->';
const body = [
marker,
`The game launched and entered a survival singleplayer world with the HUD active, on every supported Minecraft version, for \`${context.sha.slice(0, 7)}\`. A ❌ means that version's launch test did not produce a screenshot — check its job. Title-screen screenshots and game logs are in the run artifacts.`,
`The game launched, entered a survival singleplayer world with the HUD active, and opened the BetterHUD settings through Mod Menu, on every supported Minecraft version, for \`${context.sha.slice(0, 7)}\`. Each cell shows the survival world and the settings screen. A ❌ means that version's launch test did not produce that screenshot — check its job. Title-screen and mod-list screenshots and game logs are in the run artifacts.`,
'',
`<table>\n${rows}</table>`,
].join('\n');
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ Requires [Cloth Config](https://modrinth.com/mod/cloth-config), [Mod Menu](https
## Configuration (requires Mod Menu)
![General Settings](https://cdn.modrinth.com/data/cached_images/9c3ed350ef0c2206a7439d1e1c15b708aa22a332.png)
![Mod Settings](https://cdn.modrinth.com/data/cached_images/f89e15c258a5a24cfda8fe9398406a7ce16edbcc.png)

## Installation

1. Ensure you have Fabric Mod Loader installed.
2. Download the BetterHUD mod file.
3. Place the downloaded file in your Minecraft `mods` folder.
3. Place the downloaded file in your Minecraft `mods` folder.
4 changes: 4 additions & 0 deletions launchtest/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,16 @@ dependencies {
mappings loom.officialMojangMappings()
modImplementation "net.fabricmc:fabric-loader:${loaderVersion}"
modImplementation "net.fabricmc.fabric-api:fabric-api:${entry.fabricApi}"
// The test driver opens the BetterHUD settings through Mod Menu's mod
// list; compile against the exact Mod Menu launched for this version.
modCompileOnly("com.terraformersmc:modmenu:${entry.modmenu}") { transitive = false }
if (entry.clientGametest) {
modImplementation fabricApi.module('fabric-client-gametest-api-v1', entry.fabricApi)
}
} else {
implementation "net.fabricmc:fabric-loader:${loaderVersion}"
implementation "net.fabricmc.fabric-api:fabric-api:${entry.fabricApi}"
compileOnly("com.terraformersmc:modmenu:${entry.modmenu}") { transitive = false }
implementation fabricApi.module('fabric-client-gametest-api-v1', entry.fabricApi)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package dsns.betterhud.gametest;

import com.terraformersmc.modmenu.ModMenu;
import com.terraformersmc.modmenu.gui.ModsScreen;

import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.minecraft.client.Minecraft;
import net.minecraft.client.Screenshot;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.TitleScreen;

/**
Expand All @@ -13,17 +17,23 @@
* <p>When the run is started with {@code --quickPlaySingleplayer ci-world} and
* {@code -Dbetterhud.launchtest.expectWorld=true} (see the launchtest Gradle
* project), the game joins the pre-generated survival world; once it has ticked
* long enough for chunks to render with the HUD active, this mod screenshots it
* and schedules a clean shutdown, making the client exit with code 0. Without a
* pre-generated world it screenshots the title screen and shuts down there
* instead. A crash anywhere on the way fails the run.
* long enough for chunks to render with the HUD active, this mod screenshots it,
* then opens the BetterHUD settings the way a player would (through Mod Menu's
* mod list), screenshots those screens too, and schedules a clean shutdown,
* making the client exit with code 0. Without a pre-generated world it
* screenshots the title screen and shuts down there instead. A crash anywhere
* on the way fails the run.
*/
public class LaunchTestClient implements ClientModInitializer {
private static final boolean EXPECT_WORLD = Boolean.getBoolean("betterhud.launchtest.expectWorld");

// 200 ticks (10s) gives the software renderer on CI time to draw chunks.
private static final int WORLD_SCREENSHOT_TICK = 200;
private static final int WORLD_STOP_TICK = 240;
private static final int MODS_SCREEN_TICK = 220;
private static final int MODS_SCREENSHOT_TICK = 240;
private static final int SETTINGS_SCREEN_TICK = 260;
private static final int SETTINGS_SCREENSHOT_TICK = 280;
private static final int WORLD_STOP_TICK = 300;
private static final int TITLE_SCREENSHOT_TICK = 40;
private static final int TITLE_STOP_TICK = 80;
// 2400 ticks (2min) is plenty to join the pre-generated flat world; bail
Expand All @@ -48,6 +58,14 @@ public void onInitializeClient() {
worldTicks++;
if (worldTicks == WORLD_SCREENSHOT_TICK) {
takeScreenshot(client, "betterhud-survival-world");
} else if (worldTicks == MODS_SCREEN_TICK) {
client.setScreen(new ModsScreen(client.screen));
} else if (worldTicks == MODS_SCREENSHOT_TICK) {
takeScreenshot(client, "betterhud-mods-menu");
} else if (worldTicks == SETTINGS_SCREEN_TICK) {
openBetterHudSettings(client);
} else if (worldTicks == SETTINGS_SCREENSHOT_TICK) {
takeScreenshot(client, "betterhud-settings");
} else if (worldTicks == WORLD_STOP_TICK) {
client.stop();
}
Expand All @@ -62,6 +80,15 @@ public void onInitializeClient() {
});
}

private static void openBetterHudSettings(Minecraft client) {
Screen settings = ModMenu.getConfigScreen("betterhud", client.screen);
if (settings == null) {
System.err.println("betterhud launch test: Mod Menu has no config screen registered for betterhud");
System.exit(1);
}
client.setScreen(settings);
}

private static void takeScreenshot(Minecraft client, String name) {
Screenshot.grab(client.gameDirectory, name + ".png", client.getMainRenderTarget(), message -> {});
}
Expand Down
3 changes: 2 additions & 1 deletion launchtest/src/fallback/resources/fabric.mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"depends": {
"betterhud": "*",
"fabric-lifecycle-events-v1": "*"
"fabric-lifecycle-events-v1": "*",
"modmenu": "*"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@
import java.nio.file.Files;
import java.nio.file.Path;

import com.terraformersmc.modmenu.ModMenu;
import com.terraformersmc.modmenu.gui.ModsScreen;

import net.fabricmc.fabric.api.client.gametest.v1.FabricClientGameTest;
import net.fabricmc.fabric.api.client.gametest.v1.context.ClientGameTestContext;
import net.fabricmc.fabric.api.client.gametest.v1.context.TestSingleplayerContext;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.worldselection.WorldCreationUiState;

@SuppressWarnings("UnstableApiUsage")
Expand All @@ -30,6 +34,22 @@ public void runTest(ClientGameTestContext context) {
context.waitTicks(40);
assertScreenshotSaved(context.takeScreenshot("betterhud-survival-world"));
}

// Back on the title screen: open the BetterHUD settings the way a
// player would, through Mod Menu's mod list.
context.runOnClient(client -> client.setScreen(new ModsScreen(client.screen)));
context.waitTicks(10);
assertScreenshotSaved(context.takeScreenshot("betterhud-mods-menu"));

context.runOnClient(client -> {
Screen settings = ModMenu.getConfigScreen("betterhud", client.screen);
if (settings == null) {
throw new AssertionError("Mod Menu has no config screen registered for betterhud");
}
client.setScreen(settings);
});
context.waitTicks(10);
assertScreenshotSaved(context.takeScreenshot("betterhud-settings"));
}

private static void assertScreenshotSaved(Path screenshot) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
import java.nio.file.Files;
import java.nio.file.Path;

import com.terraformersmc.modmenu.ModMenu;
import com.terraformersmc.modmenu.gui.ModsScreen;

import net.fabricmc.fabric.api.client.gametest.v1.FabricClientGameTest;
import net.fabricmc.fabric.api.client.gametest.v1.context.ClientGameTestContext;
import net.fabricmc.fabric.api.client.gametest.v1.context.TestSingleplayerContext;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.worldselection.WorldCreationUiState;

@SuppressWarnings("UnstableApiUsage")
Expand All @@ -25,6 +29,22 @@
context.waitTicks(40);
assertScreenshotSaved(context.takeScreenshot("betterhud-survival-world"));
}

// Back on the title screen: open the BetterHUD settings the way a
// player would, through Mod Menu's mod list.
context.runOnClient(client -> client.setScreen(new ModsScreen(client.screen)));

Check failure on line 35 in src/gametest/java/dsns/betterhud/gametest/BetterHudClientGameTest.java

View workflow job for this annotation

GitHub Actions / launch mc26.2

cannot find symbol

Check failure on line 35 in src/gametest/java/dsns/betterhud/gametest/BetterHudClientGameTest.java

View workflow job for this annotation

GitHub Actions / launch mc26.2

cannot find symbol

Check failure on line 35 in src/gametest/java/dsns/betterhud/gametest/BetterHudClientGameTest.java

View workflow job for this annotation

GitHub Actions / launch mc26.2

cannot find symbol

Check failure on line 35 in src/gametest/java/dsns/betterhud/gametest/BetterHudClientGameTest.java

View workflow job for this annotation

GitHub Actions / launch mc26.2

cannot find symbol
context.waitTicks(10);
assertScreenshotSaved(context.takeScreenshot("betterhud-mods-menu"));

context.runOnClient(client -> {
Screen settings = ModMenu.getConfigScreen("betterhud", client.screen);

Check failure on line 40 in src/gametest/java/dsns/betterhud/gametest/BetterHudClientGameTest.java

View workflow job for this annotation

GitHub Actions / launch mc26.2

cannot find symbol
if (settings == null) {
throw new AssertionError("Mod Menu has no config screen registered for betterhud");
}
client.setScreen(settings);

Check failure on line 44 in src/gametest/java/dsns/betterhud/gametest/BetterHudClientGameTest.java

View workflow job for this annotation

GitHub Actions / launch mc26.2

cannot find symbol
});
context.waitTicks(10);
assertScreenshotSaved(context.takeScreenshot("betterhud-settings"));
}

private static void assertScreenshotSaved(Path screenshot) {
Expand Down
3 changes: 2 additions & 1 deletion src/gametest/resources/fabric.mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"depends": {
"betterhud": "*",
"fabric-client-gametest-api-v1": "*"
"fabric-client-gametest-api-v1": "*",
"modmenu": "*"
}
}
Loading
Loading