diff --git a/.github/release-notes/changelog.json b/.github/release-notes/changelog.json index b91380cac..175088fc2 100644 --- a/.github/release-notes/changelog.json +++ b/.github/release-notes/changelog.json @@ -2613,6 +2613,22 @@ "released": true, "released_in": "v0.367.0", "released_at": "2026-06-26T09:52:26Z" + }, + { + "id": "book-screen-no-pause", + "version": "0.368.0", + "type": "fix", + "title": "Reading a book no longer freezes a moving train", + "summary": "Reading a written book on the train no longer pauses (and autosaves) your singleplayer game, which previously caused nearby carriages to vanish until a world reload. The train now keeps moving while you read.", + "highlights": [ + "Books no longer pause singleplayer mid-ride", + "Fixes carriages vanishing after reading a book on the train" + ], + "pr": 597, + "date": "2026-06-26", + "released": false, + "released_in": null, + "released_at": null } ] } diff --git a/gradle.properties b/gradle.properties index 5b31d63d1..9d31f8394 100644 --- a/gradle.properties +++ b/gradle.properties @@ -20,7 +20,7 @@ loader_version_range=[1,) mod_id=dungeontrain mod_name=Dungeon Train mod_license=PolyForm Shield 1.0.0 -mod_version=0.367.0 +mod_version=0.368.0 mod_group_id=games.brennan.dungeontrain mod_authors=Brennan Hatton mod_description=A Minecraft port of Dungeon Train (brennanhatton.itch.io/dungeontrain) - a moving train that hosts procedurally generated dungeons. diff --git a/src/main/java/games/brennan/dungeontrain/mixin/client/BookViewScreenNoPauseMixin.java b/src/main/java/games/brennan/dungeontrain/mixin/client/BookViewScreenNoPauseMixin.java new file mode 100644 index 000000000..f154765e9 --- /dev/null +++ b/src/main/java/games/brennan/dungeontrain/mixin/client/BookViewScreenNoPauseMixin.java @@ -0,0 +1,44 @@ +package games.brennan.dungeontrain.mixin.client; + +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.BookViewScreen; +import net.minecraft.network.chat.Component; +import org.spongepowered.asm.mixin.Mixin; + +/** + * Makes the vanilla written-book reader ({@link BookViewScreen}) non-pausing. + * + *

Vanilla {@code Screen.isPauseScreen()} defaults to {@code true} and + * {@code BookViewScreen} does not override it, so reading a book in + * singleplayer pauses the integrated server and triggers a full autosave. + * On a moving Sable train that autosave shuffles the train's sub-levels + * through holding chunks and the resume (book close) fails to restore the + * sub-levels around the player, making nearby carriages vanish until a + * world reload. Reading a book should not pause a run mid-ride, so we add + * the {@code isPauseScreen() == false} override Mojang omitted.

+ * + *

Singleplayer-only effect by nature — multiplayer never pauses on a + * screen. Trade-off: the world keeps ticking while the book is open, so the + * player can take damage / be attacked while reading (acceptable, arguably + * more correct, on a constantly-moving roguelite train).

+ * + *

Implemented as an added override (a method merge), not an {@code @Inject} + * — {@code BookViewScreen} inherits {@code isPauseScreen()} from {@code Screen} + * rather than declaring it, so an {@code @Inject} targeting this class would + * fail to resolve at apply-time. Extending {@code Screen} lets the compiler + * verify the {@code @Override}; the private constructor is mixin boilerplate + * to satisfy {@code Screen}'s {@code protected Screen(Component)} ctor and is + * discarded at apply-time.

+ */ +@Mixin(BookViewScreen.class) +public abstract class BookViewScreenNoPauseMixin extends Screen { + + private BookViewScreenNoPauseMixin(Component title) { + super(title); + } + + @Override + public boolean isPauseScreen() { + return false; + } +} diff --git a/src/main/resources/dungeontrain.mixins.json b/src/main/resources/dungeontrain.mixins.json index 0d324194c..613e499d7 100644 --- a/src/main/resources/dungeontrain.mixins.json +++ b/src/main/resources/dungeontrain.mixins.json @@ -33,6 +33,7 @@ "client.AdvancementsScreenAccessor", "client.AdvancementWidgetHideDescMixin", "client.DeathScreenMoveTextMixin", + "client.BookViewScreenNoPauseMixin", "client.CameraCinematicMixin", "client.GameRendererSnapshotMixin", "client.LevelRendererVoidSkyMixin",