mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-11-06 03:47:13 +00:00
fix: keep the scene map of version 31 and older raws
These files have a (resolution + 1)^2 scene map, kept in sceneMapLegacy. Version 31 uses its first resolution rows and columns; older versions are all scene 0, as in the client. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -40,19 +40,6 @@ NiPoint3 Chunk::GridToWorldPos(uint32_t i, uint32_t j) const {
|
||||
return NiPoint3(offsetX + static_cast<float>(i) * scaleFactor, y, offsetZ + static_cast<float>(j) * scaleFactor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Skip bytes, such as the byte version 30 and older files have in place of a scene map
|
||||
*/
|
||||
static bool Skip(std::istream& stream, size_t bytes) {
|
||||
if (bytes > kMaxBlobBytes) {
|
||||
LOG("Raw block of %zu bytes exceeds maximum %zu bytes", bytes, kMaxBlobBytes);
|
||||
return false;
|
||||
}
|
||||
// ignore, not seekg: the asset streams don't stop a seek at the end of the data
|
||||
stream.ignore(static_cast<std::streamsize>(bytes));
|
||||
return static_cast<size_t>(stream.gcount()) == bytes && !stream.fail();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read flair attributes from stream
|
||||
*/
|
||||
@@ -295,22 +282,23 @@ NiPoint3 Chunk::GridToWorldPos(uint32_t i, uint32_t j) const {
|
||||
}
|
||||
chunk.sceneMap.resize(sceneMapSize);
|
||||
stream.read(reinterpret_cast<char*>(chunk.sceneMap.data()), static_cast<std::streamsize>(sceneMapSize));
|
||||
} else if (version == 31) {
|
||||
} else {
|
||||
const size_t sceneMapCells = static_cast<size_t>(chunk.colorMapResolution + 1) * (chunk.colorMapResolution + 1);
|
||||
if (sceneMapCells > kMaxBlobBytes) {
|
||||
LOG("Chunk v31 sceneMap size %zu exceeds maximum %zu bytes", sceneMapCells, kMaxBlobBytes);
|
||||
LOG("Chunk legacy sceneMap size %zu exceeds maximum %zu bytes", sceneMapCells, kMaxBlobBytes);
|
||||
return false;
|
||||
}
|
||||
std::vector<uint8_t> rawSceneMap(sceneMapCells);
|
||||
stream.read(reinterpret_cast<char*>(rawSceneMap.data()), static_cast<std::streamsize>(sceneMapCells));
|
||||
chunk.sceneMap.resize(static_cast<size_t>(chunk.colorMapResolution) * chunk.colorMapResolution);
|
||||
for (uint32_t row = 0; row < chunk.colorMapResolution; ++row) {
|
||||
for (uint32_t col = 0; col < chunk.colorMapResolution; ++col) {
|
||||
chunk.sceneMap[row * chunk.colorMapResolution + col] = rawSceneMap[row * (chunk.colorMapResolution + 1) + col];
|
||||
chunk.sceneMapLegacy.resize(sceneMapCells);
|
||||
stream.read(reinterpret_cast<char*>(chunk.sceneMapLegacy.data()), static_cast<std::streamsize>(sceneMapCells));
|
||||
// Like the client: version 31 uses the first colorMapResolution rows and columns, older versions are all scene 0
|
||||
chunk.sceneMap.assign(static_cast<size_t>(chunk.colorMapResolution) * chunk.colorMapResolution, 0);
|
||||
if (version == 31) {
|
||||
for (uint32_t row = 0; row < chunk.colorMapResolution; ++row) {
|
||||
for (uint32_t col = 0; col < chunk.colorMapResolution; ++col) {
|
||||
chunk.sceneMap[row * chunk.colorMapResolution + col] = chunk.sceneMapLegacy[row * (chunk.colorMapResolution + 1) + col];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!Skip(stream, 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stream.fail()) {
|
||||
|
||||
@@ -98,6 +98,9 @@ struct Chunk {
|
||||
|
||||
// The scene map is colorMapResolution * colorMapResolution scene IDs, indexed [x cell * resolution + z cell]
|
||||
std::vector<uint8_t> sceneMap;
|
||||
// Version 31 and older: the file's (colorMapResolution + 1)^2 scene map. In version 31 sceneMap is its first
|
||||
// colorMapResolution rows and columns; older versions don't use it and every cell is scene 0
|
||||
std::vector<uint8_t> sceneMapLegacy;
|
||||
|
||||
// Mesh data (version 32+)
|
||||
uint32_t vertSize = 0;
|
||||
|
||||
@@ -173,6 +173,7 @@ TEST_F(RawTest, ReadsVersion31SceneMapWithoutTheLastRowAndColumn) {
|
||||
ASSERT_EQ(raw.chunks.size(), 1);
|
||||
EXPECT_EQ(raw.chunks[0].colorMapResolution, 2);
|
||||
EXPECT_EQ(raw.chunks[0].sceneMap, (std::vector<uint8_t>{ 1, 2, 3, 4 }));
|
||||
EXPECT_EQ(raw.chunks[0].sceneMapLegacy, chunk.sceneMap);
|
||||
EXPECT_EQ(raw.chunks[0].shaderId, 77);
|
||||
EXPECT_EQ(raw.chunks[0].textureIds, (std::vector<uint32_t>{ 100, 101, 102, 103 }));
|
||||
EXPECT_EQ(raw.chunks[0].colorMap.size(), 3 * 3 * 4); // width^2 pixels
|
||||
@@ -182,8 +183,12 @@ TEST_F(RawTest, ReadsVersion31SceneMapWithoutTheLastRowAndColumn) {
|
||||
EXPECT_TRUE(raw.chunks[0].meshTri.empty());
|
||||
}
|
||||
|
||||
TEST_F(RawTest, ReadsVersion30WithoutASceneMap) {
|
||||
TEST_F(RawTest, Version30SceneMapIsReadButEveryCellIsSceneZero) {
|
||||
TestChunk chunk;
|
||||
chunk.width = 3;
|
||||
chunk.height = 3;
|
||||
// resolution is width - 1 = 2; the file has a 3x3 scene map the client doesn't use
|
||||
chunk.sceneMap = { 7, 7, 7, 7, 7, 7, 7, 7, 7 };
|
||||
const auto data = WriteRaw({ chunk, chunk }, 30, 1, 2);
|
||||
|
||||
std::istringstream stream(data);
|
||||
@@ -191,9 +196,10 @@ TEST_F(RawTest, ReadsVersion30WithoutASceneMap) {
|
||||
ASSERT_TRUE(Raw::ReadRaw(stream, raw));
|
||||
EXPECT_EQ(stream.tellg(), static_cast<std::streamoff>(data.size()));
|
||||
ASSERT_EQ(raw.chunks.size(), 2);
|
||||
EXPECT_TRUE(raw.chunks[1].sceneMap.empty());
|
||||
EXPECT_FALSE(raw.chunks[1].IsValidForSceneLookup());
|
||||
EXPECT_EQ(raw.GetSceneIDAt(0.5f, 0.5f), std::nullopt);
|
||||
EXPECT_EQ(raw.chunks[1].sceneMapLegacy, chunk.sceneMap);
|
||||
EXPECT_EQ(raw.chunks[1].sceneMap, (std::vector<uint8_t>{ 0, 0, 0, 0 }));
|
||||
EXPECT_TRUE(raw.chunks[1].IsValidForSceneLookup());
|
||||
EXPECT_EQ(raw.GetSceneIDAt(0.5f, 0.5f), 0);
|
||||
}
|
||||
|
||||
TEST_F(RawTest, DevFileHasNoChunks) {
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace TerrainTestWriter {
|
||||
float scale = 1.0f;
|
||||
// Version 32+: the color map resolution; older versions use width - 1
|
||||
uint32_t colorMapResolution = 2;
|
||||
// colorMapResolution^2 scene IDs ((resolution + 1)^2 for version 31); empty = all 0
|
||||
// colorMapResolution^2 scene IDs ((resolution + 1)^2 for version 31 and older); empty = all 0
|
||||
std::vector<uint8_t> sceneMap;
|
||||
// width * height heights; empty = the point index
|
||||
std::vector<float> heights;
|
||||
@@ -86,12 +86,9 @@ namespace TerrainTestWriter {
|
||||
for (const uint8_t channel : { 10, 20, 30, 40 }) Write(stream, channel);
|
||||
}
|
||||
|
||||
if (version >= 31) {
|
||||
const size_t cells = version >= 32 ? static_cast<size_t>(resolution) * resolution : static_cast<size_t>(resolution + 1) * (resolution + 1);
|
||||
for (size_t i = 0; i < cells; ++i) Write<uint8_t>(stream, chunk.sceneMap.empty() ? 0 : chunk.sceneMap[i]);
|
||||
} else {
|
||||
Write<uint8_t>(stream, 0);
|
||||
}
|
||||
// version 31 and older: one more row and column
|
||||
const size_t cells = version >= 32 ? static_cast<size_t>(resolution) * resolution : static_cast<size_t>(resolution + 1) * (resolution + 1);
|
||||
for (size_t i = 0; i < cells; ++i) Write<uint8_t>(stream, chunk.sceneMap.empty() ? 0 : chunk.sceneMap[i]);
|
||||
|
||||
if (version < 32) return;
|
||||
Write(stream, chunk.vertSize);
|
||||
|
||||
Reference in New Issue
Block a user