Changeset View
Changeset View
Standalone View
Standalone View
source/simulation2/components/tests/test_RangeManager.h
Show All 11 Lines | |||||
* GNU General Public License for more details. | * GNU General Public License for more details. | ||||
* | * | ||||
* You should have received a copy of the GNU General Public License | * You should have received a copy of the GNU General Public License | ||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | ||||
*/ | */ | ||||
#include "simulation2/system/ComponentTest.h" | #include "simulation2/system/ComponentTest.h" | ||||
#include "simulation2/components/ICmpRangeManager.h" | #include "simulation2/components/ICmpRangeManager.h" | ||||
#include "simulation2/components/ICmpWaterManager.h" | |||||
#include "simulation2/components/ICmpPosition.h" | #include "simulation2/components/ICmpPosition.h" | ||||
#include "simulation2/components/ICmpVision.h" | #include "simulation2/components/ICmpVision.h" | ||||
#include "simulation2/components/ICmpFootprint.h" | |||||
#include "simulation2/components/ICmpOwnership.h" | |||||
#include "graphics/Terrain.h" | |||||
#include "simulation2/helpers/Geometry.h" | |||||
#include <boost/random/mersenne_twister.hpp> | #include <boost/random/mersenne_twister.hpp> | ||||
#include <boost/random/uniform_real_distribution.hpp> | #include <boost/random/uniform_real_distribution.hpp> | ||||
class MockVision : public ICmpVision | class MockOwnership : public ICmpOwnership | ||||
{ | { | ||||
private: | |||||
player_id_t m_Owner; | |||||
public: | public: | ||||
DEFAULT_MOCK_COMPONENT() | virtual int GetComponentTypeId() const { return IID_Ownership; } | ||||
virtual void Init(const CParamNode& UNUSED(paramNode)) { } | |||||
virtual void Deinit() {} | |||||
virtual void Serialize(ISerializer& UNUSED(serialize)) { } | |||||
virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) | |||||
{ Init(paramNode);} | |||||
virtual void SetOwner(player_id_t owner) { m_Owner = owner; } | |||||
virtual player_id_t GetOwner() const { return m_Owner; }; | |||||
virtual void SetOwnerQuiet(player_id_t owner) { m_Owner = owner; } | |||||
}; | |||||
virtual entity_pos_t GetRange() const { return entity_pos_t::FromInt(66); } | class MockVision : public ICmpVision | ||||
{ | |||||
private: | |||||
entity_pos_t m_Range; | |||||
public: | |||||
virtual int GetComponentTypeId() const { return IID_Vision; } | |||||
virtual void Init(const CParamNode& UNUSED(paramNode)) { } | |||||
virtual void Deinit() {} | |||||
virtual void Serialize(ISerializer& UNUSED(serialize)) { } | |||||
virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) | |||||
{ Init(paramNode); } | |||||
virtual void SetRange(entity_pos_t range) { m_Range = range; } | |||||
virtual entity_pos_t GetRange() const { return m_Range; } | |||||
virtual bool GetRevealShore() const { return false; } | virtual bool GetRevealShore() const { return false; } | ||||
}; | }; | ||||
class MockPosition : public ICmpPosition | class MockPosition : public ICmpPosition | ||||
{ | { | ||||
private: | |||||
CFixedVector2D m_Pos2d; | |||||
public: | public: | ||||
DEFAULT_MOCK_COMPONENT() | |||||
virtual int GetComponentTypeId() const { return IID_Position; } | |||||
virtual void Init(const CParamNode& UNUSED(paramNode)) { } | |||||
virtual void Deinit() {} | |||||
virtual void Serialize(ISerializer& UNUSED(serialize)) { } | |||||
virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) | |||||
{ Init(paramNode); } | |||||
virtual void SetPosition(entity_pos_t x, entity_pos_t y) { m_Pos2d.X = x; m_Pos2d.Y = y;} | |||||
virtual void SetTurretParent(entity_id_t UNUSED(id), const CFixedVector3D& UNUSED(pos)) {} | virtual void SetTurretParent(entity_id_t UNUSED(id), const CFixedVector3D& UNUSED(pos)) {} | ||||
virtual entity_id_t GetTurretParent() const {return INVALID_ENTITY;} | virtual entity_id_t GetTurretParent() const {return INVALID_ENTITY;} | ||||
virtual void UpdateTurretPosition() {} | virtual void UpdateTurretPosition() {} | ||||
virtual std::set<entity_id_t>* GetTurrets() { return NULL; } | virtual std::set<entity_id_t>* GetTurrets() { return NULL; } | ||||
virtual bool IsInWorld() const { return true; } | virtual bool IsInWorld() const { return true; } | ||||
virtual void MoveOutOfWorld() { } | virtual void MoveOutOfWorld() { } | ||||
virtual void MoveTo(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) { } | virtual void MoveTo(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) { } | ||||
virtual void MoveAndTurnTo(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z), entity_angle_t UNUSED(a)) { } | virtual void MoveAndTurnTo(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z), entity_angle_t UNUSED(a)) { } | ||||
virtual void JumpTo(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) { } | virtual void JumpTo(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) { } | ||||
virtual void SetHeightOffset(entity_pos_t UNUSED(dy)) { } | virtual void SetHeightOffset(entity_pos_t UNUSED(dy)) { } | ||||
virtual entity_pos_t GetHeightOffset() const { return entity_pos_t::Zero(); } | virtual entity_pos_t GetHeightOffset() const { return entity_pos_t::Zero(); } | ||||
virtual void SetHeightFixed(entity_pos_t UNUSED(y)) { } | virtual void SetHeightFixed(entity_pos_t UNUSED(y)) { } | ||||
virtual entity_pos_t GetHeightFixed() const { return entity_pos_t::Zero(); } | virtual entity_pos_t GetHeightFixed() const { return entity_pos_t::Zero(); } | ||||
virtual bool IsHeightRelative() const { return true; } | virtual bool IsHeightRelative() const { return true; } | ||||
virtual void SetHeightRelative(bool UNUSED(relative)) { } | virtual void SetHeightRelative(bool UNUSED(relative)) { } | ||||
virtual bool CanFloat() const { return false; } | virtual bool CanFloat() const { return false; } | ||||
virtual void SetFloating(bool UNUSED(flag)) { } | virtual void SetFloating(bool UNUSED(flag)) { } | ||||
virtual void SetActorFloating(bool UNUSED(flag)) { } | virtual void SetActorFloating(bool UNUSED(flag)) { } | ||||
virtual void SetConstructionProgress(fixed UNUSED(progress)) { } | virtual void SetConstructionProgress(fixed UNUSED(progress)) { } | ||||
virtual CFixedVector3D GetPosition() const { return CFixedVector3D(); } | virtual CFixedVector3D GetPosition() const { return CFixedVector3D(); } | ||||
virtual CFixedVector2D GetPosition2D() const { return CFixedVector2D(); } | virtual CFixedVector2D GetPosition2D() const { return m_Pos2d; } | ||||
virtual CFixedVector3D GetPreviousPosition() const { return CFixedVector3D(); } | virtual CFixedVector3D GetPreviousPosition() const { return CFixedVector3D(); } | ||||
virtual CFixedVector2D GetPreviousPosition2D() const { return CFixedVector2D(); } | virtual CFixedVector2D GetPreviousPosition2D() const { return CFixedVector2D(); } | ||||
virtual void TurnTo(entity_angle_t UNUSED(y)) { } | virtual void TurnTo(entity_angle_t UNUSED(y)) { } | ||||
virtual void SetYRotation(entity_angle_t UNUSED(y)) { } | virtual void SetYRotation(entity_angle_t UNUSED(y)) { } | ||||
virtual void SetXZRotation(entity_angle_t UNUSED(x), entity_angle_t UNUSED(z)) { } | virtual void SetXZRotation(entity_angle_t UNUSED(x), entity_angle_t UNUSED(z)) { } | ||||
virtual CFixedVector3D GetRotation() const { return CFixedVector3D(); } | virtual CFixedVector3D GetRotation() const { return CFixedVector3D(); } | ||||
virtual fixed GetDistanceTravelled() const { return fixed::Zero(); } | virtual fixed GetDistanceTravelled() const { return fixed::Zero(); } | ||||
virtual void GetInterpolatedPosition2D(float UNUSED(frameOffset), float& x, float& z, float& rotY) const { x = z = rotY = 0; } | virtual void GetInterpolatedPosition2D(float UNUSED(frameOffset), float& x, float& z, float& rotY) const { x = z = rotY = 0; } | ||||
virtual CMatrix3D GetInterpolatedTransform(float UNUSED(frameOffset)) const { return CMatrix3D(); } | virtual CMatrix3D GetInterpolatedTransform(float UNUSED(frameOffset)) const { return CMatrix3D(); } | ||||
}; | }; | ||||
class MockWater : public ICmpWaterManager | |||||
{ | |||||
public: | |||||
DEFAULT_MOCK_COMPONENT() | |||||
virtual entity_pos_t GetWaterLevel(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) const | |||||
{ | |||||
return entity_pos_t::FromInt(0); | |||||
} | |||||
virtual float GetExactWaterLevel(float UNUSED(x), float UNUSED(z)) const | |||||
{ | |||||
return 0.f; | |||||
} | |||||
virtual void RecomputeWaterData() | |||||
{ | |||||
} | |||||
virtual void SetWaterLevel(entity_pos_t UNUSED(h)) | |||||
{ | |||||
} | |||||
}; | |||||
class MockFullTerrain : public ICmpTerrain | |||||
{ | |||||
private: | |||||
CTerrain* m_Terrain; | |||||
public: | |||||
virtual int GetComponentTypeId() const | |||||
{ | |||||
return -1; | |||||
} | |||||
static void ClassInit(CComponentManager& UNUSED(componentManager)) | |||||
{ | |||||
} | |||||
virtual bool IsLoaded() const | |||||
{ | |||||
return m_Terrain->GetVerticesPerSide() != 0; | |||||
} | |||||
virtual void Init(const CParamNode& UNUSED(paramNode)) | |||||
{ | |||||
} | |||||
virtual void Deinit() | |||||
{ | |||||
m_Terrain = nullptr; | |||||
} | |||||
virtual void Serialize(ISerializer& UNUSED(serialize)) | |||||
{ | |||||
} | |||||
virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) | |||||
{ | |||||
Init(paramNode); | |||||
} | |||||
virtual CFixedVector3D CalcNormal(entity_pos_t x, entity_pos_t z) const | |||||
{ | |||||
CFixedVector3D normal; | |||||
m_Terrain->CalcNormalFixed((x / static_cast<int>(TERRAIN_TILE_SIZE)).ToInt_RoundToZero(), (z / static_cast<int>(TERRAIN_TILE_SIZE)).ToInt_RoundToZero(), normal); | |||||
return normal; | |||||
} | |||||
virtual CVector3D CalcExactNormal(float x, float z) const | |||||
{ | |||||
return m_Terrain->CalcExactNormal(x, z); | |||||
} | |||||
virtual entity_pos_t GetGroundLevel(entity_pos_t x, entity_pos_t z) const | |||||
{ | |||||
return m_Terrain->GetExactGroundLevelFixed(x, z); | |||||
} | |||||
virtual float GetExactGroundLevel(float x, float z) const | |||||
{ | |||||
return m_Terrain->GetExactGroundLevel(x, z); | |||||
} | |||||
virtual u16 GetTilesPerSide() const | |||||
{ | |||||
ssize_t tiles = m_Terrain->GetTilesPerSide(); | |||||
if (tiles == -1) | |||||
return 0; | |||||
ENSURE(1 <= tiles && tiles <= 65535); | |||||
return (u16)tiles; | |||||
} | |||||
virtual u32 GetMapSize() const | |||||
{ | |||||
return GetTilesPerSide() * TERRAIN_TILE_SIZE; | |||||
} | |||||
virtual u16 GetVerticesPerSide() const | |||||
{ | |||||
ssize_t vertices = m_Terrain->GetVerticesPerSide(); | |||||
ENSURE(1 <= vertices && vertices <= 65535); | |||||
return (u16)vertices; | |||||
} | |||||
virtual CTerrain* GetCTerrain() | |||||
{ | |||||
return m_Terrain; | |||||
} | |||||
virtual void SetTerrain(CTerrain* t) | |||||
{ | |||||
m_Terrain = t; | |||||
} | |||||
virtual void MakeDirty(i32 i0, i32 j0, i32 i1, i32 j1) | |||||
{ | |||||
CMessageTerrainChanged msg(i0, j0, i1, j1); | |||||
GetSimContext().GetComponentManager().BroadcastMessage(msg); | |||||
} | |||||
virtual void ReloadTerrain(bool UNUSED(ReloadWater)) | |||||
{ | |||||
u16 tiles = GetTilesPerSide(); | |||||
u16 vertices = GetVerticesPerSide(); | |||||
CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity()); | |||||
if (cmpObstructionManager) | |||||
{ | |||||
cmpObstructionManager->SetBounds(entity_pos_t::Zero(), entity_pos_t::Zero(), | |||||
entity_pos_t::FromInt(tiles * static_cast<int>(TERRAIN_TILE_SIZE)), | |||||
entity_pos_t::FromInt(tiles * static_cast<int>(TERRAIN_TILE_SIZE))); | |||||
} | |||||
CmpPtr<ICmpRangeManager> cmpRangeManager(GetSystemEntity()); | |||||
if (cmpRangeManager) | |||||
{ | |||||
cmpRangeManager->SetBounds(entity_pos_t::Zero(), entity_pos_t::Zero(), | |||||
entity_pos_t::FromInt(tiles * static_cast<int>(TERRAIN_TILE_SIZE)), | |||||
entity_pos_t::FromInt(tiles * static_cast<int>(TERRAIN_TILE_SIZE)), | |||||
vertices); | |||||
} | |||||
MakeDirty(0, 0, tiles + 1, tiles + 1); | |||||
} | |||||
}; | |||||
class MockFootprint : public ICmpFootprint | |||||
{ | |||||
private: | |||||
entity_pos_t m_Height; | |||||
public: | |||||
virtual int GetComponentTypeId() const { return IID_Footprint; } | |||||
virtual void Init(const CParamNode& UNUSED(paramNode)) { } | |||||
virtual void Deinit() {} | |||||
virtual void Serialize(ISerializer& UNUSED(serialize)) { } | |||||
virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) | |||||
{ Init(paramNode); } | |||||
virtual void GetShape(EShape& UNUSED(shape), entity_pos_t& UNUSED(size0), entity_pos_t& UNUSED(size1), entity_pos_t& height) const | |||||
{ | |||||
height = m_Height; | |||||
} | |||||
virtual entity_pos_t GetHeight() const | |||||
{ | |||||
return m_Height; | |||||
} | |||||
virtual void SetHeight(entity_pos_t h) | |||||
{ | |||||
m_Height = h; | |||||
} | |||||
virtual CFixedVector3D PickSpawnPoint(entity_id_t UNUSED(spawned)) const | |||||
{ | |||||
return CFixedVector3D(); | |||||
} | |||||
virtual CFixedVector3D PickSpawnPointBothPass(entity_id_t UNUSED(spawned)) const | |||||
{ | |||||
return CFixedVector3D(); | |||||
} | |||||
}; | |||||
#include <chrono> | |||||
class TestCmpRangeManager : public CxxTest::TestSuite | class TestCmpRangeManager : public CxxTest::TestSuite | ||||
{ | { | ||||
public: | public: | ||||
void setUp() | void setUp() | ||||
{ | { | ||||
CXeromyces::Startup(); | CXeromyces::Startup(); | ||||
} | } | ||||
void tearDown() | void tearDown() | ||||
{ | { | ||||
CXeromyces::Terminate(); | CXeromyces::Terminate(); | ||||
} | } | ||||
void test_losComputation() | |||||
{ | |||||
ComponentTestHelper test(g_ScriptRuntime); | |||||
ICmpRangeManager* cmp = test.Add<ICmpRangeManager>(CID_RangeManager, "", SYSTEM_ENTITY); | |||||
entity_id_t entityId = 100; | |||||
int playerId = 1; | |||||
int playerId2 = 2; | |||||
MockVision vision; | |||||
vision.SetRange(entity_pos_t::FromInt(64)); | |||||
test.AddMock(entityId, IID_Vision, vision); | |||||
MockPosition position; | |||||
test.AddMock(entityId, IID_Position, position); | |||||
MockFootprint footprint; | |||||
footprint.SetHeight(entity_pos_t::FromInt(5)); | |||||
test.AddMock(entityId, IID_Footprint, footprint); | |||||
CTerrain mTerrain; | |||||
MockFullTerrain terrain; | |||||
terrain.SetTerrain(&mTerrain); | |||||
// Flat terrain | |||||
mTerrain.Initialize(8, nullptr); | |||||
MockWater water; | |||||
test.AddMock(SYSTEM_ENTITY, IID_WaterManager, water); | |||||
int xMax = 512; | |||||
ssize_t tvps = xMax / TERRAIN_TILE_SIZE + 1; | |||||
cmp->SetBounds(entity_pos_t::FromInt(0), entity_pos_t::FromInt(0), entity_pos_t::FromInt(xMax), entity_pos_t::FromInt(xMax), tvps); | |||||
// Check that nothing is explored | |||||
TS_ASSERT_EQUALS(cmp->GetPercentMapExplored(playerId), 0); | |||||
{ CMessageCreate msg(entityId); cmp->HandleMessage(msg, false); } | |||||
{ CMessageOwnershipChanged msg(entityId, -1, playerId); cmp->HandleMessage(msg, false); } | |||||
{ CMessagePositionChanged msg(entityId, true, entity_pos_t::FromInt(247), entity_pos_t::FromDouble(257.95), entity_angle_t::Zero()); cmp->HandleMessage(msg, false); } | |||||
// Check that something is explored for player1 | |||||
u8 expl = cmp->GetPercentMapExplored(playerId); | |||||
TS_ASSERT_LESS_THAN(0, expl); | |||||
// And the same amount is visible for player1 and nothing explored or visible for player2 | |||||
u32 vis = 0; | |||||
u32 ee = 0; | |||||
for (int i = 0; i < tvps; ++i) { | |||||
for (int j = 0; j < tvps; ++j) { | |||||
if (cmp->TestVisibility(i, j, playerId, ICmpRangeManager::LOS_VISIBLE)) | |||||
vis = vis + 1; | |||||
if (cmp->TestVisibility(i, j, playerId, ICmpRangeManager::LOS_EXPLORED)) | |||||
ee = ee + 1; | |||||
TS_ASSERT_EQUALS(cmp->TestVisibility(i, j, playerId2, ICmpRangeManager::LOS_VISIBLE), false); | |||||
TS_ASSERT_EQUALS(cmp->TestVisibility(i, j, playerId2, ICmpRangeManager::LOS_EXPLORED), false); | |||||
} | |||||
} | |||||
TS_ASSERT_LESS_THAN(0, ee); | |||||
TS_ASSERT_LESS_THAN(0, vis); | |||||
u32 explV = cmp->GetExploredVertices(playerId); | |||||
// Explored vertices matches count of explored vertices in map | |||||
TS_ASSERT_EQUALS(ee, explV); | |||||
// The same amount is explored and visible | |||||
TS_ASSERT_EQUALS(ee, vis); | |||||
{ CMessageOwnershipChanged msg(entityId, playerId, -1); cmp->HandleMessage(msg, false); } | |||||
{ CMessageDestroy msg(entityId); cmp->HandleMessage(msg, false); } | |||||
// Check that nothing is visible | |||||
u32 ee2 = 0; | |||||
for (int i = 0; i < tvps; ++i) | |||||
for (int j = 0; j < tvps; ++j) { | |||||
TS_ASSERT_EQUALS(cmp->TestVisibility(i, j, playerId, ICmpRangeManager::LOS_VISIBLE), false); | |||||
if (cmp->TestVisibility(i, j, playerId, ICmpRangeManager::LOS_EXPLORED)) | |||||
ee2 = ee2 + 1; | |||||
} | |||||
// And still the same amount is explored as before | |||||
TS_ASSERT_EQUALS(ee, ee2); | |||||
} | |||||
void test_visibility() | |||||
{ | |||||
ComponentTestHelper test(g_ScriptRuntime); | |||||
ICmpRangeManager* cmp = test.Add<ICmpRangeManager>(CID_RangeManager, "", SYSTEM_ENTITY); | |||||
entity_id_t entityId = 100; | |||||
entity_id_t entityId2 = 200; | |||||
player_id_t playerId = 1; | |||||
player_id_t playerId2 = 2; | |||||
// Setup entity 1 | |||||
int numInt1 = IID__LastNative; | |||||
MockVision vision1; | |||||
vision1.SetRange(entity_pos_t::FromInt(10)); | |||||
test.AddMock(entityId, IID_Vision, vision1); | |||||
MockPosition position1; | |||||
test.AddMock(entityId, IID_Position, position1); | |||||
MockFootprint footprint1; | |||||
footprint1.SetHeight(entity_pos_t::FromInt(5)); | |||||
test.AddMock(entityId, IID_Footprint, footprint1); | |||||
MockOwnership ownership1; | |||||
ownership1.SetOwner(playerId); | |||||
test.AddMock(entityId, IID_Ownership, ownership1); | |||||
SEntityComponentCache* compCache1 = (SEntityComponentCache*)calloc(1, | |||||
sizeof(SEntityComponentCache) + sizeof(IComponent*) * numInt1); | |||||
ENSURE(compCache1 != nullptr); | |||||
compCache1->numInterfaces = numInt1 + 1; | |||||
compCache1->interfaces[IID_Position] = &position1; | |||||
compCache1->interfaces[IID_Ownership] = &ownership1; | |||||
compCache1->interfaces[IID_Footprint] = &footprint1; | |||||
compCache1->interfaces[IID_Vision] = &vision1; | |||||
CEntityHandle handle1(entityId, compCache1); | |||||
// Setup entity 2 | |||||
MockVision vision2; | |||||
vision2.SetRange(entity_pos_t::FromInt(20)); | |||||
test.AddMock(entityId2, IID_Vision, vision2); | |||||
MockPosition position2; | |||||
test.AddMock(entityId2, IID_Position, position2); | |||||
MockFootprint footprint2; | |||||
footprint2.SetHeight(entity_pos_t::FromInt(5)); | |||||
test.AddMock(entityId2, IID_Footprint, footprint2); | |||||
MockOwnership ownership2; | |||||
ownership2.SetOwner(playerId2); | |||||
test.AddMock(entityId2, IID_Ownership, ownership2); | |||||
SEntityComponentCache* compCache2 = (SEntityComponentCache*)calloc(1, | |||||
sizeof(SEntityComponentCache) + sizeof(IComponent*) * numInt1); | |||||
ENSURE(compCache2 != nullptr); | |||||
compCache2->numInterfaces = numInt1 + 1; | |||||
compCache2->interfaces[IID_Position] = &position2; | |||||
compCache2->interfaces[IID_Ownership] = &ownership2; | |||||
compCache2->interfaces[IID_Footprint] = &footprint2; | |||||
compCache2->interfaces[IID_Vision] = &vision2; | |||||
CEntityHandle handle2(entityId2, compCache2); | |||||
// Setup players | |||||
std::vector<player_id_t> see1; | |||||
see1.push_back(playerId); | |||||
std::vector<player_id_t> see2; | |||||
see2.push_back(playerId2); | |||||
CTerrain mTerrain; | |||||
MockFullTerrain terrain; | |||||
terrain.SetTerrain(&mTerrain); | |||||
// Flat terrain | |||||
mTerrain.Initialize(8, nullptr); | |||||
MockWater water; | |||||
test.AddMock(SYSTEM_ENTITY, IID_WaterManager, water); | |||||
int xMax = 512; | |||||
ssize_t tvps = xMax / TERRAIN_TILE_SIZE + 1; | |||||
cmp->SetSharedLos(playerId, see1); | |||||
TS_ASSERT_EQUALS(cmp->GetSharedLosMask(playerId), ICmpRangeManager::LOS_MASK << (2 * (playerId - 1))); | |||||
cmp->SetSharedLos(playerId2, see2); | |||||
cmp->SetBounds(entity_pos_t::FromInt(0), entity_pos_t::FromInt(0), entity_pos_t::FromInt(xMax), entity_pos_t::FromInt(xMax), tvps); | |||||
{ CMessageCreate msg(entityId); cmp->HandleMessage(msg, false); } | |||||
{ CMessageCreate msg(entityId2); cmp->HandleMessage(msg, false); } | |||||
{ CMessageOwnershipChanged msg(entityId, -1, playerId); cmp->HandleMessage(msg, false); } | |||||
{ CMessageOwnershipChanged msg(entityId2, -1, playerId2); cmp->HandleMessage(msg, false); } | |||||
position1.SetPosition(entity_pos_t::FromInt(100), entity_pos_t::FromDouble(100)); | |||||
position2.SetPosition(entity_pos_t::FromInt(115), entity_pos_t::FromDouble(100)); | |||||
{ CMessagePositionChanged msg(entityId, true, entity_pos_t::FromInt(100), entity_pos_t::FromDouble(100), entity_angle_t::Zero()); cmp->HandleMessage(msg, false); } | |||||
{ CMessagePositionChanged msg(entityId2, true, entity_pos_t::FromInt(115), entity_pos_t::FromDouble(100), entity_angle_t::Zero()); cmp->HandleMessage(msg, false); } | |||||
CmpPtr<ICmpPosition> cmpPosition(handle1); | |||||
if (!cmpPosition) | |||||
TS_FAIL("entity with handle1 has not position component"); | |||||
CFixedVector2D pos = cmpPosition->GetPosition2D(); | |||||
int i = (pos.X / static_cast<int>(TERRAIN_TILE_SIZE)).ToInt_RoundToNearest(); | |||||
int j = (pos.Y / static_cast<int>(TERRAIN_TILE_SIZE)).ToInt_RoundToNearest(); | |||||
if (!cmp->TestVisibility(i, j, playerId, ICmpRangeManager::LOS_VISIBLE)) | |||||
TS_FAIL("Entity does not see its own position"); | |||||
// Players see their own entities | |||||
TS_ASSERT_EQUALS(cmp->GetLosVisibility(handle1, playerId), ICmpRangeManager::VIS_VISIBLE); | |||||
TS_ASSERT_EQUALS(cmp->GetLosVisibility(handle2, playerId2), ICmpRangeManager::VIS_VISIBLE); | |||||
// Player1 cannot see entity2 | |||||
TS_ASSERT_EQUALS(cmp->GetLosVisibility(handle2, playerId), ICmpRangeManager::VIS_HIDDEN); | |||||
// Player2 can see entity1 | |||||
TS_ASSERT_EQUALS(cmp->GetLosVisibility(handle1, playerId2), ICmpRangeManager::VIS_VISIBLE); | |||||
position2.SetPosition(entity_pos_t::FromInt(121), entity_pos_t::FromDouble(100)); | |||||
{ CMessagePositionChanged msg(entityId2, true, entity_pos_t::FromInt(121), entity_pos_t::FromDouble(100), entity_angle_t::Zero()); cmp->HandleMessage(msg, false); } | |||||
// Player2 cannot see entity1 | |||||
TS_ASSERT_EQUALS(cmp->GetLosVisibility(handle1, playerId2), ICmpRangeManager::VIS_HIDDEN); | |||||
position1.SetPosition(entity_pos_t::FromInt(118), entity_pos_t::FromDouble(100)); | |||||
{ CMessagePositionChanged msg(entityId, true, entity_pos_t::FromInt(118), entity_pos_t::FromDouble(100), entity_angle_t::Zero()); cmp->HandleMessage(msg, false); } | |||||
// Both players can see both entities | |||||
TS_ASSERT_EQUALS(cmp->GetLosVisibility(handle1, playerId2), ICmpRangeManager::VIS_VISIBLE); | |||||
TS_ASSERT_EQUALS(cmp->GetLosVisibility(handle2, playerId), ICmpRangeManager::VIS_VISIBLE); | |||||
} | |||||
// TODO It would be nice to call Verify() with the shore revealing system | // TODO It would be nice to call Verify() with the shore revealing system | ||||
// but that means testing on an actual map, with water and land. | // but that means testing on an actual map, with water and land. | ||||
void test_basic() | void test_basic() | ||||
{ | { | ||||
Stan: Likely useless ^^ | |||||
ComponentTestHelper test(g_ScriptRuntime); | ComponentTestHelper test(g_ScriptRuntime); | ||||
ICmpRangeManager* cmp = test.Add<ICmpRangeManager>(CID_RangeManager, "", SYSTEM_ENTITY); | ICmpRangeManager* cmp = test.Add<ICmpRangeManager>(CID_RangeManager, "", SYSTEM_ENTITY); | ||||
MockVision vision; | MockVision vision; | ||||
vision.SetRange(entity_pos_t::FromInt(64)); | |||||
test.AddMock(100, IID_Vision, vision); | test.AddMock(100, IID_Vision, vision); | ||||
MockPosition position; | MockPosition position; | ||||
test.AddMock(100, IID_Position, position); | test.AddMock(100, IID_Position, position); | ||||
MockFootprint footprint; | |||||
footprint.SetHeight(entity_pos_t::FromInt(5)); | |||||
test.AddMock(100, IID_Footprint, footprint); | |||||
CTerrain mTerrain; | |||||
MockFullTerrain terrain; | |||||
terrain.SetTerrain(&mTerrain); | |||||
// Flat terrain | |||||
mTerrain.Initialize(8, nullptr); | |||||
if (mTerrain.GetVertexGroundLevel(61, 64) > 0) | |||||
TS_FAIL("terrain get vertex ground level"); | |||||
test.AddMock(SYSTEM_ENTITY, IID_Terrain, terrain); | |||||
terrain.Init(CParamNode()); | |||||
if (!terrain.GetCTerrain()) | |||||
TS_FAIL("GetCTerrain returns null"); | |||||
MockWater water; | |||||
test.AddMock(SYSTEM_ENTITY, IID_WaterManager, water); | |||||
Not Done Inline ActionsDon't think you need to check for both, do you ? Stan: Don't think you need to check for both, do you ? | |||||
Done Inline Actionsyes I was just super cautious :) Silier: yes I was just super cautious :) | |||||
// This tests that the incremental computation produces the correct result | // This tests that the incremental computation produces the correct result | ||||
// in various edge cases | // in various edge cases | ||||
cmp->SetBounds(entity_pos_t::FromInt(0), entity_pos_t::FromInt(0), entity_pos_t::FromInt(512), entity_pos_t::FromInt(512), 512/TERRAIN_TILE_SIZE + 1); | cmp->SetBounds(entity_pos_t::FromInt(0), entity_pos_t::FromInt(0), entity_pos_t::FromInt(512), entity_pos_t::FromInt(512), 512/TERRAIN_TILE_SIZE + 1); | ||||
cmp->Verify(); | cmp->Verify(); | ||||
{ CMessageCreate msg(100); cmp->HandleMessage(msg, false); } | { CMessageCreate msg(100); cmp->HandleMessage(msg, false); } | ||||
cmp->Verify(); | cmp->Verify(); | ||||
{ CMessageOwnershipChanged msg(100, -1, 1); cmp->HandleMessage(msg, false); } | { CMessageOwnershipChanged msg(100, -1, 1); cmp->HandleMessage(msg, false); } | ||||
Show All 39 Lines | // Test OwnershipChange, GetEntitiesByPlayer, GetNonGaiaEntities | ||||
for (player_id_t i = 0; i < 8; ++i) | for (player_id_t i = 0; i < 8; ++i) | ||||
TS_ASSERT_EQUALS(cmp->GetEntitiesByPlayer(i).size(), i == newOwner ? 1 : 0); | TS_ASSERT_EQUALS(cmp->GetEntitiesByPlayer(i).size(), i == newOwner ? 1 : 0); | ||||
TS_ASSERT_EQUALS(cmp->GetNonGaiaEntities().size(), newOwner > 0 ? 1 : 0); | TS_ASSERT_EQUALS(cmp->GetNonGaiaEntities().size(), newOwner > 0 ? 1 : 0); | ||||
previousOwner = newOwner; | previousOwner = newOwner; | ||||
} | } | ||||
} | } | ||||
terrain.Deinit(); | |||||
} | } | ||||
}; | }; |
Wildfire Games · Phabricator
Likely useless ^^