2021-12-05 17:54:36 +00:00
|
|
|
|
#include "Zone.h"
|
|
|
|
|
#include "Level.h"
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
#include "Game.h"
|
2023-10-21 23:31:55 +00:00
|
|
|
|
#include "Logger.h"
|
2021-12-05 17:54:36 +00:00
|
|
|
|
#include "GeneralUtils.h"
|
|
|
|
|
#include "BinaryIO.h"
|
2023-01-07 05:17:05 +00:00
|
|
|
|
#include "LUTriggers.h"
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
2022-11-01 18:21:26 +00:00
|
|
|
|
#include "AssetManager.h"
|
2021-12-05 17:54:36 +00:00
|
|
|
|
#include "CDClientManager.h"
|
|
|
|
|
#include "CDZoneTableTable.h"
|
|
|
|
|
#include "Spawner.h"
|
|
|
|
|
#include "dZoneManager.h"
|
2023-08-06 22:41:38 +00:00
|
|
|
|
#include "dpWorld.h"
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
2023-02-10 08:29:53 +00:00
|
|
|
|
#include "eTriggerCommandType.h"
|
|
|
|
|
#include "eTriggerEventType.h"
|
2023-08-10 02:37:36 +00:00
|
|
|
|
#include "eWaypointCommandType.h"
|
2024-01-19 21:12:05 +00:00
|
|
|
|
#include "dNavMesh.h"
|
2023-02-10 08:29:53 +00:00
|
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
|
Zone::Zone(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) :
|
|
|
|
|
m_ZoneID(mapID, instanceID, cloneID) {
|
|
|
|
|
m_NumberOfObjectsLoaded = 0;
|
|
|
|
|
m_NumberOfSceneTransitionsLoaded = 0;
|
|
|
|
|
m_CheckSum = 0;
|
|
|
|
|
m_WorldID = 0;
|
|
|
|
|
m_SceneCount = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Zone::~Zone() {
|
2023-10-21 23:31:55 +00:00
|
|
|
|
LOG("Destroying zone %i", m_ZoneID.GetMapID());
|
2021-12-05 17:54:36 +00:00
|
|
|
|
for (std::map<LWOSCENEID, SceneRef>::iterator it = m_Scenes.begin(); it != m_Scenes.end(); ++it) {
|
|
|
|
|
if (it->second.level != nullptr) delete it->second.level;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Zone::Initalize() {
|
|
|
|
|
LoadZoneIntoMemory();
|
|
|
|
|
LoadLevelsIntoMemory();
|
|
|
|
|
m_CheckSum = CalculateChecksum();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Zone::LoadZoneIntoMemory() {
|
|
|
|
|
m_ZoneFilePath = GetFilePathForZoneID();
|
|
|
|
|
m_ZonePath = m_ZoneFilePath.substr(0, m_ZoneFilePath.rfind('/') + 1);
|
|
|
|
|
if (m_ZoneFilePath == "ERR") return;
|
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
auto file = Game::assetManager->GetFile(m_ZoneFilePath.c_str());
|
2022-11-10 18:59:31 +00:00
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
if (!file) {
|
2023-10-21 23:31:55 +00:00
|
|
|
|
LOG("Failed to load %s", m_ZoneFilePath.c_str());
|
2022-11-10 18:59:31 +00:00
|
|
|
|
throw std::runtime_error("Aborting Zone loading due to no Zone File.");
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
|
if (file) {
|
2023-08-10 21:35:12 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, m_FileFormatVersion);
|
2022-07-25 02:26:51 +00:00
|
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
|
uint32_t mapRevision = 0;
|
2023-08-10 21:35:12 +00:00
|
|
|
|
if (m_FileFormatVersion >= Zone::FileFormatVersion::Alpha) BinaryIO::BinaryRead(file, mapRevision);
|
2022-07-25 02:26:51 +00:00
|
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, m_WorldID);
|
2023-12-28 04:18:20 +00:00
|
|
|
|
if (static_cast<LWOMAPID>(m_WorldID) != m_ZoneID.GetMapID()) LOG("WorldID: %i doesn't match MapID %i! Is this intended?", m_WorldID, m_ZoneID.GetMapID());
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
|
|
AddRevision(LWOSCENEID_INVALID, mapRevision);
|
|
|
|
|
|
2023-08-10 21:35:12 +00:00
|
|
|
|
if (m_FileFormatVersion >= Zone::FileFormatVersion::Beta) {
|
2021-12-05 17:54:36 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, m_Spawnpoint);
|
|
|
|
|
BinaryIO::BinaryRead(file, m_SpawnpointRotation);
|
|
|
|
|
}
|
2022-07-25 02:26:51 +00:00
|
|
|
|
|
2023-08-10 21:35:12 +00:00
|
|
|
|
if (m_FileFormatVersion <= Zone::FileFormatVersion::LateAlpha) {
|
2021-12-05 17:54:36 +00:00
|
|
|
|
uint8_t sceneCount;
|
|
|
|
|
BinaryIO::BinaryRead(file, sceneCount);
|
|
|
|
|
m_SceneCount = sceneCount;
|
|
|
|
|
} else BinaryIO::BinaryRead(file, m_SceneCount);
|
|
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < m_SceneCount; ++i) {
|
|
|
|
|
LoadScene(file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Read generic zone info:
|
2023-12-23 17:24:16 +00:00
|
|
|
|
BinaryIO::ReadString<uint8_t>(file, m_ZonePath, BinaryIO::ReadType::String);
|
|
|
|
|
BinaryIO::ReadString<uint8_t>(file, m_ZoneRawPath, BinaryIO::ReadType::String);
|
|
|
|
|
BinaryIO::ReadString<uint8_t>(file, m_ZoneName, BinaryIO::ReadType::String);
|
|
|
|
|
BinaryIO::ReadString<uint8_t>(file, m_ZoneDesc, BinaryIO::ReadType::String);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
2023-08-10 21:35:12 +00:00
|
|
|
|
if (m_FileFormatVersion >= Zone::FileFormatVersion::PreAlpha) {
|
2021-12-05 17:54:36 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, m_NumberOfSceneTransitionsLoaded);
|
|
|
|
|
for (uint32_t i = 0; i < m_NumberOfSceneTransitionsLoaded; ++i) {
|
|
|
|
|
LoadSceneTransition(file);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-10 21:35:12 +00:00
|
|
|
|
if (m_FileFormatVersion >= Zone::FileFormatVersion::EarlyAlpha) {
|
2021-12-05 17:54:36 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, m_PathDataLength);
|
2022-11-12 14:44:03 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, m_PathChunkVersion); // always should be 1
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
2022-11-12 14:44:03 +00:00
|
|
|
|
uint32_t pathCount;
|
2021-12-05 17:54:36 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, pathCount);
|
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
m_Paths.reserve(pathCount);
|
2022-11-12 14:44:03 +00:00
|
|
|
|
for (uint32_t i = 0; i < pathCount; ++i) LoadPath(file);
|
2022-07-25 02:26:51 +00:00
|
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
|
for (Path path : m_Paths) {
|
2023-12-23 17:24:16 +00:00
|
|
|
|
if (path.pathType != PathType::Spawner) continue;
|
|
|
|
|
SpawnerInfo info = SpawnerInfo();
|
|
|
|
|
for (PathWaypoint waypoint : path.pathWaypoints) {
|
|
|
|
|
SpawnerNode* node = new SpawnerNode();
|
|
|
|
|
node->position = waypoint.position;
|
|
|
|
|
node->rotation = waypoint.rotation;
|
|
|
|
|
node->nodeID = 0;
|
|
|
|
|
node->config = waypoint.config;
|
|
|
|
|
|
|
|
|
|
for (LDFBaseData* data : waypoint.config) {
|
|
|
|
|
if (!data) continue;
|
|
|
|
|
|
|
|
|
|
if (data->GetKey() == u"spawner_node_id") {
|
|
|
|
|
node->nodeID = std::stoi(data->GetValueAsString());
|
|
|
|
|
} else if (data->GetKey() == u"spawner_max_per_node") {
|
|
|
|
|
node->nodeMax = std::stoi(data->GetValueAsString());
|
|
|
|
|
} else if (data->GetKey() == u"groupID") { // Load object group
|
|
|
|
|
std::string groupStr = data->GetValueAsString();
|
|
|
|
|
info.groups = GeneralUtils::SplitString(groupStr, ';');
|
2023-12-23 17:50:14 +00:00
|
|
|
|
if (info.groups.back().empty()) info.groups.erase(info.groups.end() - 1);
|
2023-12-23 17:24:16 +00:00
|
|
|
|
} else if (data->GetKey() == u"grpNameQBShowBricks") {
|
2023-12-23 17:50:14 +00:00
|
|
|
|
if (data->GetValueAsString().empty()) continue;
|
2023-12-23 17:24:16 +00:00
|
|
|
|
/*std::string groupStr = data->GetValueAsString();
|
|
|
|
|
info.groups.push_back(groupStr);*/
|
|
|
|
|
info.grpNameQBShowBricks = data->GetValueAsString();
|
|
|
|
|
} else if (data->GetKey() == u"spawner_name") {
|
|
|
|
|
info.name = data->GetValueAsString();
|
2021-12-05 17:54:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-12-23 17:24:16 +00:00
|
|
|
|
info.nodes.push_back(node);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
}
|
2023-12-23 17:24:16 +00:00
|
|
|
|
info.templateID = path.spawner.spawnedLOT;
|
|
|
|
|
info.spawnerID = path.spawner.spawnerObjID;
|
|
|
|
|
info.respawnTime = path.spawner.respawnTime;
|
|
|
|
|
info.amountMaintained = path.spawner.amountMaintained;
|
|
|
|
|
info.maxToSpawn = path.spawner.maxToSpawn;
|
|
|
|
|
info.activeOnLoad = path.spawner.spawnerNetActive;
|
|
|
|
|
info.isNetwork = true;
|
|
|
|
|
Spawner* spawner = new Spawner(info);
|
|
|
|
|
Game::zoneManager->AddSpawner(info.spawnerID, spawner);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2023-10-21 23:31:55 +00:00
|
|
|
|
LOG("Failed to open: %s", m_ZoneFilePath.c_str());
|
2021-12-05 17:54:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_ZonePath = m_ZoneFilePath.substr(0, m_ZoneFilePath.rfind('/') + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string Zone::GetFilePathForZoneID() {
|
|
|
|
|
//We're gonna go ahead and presume we've got the db loaded already:
|
2024-02-09 05:40:43 +00:00
|
|
|
|
CDZoneTableTable* zoneTable = CDClientManager::GetTable<CDZoneTableTable>();
|
2021-12-05 17:54:36 +00:00
|
|
|
|
const CDZoneTable* zone = zoneTable->Query(this->GetZoneID().GetMapID());
|
|
|
|
|
if (zone != nullptr) {
|
2022-11-01 18:21:26 +00:00
|
|
|
|
std::string toReturn = "maps/" + zone->zoneName;
|
2021-12-07 08:25:19 +00:00
|
|
|
|
std::transform(toReturn.begin(), toReturn.end(), toReturn.begin(), ::tolower);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
return toReturn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::string("ERR");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Based off code from: https://www.liquisearch.com/fletchers_checksum/implementation/optimizations
|
|
|
|
|
uint32_t Zone::CalculateChecksum() {
|
|
|
|
|
uint32_t sum1 = 0xffff, sum2 = 0xffff;
|
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
for (const auto& [scene, sceneRevision] : m_MapRevisions) {
|
|
|
|
|
uint32_t sceneID = scene.GetSceneID();
|
2021-12-05 17:54:36 +00:00
|
|
|
|
sum2 += sum1 += (sceneID >> 16);
|
|
|
|
|
sum2 += sum1 += (sceneID & 0xffff);
|
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
uint32_t layerID = scene.GetLayerID();
|
2021-12-05 17:54:36 +00:00
|
|
|
|
sum2 += sum1 += (layerID >> 16);
|
|
|
|
|
sum2 += sum1 += (layerID & 0xffff);
|
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
uint32_t revision = sceneRevision;
|
2021-12-05 17:54:36 +00:00
|
|
|
|
sum2 += sum1 += (revision >> 16);
|
|
|
|
|
sum2 += sum1 += (revision & 0xffff);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
|
|
|
|
|
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
|
|
|
|
|
|
|
|
|
|
return sum2 << 16 | sum1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Zone::LoadLevelsIntoMemory() {
|
2023-12-23 17:24:16 +00:00
|
|
|
|
for (auto& [sceneID, scene] : m_Scenes) {
|
|
|
|
|
if (scene.level) continue;
|
|
|
|
|
scene.level = new Level(this, m_ZonePath + scene.filename);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
if (scene.level->m_ChunkHeaders.empty()) continue;
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
scene.level->m_ChunkHeaders.begin()->second.lwoSceneID = sceneID;
|
|
|
|
|
AddRevision(scene.level->m_ChunkHeaders.begin()->second.lwoSceneID, scene.level->m_ChunkHeaders.begin()->second.fileInfo.revision);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
void Zone::AddRevision(LWOSCENEID sceneID, uint32_t revision) {
|
|
|
|
|
if (m_MapRevisions.find(sceneID) == m_MapRevisions.end()) {
|
|
|
|
|
m_MapRevisions.insert(std::make_pair(sceneID, revision));
|
2021-12-05 17:54:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-01 18:21:26 +00:00
|
|
|
|
void Zone::LoadScene(std::istream& file) {
|
2021-12-05 17:54:36 +00:00
|
|
|
|
SceneRef scene;
|
|
|
|
|
scene.level = nullptr;
|
|
|
|
|
LWOSCENEID lwoSceneID(LWOZONEID_INVALID, 0);
|
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
BinaryIO::ReadString<uint8_t>(file, scene.filename, BinaryIO::ReadType::String);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
|
|
std::string luTriggersPath = scene.filename.substr(0, scene.filename.size() - 4) + ".lutriggers";
|
2023-12-23 17:24:16 +00:00
|
|
|
|
if (Game::assetManager->HasFile((m_ZonePath + luTriggersPath).c_str())) LoadLUTriggers(luTriggersPath, scene);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
2023-08-10 21:35:12 +00:00
|
|
|
|
if (m_FileFormatVersion >= Zone::FileFormatVersion::LatePreAlpha || m_FileFormatVersion < Zone::FileFormatVersion::PrePreAlpha) {
|
|
|
|
|
BinaryIO::BinaryRead(file, scene.id);
|
|
|
|
|
lwoSceneID.SetSceneID(scene.id);
|
|
|
|
|
}
|
|
|
|
|
if (m_FileFormatVersion >= Zone::FileFormatVersion::LatePreAlpha) {
|
|
|
|
|
BinaryIO::BinaryRead(file, scene.sceneType);
|
|
|
|
|
lwoSceneID.SetLayerID(scene.sceneType);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
BinaryIO::ReadString<uint8_t>(file, scene.name, BinaryIO::ReadType::String);
|
2023-08-10 21:35:12 +00:00
|
|
|
|
}
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
if (m_FileFormatVersion == Zone::FileFormatVersion::LatePreAlpha) {
|
2023-08-10 21:35:12 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, scene.unknown1);
|
|
|
|
|
BinaryIO::BinaryRead(file, scene.unknown2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_FileFormatVersion >= Zone::FileFormatVersion::LatePreAlpha) {
|
|
|
|
|
BinaryIO::BinaryRead(file, scene.color_r);
|
|
|
|
|
BinaryIO::BinaryRead(file, scene.color_b);
|
|
|
|
|
BinaryIO::BinaryRead(file, scene.color_g);
|
|
|
|
|
}
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
|
|
m_Scenes.insert(std::make_pair(lwoSceneID, scene));
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
void Zone::LoadLUTriggers(std::string triggerFile, SceneRef& scene) {
|
|
|
|
|
auto file = Game::assetManager->GetFile((m_ZonePath + triggerFile).c_str());
|
2022-11-01 18:21:26 +00:00
|
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
|
std::stringstream data;
|
|
|
|
|
data << file.rdbuf();
|
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
data.seekg(0, std::ios::end);
|
|
|
|
|
int32_t size = data.tellg();
|
|
|
|
|
data.seekg(0, std::ios::beg);
|
2022-11-01 18:21:26 +00:00
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
if (size == 0) return;
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
tinyxml2::XMLDocument doc;
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
if (doc.Parse(data.str().c_str(), size) != tinyxml2::XML_SUCCESS) {
|
2023-10-21 23:31:55 +00:00
|
|
|
|
LOG("Failed to load LUTriggers from file %s", triggerFile.c_str());
|
2023-12-23 17:24:16 +00:00
|
|
|
|
return;
|
2021-12-05 17:54:36 +00:00
|
|
|
|
}
|
2022-07-25 02:26:51 +00:00
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
auto* triggers = doc.FirstChildElement("triggers");
|
|
|
|
|
if (!triggers) return;
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
auto* currentTrigger = triggers->FirstChildElement("trigger");
|
2021-12-05 17:54:36 +00:00
|
|
|
|
while (currentTrigger) {
|
|
|
|
|
LUTriggers::Trigger* newTrigger = new LUTriggers::Trigger();
|
|
|
|
|
currentTrigger->QueryAttribute("enabled", &newTrigger->enabled);
|
|
|
|
|
currentTrigger->QueryAttribute("id", &newTrigger->id);
|
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
auto* currentEvent = currentTrigger->FirstChildElement("event");
|
2021-12-05 17:54:36 +00:00
|
|
|
|
while (currentEvent) {
|
|
|
|
|
LUTriggers::Event* newEvent = new LUTriggers::Event();
|
2023-02-10 08:29:53 +00:00
|
|
|
|
newEvent->id = TriggerEventType::StringToTriggerEventType(currentEvent->Attribute("id"));
|
2023-12-23 17:24:16 +00:00
|
|
|
|
auto* currentCommand = currentEvent->FirstChildElement("command");
|
2021-12-05 17:54:36 +00:00
|
|
|
|
while (currentCommand) {
|
|
|
|
|
LUTriggers::Command* newCommand = new LUTriggers::Command();
|
2023-02-10 08:29:53 +00:00
|
|
|
|
newCommand->id = TriggerCommandType::StringToTriggerCommandType(currentCommand->Attribute("id"));
|
2021-12-05 17:54:36 +00:00
|
|
|
|
newCommand->target = currentCommand->Attribute("target");
|
2023-12-23 17:24:16 +00:00
|
|
|
|
if (currentCommand->Attribute("targetName")) {
|
2021-12-05 17:54:36 +00:00
|
|
|
|
newCommand->targetName = currentCommand->Attribute("targetName");
|
|
|
|
|
}
|
2023-12-24 20:45:27 +00:00
|
|
|
|
if (currentCommand->Attribute("args")) {
|
2021-12-05 17:54:36 +00:00
|
|
|
|
newCommand->args = currentCommand->Attribute("args");
|
|
|
|
|
}
|
2023-12-23 17:24:16 +00:00
|
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
|
newEvent->commands.push_back(newCommand);
|
|
|
|
|
currentCommand = currentCommand->NextSiblingElement("command");
|
|
|
|
|
}
|
|
|
|
|
newTrigger->events.push_back(newEvent);
|
|
|
|
|
currentEvent = currentEvent->NextSiblingElement("event");
|
|
|
|
|
}
|
|
|
|
|
currentTrigger = currentTrigger->NextSiblingElement("trigger");
|
2023-12-23 17:24:16 +00:00
|
|
|
|
scene.triggers.insert(std::make_pair(newTrigger->id, newTrigger));
|
2021-12-05 17:54:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LUTriggers::Trigger* Zone::GetTrigger(uint32_t sceneID, uint32_t triggerID) {
|
2023-12-23 17:24:16 +00:00
|
|
|
|
auto scene = m_Scenes.find(sceneID);
|
|
|
|
|
if (scene == m_Scenes.end()) return nullptr;
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
auto trigger = scene->second.triggers.find(triggerID);
|
|
|
|
|
if (trigger == scene->second.triggers.end()) return nullptr;
|
|
|
|
|
|
|
|
|
|
return trigger->second;
|
2021-12-05 17:54:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Path* Zone::GetPath(std::string name) const {
|
|
|
|
|
for (const auto& path : m_Paths) {
|
|
|
|
|
if (name == path.pathName) {
|
|
|
|
|
return &path;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-01 18:21:26 +00:00
|
|
|
|
void Zone::LoadSceneTransition(std::istream& file) {
|
2021-12-05 17:54:36 +00:00
|
|
|
|
SceneTransition sceneTrans;
|
2023-08-10 21:35:12 +00:00
|
|
|
|
if (m_FileFormatVersion < Zone::FileFormatVersion::Auramar) {
|
2023-12-23 17:24:16 +00:00
|
|
|
|
BinaryIO::ReadString<uint8_t>(file, sceneTrans.name, BinaryIO::ReadType::String);
|
2023-07-31 06:49:43 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, sceneTrans.width);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//BR<42>THER MAY I HAVE SOME L<><4C>PS?
|
2023-08-10 21:35:12 +00:00
|
|
|
|
uint8_t loops = (m_FileFormatVersion <= Zone::FileFormatVersion::LatePreAlpha || m_FileFormatVersion >= Zone::FileFormatVersion::Launch) ? 2 : 5;
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
sceneTrans.points.reserve(loops);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
for (uint8_t i = 0; i < loops; ++i) {
|
|
|
|
|
sceneTrans.points.push_back(LoadSceneTransitionInfo(file));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_SceneTransitions.push_back(sceneTrans);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-01 18:21:26 +00:00
|
|
|
|
SceneTransitionInfo Zone::LoadSceneTransitionInfo(std::istream& file) {
|
2021-12-05 17:54:36 +00:00
|
|
|
|
SceneTransitionInfo info;
|
|
|
|
|
BinaryIO::BinaryRead(file, info.sceneID);
|
|
|
|
|
BinaryIO::BinaryRead(file, info.position);
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-01 18:21:26 +00:00
|
|
|
|
void Zone::LoadPath(std::istream& file) {
|
2021-12-05 17:54:36 +00:00
|
|
|
|
Path path = Path();
|
|
|
|
|
|
|
|
|
|
BinaryIO::BinaryRead(file, path.pathVersion);
|
2022-11-12 14:44:03 +00:00
|
|
|
|
|
2023-12-23 17:24:16 +00:00
|
|
|
|
BinaryIO::ReadString<uint8_t>(file, path.pathName, BinaryIO::ReadType::WideString);
|
2022-11-12 14:44:03 +00:00
|
|
|
|
|
|
|
|
|
BinaryIO::BinaryRead(file, path.pathType);
|
|
|
|
|
BinaryIO::BinaryRead(file, path.flags);
|
|
|
|
|
BinaryIO::BinaryRead(file, path.pathBehavior);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
|
|
if (path.pathType == PathType::MovingPlatform) {
|
|
|
|
|
if (path.pathVersion >= 18) {
|
2022-11-12 14:44:03 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, path.movingPlatform.timeBasedMovement);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
} else if (path.pathVersion >= 13) {
|
2023-12-23 17:24:16 +00:00
|
|
|
|
BinaryIO::ReadString<uint8_t>(file, path.movingPlatform.platformTravelSound, BinaryIO::ReadType::WideString);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
}
|
|
|
|
|
} else if (path.pathType == PathType::Property) {
|
2022-11-12 14:44:03 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, path.property.pathType);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, path.property.price);
|
2023-08-10 21:35:12 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, path.property.rentalTime);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, path.property.associatedZone);
|
2022-10-24 05:54:21 +00:00
|
|
|
|
|
|
|
|
|
if (path.pathVersion >= 5) {
|
2023-12-23 17:24:16 +00:00
|
|
|
|
BinaryIO::ReadString<uint8_t>(file, path.property.displayName, BinaryIO::ReadType::WideString);
|
|
|
|
|
BinaryIO::ReadString<uint32_t>(file, path.property.displayDesc, BinaryIO::ReadType::WideString);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
}
|
2022-10-24 05:54:21 +00:00
|
|
|
|
|
2022-11-12 14:44:03 +00:00
|
|
|
|
if (path.pathVersion >= 6) BinaryIO::BinaryRead(file, path.property.type);
|
2022-10-24 05:54:21 +00:00
|
|
|
|
|
|
|
|
|
if (path.pathVersion >= 7) {
|
|
|
|
|
BinaryIO::BinaryRead(file, path.property.cloneLimit);
|
|
|
|
|
BinaryIO::BinaryRead(file, path.property.repMultiplier);
|
2023-08-10 21:35:12 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, path.property.rentalPeriod);
|
2022-10-24 05:54:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (path.pathVersion >= 8) {
|
|
|
|
|
BinaryIO::BinaryRead(file, path.property.achievementRequired);
|
2023-08-10 21:35:12 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, path.property.playerZoneCoords);
|
2022-10-24 05:54:21 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, path.property.maxBuildHeight);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
}
|
|
|
|
|
} else if (path.pathType == PathType::Camera) {
|
2023-12-23 17:24:16 +00:00
|
|
|
|
BinaryIO::ReadString<uint8_t>(file, path.camera.nextPath, BinaryIO::ReadType::WideString);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
if (path.pathVersion >= 14) {
|
2022-11-12 14:44:03 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, path.camera.rotatePlayer);
|
|
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
|
}
|
|
|
|
|
} else if (path.pathType == PathType::Spawner) {
|
|
|
|
|
BinaryIO::BinaryRead(file, path.spawner.spawnedLOT);
|
|
|
|
|
BinaryIO::BinaryRead(file, path.spawner.respawnTime);
|
|
|
|
|
BinaryIO::BinaryRead(file, path.spawner.maxToSpawn);
|
|
|
|
|
BinaryIO::BinaryRead(file, path.spawner.amountMaintained);
|
|
|
|
|
BinaryIO::BinaryRead(file, path.spawner.spawnerObjID);
|
|
|
|
|
BinaryIO::BinaryRead(file, path.spawner.spawnerNetActive);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read waypoints
|
|
|
|
|
|
|
|
|
|
BinaryIO::BinaryRead(file, path.waypointCount);
|
2023-12-23 17:24:16 +00:00
|
|
|
|
path.pathWaypoints.reserve(path.waypointCount);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
for (uint32_t i = 0; i < path.waypointCount; ++i) {
|
|
|
|
|
PathWaypoint waypoint = PathWaypoint();
|
|
|
|
|
|
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.position.x);
|
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.position.y);
|
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.position.z);
|
2022-07-25 02:26:51 +00:00
|
|
|
|
|
|
|
|
|
|
2022-11-12 14:44:03 +00:00
|
|
|
|
if (path.pathType == PathType::Spawner || path.pathType == PathType::MovingPlatform || path.pathType == PathType::Race || path.pathType == PathType::Camera || path.pathType == PathType::Rail) {
|
2021-12-05 17:54:36 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.rotation.w);
|
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.rotation.x);
|
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.rotation.y);
|
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.rotation.z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (path.pathType == PathType::MovingPlatform) {
|
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.movingPlatform.lockPlayer);
|
2024-02-27 14:40:49 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.speed);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.movingPlatform.wait);
|
|
|
|
|
if (path.pathVersion >= 13) {
|
2023-12-23 17:24:16 +00:00
|
|
|
|
BinaryIO::ReadString<uint8_t>(file, waypoint.movingPlatform.departSound, BinaryIO::ReadType::WideString);
|
|
|
|
|
BinaryIO::ReadString<uint8_t>(file, waypoint.movingPlatform.arriveSound, BinaryIO::ReadType::WideString);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
}
|
|
|
|
|
} else if (path.pathType == PathType::Camera) {
|
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.camera.time);
|
2022-11-12 14:44:03 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.camera.fov);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.camera.tension);
|
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.camera.continuity);
|
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.camera.bias);
|
|
|
|
|
} else if (path.pathType == PathType::Race) {
|
2022-11-12 14:44:03 +00:00
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.racing.isResetNode);
|
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.racing.isNonHorizontalCamera);
|
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.racing.planeWidth);
|
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.racing.planeHeight);
|
|
|
|
|
BinaryIO::BinaryRead(file, waypoint.racing.shortestDistanceToEnd);
|
2022-11-14 19:57:49 +00:00
|
|
|
|
} else if (path.pathType == PathType::Rail) {
|
2024-02-27 14:40:49 +00:00
|
|
|
|
if (path.pathVersion > 16) BinaryIO::BinaryRead(file, waypoint.speed);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// object LDF configs
|
|
|
|
|
if (path.pathType == PathType::Movement || path.pathType == PathType::Spawner || path.pathType == PathType::Rail) {
|
|
|
|
|
uint32_t count;
|
|
|
|
|
BinaryIO::BinaryRead(file, count);
|
|
|
|
|
for (uint32_t i = 0; i < count; ++i) {
|
|
|
|
|
std::string parameter;
|
2023-12-23 17:24:16 +00:00
|
|
|
|
BinaryIO::ReadString<uint8_t>(file, parameter, BinaryIO::ReadType::WideString);
|
|
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
|
std::string value;
|
2023-12-23 17:24:16 +00:00
|
|
|
|
BinaryIO::ReadString<uint8_t>(file, value, BinaryIO::ReadType::WideString);
|
2022-11-12 14:44:03 +00:00
|
|
|
|
|
|
|
|
|
LDFBaseData* ldfConfig = nullptr;
|
2022-11-14 19:57:49 +00:00
|
|
|
|
if (path.pathType == PathType::Movement || path.pathType == PathType::Rail) {
|
2023-08-16 20:53:13 +00:00
|
|
|
|
// cause NetDevil puts spaces in things that don't need spaces
|
2023-08-20 05:13:01 +00:00
|
|
|
|
parameter.erase(std::remove_if(parameter.begin(), parameter.end(), ::isspace), parameter.end());
|
2023-08-16 20:53:13 +00:00
|
|
|
|
auto waypointCommand = WaypointCommandType::StringToWaypointCommandType(parameter);
|
2023-08-20 05:13:01 +00:00
|
|
|
|
if (waypointCommand == eWaypointCommandType::DELAY) value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end());
|
|
|
|
|
if (waypointCommand != eWaypointCommandType::INVALID) waypoint.commands.push_back(WaypointCommand(waypointCommand, value));
|
2024-02-25 07:29:41 +00:00
|
|
|
|
else LOG("Tried to load invalid waypoint command '%s'", parameter.c_str());
|
2022-11-12 14:44:03 +00:00
|
|
|
|
} else {
|
|
|
|
|
ldfConfig = LDFBaseData::DataFromString(parameter + "=" + value);
|
2023-08-10 02:37:36 +00:00
|
|
|
|
if (ldfConfig) waypoint.config.push_back(ldfConfig);
|
2022-11-12 14:44:03 +00:00
|
|
|
|
}
|
2021-12-05 17:54:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-06 22:41:38 +00:00
|
|
|
|
// We verify the waypoint heights against the navmesh because in many movement paths,
|
2023-08-10 02:37:36 +00:00
|
|
|
|
// the waypoint is located near 0 height,
|
2023-08-06 22:41:38 +00:00
|
|
|
|
if (path.pathType == PathType::Movement) {
|
2024-01-19 21:12:05 +00:00
|
|
|
|
if (dpWorld::IsLoaded()) {
|
2023-08-06 23:06:12 +00:00
|
|
|
|
// 2000 should be large enough for every world.
|
2024-01-19 21:12:05 +00:00
|
|
|
|
waypoint.position.y = dpWorld::GetNavMesh()->GetHeightAtPoint(waypoint.position, 2000.0f);
|
2023-08-06 22:41:38 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-05 17:54:36 +00:00
|
|
|
|
path.pathWaypoints.push_back(waypoint);
|
|
|
|
|
}
|
|
|
|
|
m_Paths.push_back(path);
|
|
|
|
|
}
|