Skip to content

fix: Display save thumbnails on Windows64#1517

Closed
dtentiion wants to merge 1 commit intoMCLCE:mainfrom
dtentiion:pr/win64-save-thumbnails
Closed

fix: Display save thumbnails on Windows64#1517
dtentiion wants to merge 1 commit intoMCLCE:mainfrom
dtentiion:pr/win64-save-thumbnails

Conversation

@dtentiion
Copy link
Copy Markdown
Contributor

@dtentiion dtentiion commented Apr 15, 2026

Description

Fixes save thumbnails not displaying on Windows 64-bit. Both the save list and the world detail screen showed placeholder icons (grass block / grey box) instead of the actual world thumbnail. This affected both worlds created in-game and worlds converted from Xbox 360. The game was already capturing thumbnail screenshots on every save internally, but the precompiled storage lib never stored or returned them properly on this platform.

thumbnail_demo.mp4

Changes

Previous Behavior

  • The save list displayed a grass block icon for every world regardless of whether a thumbnail existed.
  • Clicking on a world to view its details showed a grey empty box where the thumbnail should be.
  • The game captured a thumbnail screenshot on every save via RenderManager.CaptureThumbnail() but the data was passed to StorageManager.SetSaveImages() and then lost. LoadSaveDataThumbnail() in the storage lib returned an error status on Win64, so the callback never fired and no thumbnails were ever loaded back.
  • GetSaveUniqueFilename() returned false with an empty string, so there was no way to associate the captured thumbnail with its save folder at save time.
  • The UIScene_LoadMenu constructor had no _WINDOWS64 path for thumbnail handling at all.

Root Cause

The precompiled 4J_Storage.lib does not embed or retrieve thumbnail data from saveData.ms on Windows 64-bit. LoadSaveDataThumbnail() returns an error immediately (not ESaveGame_GetSaveThumbnail), so the async callback-based thumbnail loading loop in UIScene_LoadOrJoinMenu bailed out on the very first save and set m_bAllLoaded = true, skipping all thumbnails. GetSaveUniqueFilename() also returns false, so even though the game had valid PNG data in hand during Flush(), it couldn't figure out which folder to write it to. On top of all that, CaptureThumbnail() in the render lib produced no data either, so the D3D11 back buffer had to be read manually.

New Behavior

  • The save list shows the correct thumbnail for each world that has a thumbnail.png file in its save folder.
  • The world detail screen displays the thumbnail when you click on a world.
  • On every save (manual, autosave, exit), the game writes thumbnail.png to the save folder alongside saveData.ms. The file is written in the SaveSaveDataCallback after the storage lib has finished creating the folder, by scanning GameHDD for the most recently modified saveData.ms.
  • Converted Xbox 360 saves that already include thumbnail.png from converter tools work immediately.
  • New worlds show their thumbnail from the second visit to the save list onwards (first save has to happen to generate the file).

Fix Implementation

  • Windows64_App.cpp - CaptureSaveThumbnail: Falls back to grabbing the D3D11 back buffer directly when the render lib's CaptureThumbnail doesn't produce data. Copies the swap chain back buffer to a staging texture (resolving MSAA if needed), downsamples to 64x64, and hand-rolls an uncompressed PNG into the ImageFileBuffer. This is the part that was the most fun to write.
  • ConsoleSaveFileOriginal.cpp - Flush: After GetSaveThumbnail() returns valid data, stashes a copy in s_pendingThumbData / s_pendingThumbSize statics. Can't write the file here because GetSaveUniqueFilename() doesn't work and the save folder may not exist yet.
  • ConsoleSaveFileOriginal.cpp - SaveSaveDataCallback: When pending thumbnail data exists, scans Windows64\GameHDD\* for the directory whose saveData.ms has the most recent write time, and writes thumbnail.png next to it.
  • UIScene_LoadOrJoinMenu.cpp - thumbnail loading in tick(): On Win64, replaces the broken StorageManager.LoadSaveDataThumbnail() loop with direct file reads. Iterates over all saves, reads thumbnail.png from each save folder, registers it as a substitution texture, and sets it on the list item.
  • UIScene_LoadMenu.cpp - constructor: Added _WINDOWS64 thumbnail handling. Uses the thumbnail already loaded by the save list if available, otherwise reads thumbnail.png from disk. Sets the texture directly on m_bitmapIcon in the constructor instead of going through m_bSaveThumbnailReady (which would trigger NavigateBack() meant for dismissing the timer loading scene on other platforms). Also initializes m_pbThumbnailData and m_uiThumbnailSize to prevent undefined reads.

AI Use Disclosure

No AI was used in the development of this pull request.

@codeHusky
Copy link
Copy Markdown
Contributor

codeHusky commented Apr 16, 2026

This was just fixed partially with the inclusion of the 4JLibs project. Please re-do this fix considering the now working 4J library functions for this purpose and I can merge the new PR for that.
https://github.com/Patoke/4JLibs is the original source, https://github.com/MCLCE/4JLibs has a full working source so you don't need to copy anything if you want to investigate there.

Thanks for your PR, tho the timing here is very coincidentally inconvenient. Apologies.

@codeHusky codeHusky closed this Apr 16, 2026
@dtentiion
Copy link
Copy Markdown
Contributor Author

This was just fixed partially with the inclusion of the 4JLibs project. Please re-do this fix considering the now working 4J library functions for this purpose and I can merge the new PR for that. https://github.com/Patoke/4JLibs is the original source, https://github.com/MCLCE/4JLibs has a full working source so you don't need to copy anything if you want to investigate there.

Thanks for your PR, tho the timing here is very coincidentally inconvenient. Apologies.

No worries, the timing couldn't have been worse for me unfortunately haha, but I'll have a look at the 4j library functions

@dtentiion dtentiion deleted the pr/win64-save-thumbnails branch April 16, 2026 00:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants