using AcDream.Core.World; using Xunit; namespace AcDream.Core.Tests.World; /// /// #192 (2026-07-09) — login into a non-Holtburg position sometimes showed /// stabs/scenery floating in the wrong place. Root cause: the streaming/render /// gate opened as soon as WorldSession reached InWorld /// (GameWindow.cs's old !IsLiveModeWaitingForLogin || liveInWorld /// condition) — but InWorld fires immediately after the login handshake /// (WorldSession.cs:608), BEFORE the player's own spawn CreateObject /// (which carries their real position) has even arrived over the network. Any /// landblock streamed in that window baked its world offset from /// _liveCenterX/Y's STARTUP placeholder (Holtburg, 0xA9B4) — a real /// position, not a "we don't know yet" sentinel — and that stale-baked geometry /// still got applied once it finished building, landing wherever the guess put /// it relative to whatever streamed in afterward with the corrected center. /// /// The fix isn't "pick a different placeholder" (any placeholder racing against /// the real answer reproduces the same bug) — it's gating on whether the real /// position is actually known yet, independent of session state. /// public class StreamingReadinessGateTests { [Fact] public void ShouldStream_OfflineMode_AlwaysTrue() { // Not live mode at all — no race is possible, no real position to wait for. Assert.True(StreamingReadinessGate.ShouldStream( liveModeEnabled: false, chaseModeEverEntered: false, liveInWorld: false, liveCenterKnown: false)); } [Fact] public void ShouldStream_ChaseModeEverEntered_AlwaysTrueRegardlessOfCenterKnown() { // Once chase mode has engaged even once, the gate latches open for the // rest of the session (matches the pre-existing IsLiveModeWaitingForLogin // latch semantics) — this is well past the login race window. Assert.True(StreamingReadinessGate.ShouldStream( liveModeEnabled: true, chaseModeEverEntered: true, liveInWorld: true, liveCenterKnown: false)); } [Fact] public void ShouldStream_LiveModeNotYetInWorld_False() { Assert.False(StreamingReadinessGate.ShouldStream( liveModeEnabled: true, chaseModeEverEntered: false, liveInWorld: false, liveCenterKnown: false)); } [Fact] public void ShouldStream_LiveModeInWorldButCenterUnknown_False() { // THE REGRESSION TEST. Under the old code, liveInWorld alone opened the // gate here — this is exactly the window where InWorld has fired but the // player's own spawn CreateObject (and hence the real center) hasn't // arrived yet. Must stay closed. Assert.False(StreamingReadinessGate.ShouldStream( liveModeEnabled: true, chaseModeEverEntered: false, liveInWorld: true, liveCenterKnown: false)); } [Fact] public void ShouldStream_LiveModeInWorldAndCenterKnown_True() { // Once the real position is confirmed, stream even though chase mode // hasn't engaged yet — this preserves the #106 gate-3 fix (auto-entry // waits for terrain under the spawn; terrain streaming must not wait for // auto-entry in turn, or the two deadlock each other). Assert.True(StreamingReadinessGate.ShouldStream( liveModeEnabled: true, chaseModeEverEntered: false, liveInWorld: true, liveCenterKnown: true)); } }