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:
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user