mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-11-06 11:57:13 +00:00
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:
@@ -11,6 +11,7 @@
|
|||||||
#include "dConfig.h"
|
#include "dConfig.h"
|
||||||
|
|
||||||
#include "AssetManager.h"
|
#include "AssetManager.h"
|
||||||
|
#include "CDClientDatabase.h"
|
||||||
#include "CDClientManager.h"
|
#include "CDClientManager.h"
|
||||||
#include "CDZoneTableTable.h"
|
#include "CDZoneTableTable.h"
|
||||||
#include "Spawner.h"
|
#include "Spawner.h"
|
||||||
@@ -30,6 +31,13 @@ Zone::Zone(const LWOZONEID zoneID) :
|
|||||||
m_CheckSum = 0;
|
m_CheckSum = 0;
|
||||||
m_WorldID = 0;
|
m_WorldID = 0;
|
||||||
m_SceneCount = 0;
|
m_SceneCount = 0;
|
||||||
|
m_SceneTableLookup = [](uint32_t sceneTableID) -> std::optional<std::string> {
|
||||||
|
auto query = CDClientDatabase::CreatePreppedStmt("SELECT sceneName FROM SceneTable WHERE sceneID = ?;");
|
||||||
|
query.bind(1, static_cast<int32_t>(sceneTableID));
|
||||||
|
auto result = query.execQuery();
|
||||||
|
if (result.eof() || result.fieldIsNull("sceneName")) return std::nullopt;
|
||||||
|
return std::string(result.getStringField("sceneName"));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Zone::~Zone() {
|
Zone::~Zone() {
|
||||||
@@ -56,6 +64,8 @@ void Zone::LoadZoneIntoMemory() {
|
|||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
BinaryIO::BinaryRead(file, m_FileFormatVersion);
|
BinaryIO::BinaryRead(file, m_FileFormatVersion);
|
||||||
|
// The client reads anything older than 20 as 20 (LuzFile::ReadLUZFile)
|
||||||
|
if (m_FileFormatVersion < Zone::FileFormatVersion::Oldest) m_FileFormatVersion = Zone::FileFormatVersion::Oldest;
|
||||||
|
|
||||||
uint32_t mapRevision = 0;
|
uint32_t mapRevision = 0;
|
||||||
if (m_FileFormatVersion >= Zone::FileFormatVersion::Alpha) BinaryIO::BinaryRead(file, mapRevision);
|
if (m_FileFormatVersion >= Zone::FileFormatVersion::Alpha) BinaryIO::BinaryRead(file, mapRevision);
|
||||||
@@ -78,8 +88,9 @@ void Zone::LoadZoneIntoMemory() {
|
|||||||
} else BinaryIO::BinaryRead(file, m_SceneCount);
|
} else BinaryIO::BinaryRead(file, m_SceneCount);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < m_SceneCount; ++i) {
|
for (uint32_t i = 0; i < m_SceneCount; ++i) {
|
||||||
LoadScene(file);
|
LoadScene(file, i);
|
||||||
}
|
}
|
||||||
|
KeepLoadedScenes();
|
||||||
|
|
||||||
// Zone boundary lines: a count byte, then the lines
|
// Zone boundary lines: a count byte, then the lines
|
||||||
uint8_t numBoundaries = 0;
|
uint8_t numBoundaries = 0;
|
||||||
@@ -268,21 +279,29 @@ void Zone::AddRevision(LWOSCENEID sceneID, uint32_t revision) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Zone::LoadScene(std::istream& file) {
|
void Zone::LoadScene(std::istream& file, uint32_t index) {
|
||||||
SceneRef scene;
|
SceneRef scene;
|
||||||
scene.level = nullptr;
|
scene.level = nullptr;
|
||||||
LWOSCENEID lwoSceneID(LWOZONEID_INVALID, 0);
|
|
||||||
|
// Before PrePreAlpha a scene is only its SceneTable ID; KeepLoadedScenes finds its file (LuzReader::ReadScenes)
|
||||||
|
if (m_FileFormatVersion < Zone::FileFormatVersion::PrePreAlpha) {
|
||||||
|
BinaryIO::BinaryRead(file, scene.sceneTableID);
|
||||||
|
scene.id = scene.sceneTableID;
|
||||||
|
m_Scenes[LWOSCENEID(scene.id, 0)] = std::move(scene);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
BinaryIO::ReadString<uint8_t>(file, scene.filename, BinaryIO::ReadType::String);
|
BinaryIO::ReadString<uint8_t>(file, scene.filename, BinaryIO::ReadType::String);
|
||||||
|
|
||||||
std::string luTriggersPath = scene.filename.substr(0, scene.filename.size() - 4) + ".lutriggers";
|
std::string luTriggersPath = scene.filename.substr(0, scene.filename.size() - 4) + ".lutriggers";
|
||||||
if (Game::assetManager->HasFile((m_ZonePath + luTriggersPath).c_str())) LoadLUTriggers(luTriggersPath, scene);
|
if (Game::assetManager->HasFile((m_ZonePath + luTriggersPath).c_str())) LoadLUTriggers(luTriggersPath, scene);
|
||||||
|
|
||||||
if (m_FileFormatVersion >= Zone::FileFormatVersion::LatePreAlpha || m_FileFormatVersion < Zone::FileFormatVersion::PrePreAlpha) {
|
// Until LatePreAlpha the file has no scene IDs: a scene's ID is its index (-1 past 255) in the file
|
||||||
|
scene.id = index < 256 ? index : UINT32_MAX;
|
||||||
|
LWOSCENEID lwoSceneID(scene.id, 0);
|
||||||
|
if (m_FileFormatVersion >= Zone::FileFormatVersion::LatePreAlpha) {
|
||||||
BinaryIO::BinaryRead(file, scene.id);
|
BinaryIO::BinaryRead(file, scene.id);
|
||||||
lwoSceneID.SetSceneID(scene.id);
|
lwoSceneID.SetSceneID(scene.id);
|
||||||
}
|
|
||||||
if (m_FileFormatVersion >= Zone::FileFormatVersion::LatePreAlpha) {
|
|
||||||
BinaryIO::BinaryRead(file, scene.sceneType);
|
BinaryIO::BinaryRead(file, scene.sceneType);
|
||||||
lwoSceneID.SetLayerID(static_cast<uint32_t>(scene.sceneType));
|
lwoSceneID.SetLayerID(static_cast<uint32_t>(scene.sceneType));
|
||||||
|
|
||||||
@@ -306,6 +325,37 @@ void Zone::LoadScene(std::istream& file) {
|
|||||||
m_Scenes[lwoSceneID] = std::move(scene);
|
m_Scenes[lwoSceneID] = std::move(scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Zone::KeepLoadedScenes() {
|
||||||
|
if (m_FileFormatVersion < Zone::FileFormatVersion::PrePreAlpha) {
|
||||||
|
// ZoneLoader::ReadZoneFile: the scenes go by their SceneTable ID; each one with a row there gets the next index
|
||||||
|
// (0, 1, ...; -1 past 255) as its ID and the row's sceneName as its file, the others are left out
|
||||||
|
std::map<LWOSCENEID, SceneRef> resolved;
|
||||||
|
uint32_t index = 0;
|
||||||
|
for (auto& scene : m_Scenes | std::views::values) {
|
||||||
|
const auto sceneName = m_SceneTableLookup(scene.sceneTableID);
|
||||||
|
if (!sceneName) continue;
|
||||||
|
scene.id = index < 256 ? index : UINT32_MAX;
|
||||||
|
scene.filename = *sceneName;
|
||||||
|
scene.name = *sceneName;
|
||||||
|
const std::string luTriggersPath = scene.filename.substr(0, scene.filename.size() - 4) + ".lutriggers";
|
||||||
|
if (Game::assetManager->HasFile((m_ZonePath + luTriggersPath).c_str())) LoadLUTriggers(luTriggersPath, scene);
|
||||||
|
resolved[LWOSCENEID(scene.id, 0)] = std::move(scene);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
m_Scenes = std::move(resolved);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LuzReader::ReadScenes keeps the scenes by scene ID and layer, a later one replacing an earlier one (as m_Scenes
|
||||||
|
// does). ZoneLoader::ReadZoneFile then goes through them by scene ID: a scene ID with no layer 0 (General) scene is
|
||||||
|
// left out, and before Latest only the layer 0 scene is loaded
|
||||||
|
std::erase_if(m_Scenes, [this](const auto& entry) {
|
||||||
|
const auto& [sceneID, scene] = entry;
|
||||||
|
if (!m_Scenes.contains(LWOSCENEID(sceneID.GetSceneID(), 0))) return true;
|
||||||
|
return sceneID.GetLayerID() != 0 && m_FileFormatVersion < Zone::FileFormatVersion::Latest;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void Zone::LoadLUTriggers(std::string triggerFile, SceneRef& scene) {
|
void Zone::LoadLUTriggers(std::string triggerFile, SceneRef& scene) {
|
||||||
auto file = Game::assetManager->GetFile((m_ZonePath + triggerFile).c_str());
|
auto file = Game::assetManager->GetFile((m_ZonePath + triggerFile).c_str());
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <functional>
|
||||||
|
#include <optional>
|
||||||
#include "Raw.h"
|
#include "Raw.h"
|
||||||
|
|
||||||
namespace LUTriggers {
|
namespace LUTriggers {
|
||||||
@@ -31,6 +33,7 @@ enum class eSceneType : uint32_t {
|
|||||||
struct SceneRef {
|
struct SceneRef {
|
||||||
std::string filename;
|
std::string filename;
|
||||||
uint32_t id{};
|
uint32_t id{};
|
||||||
|
uint32_t sceneTableID{}; // before PrePreAlpha: the scene's row in the CDClient SceneTable
|
||||||
eSceneType sceneType{};
|
eSceneType sceneType{};
|
||||||
std::string name;
|
std::string name;
|
||||||
NiPoint3 unknown1;
|
NiPoint3 unknown1;
|
||||||
@@ -204,6 +207,7 @@ struct Path {
|
|||||||
class Zone {
|
class Zone {
|
||||||
public:
|
public:
|
||||||
enum class FileFormatVersion : uint32_t { //Times are guessed.
|
enum class FileFormatVersion : uint32_t { //Times are guessed.
|
||||||
|
Oldest = 20, // the client reads anything older as this
|
||||||
PrePreAlpha = 30,
|
PrePreAlpha = 30,
|
||||||
PreAlpha = 32,
|
PreAlpha = 32,
|
||||||
LatePreAlpha = 33,
|
LatePreAlpha = 33,
|
||||||
@@ -231,6 +235,10 @@ public:
|
|||||||
LUTriggers::Trigger* GetTrigger(uint32_t sceneID, uint32_t triggerID) const;
|
LUTriggers::Trigger* GetTrigger(uint32_t sceneID, uint32_t triggerID) const;
|
||||||
const Path* GetPath(std::string name) 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; }
|
uint32_t GetWorldID() const { return m_WorldID; }
|
||||||
[[nodiscard]] std::string GetZoneName() const { return m_ZoneName; }
|
[[nodiscard]] std::string GetZoneName() const { return m_ZoneName; }
|
||||||
std::string GetZoneRawPath() const { return m_ZoneRawPath; }
|
std::string GetZoneRawPath() const { return m_ZoneRawPath; }
|
||||||
@@ -276,7 +284,9 @@ private:
|
|||||||
|
|
||||||
std::map<LWOSCENEID, uint32_t> m_MapRevisions; //rhs is the revision!
|
std::map<LWOSCENEID, uint32_t> m_MapRevisions; //rhs is the revision!
|
||||||
//private ("helper") functions:
|
//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 LoadLUTriggers(std::string triggerFile, SceneRef& scene);
|
||||||
void LoadSceneTransition(std::istream& file);
|
void LoadSceneTransition(std::istream& file);
|
||||||
SceneTransitionInfo LoadSceneTransitionInfo(std::istream& file);
|
SceneTransitionInfo LoadSceneTransitionInfo(std::istream& file);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
SET(DZONEMANAGER_TESTS
|
SET(DZONEMANAGER_TESTS
|
||||||
"RawTests.cpp"
|
"RawTests.cpp"
|
||||||
|
"ZoneFileVersionTests.cpp"
|
||||||
"ZoneSceneTests.cpp")
|
"ZoneSceneTests.cpp")
|
||||||
|
|
||||||
# Get the folder name and prepend it to the files above
|
# Get the folder name and prepend it to the files above
|
||||||
|
|||||||
157
tests/dGameTests/dZoneManagerTests/ZoneFileVersionTests.cpp
Normal file
157
tests/dGameTests/dZoneManagerTests/ZoneFileVersionTests.cpp
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
#include "GameDependencies.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "AssetManager.h"
|
||||||
|
#include "CDZoneTableTable.h"
|
||||||
|
#include "Zone.h"
|
||||||
|
#include "dZoneManager.h"
|
||||||
|
|
||||||
|
// The zone table's storage (CDZoneTableTable.cpp), to add the test zone
|
||||||
|
namespace CDZoneTableTable {
|
||||||
|
extern Table entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
template<typename T>
|
||||||
|
void Write(std::ostream& stream, const T& value) {
|
||||||
|
stream.write(reinterpret_cast<const char*>(&value), sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteString8(std::ostream& stream, const std::string& value) {
|
||||||
|
Write<uint8_t>(stream, static_cast<uint8_t>(value.size()));
|
||||||
|
stream.write(value.data(), value.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TestScene {
|
||||||
|
std::string filename;
|
||||||
|
uint32_t id = 0;
|
||||||
|
uint32_t layer = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A zone file of a version from 31 on with the given scenes and no transitions or paths
|
||||||
|
std::string WriteZone(uint32_t version, const std::vector<TestScene>& scenes) {
|
||||||
|
std::ostringstream stream;
|
||||||
|
Write(stream, version);
|
||||||
|
if (version >= 36) Write<uint32_t>(stream, 1); // revision
|
||||||
|
Write<uint32_t>(stream, 1);
|
||||||
|
if (version >= 38) {
|
||||||
|
Write(stream, NiPoint3(0.0f, 0.0f, 0.0f)); // spawn position
|
||||||
|
for (const float value : { 1.0f, 0.0f, 0.0f, 0.0f }) Write(stream, value); // spawn rotation
|
||||||
|
}
|
||||||
|
if (version >= 38) Write<uint32_t>(stream, static_cast<uint32_t>(scenes.size()));
|
||||||
|
else Write<uint8_t>(stream, static_cast<uint8_t>(scenes.size()));
|
||||||
|
for (const auto& scene : scenes) {
|
||||||
|
WriteString8(stream, scene.filename);
|
||||||
|
if (version >= 33) {
|
||||||
|
Write(stream, scene.id);
|
||||||
|
Write(stream, scene.layer);
|
||||||
|
WriteString8(stream, scene.filename);
|
||||||
|
for (const uint8_t color : { 1, 2, 3 }) Write(stream, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Write<uint8_t>(stream, 0); // boundary lines
|
||||||
|
WriteString8(stream, "test.raw");
|
||||||
|
WriteString8(stream, "Test Zone");
|
||||||
|
WriteString8(stream, "A zone for tests");
|
||||||
|
if (version >= 32) Write<uint32_t>(stream, 0); // transitions
|
||||||
|
if (version >= 35) {
|
||||||
|
Write<uint32_t>(stream, 8); // path chunk length
|
||||||
|
Write<uint32_t>(stream, 1); // path chunk version
|
||||||
|
Write<uint32_t>(stream, 0); // paths
|
||||||
|
}
|
||||||
|
return stream.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loads a written .luz through the zone manager
|
||||||
|
class ZoneFileVersionTest : public GameDependenciesTest {
|
||||||
|
protected:
|
||||||
|
static constexpr LWOMAPID TEST_MAP = 9993;
|
||||||
|
std::filesystem::path root;
|
||||||
|
|
||||||
|
void SetUp() override {
|
||||||
|
SetUpDependencies();
|
||||||
|
root = std::filesystem::temp_directory_path() / (std::string("dlu_zone_version_test_") + ::testing::UnitTest::GetInstance()->current_test_info()->name());
|
||||||
|
std::filesystem::create_directories(root / "res" / "maps" / "testzone");
|
||||||
|
std::ofstream(root / "res" / "CDServer.sqlite").close(); // marks an unpacked client
|
||||||
|
Game::assetManager = new AssetManager(root);
|
||||||
|
|
||||||
|
CDZoneTable zone{};
|
||||||
|
zone.zoneID = TEST_MAP;
|
||||||
|
zone.zoneName = "testzone/test.luz";
|
||||||
|
CDZoneTableTable::entries[TEST_MAP] = zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override {
|
||||||
|
CDZoneTableTable::entries.erase(TEST_MAP);
|
||||||
|
delete Game::assetManager;
|
||||||
|
Game::assetManager = nullptr;
|
||||||
|
std::filesystem::remove_all(root);
|
||||||
|
TearDownDependencies();
|
||||||
|
}
|
||||||
|
|
||||||
|
Zone* LoadZone(const std::string& data, Zone::SceneTableLookup lookup = nullptr) const {
|
||||||
|
std::ofstream(root / "res" / "maps" / "testzone" / "test.luz", std::ios::binary).write(data.data(), data.size());
|
||||||
|
Game::zoneManager->LoadZone(LWOZONEID(TEST_MAP, 0, 0));
|
||||||
|
Zone* zone = Game::zoneManager->GetZoneMut();
|
||||||
|
if (lookup) zone->SetSceneTableLookup(std::move(lookup));
|
||||||
|
zone->LoadZoneIntoMemory();
|
||||||
|
return zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::pair<LWOSCENEID, std::string>> Scenes(const Zone* zone) {
|
||||||
|
std::vector<std::pair<LWOSCENEID, std::string>> scenes;
|
||||||
|
for (const auto& [id, scene] : zone->GetScenes()) scenes.emplace_back(id, scene.filename);
|
||||||
|
return scenes;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Until version 33 a zone file has no scene IDs: each scene's ID is its index in the file
|
||||||
|
TEST_F(ZoneFileVersionTest, OldScenesAreNumberedByTheirIndex) {
|
||||||
|
const Zone* zone = LoadZone(WriteZone(31, { { "a.lvl" }, { "b.lvl" } }));
|
||||||
|
const std::vector<std::pair<LWOSCENEID, std::string>> expected = { { LWOSCENEID(0, 0), "a.lvl" }, { LWOSCENEID(1, 0), "b.lvl" } };
|
||||||
|
EXPECT_EQ(Scenes(zone), expected);
|
||||||
|
EXPECT_EQ(zone->GetZoneName(), "Test Zone");
|
||||||
|
}
|
||||||
|
|
||||||
|
// A later scene with the same ID and layer replaces an earlier one; a scene ID without a layer 0 scene isn't loaded,
|
||||||
|
// and before version 41 only the layer 0 scenes are
|
||||||
|
TEST_F(ZoneFileVersionTest, KeepsTheScenesTheClientLoads) {
|
||||||
|
const std::vector<TestScene> scenes = {
|
||||||
|
{ "first.lvl", 1, 0 }, { "audio.lvl", 1, 1 }, { "orphan_audio.lvl", 2, 1 }, { "second.lvl", 1, 0 }, { "three.lvl", 3, 0 },
|
||||||
|
};
|
||||||
|
const std::vector<std::pair<LWOSCENEID, std::string>> latest = {
|
||||||
|
{ LWOSCENEID(1, 0), "second.lvl" }, { LWOSCENEID(1, 1), "audio.lvl" }, { LWOSCENEID(3, 0), "three.lvl" },
|
||||||
|
};
|
||||||
|
EXPECT_EQ(Scenes(LoadZone(WriteZone(41, scenes))), latest);
|
||||||
|
|
||||||
|
const std::vector<std::pair<LWOSCENEID, std::string>> older = { { LWOSCENEID(1, 0), "second.lvl" }, { LWOSCENEID(3, 0), "three.lvl" } };
|
||||||
|
EXPECT_EQ(Scenes(LoadZone(WriteZone(40, scenes))), older);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Before version 30 a scene is a SceneTable ID: in ID order, each one with a row gets the next index as its ID and the
|
||||||
|
// row's scene name as its file; the others aren't loaded. A file older than version 20 is read as 20
|
||||||
|
TEST_F(ZoneFileVersionTest, OldestScenesComeFromTheSceneTable) {
|
||||||
|
for (const uint32_t version : { 25u, 10u }) {
|
||||||
|
std::ostringstream stream;
|
||||||
|
Write(stream, version);
|
||||||
|
Write<uint32_t>(stream, 1); // world ID
|
||||||
|
Write<uint8_t>(stream, 3);
|
||||||
|
for (const uint32_t sceneTableID : { 7u, 9u, 3u }) Write(stream, sceneTableID);
|
||||||
|
Write<uint8_t>(stream, 0); // boundary lines
|
||||||
|
WriteString8(stream, "test.raw");
|
||||||
|
Write<uint16_t>(stream, 0); // trailing bytes: older readers read a name and description here
|
||||||
|
const Zone* zone = LoadZone(stream.str(), [](uint32_t sceneTableID) -> std::optional<std::string> {
|
||||||
|
if (sceneTableID == 3) return "three.lvl";
|
||||||
|
if (sceneTableID == 7) return "seven.lvl";
|
||||||
|
return std::nullopt;
|
||||||
|
});
|
||||||
|
|
||||||
|
const std::vector<std::pair<LWOSCENEID, std::string>> expected = { { LWOSCENEID(0, 0), "three.lvl" }, { LWOSCENEID(1, 0), "seven.lvl" } };
|
||||||
|
EXPECT_EQ(Scenes(zone), expected) << version;
|
||||||
|
EXPECT_EQ(zone->GetZoneRawPath(), "test.raw") << version;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -51,14 +51,14 @@ protected:
|
|||||||
file.write(data.data(), data.size());
|
file.write(data.data(), data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scenes 0 (global), 1, 2 and 3 (general) and 5 (audio, layer 1); transitions 1 <-> 2 and 2 <-> 3
|
// Scenes 0 (global), 1, 2 and 3 (general) and 3 (audio, layer 1); transitions 1 <-> 2 and 2 <-> 3
|
||||||
void WriteZone(const std::string& rawName = "test.raw", uint8_t boundaryCount = 2, uint32_t version = 41) const {
|
void WriteZone(const std::string& rawName = "test.raw", uint8_t boundaryCount = 2, uint32_t version = 41) const {
|
||||||
const std::vector<TestScene> scenes = {
|
const std::vector<TestScene> scenes = {
|
||||||
{ "global.lvl", 0, 0, "Global", 10, 20, 30 },
|
{ "global.lvl", 0, 0, "Global", 10, 20, 30 },
|
||||||
{ "one.lvl", 1, 0, "Scene One", 255, 0, 0 },
|
{ "one.lvl", 1, 0, "Scene One", 255, 0, 0 },
|
||||||
{ "two.lvl", 2, 0, "Scene Two", 0, 255, 0 },
|
{ "two.lvl", 2, 0, "Scene Two", 0, 255, 0 },
|
||||||
{ "three.lvl", 3, 0, "Scene Three", 0, 0, 255 },
|
{ "three.lvl", 3, 0, "Scene Three", 0, 0, 255 },
|
||||||
{ "audio.lvl", 5, 1, "Audio", 0, 0, 0 },
|
{ "audio.lvl", 3, 1, "Audio", 0, 0, 0 },
|
||||||
};
|
};
|
||||||
WriteFile("test.luz", WriteLuz(TEST_MAP, scenes, boundaryCount, rawName, {
|
WriteFile("test.luz", WriteLuz(TEST_MAP, scenes, boundaryCount, rawName, {
|
||||||
{ { 1, 0, NiPoint3(1.0f, 0.0f, 0.0f) }, { 2, 0, NiPoint3(2.0f, 0.0f, 0.0f) } },
|
{ { 1, 0, NiPoint3(1.0f, 0.0f, 0.0f) }, { 2, 0, NiPoint3(2.0f, 0.0f, 0.0f) } },
|
||||||
@@ -123,7 +123,7 @@ TEST_F(ZoneSceneTest, ReadsScenesBoundariesAndTransitions) {
|
|||||||
EXPECT_FLOAT_EQ(global->color.m_Red, 10 / 255.0f);
|
EXPECT_FLOAT_EQ(global->color.m_Red, 10 / 255.0f);
|
||||||
EXPECT_FLOAT_EQ(global->color.m_Green, 20 / 255.0f);
|
EXPECT_FLOAT_EQ(global->color.m_Green, 20 / 255.0f);
|
||||||
EXPECT_FLOAT_EQ(global->color.m_Blue, 30 / 255.0f);
|
EXPECT_FLOAT_EQ(global->color.m_Blue, 30 / 255.0f);
|
||||||
const SceneRef* audio = zone->GetScene(LWOSCENEID(5, 1));
|
const SceneRef* audio = zone->GetScene(LWOSCENEID(3, 1));
|
||||||
ASSERT_NE(audio, nullptr);
|
ASSERT_NE(audio, nullptr);
|
||||||
EXPECT_EQ(audio->sceneType, eSceneType::Audio);
|
EXPECT_EQ(audio->sceneType, eSceneType::Audio);
|
||||||
EXPECT_EQ(zone->GetScene(LWOSCENEID(4, 0)), nullptr);
|
EXPECT_EQ(zone->GetScene(LWOSCENEID(4, 0)), nullptr);
|
||||||
@@ -151,7 +151,7 @@ TEST_F(ZoneSceneTest, ReadsOlderZoneVersions) {
|
|||||||
WriteZone("test.raw", 2, version);
|
WriteZone("test.raw", 2, version);
|
||||||
WriteFile("test.raw", MakeRaw());
|
WriteFile("test.raw", MakeRaw());
|
||||||
const Zone* zone = LoadZone();
|
const Zone* zone = LoadZone();
|
||||||
EXPECT_EQ(zone->GetScenes().size(), 5) << version;
|
EXPECT_EQ(zone->GetScenes().size(), 4) << version; // before Latest only layer 0 scenes are loaded
|
||||||
EXPECT_EQ(zone->GetBoundaries().size(), 2) << version;
|
EXPECT_EQ(zone->GetBoundaries().size(), 2) << version;
|
||||||
EXPECT_EQ(zone->GetZoneRawPath(), "test.raw") << version;
|
EXPECT_EQ(zone->GetZoneRawPath(), "test.raw") << version;
|
||||||
EXPECT_EQ(zone->GetZoneName(), "Test Zone") << version;
|
EXPECT_EQ(zone->GetZoneName(), "Test Zone") << version;
|
||||||
@@ -185,7 +185,7 @@ TEST_F(ZoneSceneTest, SceneGraphFromTransitions) {
|
|||||||
|
|
||||||
const auto& graph = Game::zoneManager->GetSceneAdjacencyList();
|
const auto& graph = Game::zoneManager->GetSceneAdjacencyList();
|
||||||
EXPECT_EQ(graph.size(), 4); // the audio scene is left out
|
EXPECT_EQ(graph.size(), 4); // the audio scene is left out
|
||||||
EXPECT_FALSE(graph.contains(LWOSCENEID(5, 1)));
|
EXPECT_FALSE(graph.contains(LWOSCENEID(3, 1)));
|
||||||
|
|
||||||
const auto one = Game::zoneManager->GetAdjacentScenes(LWOSCENEID(1, 0));
|
const auto one = Game::zoneManager->GetAdjacentScenes(LWOSCENEID(1, 0));
|
||||||
EXPECT_EQ(one.size(), 2);
|
EXPECT_EQ(one.size(), 2);
|
||||||
|
|||||||
Reference in New Issue
Block a user