mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-12-12 11:08:27 +00:00
better algo for finding what scene we are in
This commit is contained in:
@@ -1951,35 +1951,65 @@ namespace DEVGMCommands {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the pre-generated terrain mesh
|
// Get the Raw terrain data
|
||||||
const auto& terrainMesh = zone->GetTerrainMesh();
|
const auto& raw = zone->GetZoneRaw();
|
||||||
if (terrainMesh.vertices.empty()) {
|
if (raw.chunks.empty()) {
|
||||||
ChatPackets::SendSystemMessage(sysAddr, u"Zone does not have valid terrain mesh data.");
|
ChatPackets::SendSystemMessage(sysAddr, u"Zone does not have valid terrain data.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawn at ALL vertices in the current scene without any filtering or spacing
|
// Spawn at all sceneMap points in the current scene
|
||||||
uint32_t spawnedCount = 0;
|
uint32_t spawnedCount = 0;
|
||||||
|
|
||||||
for (const auto& vertex : terrainMesh.vertices) {
|
for (const auto& chunk : raw.chunks) {
|
||||||
// Check if this vertex belongs to the current scene
|
if (chunk.sceneMap.empty() || chunk.colorMapResolution == 0 || chunk.heightMap.empty()) continue;
|
||||||
if (LWOSCENEID(vertex.sceneID) == currentSceneID) {
|
|
||||||
// Use the vertex position
|
|
||||||
NiPoint3 spawnPos = vertex.position;
|
|
||||||
|
|
||||||
EntityInfo info;
|
// Iterate through the heightmap (same as GenerateTerrainMesh)
|
||||||
info.lot = lot + currentSceneID.GetSceneID(); // to differentiate scenes
|
for (uint32_t i = 0; i < chunk.width; ++i) {
|
||||||
info.pos = spawnPos;
|
for (uint32_t j = 0; j < chunk.height; ++j) {
|
||||||
info.rot = QuatUtils::IDENTITY;
|
// Get height at this position
|
||||||
info.spawner = nullptr;
|
const uint32_t heightIndex = chunk.width * i + j;
|
||||||
info.spawnerID = entity->GetObjectID();
|
if (heightIndex >= chunk.heightMap.size()) continue;
|
||||||
info.spawnerNodeID = 0;
|
|
||||||
info.settings = { new LDFData<bool>(u"SpawnedFromSlashCommand", true) };
|
|
||||||
|
|
||||||
Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr);
|
const float y = chunk.heightMap[heightIndex];
|
||||||
if (newEntity != nullptr) {
|
|
||||||
Game::entityManager->ConstructEntity(newEntity);
|
// Map heightmap position to scene map position (same as GenerateTerrainMesh)
|
||||||
spawnedCount++;
|
const float sceneMapI = (static_cast<float>(i) / static_cast<float>(chunk.width - 1)) * static_cast<float>(chunk.colorMapResolution - 1);
|
||||||
|
const float sceneMapJ = (static_cast<float>(j) / static_cast<float>(chunk.height - 1)) * static_cast<float>(chunk.colorMapResolution - 1);
|
||||||
|
|
||||||
|
const uint32_t sceneI = std::min(static_cast<uint32_t>(sceneMapI), chunk.colorMapResolution - 1);
|
||||||
|
const uint32_t sceneJ = std::min(static_cast<uint32_t>(sceneMapJ), chunk.colorMapResolution - 1);
|
||||||
|
const uint32_t sceneIndex = sceneI * chunk.colorMapResolution + sceneJ;
|
||||||
|
|
||||||
|
uint8_t sceneID = 0;
|
||||||
|
if (sceneIndex < chunk.sceneMap.size()) {
|
||||||
|
sceneID = chunk.sceneMap[sceneIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this point belongs to the current scene
|
||||||
|
if (sceneID == currentSceneID.GetSceneID()) {
|
||||||
|
// Calculate world position (same as GenerateTerrainMesh)
|
||||||
|
const float worldX = (static_cast<float>(i) + (chunk.offsetWorldX / chunk.scaleFactor)) * chunk.scaleFactor;
|
||||||
|
const float worldY = (y / chunk.scaleFactor) * chunk.scaleFactor;
|
||||||
|
const float worldZ = (static_cast<float>(j) + (chunk.offsetWorldZ / chunk.scaleFactor)) * chunk.scaleFactor;
|
||||||
|
|
||||||
|
NiPoint3 spawnPos(worldX, worldY, worldZ);
|
||||||
|
|
||||||
|
EntityInfo info;
|
||||||
|
info.lot = lot + currentSceneID.GetSceneID(); // to differentiate scenes
|
||||||
|
info.pos = spawnPos;
|
||||||
|
info.rot = QuatUtils::IDENTITY;
|
||||||
|
info.spawner = nullptr;
|
||||||
|
info.spawnerID = entity->GetObjectID();
|
||||||
|
info.spawnerNodeID = 0;
|
||||||
|
info.settings = { new LDFData<bool>(u"SpawnedFromSlashCommand", true) };
|
||||||
|
|
||||||
|
Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr);
|
||||||
|
if (newEntity != nullptr) {
|
||||||
|
Game::entityManager->ConstructEntity(newEntity);
|
||||||
|
spawnedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2011,34 +2041,68 @@ namespace DEVGMCommands {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the pre-generated terrain mesh
|
// Get the Raw terrain data
|
||||||
const auto& terrainMesh = zone->GetTerrainMesh();
|
const auto& raw = zone->GetZoneRaw();
|
||||||
if (terrainMesh.vertices.empty()) {
|
if (raw.chunks.empty()) {
|
||||||
ChatPackets::SendSystemMessage(sysAddr, u"Zone does not have valid terrain mesh data.");
|
ChatPackets::SendSystemMessage(sysAddr, u"Zone does not have valid terrain data.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawn at ALL vertices without any filtering or spacing restrictions for maximum accuracy
|
// Spawn at all sceneMap points across all scenes
|
||||||
uint32_t spawnedCount = 0;
|
uint32_t spawnedCount = 0;
|
||||||
std::map<uint8_t, uint32_t> sceneSpawnCounts; // Track spawns per scene
|
std::map<uint8_t, uint32_t> sceneSpawnCounts; // Track spawns per scene
|
||||||
|
|
||||||
for (const auto& vertex : terrainMesh.vertices) {
|
for (const auto& chunk : raw.chunks) {
|
||||||
// Skip invalid scenes (scene ID 0 typically means no scene)
|
if (chunk.sceneMap.empty() || chunk.colorMapResolution == 0 || chunk.heightMap.empty()) continue;
|
||||||
if (vertex.sceneID == 0) continue;
|
|
||||||
EntityInfo info;
|
|
||||||
info.lot = lot + vertex.sceneID; // to show different scenes
|
|
||||||
info.pos = vertex.position;
|
|
||||||
info.rot = QuatUtils::IDENTITY;
|
|
||||||
info.spawner = nullptr;
|
|
||||||
info.spawnerID = entity->GetObjectID();
|
|
||||||
info.spawnerNodeID = 0;
|
|
||||||
info.settings = { new LDFData<bool>(u"SpawnedFromSlashCommand", true) };
|
|
||||||
|
|
||||||
Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr);
|
// Iterate through the heightmap (same as GenerateTerrainMesh)
|
||||||
if (newEntity != nullptr) {
|
for (uint32_t i = 0; i < chunk.width; ++i) {
|
||||||
Game::entityManager->ConstructEntity(newEntity);
|
for (uint32_t j = 0; j < chunk.height; ++j) {
|
||||||
spawnedCount++;
|
// Get height at this position
|
||||||
sceneSpawnCounts[vertex.sceneID]++;
|
const uint32_t heightIndex = chunk.width * i + j;
|
||||||
|
if (heightIndex >= chunk.heightMap.size()) continue;
|
||||||
|
|
||||||
|
const float y = chunk.heightMap[heightIndex];
|
||||||
|
|
||||||
|
// Map heightmap position to scene map position (same as GenerateTerrainMesh)
|
||||||
|
const float sceneMapI = (static_cast<float>(i) / static_cast<float>(chunk.width - 1)) * static_cast<float>(chunk.colorMapResolution - 1);
|
||||||
|
const float sceneMapJ = (static_cast<float>(j) / static_cast<float>(chunk.height - 1)) * static_cast<float>(chunk.colorMapResolution - 1);
|
||||||
|
|
||||||
|
const uint32_t sceneI = std::min(static_cast<uint32_t>(sceneMapI), chunk.colorMapResolution - 1);
|
||||||
|
const uint32_t sceneJ = std::min(static_cast<uint32_t>(sceneMapJ), chunk.colorMapResolution - 1);
|
||||||
|
const uint32_t sceneIndex = sceneI * chunk.colorMapResolution + sceneJ;
|
||||||
|
|
||||||
|
uint8_t sceneID = 0;
|
||||||
|
if (sceneIndex < chunk.sceneMap.size()) {
|
||||||
|
sceneID = chunk.sceneMap[sceneIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip invalid scenes (scene ID 0 typically means no scene)
|
||||||
|
if (sceneID == 0) continue;
|
||||||
|
|
||||||
|
// Calculate world position (same as GenerateTerrainMesh)
|
||||||
|
const float worldX = (static_cast<float>(i) + (chunk.offsetWorldX / chunk.scaleFactor)) * chunk.scaleFactor;
|
||||||
|
const float worldY = (y / chunk.scaleFactor) * chunk.scaleFactor;
|
||||||
|
const float worldZ = (static_cast<float>(j) + (chunk.offsetWorldZ / chunk.scaleFactor)) * chunk.scaleFactor;
|
||||||
|
|
||||||
|
NiPoint3 spawnPos(worldX, worldY, worldZ);
|
||||||
|
|
||||||
|
EntityInfo info;
|
||||||
|
info.lot = lot + sceneID; // to show different scenes
|
||||||
|
info.pos = spawnPos;
|
||||||
|
info.rot = QuatUtils::IDENTITY;
|
||||||
|
info.spawner = nullptr;
|
||||||
|
info.spawnerID = entity->GetObjectID();
|
||||||
|
info.spawnerNodeID = 0;
|
||||||
|
info.settings = { new LDFData<bool>(u"SpawnedFromSlashCommand", true) };
|
||||||
|
|
||||||
|
Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr);
|
||||||
|
if (newEntity != nullptr) {
|
||||||
|
Game::entityManager->ConstructEntity(newEntity);
|
||||||
|
spawnedCount++;
|
||||||
|
sceneSpawnCounts[sceneID]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -308,46 +308,49 @@ LWOSCENEID dZoneManager::GetSceneIDFromPosition(const NiPoint3& position) const
|
|||||||
|
|
||||||
const auto& terrainMesh = m_pZone->GetTerrainMesh();
|
const auto& terrainMesh = m_pZone->GetTerrainMesh();
|
||||||
|
|
||||||
// If mesh is empty, no scene data available
|
// If no chunks, no scene data available
|
||||||
if (terrainMesh.vertices.empty() || terrainMesh.triangles.empty()) {
|
if (raw.chunks.empty()) {
|
||||||
return LWOSCENEID_INVALID;
|
return LWOSCENEID_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the triangle containing this position (ignoring Y coordinate for scene lookup)
|
// Find the chunk containing this position
|
||||||
// We iterate through all triangles and find the one that contains the point in 2D (XZ plane)
|
// Reverse the world position calculation from GenerateTerrainMesh
|
||||||
for (size_t i = 0; i < terrainMesh.triangles.size(); i += 3) {
|
for (const auto& chunk : raw.chunks) {
|
||||||
const auto& v0 = terrainMesh.vertices[terrainMesh.triangles[i]];
|
if (chunk.sceneMap.empty()) continue;
|
||||||
const auto& v1 = terrainMesh.vertices[terrainMesh.triangles[i + 1]];
|
|
||||||
const auto& v2 = terrainMesh.vertices[terrainMesh.triangles[i + 2]];
|
|
||||||
|
|
||||||
// Check if position is inside this triangle using 2D (XZ) coordinates
|
// Reverse: worldX = (i + offsetWorldX/scaleFactor) * scaleFactor
|
||||||
// Using barycentric coordinates / cross product method
|
// Therefore: i = worldX/scaleFactor - offsetWorldX/scaleFactor
|
||||||
const float x = position.x;
|
const float heightI = position.x / chunk.scaleFactor - (chunk.offsetWorldX / chunk.scaleFactor);
|
||||||
const float z = position.z;
|
const float heightJ = position.z / chunk.scaleFactor - (chunk.offsetWorldZ / chunk.scaleFactor);
|
||||||
|
|
||||||
const float x0 = v0.position.x;
|
// Check if position is within this chunk's heightmap bounds
|
||||||
const float z0 = v0.position.z;
|
if (heightI >= 0.0f && heightI < chunk.width &&
|
||||||
const float x1 = v1.position.x;
|
heightJ >= 0.0f && heightJ < chunk.height) {
|
||||||
const float z1 = v1.position.z;
|
|
||||||
const float x2 = v2.position.x;
|
|
||||||
const float z2 = v2.position.z;
|
|
||||||
|
|
||||||
// Calculate barycentric coordinates
|
// Map heightmap position to scene map position (same as GenerateTerrainMesh)
|
||||||
const float denom = (z1 - z2) * (x0 - x2) + (x2 - x1) * (z0 - z2);
|
const float sceneMapI = (heightI / (chunk.width - 1)) * (chunk.colorMapResolution - 1);
|
||||||
if (std::abs(denom) < 0.0001f) continue; // Degenerate triangle
|
const float sceneMapJ = (heightJ / (chunk.height - 1)) * (chunk.colorMapResolution - 1);
|
||||||
|
|
||||||
const float a = ((z1 - z2) * (x - x2) + (x2 - x1) * (z - z2)) / denom;
|
const uint32_t sceneI = std::min(static_cast<uint32_t>(sceneMapI), chunk.colorMapResolution - 1);
|
||||||
const float b = ((z2 - z0) * (x - x2) + (x0 - x2) * (z - z2)) / denom;
|
const uint32_t sceneJ = std::min(static_cast<uint32_t>(sceneMapJ), chunk.colorMapResolution - 1);
|
||||||
const float c = 1.0f - a - b;
|
|
||||||
|
|
||||||
// Point is inside triangle if all barycentric coordinates are non-negative
|
// Scene map uses the same indexing pattern as heightmap: row * width + col
|
||||||
if (a >= 0.0f && b >= 0.0f && c >= 0.0f) {
|
const uint32_t sceneIndex = sceneI * chunk.colorMapResolution + sceneJ;
|
||||||
// Return the scene ID from the first vertex (all vertices in a triangle should have the same scene ID)
|
|
||||||
return LWOSCENEID(v0.sceneID);
|
// Bounds check
|
||||||
|
if (sceneIndex >= chunk.sceneMap.size()) {
|
||||||
|
return LWOSCENEID_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get scene ID from sceneMap
|
||||||
|
const uint8_t sceneID = chunk.sceneMap[sceneIndex];
|
||||||
|
|
||||||
|
// Return the scene ID
|
||||||
|
return LWOSCENEID(sceneID, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Position not found in any triangle
|
// Position not found in any chunk
|
||||||
return LWOSCENEID_INVALID;
|
return LWOSCENEID_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user