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:
Aaron Kimbrell
2026-09-29 02:02:47 -05:00
parent cde8ea4979
commit 8d6fe4b116
4 changed files with 45 additions and 9 deletions

View File

@@ -63,6 +63,15 @@ TEST(ZoneScenesTests, LoadsTheConnectedScenes) {
EXPECT_TRUE(graph.Neighbours(9).empty());
}
TEST(ZoneScenesTests, AddsTheScenesAroundThePlayerWhileTheReferenceIsOverridden) {
const ZoneScenes::SceneGraph graph(Scenes({ 0, 1, 2, 3, 4 }), { Transition(1, 2), Transition(3, 4) });
// Not overridden: only the reference point's scenes, wherever the player is
EXPECT_EQ(graph.Loaded(1, 3, false), (std::set<uint32_t>{ 0, 1, 2 }));
// Overridden (a cinematic moved it): the client also loads the scene under the player and its neighbours
EXPECT_EQ(graph.Loaded(1, 3, true), (std::set<uint32_t>{ 0, 1, 2, 3, 4 }));
EXPECT_EQ(graph.Loaded(1, 1, true), graph.Loaded(1));
}
TEST(ZoneScenesTests, SendsSceneMapsAsRuns) {
std::vector<uint8_t> cells(300, 4);
cells[0] = 1;