fix: read and keep a zone file's scenes as the client does

LuzFile::ReadLUZFile, LuzReader::ReadScenes and ZoneLoader::ReadZoneFile
(1.10.64):
- a version older than 20 is read as 20;
- before version 30 a scene is a bare u32 SceneTable ID: in ID order,
  each one with a SceneTable row gets the next index (-1 past 255) as
  its ID and the row's sceneName as its file; the others are left out;
- from 30 to 32 the file has no scene IDs: a scene's ID is its index in
  the file (they all had ID 0, colliding);
- a later scene with the same ID and layer replaces an earlier one, a
  scene ID with no layer 0 scene is left out, and before version 41
  only the layer 0 scenes are loaded.

No 1.10.64 zone file has a duplicate scene, a scene without a layer 0
scene or another layer before version 41, so what live zones load is
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-10-26 21:29:58 -05:00
parent 0ff5d2bf87
commit 1c5c615670
5 changed files with 230 additions and 12 deletions

View File

@@ -7,6 +7,8 @@
#include <string>
#include <vector>
#include <map>
#include <functional>
#include <optional>
#include "Raw.h"
namespace LUTriggers {
@@ -31,6 +33,7 @@ enum class eSceneType : uint32_t {
struct SceneRef {
std::string filename;
uint32_t id{};
uint32_t sceneTableID{}; // before PrePreAlpha: the scene's row in the CDClient SceneTable
eSceneType sceneType{};
std::string name;
NiPoint3 unknown1;
@@ -204,6 +207,7 @@ struct Path {
class Zone {
public:
enum class FileFormatVersion : uint32_t { //Times are guessed.
Oldest = 20, // the client reads anything older as this
PrePreAlpha = 30,
PreAlpha = 32,
LatePreAlpha = 33,
@@ -231,6 +235,10 @@ public:
LUTriggers::Trigger* GetTrigger(uint32_t sceneID, uint32_t triggerID) const;
const Path* GetPath(std::string name) const;
// The CDClient SceneTable's sceneName for a scene of a file from before PrePreAlpha; the database's by default
using SceneTableLookup = std::function<std::optional<std::string>(uint32_t sceneTableID)>;
void SetSceneTableLookup(SceneTableLookup lookup) { m_SceneTableLookup = std::move(lookup); }
uint32_t GetWorldID() const { return m_WorldID; }
[[nodiscard]] std::string GetZoneName() const { return m_ZoneName; }
std::string GetZoneRawPath() const { return m_ZoneRawPath; }
@@ -276,7 +284,9 @@ private:
std::map<LWOSCENEID, uint32_t> m_MapRevisions; //rhs is the revision!
//private ("helper") functions:
void LoadScene(std::istream& file);
SceneTableLookup m_SceneTableLookup;
void LoadScene(std::istream& file, uint32_t index);
void KeepLoadedScenes();
void LoadLUTriggers(std::string triggerFile, SceneRef& scene);
void LoadSceneTransition(std::istream& file);
SceneTransitionInfo LoadSceneTransitionInfo(std::istream& file);