mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-17 18:22:50 +00:00
feat: scene ghosting, as the client streams a zone's scenes
The client keeps the scene under the player loaded, the scenes the zone file's transitions connect to it, and the global scene (Zone::StreamScenesAroundPosition 0x0108a3f0, TerrainManager::GetSceneAtPos 0x01069010, the connected scenes at 0x01066500; transitions naming a missing scene dropped as Zone::FixupInvalidTransitions 0x010842e0 does). - ZoneScenes (dCommon): the terrain's scene map lookup and the scene graph, shared by the world server and the dashboard. - Objects remember the scene they were placed in (spawners pass theirs on). - ghosting_scenes=1 (world config, off by default): players get the objects of their loaded scenes instead of the ones within the ghosting distances; objects from no scene go by the scene under them. Zones without a scene map keep distance ghosting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -19,8 +19,9 @@
|
||||
#include "dConfig.h"
|
||||
#include <ranges>
|
||||
|
||||
Level::Level(Zone* parentZone, const std::string& filepath) {
|
||||
Level::Level(Zone* parentZone, const std::string& filepath, int32_t sceneID) {
|
||||
m_ParentZone = parentZone;
|
||||
m_SceneID = sceneID;
|
||||
|
||||
auto stream = Game::assetManager->GetFile(filepath.c_str());
|
||||
|
||||
@@ -40,8 +41,9 @@ Level::Level(Zone* parentZone, const std::string& filepath) {
|
||||
LoadSceneObjects(levelFile.objects);
|
||||
}
|
||||
|
||||
void Level::MakeSpawner(const SceneObject& obj) {
|
||||
void Level::MakeSpawner(const SceneObject& obj, int32_t sceneID) {
|
||||
SpawnerInfo spawnInfo = SpawnerInfo();
|
||||
spawnInfo.scene = sceneID;
|
||||
SpawnerNode* node = new SpawnerNode();
|
||||
spawnInfo.templateID = obj.lot;
|
||||
spawnInfo.spawnerID = obj.id;
|
||||
@@ -162,7 +164,7 @@ void Level::LoadSceneObjects(const std::vector<SceneObject>& objects) {
|
||||
}
|
||||
|
||||
if (obj.lot == 176) { //Spawner
|
||||
MakeSpawner(obj);
|
||||
MakeSpawner(obj, m_SceneID);
|
||||
} else { //Regular object
|
||||
EntityInfo info;
|
||||
info.spawnerID = 0;
|
||||
@@ -172,6 +174,7 @@ void Level::LoadSceneObjects(const std::vector<SceneObject>& objects) {
|
||||
info.rot = obj.rotation;
|
||||
info.settings = obj.settings;
|
||||
info.scale = obj.scale;
|
||||
info.scene = m_SceneID;
|
||||
Game::entityManager->CreateEntity(info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,13 +15,15 @@ public:
|
||||
};
|
||||
|
||||
public:
|
||||
Level(Zone* parentZone, const std::string& filepath);
|
||||
|
||||
static void MakeSpawner(const SceneObject& obj);
|
||||
// sceneID: the scene id of the zone scene the file is (EntityInfo::scene of its objects)
|
||||
Level(Zone* parentZone, const std::string& filepath, int32_t sceneID = -1);
|
||||
|
||||
static void MakeSpawner(const SceneObject& obj, int32_t sceneID = -1);
|
||||
|
||||
std::map<uint32_t, Header> m_ChunkHeaders;
|
||||
private:
|
||||
Zone* m_ParentZone;
|
||||
int32_t m_SceneID = -1;
|
||||
|
||||
//private functions:
|
||||
void LoadSceneObjects(const std::vector<SceneObject>& objects);
|
||||
|
||||
@@ -24,6 +24,7 @@ Spawner::Spawner(const SpawnerInfo& info) {
|
||||
|
||||
m_EntityInfo.lot = m_Info.templateID;
|
||||
m_EntityInfo.scale = m_Info.templateScale;
|
||||
m_EntityInfo.scene = m_Info.scene;
|
||||
|
||||
m_Start = m_Info.noTimedSpawn;
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ struct SpawnerInfo {
|
||||
|
||||
bool emulated = false;
|
||||
LWOOBJID emulator = LWOOBJID_EMPTY;
|
||||
int32_t scene = -1; // the zone scene the spawner was placed in, passed to what it spawns (EntityInfo::scene)
|
||||
};
|
||||
|
||||
class Spawner {
|
||||
|
||||
@@ -66,6 +66,7 @@ void Zone::LoadZoneIntoMemory() {
|
||||
m_SpawnpointRotation = zoneFile.spawnpointRotation;
|
||||
|
||||
m_SceneCount = zoneFile.scenes.size();
|
||||
m_SceneGraph = ZoneScenes::SceneGraph(zoneFile.scenes, zoneFile.sceneTransitions);
|
||||
for (auto& scene : zoneFile.scenes) {
|
||||
LoadScene(std::move(scene));
|
||||
}
|
||||
@@ -198,7 +199,7 @@ uint32_t Zone::CalculateChecksum() const {
|
||||
void Zone::LoadLevelsIntoMemory() {
|
||||
for (auto& [sceneID, scene] : m_Scenes) {
|
||||
if (scene.level) continue;
|
||||
scene.level = std::make_unique<Level>(this, m_ZonePath + scene.filename);
|
||||
scene.level = std::make_unique<Level>(this, m_ZonePath + scene.filename, sceneID.GetSceneID());
|
||||
|
||||
if (scene.level->m_ChunkHeaders.empty()) continue;
|
||||
|
||||
@@ -207,6 +208,22 @@ void Zone::LoadLevelsIntoMemory() {
|
||||
}
|
||||
}
|
||||
|
||||
bool Zone::LoadSceneMap() {
|
||||
if (m_ZoneRawPath.empty()) return false;
|
||||
auto file = Game::assetManager->GetFile((m_ZonePath + m_ZoneRawPath).c_str());
|
||||
if (!file) {
|
||||
LOG("Could not open the terrain file %s for its scene map", (m_ZonePath + m_ZoneRawPath).c_str());
|
||||
return false;
|
||||
}
|
||||
Raw::Raw raw;
|
||||
if (!Raw::ReadRaw(file, raw)) {
|
||||
LOG("Could not read the terrain file %s for its scene map", (m_ZonePath + m_ZoneRawPath).c_str());
|
||||
return false;
|
||||
}
|
||||
m_SceneMap = ZoneScenes::SceneMap(raw);
|
||||
return !m_SceneMap.Empty();
|
||||
}
|
||||
|
||||
void Zone::AddRevision(LWOSCENEID sceneID, uint32_t revision) {
|
||||
if (m_MapRevisions.find(sceneID) == m_MapRevisions.end()) {
|
||||
m_MapRevisions.insert(std::make_pair(sceneID, revision));
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "dZMCommon.h"
|
||||
#include "LDFFormat.h"
|
||||
#include "ZoneFile.h"
|
||||
#include "ZoneScenes.h"
|
||||
#include "tinyxml2.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -48,6 +49,12 @@ public:
|
||||
const NiPoint3& GetSpawnPos() const { return m_Spawnpoint; }
|
||||
const NiQuaternion& GetSpawnRot() const { return m_SpawnpointRotation; }
|
||||
|
||||
// Which scenes the client keeps loaded where (ZoneScenes); the scene map is empty unless LoadSceneMap read it
|
||||
const ZoneScenes::SceneGraph& GetSceneGraph() const { return m_SceneGraph; }
|
||||
const ZoneScenes::SceneMap& GetSceneMap() const { return m_SceneMap; }
|
||||
// Reads the terrain file's scene map (for scene ghosting); false when the zone has none
|
||||
bool LoadSceneMap();
|
||||
|
||||
void SetSpawnPos(const NiPoint3& pos) { m_Spawnpoint = pos; }
|
||||
void SetSpawnRot(const NiQuaternion& rot) { m_SpawnpointRotation = rot; }
|
||||
|
||||
@@ -70,6 +77,8 @@ private:
|
||||
|
||||
std::map<LWOSCENEID, SceneRef> m_Scenes;
|
||||
std::vector<SceneTransition> m_SceneTransitions;
|
||||
ZoneScenes::SceneGraph m_SceneGraph;
|
||||
ZoneScenes::SceneMap m_SceneMap;
|
||||
|
||||
uint32_t m_PathDataLength;
|
||||
uint32_t m_PathChunkVersion;
|
||||
|
||||
Reference in New Issue
Block a user