feat(zone): read zone files of every version the client reads

Zone files older than version 30 were refused. The client reads them
(1.10.64):
- LuzFile::ReadLUZFile reads a version below 20 as 20;
- LuzReader::ReadScenes reads a scene of a version 20-29 file as a bare
  u32 SceneTable ID, with no file name;
- ZoneLoader::ReadZoneFile takes those scenes in SceneTable ID order,
  looks each one up in the CDClient SceneTable and, when there is a
  row, makes it a scene with the next index (0, 1, ...; -1 past 255) as
  its ID and the row's sceneName as its file; a scene with no row is
  left out.

ZoneFile now reads these files (FileFormatVersion::Oldest = 20 for
anything older), keeps the SceneTable ID on ZoneScene::sceneTableID,
and ZoneFile::ResolveSceneTable does the lookup the client does; the
world looks the names up in the CDClient SceneTable.

The only such file on disk (version 20) now reads.

Check in game: nothing to check on live worlds (all are version 36+).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-09-29 05:10:07 -05:00
parent 00b62edfa0
commit d4fc595e2d
4 changed files with 75 additions and 10 deletions

View File

@@ -1,6 +1,8 @@
#pragma once
#include <cstdint>
#include <functional>
#include <optional>
#include <iosfwd>
#include <map>
#include <string>
@@ -27,6 +29,7 @@ struct WaypointCommand {
struct ZoneScene {
std::string filename;
uint32_t id{};
uint32_t sceneTableID{}; // before PrePreAlpha: the scene's row in the CDClient SceneTable (see ResolveSceneTable)
eSceneType sceneType{};
std::string name;
NiPoint3 unknown1;
@@ -199,6 +202,7 @@ struct Path {
struct ZoneFile {
enum class FileFormatVersion : uint32_t { //Times are guessed.
Oldest = 20, // the client reads anything older as this
PrePreAlpha = 30,
PreAlpha = 32,
LatePreAlpha = 33,
@@ -243,6 +247,13 @@ struct ZoneFile {
*/
void ReadHeader(std::istream& file);
/**
* Before PrePreAlpha a scene is only its SceneTable ID. As the client does (ZoneLoader::ReadZoneFile), the scenes
* are taken in SceneTable ID order, each one `sceneName` finds a row for gets that row's sceneName as its file and
* name and the next index as its ID, and the others are left out. Nothing to do for newer files.
*/
void ResolveSceneTable(const std::function<std::optional<std::string>(uint32_t)>& sceneName);
private:
void ReadScene(std::istream& file);
void ReadZoneBoundaries(std::istream& file);