fix(zone): zone files older than version 30 are refused

Before version 30 (PrePreAlpha) a zone file's scene is only a u32 scene
ID, with no scene file name (LuzReader::ReadScenes, 1.10.64:
revision < 30 reads the ID alone; LuzFile::ReadLUZFile treats anything
below 20 as 20). The reader read a file name and then an ID for those
versions, which is not the format, and the world could not load such a
zone's scenes anyway. Reading one now throws a runtime_error that says
why, before anything else is read.

No zone file of any client on disk is older than 30 except an unnamed
editor stub (a res/.luz, version 20).

Check in game: every world loads as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-09-29 04:26:06 -05:00
parent 04852fce7e
commit 69093c6816
2 changed files with 17 additions and 3 deletions

View File

@@ -3,6 +3,8 @@
#include <algorithm>
#include <cctype>
#include <istream>
#include <stdexcept>
#include <string>
#include "BinaryIO.h"
#include "Game.h"
@@ -10,6 +12,10 @@
void ZoneFile::ReadHeader(std::istream& file) {
BinaryIO::BinaryRead(file, fileFormatVersion);
// Before PrePreAlpha a scene is only its ID, with no file to load it from (LuzReader::ReadScenes)
if (fileFormatVersion < FileFormatVersion::PrePreAlpha) {
throw std::runtime_error("Zone file version " + std::to_string(static_cast<uint32_t>(fileFormatVersion)) + " is older than " + std::to_string(static_cast<uint32_t>(FileFormatVersion::PrePreAlpha)) + ": its scenes have no files");
}
if (fileFormatVersion >= FileFormatVersion::Alpha) BinaryIO::BinaryRead(file, mapRevision);
@@ -68,10 +74,8 @@ void ZoneFile::ReadScene(std::istream& file) {
BinaryIO::ReadString<uint8_t>(file, scene.filename, BinaryIO::ReadType::String);
if (fileFormatVersion >= FileFormatVersion::LatePreAlpha || fileFormatVersion < FileFormatVersion::PrePreAlpha) {
BinaryIO::BinaryRead(file, scene.id);
}
if (fileFormatVersion >= FileFormatVersion::LatePreAlpha) {
BinaryIO::BinaryRead(file, scene.id);
BinaryIO::BinaryRead(file, scene.sceneType);
BinaryIO::ReadString<uint8_t>(file, scene.name, BinaryIO::ReadType::String);

View File

@@ -138,6 +138,16 @@ TEST(ZoneFileTests, LateAlphaSceneCountIsAU32) {
EXPECT_EQ(zone.zoneRawPath, "zone.raw");
}
// Before version 30 a scene is only an ID, with no file to load
TEST(ZoneFileTests, VersionsBeforePrePreAlphaThrow) {
ZoneBytes w;
w.Put<uint32_t>(20).Put<uint32_t>(53).Put<uint8_t>(1).Put<uint32_t>(53).Put<uint8_t>(0).Text(".raw");
std::istringstream stream(w.data);
ZoneFile zone;
EXPECT_THROW(zone.Read(stream), std::runtime_error);
EXPECT_TRUE(zone.scenes.empty());
}
TEST(ZoneFileTests, ShortFilesThrowOrFail) {
const auto zone = SampleZone();
for (const size_t length : { size_t{ 3 }, size_t{ 40 }, zone.size() / 2, zone.size() - 1 }) {