mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-06-25 08:04:22 +00:00
feat: raw terrain parsing for scene data
Replace old dNavigation/dTerrain raw parser with new Raw module in dZoneManager. Parse heightmaps, color maps, and scene maps from .raw files to determine which scene a position belongs to. Build scene adjacency graph from terrain data and scene transitions. Adds NiColor type, SceneColor lookup table, eSceneType enum, terrain mesh generation with OBJ export, and debug slash commands for scene visualization. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include "GeneralUtils.h"
|
||||
#include "BinaryIO.h"
|
||||
#include "LUTriggers.h"
|
||||
#include "dConfig.h"
|
||||
|
||||
#include "AssetManager.h"
|
||||
#include "CDClientManager.h"
|
||||
@@ -20,6 +21,7 @@
|
||||
#include "eTriggerEventType.h"
|
||||
#include "eWaypointCommandType.h"
|
||||
#include "dNavMesh.h"
|
||||
#include "Raw.h"
|
||||
|
||||
Zone::Zone(const LWOZONEID zoneID) :
|
||||
m_ZoneID(zoneID) {
|
||||
@@ -78,12 +80,51 @@ void Zone::LoadZoneIntoMemory() {
|
||||
LoadScene(file);
|
||||
}
|
||||
|
||||
//Read generic zone info:
|
||||
BinaryIO::ReadString<uint8_t>(file, m_ZonePath, BinaryIO::ReadType::String);
|
||||
// Zone boundary lines — skip past them for correct file positioning
|
||||
uint8_t numBoundaries = 0;
|
||||
BinaryIO::BinaryRead(file, numBoundaries);
|
||||
for (uint8_t i = 0; i < numBoundaries; ++i) {
|
||||
NiPoint3 normal, point, spawnLocation;
|
||||
uint32_t packed, destSceneID;
|
||||
BinaryIO::BinaryRead(file, normal);
|
||||
BinaryIO::BinaryRead(file, point);
|
||||
BinaryIO::BinaryRead(file, packed);
|
||||
BinaryIO::BinaryRead(file, destSceneID);
|
||||
BinaryIO::BinaryRead(file, spawnLocation);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
auto zoneFolderPath = m_ZoneFilePath.substr(0, m_ZoneFilePath.rfind('/') + 1);
|
||||
if (!Game::assetManager->HasFile(zoneFolderPath + m_ZoneRawPath)) {
|
||||
LOG("Failed to find %s", (zoneFolderPath + m_ZoneRawPath).c_str());
|
||||
throw std::runtime_error("Aborting Zone loading due to no Zone Raw File.");
|
||||
}
|
||||
|
||||
auto rawFile = Game::assetManager->GetFile(zoneFolderPath + m_ZoneRawPath);
|
||||
if (!Raw::ReadRaw(rawFile, m_Raw)) {
|
||||
LOG("Failed to parse %s", (zoneFolderPath + m_ZoneRawPath).c_str());
|
||||
throw std::runtime_error("Aborting Zone loading due to invalid Raw File.");
|
||||
}
|
||||
LOG("Loaded Raw Terrain with %u chunks", m_Raw.numChunks);
|
||||
|
||||
|
||||
// Optionally export terrain mesh to OBJ for debugging/visualization
|
||||
if (Game::config->GetValue("export_terrain_to_obj") == "1") {
|
||||
|
||||
// Generate terrain mesh
|
||||
Raw::GenerateTerrainMesh(m_Raw, m_TerrainMesh);
|
||||
LOG("Generated terrain mesh with %zu vertices and %zu triangles", m_TerrainMesh.vertices.size(), m_TerrainMesh.triangles.size() / 3);
|
||||
|
||||
// Write to OBJ
|
||||
std::string objFileName = "terrain_" + std::to_string(m_ZoneID.GetMapID()) + ".obj";
|
||||
if (Raw::WriteTerrainMeshToOBJ(m_TerrainMesh, objFileName)) {
|
||||
LOG("Exported terrain mesh to %s", objFileName.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (m_FileFormatVersion >= Zone::FileFormatVersion::PreAlpha) {
|
||||
BinaryIO::BinaryRead(file, m_NumberOfSceneTransitionsLoaded);
|
||||
for (uint32_t i = 0; i < m_NumberOfSceneTransitionsLoaded; ++i) {
|
||||
@@ -236,20 +277,23 @@ void Zone::LoadScene(std::istream& file) {
|
||||
}
|
||||
if (m_FileFormatVersion >= Zone::FileFormatVersion::LatePreAlpha) {
|
||||
BinaryIO::BinaryRead(file, scene.sceneType);
|
||||
lwoSceneID.SetLayerID(scene.sceneType);
|
||||
lwoSceneID.SetLayerID(static_cast<uint32_t>(scene.sceneType));
|
||||
|
||||
|
||||
BinaryIO::ReadString<uint8_t>(file, scene.name, BinaryIO::ReadType::String);
|
||||
}
|
||||
|
||||
if (m_FileFormatVersion == Zone::FileFormatVersion::LatePreAlpha) {
|
||||
BinaryIO::BinaryRead(file, scene.unknown1);
|
||||
BinaryIO::BinaryRead(file, scene.unknown2);
|
||||
BinaryIO::BinaryRead(file, scene.scenePosition);
|
||||
BinaryIO::BinaryRead(file, scene.sceneRadius);
|
||||
}
|
||||
|
||||
if (m_FileFormatVersion >= Zone::FileFormatVersion::LatePreAlpha) {
|
||||
BinaryIO::BinaryRead(file, scene.color_r);
|
||||
BinaryIO::BinaryRead(file, scene.color_b);
|
||||
BinaryIO::BinaryRead(file, scene.color_g);
|
||||
uint8_t r, b, g;
|
||||
BinaryIO::BinaryRead(file, r);
|
||||
BinaryIO::BinaryRead(file, b);
|
||||
BinaryIO::BinaryRead(file, g);
|
||||
scene.color = NiColor(r / 255.0f, g / 255.0f, b / 255.0f);
|
||||
}
|
||||
|
||||
m_Scenes[lwoSceneID] = std::move(scene);
|
||||
@@ -350,7 +394,10 @@ void Zone::LoadSceneTransition(std::istream& file) {
|
||||
|
||||
SceneTransitionInfo Zone::LoadSceneTransitionInfo(std::istream& file) {
|
||||
SceneTransitionInfo info;
|
||||
BinaryIO::BinaryRead(file, info.sceneID);
|
||||
uint32_t sceneID, layerID;
|
||||
BinaryIO::BinaryRead(file, sceneID);
|
||||
BinaryIO::BinaryRead(file, layerID);
|
||||
info.sceneID = LWOSCENEID(static_cast<int32_t>(sceneID), layerID);
|
||||
BinaryIO::BinaryRead(file, info.position);
|
||||
return info;
|
||||
}
|
||||
@@ -422,7 +469,6 @@ void Zone::LoadPath(std::istream& file) {
|
||||
BinaryIO::BinaryRead(file, waypoint.position.y);
|
||||
BinaryIO::BinaryRead(file, waypoint.position.z);
|
||||
|
||||
|
||||
if (path.pathType == PathType::Spawner || path.pathType == PathType::MovingPlatform || path.pathType == PathType::Race || path.pathType == PathType::Camera || path.pathType == PathType::Rail) {
|
||||
BinaryIO::BinaryRead(file, waypoint.rotation.w);
|
||||
BinaryIO::BinaryRead(file, waypoint.rotation.x);
|
||||
@@ -483,7 +529,7 @@ void Zone::LoadPath(std::istream& file) {
|
||||
}
|
||||
|
||||
// We verify the waypoint heights against the navmesh because in many movement paths,
|
||||
// the waypoint is located near 0 height,
|
||||
// the waypoint is located near 0 height,
|
||||
if (path.pathType == PathType::Movement) {
|
||||
if (dpWorld::IsLoaded()) {
|
||||
// 2000 should be large enough for every world.
|
||||
@@ -494,3 +540,9 @@ void Zone::LoadPath(std::istream& file) {
|
||||
}
|
||||
m_Paths.push_back(path);
|
||||
}
|
||||
|
||||
const SceneRef* Zone::GetScene(LWOSCENEID sceneID) const {
|
||||
auto it = m_Scenes.find(sceneID);
|
||||
if (it != m_Scenes.end()) return &it->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user