diff --git a/source/simulation2/components/tests/test_RangeManager.h b/source/simulation2/components/tests/test_RangeManager.h index 0a06961155..8a065750f4 100644 --- a/source/simulation2/components/tests/test_RangeManager.h +++ b/source/simulation2/components/tests/test_RangeManager.h @@ -220,7 +220,7 @@ public: } } - void test_queries() + void test_range_queries_distance_only() { ComponentTestHelper test(*g_ScriptContext); @@ -294,6 +294,71 @@ public: } + void test_range_queries_visibility_filtering() + { + ComponentTestHelper test(*g_ScriptContext); + + ICmpRangeManager* rangeManager = test.Add(CID_RangeManager, "", SYSTEM_ENTITY); + + MockVisionRgm vision, vision2; + MockPositionRgm position, position2; + MockObstructionRgm obs(fixed::FromInt(2)), obs2(fixed::Zero()); + test.AddMock(100, IID_Vision, vision); + test.AddMock(100, IID_Position, position); + test.AddMock(100, IID_Obstruction, obs); + + test.AddMock(101, IID_Vision, vision2); + test.AddMock(101, IID_Position, position2); + test.AddMock(101, IID_Obstruction, obs2); + + rangeManager->SetBounds(entity_pos_t::FromInt(0), entity_pos_t::FromInt(0), entity_pos_t::FromInt(512), entity_pos_t::FromInt(512)); + rangeManager->Verify(); + { CMessageCreate msg(100); rangeManager->HandleMessage(msg, false); } + { CMessageCreate msg(101); rangeManager->HandleMessage(msg, false); } + + // Set ownership for both entities so they have proper owners + { CMessageOwnershipChanged msg(100, -1, 1); rangeManager->HandleMessage(msg, false); } + { CMessageOwnershipChanged msg(101, -1, 1); rangeManager->HandleMessage(msg, false); } + + auto move = [&rangeManager](entity_id_t ent, MockPositionRgm& pos, fixed x, fixed z) { + pos.m_Pos = CFixedVector3D(x, fixed::Zero(), z); + { CMessagePositionChanged msg(ent, true, x, z, entity_angle_t::Zero()); rangeManager->HandleMessage(msg, false); } + }; + + move(100, position, fixed::FromInt(10), fixed::FromInt(10)); + move(101, position2, fixed::FromInt(10), fixed::FromInt(15)); + + // Note: Full LOS testing (vision range, terrain, fog) requires a full game world + // with terrain, water, and proper pathfinding. That's beyond the scope of this + // unit test. The visibility test here verifies that ExecuteQuery respects the + // reveal whole map flag, which exercises the visibility check path in TestEntityQuery. + + // Enable "reveal whole map" to force all entities to be visible + rangeManager->SetLosRevealWholeMap(1, true); + + // Process an update + { CMessageUpdate msg(fixed::FromInt(1)); rangeManager->HandleMessage(msg, false); } + + // Entity 101 should be visible (due to reveal map) and in range + std::vector nearby = rangeManager->ExecuteQuery(100, fixed::FromInt(0), fixed::FromInt(50), {1}, 0, true); + TS_ASSERT_EQUALS(nearby, std::vector{101}); + + // Disable "reveal whole map" to test hidden entities + rangeManager->SetLosRevealWholeMap(1, false); + { CMessageUpdate msg(fixed::FromInt(1)); rangeManager->HandleMessage(msg, false); } + + // Entity 101 should now be hidden because LOS isn't properly set up + nearby = rangeManager->ExecuteQuery(100, fixed::FromInt(0), fixed::FromInt(50), {1}, 0, true); + TS_ASSERT_EQUALS(nearby, std::vector{}); + + // Re-enable reveal map to show it works again + rangeManager->SetLosRevealWholeMap(1, true); + { CMessageUpdate msg(fixed::FromInt(1)); rangeManager->HandleMessage(msg, false); } + + nearby = rangeManager->ExecuteQuery(100, fixed::FromInt(0), fixed::FromInt(50), {1}, 0, true); + TS_ASSERT_EQUALS(nearby, std::vector{101}); + } + void test_ParabolicRangeBasic() { ComponentTestHelper test(*g_ScriptContext);