mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
fix(ghosting): scene ghosting follows the client's scene streaming
Re-checked against client 1.10.64: Zone::Run calls StreamScenesAroundPosition with the ghost reference position, and with the controlled object's own position only when the two differ (ghost reference override on). The client loads the scene under the reference point and the global scene; with the override on it also loads the scene under the player and its connected scenes. The cell lookup (floor(v + 0.5), x cell * resolution + z cell), the transition pairs and FixupInvalidTransitions match what ZoneScenes does. Scene ghosting now adds the scenes around the player while the ghost reference is overridden (cinematics), and the comments say the server keeps each scene's neighbours too (a superset, so objects across a transition exist before the player crosses it). Check in game (with ghosting_scenes=1): walk across scene transitions in Avant Gardens and Gnarled Forest; objects on both sides show up and nothing pops in at the line. Play a cinematic that moves the camera away (e.g. a mission cinematic) and objects around the player stay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -507,6 +507,17 @@ void EntityManager::UpdateGhosting() {
|
||||
m_PlayersToUpdateGhosting.clear();
|
||||
}
|
||||
|
||||
namespace {
|
||||
// The scenes a player gets the objects of (ZoneScenes::SceneGraph::Loaded): around the ghost reference point, and
|
||||
// around the player too while the reference is overridden
|
||||
std::set<uint32_t> ClientScenes(const Zone& zone, const GhostComponent& ghost) {
|
||||
const auto& reference = ghost.GetGhostReferencePoint();
|
||||
const auto& position = ghost.GetOriginGhostReferencePoint();
|
||||
const auto& map = zone.GetSceneMap();
|
||||
return zone.GetSceneGraph().Loaded(map.SceneAt(reference.x, reference.z), map.SceneAt(position.x, position.z), ghost.GetGhostOverride());
|
||||
}
|
||||
}
|
||||
|
||||
void EntityManager::UpdateGhosting(Entity* player) {
|
||||
if (!player) return;
|
||||
|
||||
@@ -518,7 +529,7 @@ void EntityManager::UpdateGhosting(Entity* player) {
|
||||
const auto& referencePoint = ghostComponent->GetGhostReferencePoint();
|
||||
const auto isOverride = ghostComponent->GetGhostOverride();
|
||||
const auto* zone = m_SceneGhosting ? Game::zoneManager->GetZone() : nullptr;
|
||||
const auto loaded = zone ? zone->GetSceneGraph().Loaded(zone->GetSceneMap().SceneAt(referencePoint.x, referencePoint.z)) : std::set<uint32_t>{};
|
||||
const auto loaded = zone ? ClientScenes(*zone, *ghostComponent) : std::set<uint32_t>{};
|
||||
|
||||
for (auto* entity : m_EntitiesToGhost) {
|
||||
const auto& entityPoint = entity->GetPosition();
|
||||
@@ -588,7 +599,7 @@ void EntityManager::CheckGhosting(Entity* entity) {
|
||||
const auto observed = ghostComponent->IsObserved(id);
|
||||
bool tooFar = false, nearEnough = false;
|
||||
if (zone) {
|
||||
const auto loaded = zone->GetSceneGraph().Loaded(zone->GetSceneMap().SceneAt(entityPoint.x, entityPoint.z));
|
||||
const auto loaded = ClientScenes(*zone, *ghostComponent);
|
||||
nearEnough = ZoneScenes::InLoadedScene(entity->GetScene(), entityScene, loaded);
|
||||
tooFar = !nearEnough;
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user