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:
Aaron Kimbrell
2026-10-26 20:33:41 -05:00
parent 6262be5d25
commit a40169a251
4 changed files with 28 additions and 34 deletions

View File

@@ -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()) {

View File

@@ -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;