diff --git a/dCommon/LevelFile.cpp b/dCommon/LevelFile.cpp index ddf13bc9e..7a2b0819a 100644 --- a/dCommon/LevelFile.cpp +++ b/dCommon/LevelFile.cpp @@ -146,7 +146,15 @@ void LevelFile::ReadSceneObjectDataChunk(std::istream& file, uint32_t version) { BinaryIO::BinaryRead(file, obj.rotation); BinaryIO::BinaryRead(file, obj.scale); BinaryIO::ReadString(file, ldfString); - BinaryIO::BinaryRead(file, obj.value3); + // From version 7 the object's render techniques: a count, and when there are any a 64 byte header and 133 bytes + // each (64 byte name, u32, u8, 16 floats) (ReadLvlObjectData) + if (version > 6) { + BinaryIO::BinaryRead(file, obj.renderTechniqueCount); + if (obj.renderTechniqueCount != 0) { + std::string techniques(64 + static_cast(obj.renderTechniqueCount) * (64 + 4 + 1 + 64), '\0'); + file.read(techniques.data(), static_cast(techniques.size())); + } + } if (file.fail()) throw std::runtime_error("Failed to read from istream."); for (const auto& token : GeneralUtils::SplitString(GeneralUtils::UTF16ToWTF8(ldfString), '\n')) { diff --git a/dCommon/LevelFile.h b/dCommon/LevelFile.h index daaad1c9d..c0631df6d 100644 --- a/dCommon/LevelFile.h +++ b/dCommon/LevelFile.h @@ -13,12 +13,12 @@ struct SceneObject { LWOOBJID id; LOT lot; - uint32_t nodeType; - uint32_t glomId; + uint32_t nodeType = 1; // the client's default when the file has none, or one outside 0-10 + uint32_t glomId = 1; NiPoint3 position; NiQuaternion rotation = QuatUtils::IDENTITY; float scale = 1.0f; - uint32_t value3; + uint32_t renderTechniqueCount{}; LwoNameValue settings; }; diff --git a/tests/dCommonTests/ZoneFileTests.cpp b/tests/dCommonTests/ZoneFileTests.cpp index 6161162c5..98fa0db05 100644 --- a/tests/dCommonTests/ZoneFileTests.cpp +++ b/tests/dCommonTests/ZoneFileTests.cpp @@ -451,6 +451,29 @@ TEST(LevelFileTests, ReadsFilesWithoutChunks) { EXPECT_EQ(level.chunkHeaders.count(LevelFile::SceneObjectData), 1u); } +// An object's render techniques (from version 7) are skipped; the fields a file has no room for get the client's defaults +TEST(LevelFileTests, ReadsObjectsAsTheClient) { + ZoneBytes w; + w.Put(30).Put(0); + w.data.append(48 + 12, '\0'); + w.Put(0).Put(2); + // With two render techniques + w.Put(10).Put(1).Point(1, 0, 0).Put(1.0f).Put(0.0f).Put(0.0f).Put(0.0f).Put(1.0f).Put(0); + w.Put(2); + w.data.append(64 + 2 * 133, '\x7f'); + w.Object(30, 2, 5, "a=0:b"); + + std::istringstream stream(w.Done()); + LevelFile level; + level.Read(stream); + ASSERT_EQ(level.objects.size(), 2u); + EXPECT_EQ(level.objects[0].renderTechniqueCount, 2u); + EXPECT_EQ(level.objects[0].nodeType, 1u); + EXPECT_EQ(level.objects[0].glomId, 1u); + EXPECT_EQ(level.objects[1].lot, 2); + EXPECT_EQ(level.objects[1].position.x, 5.0f); +} + TEST(LevelFileTests, DamagedFilesKeepWhatWasRead) { ZoneBytes w; w.Put(30).Put(0);