Fix crash when loading saved tutorial worlds (#1001)

writeRuleFile() was missing the schematic file count integer before the schematic entries. The reader in readRuleFile() expected this count, causing a stream misalignment that led to an assertion failure (Unrecognised schematic version) when reloading a saved tutorial world.

The fix writes the count on save and adds backward-compatible reading that detects old saves (without count) via a peek heuristic and falls back to count-less parsing.

Co-authored-by: MCbabel <MCbabel@users.noreply.github.com>
This commit is contained in:
Marlian
2026-03-10 04:02:39 +01:00
committed by GitHub
parent 58c236ead5
commit 3bcf588fbe

View File

@@ -344,6 +344,7 @@ void GameRuleManager::writeRuleFile(DataOutputStream *dos)
// Write schematic files. // Write schematic files.
unordered_map<wstring, ConsoleSchematicFile *> *files; unordered_map<wstring, ConsoleSchematicFile *> *files;
files = getLevelGenerationOptions()->getUnfinishedSchematicFiles(); files = getLevelGenerationOptions()->getUnfinishedSchematicFiles();
dos->writeInt((int)files->size());
for ( auto& it : *files ) for ( auto& it : *files )
{ {
const wstring& filename = it.first; const wstring& filename = it.first;
@@ -497,17 +498,36 @@ bool GameRuleManager::readRuleFile(LevelGenerationOptions *lgo, byte *dIn, UINT
}*/ }*/
// subfile // subfile
// Old saves didn't write a numFiles count before the schematic entries.
// Detect this: a real count is small, but a UTF filename prefix reads as a large int.
UINT numFiles = contentDis->readInt(); UINT numFiles = contentDis->readInt();
for (UINT i = 0; i < numFiles; i++)
if (lgo->isFromSave() && numFiles > 100)
{ {
wstring sFilename = contentDis->readUTF(); contentDis->skip(-4);
int length = contentDis->readInt(); while (true)
byteArray ba( length ); {
int peek = contentDis->readInt();
contentDis->read(ba); if (peek <= 100) { contentDis->skip(-4); break; }
contentDis->skip(-4);
levelGenerator->loadSchematicFile(sFilename, ba.data, ba.length);
wstring sFilename = contentDis->readUTF();
int length = contentDis->readInt();
byteArray ba( length );
contentDis->read(ba);
levelGenerator->loadSchematicFile(sFilename, ba.data, ba.length);
}
}
else
{
for (UINT i = 0; i < numFiles; i++)
{
wstring sFilename = contentDis->readUTF();
int length = contentDis->readInt();
byteArray ba( length );
contentDis->read(ba);
levelGenerator->loadSchematicFile(sFilename, ba.data, ba.length);
}
} }
LEVEL_GEN_ID lgoID = LEVEL_GEN_ID_NULL; LEVEL_GEN_ID lgoID = LEVEL_GEN_ID_NULL;