chore: Speed up and cleanup level and zone loading; Add safer asset buffer reading (#1314)

* Remove std::couts littered throughout the base

* working

End of optimizations for now

going faster

* Remove extraneous compare function

std::less<LWOSCENEID> already does this in a map.

* gaming

* Update Zone.cpp

* dlu is moving to bitbucket again

* Update Level.cpp

---------

Co-authored-by: Jettford <mrjettbradford@gmail.com>
This commit is contained in:
David Markowitz
2023-12-23 09:24:16 -08:00
committed by GitHub
parent fcf4d6c6fa
commit e58218cfbc
20 changed files with 247 additions and 487 deletions

View File

@@ -20,7 +20,6 @@
Zone::Zone(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) :
m_ZoneID(mapID, instanceID, cloneID) {
m_NumberOfScenesLoaded = 0;
m_NumberOfObjectsLoaded = 0;
m_NumberOfSceneTransitionsLoaded = 0;
m_CheckSum = 0;
@@ -46,14 +45,13 @@ void Zone::LoadZoneIntoMemory() {
m_ZonePath = m_ZoneFilePath.substr(0, m_ZoneFilePath.rfind('/') + 1);
if (m_ZoneFilePath == "ERR") return;
AssetMemoryBuffer buffer = Game::assetManager->GetFileAsBuffer(m_ZoneFilePath.c_str());
auto file = Game::assetManager->GetFile(m_ZoneFilePath.c_str());
if (!buffer.m_Success) {
if (!file) {
LOG("Failed to load %s", m_ZoneFilePath.c_str());
throw std::runtime_error("Aborting Zone loading due to no Zone File.");
}
std::istream file(&buffer);
if (file) {
BinaryIO::BinaryRead(file, m_FileFormatVersion);
@@ -81,18 +79,10 @@ void Zone::LoadZoneIntoMemory() {
}
//Read generic zone info:
uint8_t stringLength;
BinaryIO::BinaryRead(file, stringLength);
m_ZonePath = BinaryIO::ReadString(file, stringLength);
BinaryIO::BinaryRead(file, stringLength);
m_ZoneRawPath = BinaryIO::ReadString(file, stringLength);
BinaryIO::BinaryRead(file, stringLength);
m_ZoneName = BinaryIO::ReadString(file, stringLength);
BinaryIO::BinaryRead(file, stringLength);
m_ZoneDesc = BinaryIO::ReadString(file, stringLength);
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);
if (m_FileFormatVersion >= Zone::FileFormatVersion::PreAlpha) {
BinaryIO::BinaryRead(file, m_NumberOfSceneTransitionsLoaded);
@@ -108,59 +98,57 @@ void Zone::LoadZoneIntoMemory() {
uint32_t pathCount;
BinaryIO::BinaryRead(file, pathCount);
m_Paths.reserve(pathCount);
for (uint32_t i = 0; i < pathCount; ++i) LoadPath(file);
for (Path path : m_Paths) {
if (path.pathType == PathType::Spawner) {
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;
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) {
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, ';');
info.groups.erase(info.groups.end() - 1);
} else if (data->GetKey() == u"grpNameQBShowBricks") {
if (data->GetValueAsString() == "") continue;
/*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();
}
}
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, ';');
info.groups.erase(info.groups.end() - 1);
} else if (data->GetKey() == u"grpNameQBShowBricks") {
if (data->GetValueAsString() == "") continue;
/*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();
}
info.nodes.push_back(node);
}
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);
info.nodes.push_back(node);
}
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);
}
}
} else {
LOG("Failed to open: %s", m_ZoneFilePath.c_str());
}
m_ZonePath = m_ZoneFilePath.substr(0, m_ZoneFilePath.rfind('/') + 1);
buffer.close();
}
std::string Zone::GetFilePathForZoneID() {
@@ -180,16 +168,16 @@ std::string Zone::GetFilePathForZoneID() {
uint32_t Zone::CalculateChecksum() {
uint32_t sum1 = 0xffff, sum2 = 0xffff;
for (std::map<LWOSCENEID, uint32_t>::const_iterator it = m_MapRevisions.cbegin(); it != m_MapRevisions.cend(); ++it) {
uint32_t sceneID = it->first.GetSceneID();
for (const auto& [scene, sceneRevision] : m_MapRevisions) {
uint32_t sceneID = scene.GetSceneID();
sum2 += sum1 += (sceneID >> 16);
sum2 += sum1 += (sceneID & 0xffff);
uint32_t layerID = it->first.GetLayerID();
uint32_t layerID = scene.GetLayerID();
sum2 += sum1 += (layerID >> 16);
sum2 += sum1 += (layerID & 0xffff);
uint32_t revision = it->second;
uint32_t revision = sceneRevision;
sum2 += sum1 += (revision >> 16);
sum2 += sum1 += (revision & 0xffff);
}
@@ -201,30 +189,20 @@ uint32_t Zone::CalculateChecksum() {
}
void Zone::LoadLevelsIntoMemory() {
for (std::map<LWOSCENEID, SceneRef>::iterator it = m_Scenes.begin(); it != m_Scenes.end(); ++it) {
if (it->second.level == nullptr) {
it->second.level = new Level(this, m_ZonePath + it->second.filename);
for (auto& [sceneID, scene] : m_Scenes) {
if (scene.level) continue;
scene.level = new Level(this, m_ZonePath + scene.filename);
if (it->second.level->m_ChunkHeaders.size() > 0) {
it->second.level->m_ChunkHeaders.begin()->second.lwoSceneID = it->first;
AddRevision(it->second.level->m_ChunkHeaders.begin()->second.lwoSceneID, it->second.level->m_ChunkHeaders.begin()->second.fileInfo->revision);
}
}
if (scene.level->m_ChunkHeaders.empty()) continue;
scene.level->m_ChunkHeaders.begin()->second.lwoSceneID = sceneID;
AddRevision(scene.level->m_ChunkHeaders.begin()->second.lwoSceneID, scene.level->m_ChunkHeaders.begin()->second.fileInfo.revision);
}
}
void Zone::AddRevision(LWOSCENEID sceneID, uint32_t revision) {
for (std::pair<LWOSCENEID, uint32_t> item : m_MapRevisions) {
if (item.first == sceneID) return;
}
m_MapRevisions[LWOSCENEID(sceneID)] = revision;
}
const void Zone::PrintAllGameObjects() {
for (std::pair<LWOSCENEID, SceneRef> scene : m_Scenes) {
LOG("In sceneID: %i", scene.first.GetSceneID());
scene.second.level->PrintAllObjects();
if (m_MapRevisions.find(sceneID) == m_MapRevisions.end()) {
m_MapRevisions.insert(std::make_pair(sceneID, revision));
}
}
@@ -233,17 +211,10 @@ void Zone::LoadScene(std::istream& file) {
scene.level = nullptr;
LWOSCENEID lwoSceneID(LWOZONEID_INVALID, 0);
uint8_t sceneFilenameLength;
BinaryIO::BinaryRead(file, sceneFilenameLength);
scene.filename = BinaryIO::ReadString(file, sceneFilenameLength);
BinaryIO::ReadString<uint8_t>(file, scene.filename, BinaryIO::ReadType::String);
std::string luTriggersPath = scene.filename.substr(0, scene.filename.size() - 4) + ".lutriggers";
std::vector<LUTriggers::Trigger*> triggers;
if(Game::assetManager->HasFile((m_ZonePath + luTriggersPath).c_str())) triggers = LoadLUTriggers(luTriggersPath, scene.id);
for (LUTriggers::Trigger* trigger : triggers) {
scene.triggers.insert({ trigger->id, trigger });
}
if (Game::assetManager->HasFile((m_ZonePath + luTriggersPath).c_str())) LoadLUTriggers(luTriggersPath, scene);
if (m_FileFormatVersion >= Zone::FileFormatVersion::LatePreAlpha || m_FileFormatVersion < Zone::FileFormatVersion::PrePreAlpha) {
BinaryIO::BinaryRead(file, scene.id);
@@ -253,12 +224,10 @@ void Zone::LoadScene(std::istream& file) {
BinaryIO::BinaryRead(file, scene.sceneType);
lwoSceneID.SetLayerID(scene.sceneType);
uint8_t sceneNameLength;
BinaryIO::BinaryRead(file, sceneNameLength);
scene.name = BinaryIO::ReadString(file, sceneNameLength);
BinaryIO::ReadString<uint8_t>(file, scene.name, BinaryIO::ReadType::String);
}
if (m_FileFormatVersion == Zone::FileFormatVersion::LatePreAlpha){
if (m_FileFormatVersion == Zone::FileFormatVersion::LatePreAlpha) {
BinaryIO::BinaryRead(file, scene.unknown1);
BinaryIO::BinaryRead(file, scene.unknown2);
}
@@ -270,61 +239,51 @@ void Zone::LoadScene(std::istream& file) {
}
m_Scenes.insert(std::make_pair(lwoSceneID, scene));
m_NumberOfScenesLoaded++;
}
std::vector<LUTriggers::Trigger*> Zone::LoadLUTriggers(std::string triggerFile, LWOSCENEID sceneID) {
std::vector<LUTriggers::Trigger*> lvlTriggers;
auto buffer = Game::assetManager->GetFileAsBuffer((m_ZonePath + triggerFile).c_str());
if (!buffer.m_Success) {
LOG("Failed to load %s from disk. Skipping loading triggers", (m_ZonePath + triggerFile).c_str());
return lvlTriggers;
}
std::istream file(&buffer);
void Zone::LoadLUTriggers(std::string triggerFile, SceneRef& scene) {
auto file = Game::assetManager->GetFile((m_ZonePath + triggerFile).c_str());
std::stringstream data;
data << file.rdbuf();
buffer.close();
data.seekg(0, std::ios::end);
int32_t size = data.tellg();
data.seekg(0, std::ios::beg);
if (data.str().size() == 0) return lvlTriggers;
if (size == 0) return;
tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
if (!doc) return lvlTriggers;
tinyxml2::XMLDocument doc;
if (doc->Parse(data.str().c_str(), data.str().size()) == 0) {
//LOG("Loaded LUTriggers from file %s!", triggerFile.c_str());
} else {
if (doc.Parse(data.str().c_str(), size) != tinyxml2::XML_SUCCESS) {
LOG("Failed to load LUTriggers from file %s", triggerFile.c_str());
return lvlTriggers;
return;
}
tinyxml2::XMLElement* triggers = doc->FirstChildElement("triggers");
if (!triggers) return lvlTriggers;
auto* triggers = doc.FirstChildElement("triggers");
if (!triggers) return;
auto currentTrigger = triggers->FirstChildElement("trigger");
auto* currentTrigger = triggers->FirstChildElement("trigger");
while (currentTrigger) {
LUTriggers::Trigger* newTrigger = new LUTriggers::Trigger();
currentTrigger->QueryAttribute("enabled", &newTrigger->enabled);
currentTrigger->QueryAttribute("id", &newTrigger->id);
auto currentEvent = currentTrigger->FirstChildElement("event");
auto* currentEvent = currentTrigger->FirstChildElement("event");
while (currentEvent) {
LUTriggers::Event* newEvent = new LUTriggers::Event();
newEvent->id = TriggerEventType::StringToTriggerEventType(currentEvent->Attribute("id"));
auto currentCommand = currentEvent->FirstChildElement("command");
auto* currentCommand = currentEvent->FirstChildElement("command");
while (currentCommand) {
LUTriggers::Command* newCommand = new LUTriggers::Command();
newCommand->id = TriggerCommandType::StringToTriggerCommandType(currentCommand->Attribute("id"));
newCommand->target = currentCommand->Attribute("target");
if (currentCommand->Attribute("targetName") != NULL) {
if (currentCommand->Attribute("targetName")) {
newCommand->targetName = currentCommand->Attribute("targetName");
}
if (currentCommand->Attribute("args") != NULL) {
} else if (currentCommand->Attribute("args")) {
newCommand->args = currentCommand->Attribute("args");
}
newEvent->commands.push_back(newCommand);
currentCommand = currentCommand->NextSiblingElement("command");
}
@@ -332,19 +291,18 @@ std::vector<LUTriggers::Trigger*> Zone::LoadLUTriggers(std::string triggerFile,
currentEvent = currentEvent->NextSiblingElement("event");
}
currentTrigger = currentTrigger->NextSiblingElement("trigger");
lvlTriggers.push_back(newTrigger);
scene.triggers.insert(std::make_pair(newTrigger->id, newTrigger));
}
delete doc;
return lvlTriggers;
}
LUTriggers::Trigger* Zone::GetTrigger(uint32_t sceneID, uint32_t triggerID) {
if (m_Scenes.find(sceneID) == m_Scenes.end()) return nullptr;
if (m_Scenes[sceneID].triggers.find(triggerID) == m_Scenes[sceneID].triggers.end()) return nullptr;
auto scene = m_Scenes.find(sceneID);
if (scene == m_Scenes.end()) return nullptr;
return m_Scenes[sceneID].triggers[triggerID];
auto trigger = scene->second.triggers.find(triggerID);
if (trigger == scene->second.triggers.end()) return nullptr;
return trigger->second;
}
const Path* Zone::GetPath(std::string name) const {
@@ -360,15 +318,14 @@ const Path* Zone::GetPath(std::string name) const {
void Zone::LoadSceneTransition(std::istream& file) {
SceneTransition sceneTrans;
if (m_FileFormatVersion < Zone::FileFormatVersion::Auramar) {
uint8_t length;
BinaryIO::BinaryRead(file, length);
sceneTrans.name = BinaryIO::ReadString(file, length);
BinaryIO::ReadString<uint8_t>(file, sceneTrans.name, BinaryIO::ReadType::String);
BinaryIO::BinaryRead(file, sceneTrans.width);
}
//BR<42>THER MAY I HAVE SOME L<><4C>PS?
uint8_t loops = (m_FileFormatVersion <= Zone::FileFormatVersion::LatePreAlpha || m_FileFormatVersion >= Zone::FileFormatVersion::Launch) ? 2 : 5;
sceneTrans.points.reserve(loops);
for (uint8_t i = 0; i < loops; ++i) {
sceneTrans.points.push_back(LoadSceneTransitionInfo(file));
}
@@ -388,13 +345,7 @@ void Zone::LoadPath(std::istream& file) {
BinaryIO::BinaryRead(file, path.pathVersion);
uint8_t stringLength;
BinaryIO::BinaryRead(file, stringLength);
for (uint8_t i = 0; i < stringLength; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
path.pathName.push_back(character);
}
BinaryIO::ReadString<uint8_t>(file, path.pathName, BinaryIO::ReadType::WideString);
BinaryIO::BinaryRead(file, path.pathType);
BinaryIO::BinaryRead(file, path.flags);
@@ -404,13 +355,7 @@ void Zone::LoadPath(std::istream& file) {
if (path.pathVersion >= 18) {
BinaryIO::BinaryRead(file, path.movingPlatform.timeBasedMovement);
} else if (path.pathVersion >= 13) {
uint8_t count;
BinaryIO::BinaryRead(file, count);
for (uint8_t i = 0; i < count; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
path.movingPlatform.platformTravelSound.push_back(character);
}
BinaryIO::ReadString<uint8_t>(file, path.movingPlatform.platformTravelSound, BinaryIO::ReadType::WideString);
}
} else if (path.pathType == PathType::Property) {
BinaryIO::BinaryRead(file, path.property.pathType);
@@ -419,20 +364,8 @@ void Zone::LoadPath(std::istream& file) {
BinaryIO::BinaryRead(file, path.property.associatedZone);
if (path.pathVersion >= 5) {
uint8_t count1;
BinaryIO::BinaryRead(file, count1);
for (uint8_t i = 0; i < count1; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
path.property.displayName.push_back(character);
}
uint32_t count2;
BinaryIO::BinaryRead(file, count2);
for (uint8_t i = 0; i < count2; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
path.property.displayDesc.push_back(character);
}
BinaryIO::ReadString<uint8_t>(file, path.property.displayName, BinaryIO::ReadType::WideString);
BinaryIO::ReadString<uint32_t>(file, path.property.displayDesc, BinaryIO::ReadType::WideString);
}
if (path.pathVersion >= 6) BinaryIO::BinaryRead(file, path.property.type);
@@ -449,13 +382,7 @@ void Zone::LoadPath(std::istream& file) {
BinaryIO::BinaryRead(file, path.property.maxBuildHeight);
}
} else if (path.pathType == PathType::Camera) {
uint8_t count;
BinaryIO::BinaryRead(file, count);
for (uint8_t i = 0; i < count; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
path.camera.nextPath.push_back(character);
}
BinaryIO::ReadString<uint8_t>(file, path.camera.nextPath, BinaryIO::ReadType::WideString);
if (path.pathVersion >= 14) {
BinaryIO::BinaryRead(file, path.camera.rotatePlayer);
@@ -472,7 +399,7 @@ void Zone::LoadPath(std::istream& file) {
// Read waypoints
BinaryIO::BinaryRead(file, path.waypointCount);
path.pathWaypoints.reserve(path.waypointCount);
for (uint32_t i = 0; i < path.waypointCount; ++i) {
PathWaypoint waypoint = PathWaypoint();
@@ -493,20 +420,8 @@ void Zone::LoadPath(std::istream& file) {
BinaryIO::BinaryRead(file, waypoint.movingPlatform.speed);
BinaryIO::BinaryRead(file, waypoint.movingPlatform.wait);
if (path.pathVersion >= 13) {
uint8_t count1;
BinaryIO::BinaryRead(file, count1);
for (uint8_t i = 0; i < count1; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
waypoint.movingPlatform.departSound.push_back(character);
}
uint8_t count2;
BinaryIO::BinaryRead(file, count2);
for (uint8_t i = 0; i < count2; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
waypoint.movingPlatform.arriveSound.push_back(character);
}
BinaryIO::ReadString<uint8_t>(file, waypoint.movingPlatform.departSound, BinaryIO::ReadType::WideString);
BinaryIO::ReadString<uint8_t>(file, waypoint.movingPlatform.arriveSound, BinaryIO::ReadType::WideString);
}
} else if (path.pathType == PathType::Camera) {
BinaryIO::BinaryRead(file, waypoint.camera.time);
@@ -529,22 +444,11 @@ void Zone::LoadPath(std::istream& file) {
uint32_t count;
BinaryIO::BinaryRead(file, count);
for (uint32_t i = 0; i < count; ++i) {
uint8_t count1;
std::string parameter;
BinaryIO::ReadString<uint8_t>(file, parameter, BinaryIO::ReadType::WideString);
std::string value;
BinaryIO::BinaryRead(file, count1);
for (uint8_t i = 0; i < count1; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
parameter.push_back(character);
}
uint8_t count2;
BinaryIO::BinaryRead(file, count2);
for (uint8_t i = 0; i < count2; ++i) {
uint16_t character;
BinaryIO::BinaryRead(file, character);
value.push_back(character);
}
BinaryIO::ReadString<uint8_t>(file, value, BinaryIO::ReadType::WideString);
LDFBaseData* ldfConfig = nullptr;
if (path.pathType == PathType::Movement || path.pathType == PathType::Rail) {