RangeManager: Grid for 2D array, enum cleanups.
Range manager has several `std::vector` for fixed-size arrays and 2D grids. By using proper data structures, the code readability is improved. This also moves around the LosVisibility enum. Comments by: Stan`, nani Differential Revision: https://code.wildfiregames.com/D2770 This was SVN commit r23769.
This commit is contained in:
parent
6f70a901f8
commit
939002f0dc
@ -249,7 +249,7 @@ void CCameraController::Update(const float deltaRealTime)
|
||||
CmpPtr<ICmpPosition> cmpPosition(*(g_Game->GetSimulation2()), m_FollowEntity);
|
||||
CmpPtr<ICmpRangeManager> cmpRangeManager(*(g_Game->GetSimulation2()), SYSTEM_ENTITY);
|
||||
if (cmpPosition && cmpPosition->IsInWorld() &&
|
||||
cmpRangeManager && cmpRangeManager->GetLosVisibility(m_FollowEntity, g_Game->GetViewedPlayerID()) == ICmpRangeManager::VIS_VISIBLE)
|
||||
cmpRangeManager && cmpRangeManager->GetLosVisibility(m_FollowEntity, g_Game->GetViewedPlayerID()) == LosVisibility::VISIBLE)
|
||||
{
|
||||
// Get the most recent interpolated position
|
||||
float frameOffset = g_Game->GetSimulation2()->GetLastFrameOffset();
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -41,12 +41,16 @@ public:
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 2
|
||||
};
|
||||
std::vector<u32> inputDataVec(inputData, inputData+size*size);
|
||||
Grid<u32> inputDataVec(size, size);
|
||||
|
||||
// LOS_MASK should be cmpRanageManager->GetSharedLosMask(1),
|
||||
for (u8 i = 0; i < size; ++i)
|
||||
for (u8 j = 0; j < size; ++j)
|
||||
inputDataVec.set(i, j, inputData[i + j * size]);
|
||||
|
||||
// LosState::MASK should be cmpRanageManager->GetSharedLosMask(1),
|
||||
// but that would mean adding a huge mock component for this and it
|
||||
// should always be LOS_MASK for player 1 (as the other players are bit-shifted).
|
||||
ICmpRangeManager::CLosQuerier los(ICmpRangeManager::LOS_MASK, inputDataVec, size);
|
||||
// should always be LosState::MASK for player 1 (as the other players are bit-shifted).
|
||||
ICmpRangeManager::CLosQuerier los((u32)LosState::MASK, inputDataVec, size);
|
||||
|
||||
std::vector<u8> losData;
|
||||
size_t pitch;
|
||||
@ -66,13 +70,12 @@ public:
|
||||
CLOSTexture tex(sim);
|
||||
|
||||
const ssize_t size = 257;
|
||||
std::vector<u32> inputDataVec;
|
||||
inputDataVec.resize(size*size);
|
||||
Grid<u32> inputDataVec(size, size);
|
||||
|
||||
// LOS_MASK should be cmpRanageManager->GetSharedLosMask(1),
|
||||
// LosState::MASK should be cmpRanageManager->GetSharedLosMask(1),
|
||||
// but that would mean adding a huge mock component for this and it
|
||||
// should always be LOS_MASK for player 1 (as the other players are bit-shifted).
|
||||
ICmpRangeManager::CLosQuerier los(ICmpRangeManager::LOS_MASK, inputDataVec, size);
|
||||
// should always be LosState::MASK for player 1 (as the other players are bit-shifted).
|
||||
ICmpRangeManager::CLosQuerier los((u32)LosState::MASK, inputDataVec, size);
|
||||
|
||||
size_t reps = 128;
|
||||
double t = timer_Time();
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -544,8 +544,8 @@ void CMiniMap::Draw()
|
||||
ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second);
|
||||
if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ))
|
||||
{
|
||||
ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetSimulation2()->GetSimContext().GetCurrentDisplayedPlayer());
|
||||
if (vis != ICmpRangeManager::VIS_HIDDEN)
|
||||
LosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetSimulation2()->GetSimContext().GetCurrentDisplayedPlayer());
|
||||
if (vis != LosVisibility::HIDDEN)
|
||||
{
|
||||
v.a = 255;
|
||||
v.x = posX.ToFloat() * sx;
|
||||
|
@ -46,22 +46,6 @@
|
||||
#define LOS_TILES_RATIO 8
|
||||
#define DEBUG_RANGE_MANAGER_BOUNDS 0
|
||||
|
||||
/**
|
||||
* Representation of a range query.
|
||||
*/
|
||||
struct Query
|
||||
{
|
||||
bool enabled;
|
||||
bool parabolic;
|
||||
CEntityHandle source; // TODO: this could crash if an entity is destroyed while a Query is still referencing it
|
||||
entity_pos_t minRange;
|
||||
entity_pos_t maxRange;
|
||||
entity_pos_t elevationBonus;
|
||||
u32 ownersMask;
|
||||
i32 interface;
|
||||
std::vector<entity_id_t> lastMatch;
|
||||
u8 flagsMask;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert an owner ID (-1 = unowned, 0 = gaia, 1..30 = players)
|
||||
@ -81,7 +65,7 @@ static inline u32 CalcOwnerMask(player_id_t owner)
|
||||
static inline u32 CalcPlayerLosMask(player_id_t player)
|
||||
{
|
||||
if (player > 0 && player <= 16)
|
||||
return ICmpRangeManager::LOS_MASK << (2*(player-1));
|
||||
return (u32)LosState::MASK << (2*(player-1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -119,11 +103,11 @@ static bool SetPlayerSharedDirtyVisibilityBit(u16& mask, player_id_t player, boo
|
||||
/**
|
||||
* Computes the 2-bit visibility for one player, given the total 32-bit visibilities
|
||||
*/
|
||||
static inline u8 GetPlayerVisibility(u32 visibilities, player_id_t player)
|
||||
static inline LosVisibility GetPlayerVisibility(u32 visibilities, player_id_t player)
|
||||
{
|
||||
if (player > 0 && player <= 16)
|
||||
return (visibilities >> (2 *(player-1))) & 0x3;
|
||||
return 0;
|
||||
return static_cast<LosVisibility>( (visibilities >> (2 *(player-1))) & 0x3 );
|
||||
return LosVisibility::HIDDEN;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -152,6 +136,23 @@ static inline u16 CalcVisionSharingMask(player_id_t player)
|
||||
return 1 << (player-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Representation of a range query.
|
||||
*/
|
||||
struct Query
|
||||
{
|
||||
bool enabled;
|
||||
bool parabolic;
|
||||
CEntityHandle source; // TODO: this could crash if an entity is destroyed while a Query is still referencing it
|
||||
entity_pos_t minRange;
|
||||
entity_pos_t maxRange;
|
||||
entity_pos_t elevationBonus;
|
||||
u32 ownersMask;
|
||||
i32 interface;
|
||||
std::vector<entity_id_t> lastMatch;
|
||||
u8 flagsMask;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether v is in a parabolic range of (0,0,0)
|
||||
* The highest point of the paraboloid is (0,range/2,0)
|
||||
@ -372,16 +373,18 @@ public:
|
||||
// LOS state:
|
||||
static const player_id_t MAX_LOS_PLAYER_ID = 16;
|
||||
|
||||
std::vector<bool> m_LosRevealAll;
|
||||
using LosTile = std::pair<u16, u16>;
|
||||
|
||||
std::array<bool, MAX_LOS_PLAYER_ID+2> m_LosRevealAll;
|
||||
bool m_LosCircular;
|
||||
i32 m_TerrainVerticesPerSide;
|
||||
|
||||
// Cache for visibility tracking
|
||||
i32 m_LosTilesPerSide;
|
||||
bool m_GlobalVisibilityUpdate;
|
||||
std::vector<u8> m_GlobalPlayerVisibilityUpdate;
|
||||
std::vector<u16> m_DirtyVisibility;
|
||||
std::vector<std::set<entity_id_t> > m_LosTiles;
|
||||
std::array<bool, MAX_LOS_PLAYER_ID> m_GlobalPlayerVisibilityUpdate;
|
||||
Grid<u16> m_DirtyVisibility;
|
||||
Grid<std::set<entity_id_t>> m_LosTiles;
|
||||
// List of entities that must be updated, regardless of the status of their tile
|
||||
std::vector<entity_id_t> m_ModifiedEntities;
|
||||
|
||||
@ -390,19 +393,19 @@ public:
|
||||
// of units in a very small area.
|
||||
// (Note we use vertexes, not tiles, to better match the renderer.)
|
||||
// Lazily constructed when it's needed, to save memory in smaller games.
|
||||
std::vector<std::vector<u16> > m_LosPlayerCounts;
|
||||
std::array<Grid<u16>, MAX_LOS_PLAYER_ID> m_LosPlayerCounts;
|
||||
|
||||
// 2-bit ELosState per player, starting with player 1 (not 0!) up to player MAX_LOS_PLAYER_ID (inclusive)
|
||||
std::vector<u32> m_LosState;
|
||||
// 2-bit LosState per player, starting with player 1 (not 0!) up to player MAX_LOS_PLAYER_ID (inclusive)
|
||||
Grid<u32> m_LosState;
|
||||
|
||||
// Special static visibility data for the "reveal whole map" mode
|
||||
// (TODO: this is usually a waste of memory)
|
||||
std::vector<u32> m_LosStateRevealed;
|
||||
Grid<u32> m_LosStateRevealed;
|
||||
|
||||
// Shared LOS masks, one per player.
|
||||
std::vector<u32> m_SharedLosMasks;
|
||||
std::array<u32, MAX_LOS_PLAYER_ID+2> m_SharedLosMasks;
|
||||
// Shared dirty visibility masks, one per player.
|
||||
std::vector<u16> m_SharedDirtyVisibilityMasks;
|
||||
std::array<u16, MAX_LOS_PLAYER_ID+2> m_SharedDirtyVisibilityMasks;
|
||||
|
||||
// Cache explored vertices per player (not serialized)
|
||||
u32 m_TotalInworldVertices;
|
||||
@ -431,13 +434,9 @@ public:
|
||||
|
||||
// The whole map should be visible to Gaia by default, else e.g. animals
|
||||
// will get confused when trying to run from enemies
|
||||
m_LosRevealAll.resize(MAX_LOS_PLAYER_ID+2,false);
|
||||
m_LosRevealAll[0] = true;
|
||||
m_SharedLosMasks.resize(MAX_LOS_PLAYER_ID+2,0);
|
||||
m_SharedDirtyVisibilityMasks.resize(MAX_LOS_PLAYER_ID + 2, 0);
|
||||
|
||||
m_GlobalVisibilityUpdate = true;
|
||||
m_GlobalPlayerVisibilityUpdate.resize(MAX_LOS_PLAYER_ID);
|
||||
|
||||
m_LosCircular = false;
|
||||
m_TerrainVerticesPerSide = 0;
|
||||
@ -459,22 +458,22 @@ public:
|
||||
SerializeMap<SerializeU32_Unbounded, SerializeQuery>()(serialize, "queries", m_Queries, GetSimContext());
|
||||
SerializeEntityMap<SerializeEntityData>()(serialize, "entity data", m_EntityData);
|
||||
|
||||
SerializeVector<SerializeBool>()(serialize, "los reveal all", m_LosRevealAll);
|
||||
SerializeArray<SerializeBool>()(serialize, "los reveal all", m_LosRevealAll);
|
||||
serialize.Bool("los circular", m_LosCircular);
|
||||
serialize.NumberI32_Unbounded("terrain verts per side", m_TerrainVerticesPerSide);
|
||||
|
||||
serialize.Bool("global visibility update", m_GlobalVisibilityUpdate);
|
||||
SerializeVector<SerializeU8_Unbounded>()(serialize, "global player visibility update", m_GlobalPlayerVisibilityUpdate);
|
||||
SerializeRepetitiveVector<SerializeU16_Unbounded>()(serialize, "dirty visibility", m_DirtyVisibility);
|
||||
SerializeArray<SerializeBool>()(serialize, "global player visibility update", m_GlobalPlayerVisibilityUpdate);
|
||||
SerializedGridCompressed<SerializeU16_Unbounded>()(serialize, "dirty visibility", m_DirtyVisibility);
|
||||
SerializeVector<SerializeU32_Unbounded>()(serialize, "modified entities", m_ModifiedEntities);
|
||||
|
||||
// We don't serialize m_Subdivision, m_LosPlayerCounts or m_LosTiles
|
||||
// since they can be recomputed from the entity data when deserializing;
|
||||
// m_LosState must be serialized since it depends on the history of exploration
|
||||
|
||||
SerializeRepetitiveVector<SerializeU32_Unbounded>()(serialize, "los state", m_LosState);
|
||||
SerializeVector<SerializeU32_Unbounded>()(serialize, "shared los masks", m_SharedLosMasks);
|
||||
SerializeVector<SerializeU16_Unbounded>()(serialize, "shared dirty visibility masks", m_SharedDirtyVisibilityMasks);
|
||||
SerializedGridCompressed<SerializeU32_Unbounded>()(serialize, "los state", m_LosState);
|
||||
SerializeArray<SerializeU32_Unbounded>()(serialize, "shared los masks", m_SharedLosMasks);
|
||||
SerializeArray<SerializeU16_Unbounded>()(serialize, "shared dirty visibility masks", m_SharedDirtyVisibilityMasks);
|
||||
}
|
||||
|
||||
virtual void Serialize(ISerializer& serialize)
|
||||
@ -563,8 +562,8 @@ public:
|
||||
SharingLosMove(it->second.visionSharing, it->second.visionRange, from, to);
|
||||
else
|
||||
LosMove(it->second.owner, it->second.visionRange, from, to);
|
||||
i32 oldLosTile = PosToLosTilesHelper(it->second.x, it->second.z);
|
||||
i32 newLosTile = PosToLosTilesHelper(msgData.x, msgData.z);
|
||||
LosTile oldLosTile = PosToLosTilesHelper(it->second.x, it->second.z);
|
||||
LosTile newLosTile = PosToLosTilesHelper(msgData.x, msgData.z);
|
||||
if (oldLosTile != newLosTile)
|
||||
{
|
||||
RemoveFromTile(oldLosTile, ent);
|
||||
@ -782,10 +781,10 @@ public:
|
||||
// Check that calling ResetDerivedData (i.e. recomputing all the state from scratch)
|
||||
// does not affect the incrementally-computed state
|
||||
|
||||
std::vector<std::vector<u16> > oldPlayerCounts = m_LosPlayerCounts;
|
||||
std::vector<u32> oldStateRevealed = m_LosStateRevealed;
|
||||
std::array<Grid<u16>, MAX_LOS_PLAYER_ID> oldPlayerCounts = m_LosPlayerCounts;
|
||||
Grid<u32> oldStateRevealed = m_LosStateRevealed;
|
||||
FastSpatialSubdivision oldSubdivision = m_Subdivision;
|
||||
std::vector<std::set<entity_id_t> > oldLosTiles = m_LosTiles;
|
||||
Grid<std::set<entity_id_t> > oldLosTiles = m_LosTiles;
|
||||
|
||||
m_Deserializing = true;
|
||||
ResetDerivedData();
|
||||
@ -793,19 +792,25 @@ public:
|
||||
|
||||
if (oldPlayerCounts != m_LosPlayerCounts)
|
||||
{
|
||||
for (size_t i = 0; i < oldPlayerCounts.size(); ++i)
|
||||
for (size_t id = 0; id < m_LosPlayerCounts.size(); ++id)
|
||||
{
|
||||
debug_printf("%d: ", (int)i);
|
||||
for (size_t j = 0; j < oldPlayerCounts[i].size(); ++j)
|
||||
debug_printf("%d ", oldPlayerCounts[i][j]);
|
||||
debug_printf("\n");
|
||||
debug_printf("player %li\n", id);
|
||||
for (size_t i = 0; i < oldPlayerCounts[id].width(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < oldPlayerCounts[id].height(); ++j)
|
||||
debug_printf("%i ", oldPlayerCounts[id].get(i,j));
|
||||
debug_printf("\n");
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < m_LosPlayerCounts.size(); ++i)
|
||||
for (size_t id = 0; id < m_LosPlayerCounts.size(); ++id)
|
||||
{
|
||||
debug_printf("%d: ", (int)i);
|
||||
for (size_t j = 0; j < m_LosPlayerCounts[i].size(); ++j)
|
||||
debug_printf("%d ", m_LosPlayerCounts[i][j]);
|
||||
debug_printf("\n");
|
||||
debug_printf("player %li\n", id);
|
||||
for (size_t i = 0; i < m_LosPlayerCounts[id].width(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < m_LosPlayerCounts[id].height(); ++j)
|
||||
debug_printf("%i ", m_LosPlayerCounts[id].get(i,j));
|
||||
debug_printf("\n");
|
||||
}
|
||||
}
|
||||
debug_warn(L"inconsistent player counts");
|
||||
}
|
||||
@ -830,10 +835,12 @@ public:
|
||||
|
||||
m_LosTilesPerSide = (m_TerrainVerticesPerSide - 1)/LOS_TILES_RATIO;
|
||||
|
||||
m_LosPlayerCounts.clear();
|
||||
m_LosPlayerCounts.resize(MAX_LOS_PLAYER_ID+1);
|
||||
for (size_t player_id = 0; player_id < m_LosPlayerCounts.size(); ++player_id)
|
||||
m_LosPlayerCounts[player_id].reset();
|
||||
|
||||
m_ExploredVertices.clear();
|
||||
m_ExploredVertices.resize(MAX_LOS_PLAYER_ID+1, 0);
|
||||
|
||||
if (m_Deserializing)
|
||||
{
|
||||
// recalc current exploration stats.
|
||||
@ -841,25 +848,20 @@ public:
|
||||
for (i32 i = 0; i < m_TerrainVerticesPerSide; i++)
|
||||
if (!LosIsOffWorld(i, j))
|
||||
for (u8 k = 1; k < MAX_LOS_PLAYER_ID+1; ++k)
|
||||
m_ExploredVertices.at(k) += ((m_LosState[j*m_TerrainVerticesPerSide + i] & (LOS_EXPLORED << (2*(k-1)))) > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_LosState.clear();
|
||||
m_LosState.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide);
|
||||
}
|
||||
m_LosStateRevealed.clear();
|
||||
m_LosStateRevealed.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide);
|
||||
m_ExploredVertices.at(k) += ((m_LosState.get(i, j) & ((u32)LosState::EXPLORED << (2*(k-1)))) > 0);
|
||||
} else
|
||||
m_LosState.resize(m_TerrainVerticesPerSide, m_TerrainVerticesPerSide);
|
||||
|
||||
m_LosStateRevealed.resize(m_TerrainVerticesPerSide, m_TerrainVerticesPerSide);
|
||||
|
||||
if (!m_Deserializing)
|
||||
{
|
||||
m_DirtyVisibility.clear();
|
||||
m_DirtyVisibility.resize(m_LosTilesPerSide*m_LosTilesPerSide);
|
||||
m_DirtyVisibility.resize(m_LosTilesPerSide, m_LosTilesPerSide);
|
||||
}
|
||||
ENSURE(m_DirtyVisibility.size() == (size_t)(m_LosTilesPerSide*m_LosTilesPerSide));
|
||||
ENSURE(m_DirtyVisibility.width() == m_LosTilesPerSide);
|
||||
ENSURE(m_DirtyVisibility.height() == m_LosTilesPerSide);
|
||||
|
||||
m_LosTiles.clear();
|
||||
m_LosTiles.resize(m_LosTilesPerSide*m_LosTilesPerSide);
|
||||
m_LosTiles.resize(m_LosTilesPerSide, m_LosTilesPerSide);
|
||||
|
||||
for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
|
||||
if (it->second.HasFlag<FlagMasks::InWorld>())
|
||||
@ -879,10 +881,10 @@ public:
|
||||
for (ssize_t i = 0; i < m_TerrainVerticesPerSide; ++i)
|
||||
{
|
||||
if (LosIsOffWorld(i,j))
|
||||
m_LosStateRevealed[i + j*m_TerrainVerticesPerSide] = 0;
|
||||
m_LosStateRevealed.get(i, j) = 0;
|
||||
else
|
||||
{
|
||||
m_LosStateRevealed[i + j*m_TerrainVerticesPerSide] = 0xFFFFFFFFu;
|
||||
m_LosStateRevealed.get(i, j) = 0xFFFFFFFFu;
|
||||
m_TotalInworldVertices++;
|
||||
}
|
||||
}
|
||||
@ -1582,19 +1584,19 @@ public:
|
||||
it->second.SetFlag<FlagMasks::ScriptedVisibility>(status);
|
||||
}
|
||||
|
||||
ELosVisibility ComputeLosVisibility(CEntityHandle ent, player_id_t player) const
|
||||
LosVisibility ComputeLosVisibility(CEntityHandle ent, player_id_t player) const
|
||||
{
|
||||
// Entities not with positions in the world are never visible
|
||||
if (ent.GetId() == INVALID_ENTITY)
|
||||
return VIS_HIDDEN;
|
||||
return LosVisibility::HIDDEN;
|
||||
CmpPtr<ICmpPosition> cmpPosition(ent);
|
||||
if (!cmpPosition || !cmpPosition->IsInWorld())
|
||||
return VIS_HIDDEN;
|
||||
return LosVisibility::HIDDEN;
|
||||
|
||||
// Mirage entities, whatever the situation, are visible for one specific player
|
||||
CmpPtr<ICmpMirage> cmpMirage(ent);
|
||||
if (cmpMirage && cmpMirage->GetPlayer() != player)
|
||||
return VIS_HIDDEN;
|
||||
return LosVisibility::HIDDEN;
|
||||
|
||||
CFixedVector2D pos = cmpPosition->GetPosition2D();
|
||||
int i = (pos.X / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNearest();
|
||||
@ -1604,9 +1606,8 @@ public:
|
||||
if (GetLosRevealAll(player))
|
||||
{
|
||||
if (LosIsOffWorld(i, j) || cmpMirage)
|
||||
return VIS_HIDDEN;
|
||||
else
|
||||
return VIS_VISIBLE;
|
||||
return LosVisibility::HIDDEN;
|
||||
return LosVisibility::VISIBLE;
|
||||
}
|
||||
|
||||
// Get visible regions
|
||||
@ -1632,41 +1633,41 @@ public:
|
||||
if (los.IsVisible(i, j))
|
||||
{
|
||||
if (cmpMirage)
|
||||
return VIS_HIDDEN;
|
||||
return LosVisibility::HIDDEN;
|
||||
|
||||
return VIS_VISIBLE;
|
||||
return LosVisibility::VISIBLE;
|
||||
}
|
||||
|
||||
if (!los.IsExplored(i, j))
|
||||
return VIS_HIDDEN;
|
||||
return LosVisibility::HIDDEN;
|
||||
|
||||
// Invisible if the 'retain in fog' flag is not set, and in a non-visible explored region
|
||||
// Try using the 'retainInFog' flag in m_EntityData to save a script call
|
||||
if (it != m_EntityData.end())
|
||||
{
|
||||
if (!it->second.HasFlag<FlagMasks::RetainInFog>())
|
||||
return VIS_HIDDEN;
|
||||
return LosVisibility::HIDDEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(cmpVisibility && cmpVisibility->GetRetainInFog()))
|
||||
return VIS_HIDDEN;
|
||||
return LosVisibility::HIDDEN;
|
||||
}
|
||||
|
||||
if (cmpMirage)
|
||||
return VIS_FOGGED;
|
||||
return LosVisibility::FOGGED;
|
||||
|
||||
CmpPtr<ICmpOwnership> cmpOwnership(ent);
|
||||
if (!cmpOwnership)
|
||||
return VIS_FOGGED;
|
||||
return LosVisibility::FOGGED;
|
||||
|
||||
if (cmpOwnership->GetOwner() == player)
|
||||
{
|
||||
CmpPtr<ICmpFogging> cmpFogging(ent);
|
||||
if (!(cmpFogging && cmpFogging->IsMiraged(player)))
|
||||
return VIS_FOGGED;
|
||||
return LosVisibility::FOGGED;
|
||||
|
||||
return VIS_HIDDEN;
|
||||
return LosVisibility::HIDDEN;
|
||||
}
|
||||
|
||||
// Fogged entities are hidden in two cases:
|
||||
@ -1675,37 +1676,36 @@ public:
|
||||
CmpPtr<ICmpFogging> cmpFogging(ent);
|
||||
if (cmpFogging && cmpFogging->IsActivated() &&
|
||||
(!cmpFogging->WasSeen(player) || cmpFogging->IsMiraged(player)))
|
||||
return VIS_HIDDEN;
|
||||
return LosVisibility::HIDDEN;
|
||||
|
||||
return VIS_FOGGED;
|
||||
return LosVisibility::FOGGED;
|
||||
}
|
||||
|
||||
ELosVisibility ComputeLosVisibility(entity_id_t ent, player_id_t player) const
|
||||
LosVisibility ComputeLosVisibility(entity_id_t ent, player_id_t player) const
|
||||
{
|
||||
CEntityHandle handle = GetSimContext().GetComponentManager().LookupEntityHandle(ent);
|
||||
return ComputeLosVisibility(handle, player);
|
||||
}
|
||||
|
||||
virtual ELosVisibility GetLosVisibility(CEntityHandle ent, player_id_t player) const
|
||||
virtual LosVisibility GetLosVisibility(CEntityHandle ent, player_id_t player) const
|
||||
{
|
||||
entity_id_t entId = ent.GetId();
|
||||
|
||||
// Entities not with positions in the world are never visible
|
||||
if (entId == INVALID_ENTITY)
|
||||
return VIS_HIDDEN;
|
||||
return LosVisibility::HIDDEN;
|
||||
|
||||
CmpPtr<ICmpPosition> cmpPosition(ent);
|
||||
if (!cmpPosition || !cmpPosition->IsInWorld())
|
||||
return VIS_HIDDEN;
|
||||
return LosVisibility::HIDDEN;
|
||||
|
||||
// Gaia and observers do not have a visibility cache
|
||||
if (player <= 0)
|
||||
return ComputeLosVisibility(ent, player);
|
||||
|
||||
CFixedVector2D pos = cmpPosition->GetPosition2D();
|
||||
i32 n = PosToLosTilesHelper(pos.X, pos.Y);
|
||||
|
||||
if (IsVisibilityDirty(m_DirtyVisibility[n], player))
|
||||
if (IsVisibilityDirty(m_DirtyVisibility[PosToLosTilesHelper(pos.X, pos.Y)], player))
|
||||
return ComputeLosVisibility(ent, player);
|
||||
|
||||
if (std::find(m_ModifiedEntities.begin(), m_ModifiedEntities.end(), entId) != m_ModifiedEntities.end())
|
||||
@ -1715,16 +1715,16 @@ public:
|
||||
if (it == m_EntityData.end())
|
||||
return ComputeLosVisibility(ent, player);
|
||||
|
||||
return static_cast<ELosVisibility>(GetPlayerVisibility(it->second.visibilities, player));
|
||||
return static_cast<LosVisibility>(GetPlayerVisibility(it->second.visibilities, player));
|
||||
}
|
||||
|
||||
virtual ELosVisibility GetLosVisibility(entity_id_t ent, player_id_t player) const
|
||||
virtual LosVisibility GetLosVisibility(entity_id_t ent, player_id_t player) const
|
||||
{
|
||||
CEntityHandle handle = GetSimContext().GetComponentManager().LookupEntityHandle(ent);
|
||||
return GetLosVisibility(handle, player);
|
||||
}
|
||||
|
||||
virtual ELosVisibility GetLosVisibilityPosition(entity_pos_t x, entity_pos_t z, player_id_t player) const
|
||||
virtual LosVisibility GetLosVisibilityPosition(entity_pos_t x, entity_pos_t z, player_id_t player) const
|
||||
{
|
||||
int i = (x / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNearest();
|
||||
int j = (z / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNearest();
|
||||
@ -1733,22 +1733,27 @@ public:
|
||||
if (GetLosRevealAll(player))
|
||||
{
|
||||
if (LosIsOffWorld(i, j))
|
||||
return VIS_HIDDEN;
|
||||
return LosVisibility::HIDDEN;
|
||||
else
|
||||
return VIS_VISIBLE;
|
||||
return LosVisibility::VISIBLE;
|
||||
}
|
||||
|
||||
// Get visible regions
|
||||
CLosQuerier los(GetSharedLosMask(player), m_LosState, m_TerrainVerticesPerSide);
|
||||
|
||||
if (los.IsVisible(i,j))
|
||||
return VIS_VISIBLE;
|
||||
return LosVisibility::VISIBLE;
|
||||
if (los.IsExplored(i,j))
|
||||
return VIS_FOGGED;
|
||||
return VIS_HIDDEN;
|
||||
return LosVisibility::FOGGED;
|
||||
return LosVisibility::HIDDEN;
|
||||
}
|
||||
|
||||
i32 PosToLosTilesHelper(entity_pos_t x, entity_pos_t z) const
|
||||
LosTile PosToLosTilesHelper(u16 x, u16 z) const
|
||||
{
|
||||
return LosTile{ Clamp(x/LOS_TILES_RATIO, 0, m_LosTilesPerSide - 1), Clamp(z/LOS_TILES_RATIO, 0, m_LosTilesPerSide - 1) };
|
||||
}
|
||||
|
||||
LosTile PosToLosTilesHelper(entity_pos_t x, entity_pos_t z) const
|
||||
{
|
||||
i32 i = Clamp(
|
||||
(x/(entity_pos_t::FromInt(TERRAIN_TILE_SIZE * LOS_TILES_RATIO))).ToInt_RoundToZero(),
|
||||
@ -1758,15 +1763,15 @@ public:
|
||||
(z/(entity_pos_t::FromInt(TERRAIN_TILE_SIZE * LOS_TILES_RATIO))).ToInt_RoundToZero(),
|
||||
0,
|
||||
m_LosTilesPerSide - 1);
|
||||
return j*m_LosTilesPerSide + i;
|
||||
return std::make_pair(i, j);
|
||||
}
|
||||
|
||||
void AddToTile(i32 tile, entity_id_t ent)
|
||||
void AddToTile(LosTile tile, entity_id_t ent)
|
||||
{
|
||||
m_LosTiles[tile].insert(ent);
|
||||
}
|
||||
|
||||
void RemoveFromTile(i32 tile, entity_id_t ent)
|
||||
void RemoveFromTile(LosTile tile, entity_id_t ent)
|
||||
{
|
||||
std::set<entity_id_t>::const_iterator tileIt = m_LosTiles[tile].find(ent);
|
||||
if (tileIt != m_LosTiles[tile].end())
|
||||
@ -1777,17 +1782,19 @@ public:
|
||||
{
|
||||
PROFILE("UpdateVisibilityData");
|
||||
|
||||
for (i32 n = 0; n < m_LosTilesPerSide * m_LosTilesPerSide; ++n)
|
||||
{
|
||||
for (player_id_t player = 1; player < MAX_LOS_PLAYER_ID + 1; ++player)
|
||||
if (IsVisibilityDirty(m_DirtyVisibility[n], player) || m_GlobalPlayerVisibilityUpdate[player-1] == 1 || m_GlobalVisibilityUpdate)
|
||||
for (const entity_id_t& ent : m_LosTiles[n])
|
||||
UpdateVisibility(ent, player);
|
||||
for (u16 i = 0; i < m_LosTilesPerSide; ++i)
|
||||
for (u16 j = 0; j < m_LosTilesPerSide; ++j)
|
||||
{
|
||||
LosTile pos{i, j};
|
||||
for (player_id_t player = 1; player < MAX_LOS_PLAYER_ID + 1; ++player)
|
||||
if (IsVisibilityDirty(m_DirtyVisibility[pos], player) || m_GlobalPlayerVisibilityUpdate[player-1] == 1 || m_GlobalVisibilityUpdate)
|
||||
for (const entity_id_t& ent : m_LosTiles[pos])
|
||||
UpdateVisibility(ent, player);
|
||||
|
||||
m_DirtyVisibility[n] = 0;
|
||||
}
|
||||
m_DirtyVisibility[pos] = 0;
|
||||
}
|
||||
|
||||
std::fill(m_GlobalPlayerVisibilityUpdate.begin(), m_GlobalPlayerVisibilityUpdate.end(), 0);
|
||||
std::fill(m_GlobalPlayerVisibilityUpdate.begin(), m_GlobalPlayerVisibilityUpdate.end(), false);
|
||||
m_GlobalVisibilityUpdate = false;
|
||||
|
||||
// Calling UpdateVisibility can modify m_ModifiedEntities, so be careful:
|
||||
@ -1817,15 +1824,15 @@ public:
|
||||
if (itEnts == m_EntityData.end())
|
||||
return;
|
||||
|
||||
u8 oldVis = GetPlayerVisibility(itEnts->second.visibilities, player);
|
||||
u8 newVis = ComputeLosVisibility(itEnts->first, player);
|
||||
LosVisibility oldVis = GetPlayerVisibility(itEnts->second.visibilities, player);
|
||||
LosVisibility newVis = ComputeLosVisibility(itEnts->first, player);
|
||||
|
||||
if (oldVis == newVis)
|
||||
return;
|
||||
|
||||
itEnts->second.visibilities = (itEnts->second.visibilities & ~(0x3 << 2 * (player - 1))) | (newVis << 2 * (player - 1));
|
||||
itEnts->second.visibilities = (itEnts->second.visibilities & ~(0x3 << 2 * (player - 1))) | ((u8)newVis << 2 * (player - 1));
|
||||
|
||||
CMessageVisibilityChanged msg(player, ent, oldVis, newVis);
|
||||
CMessageVisibilityChanged msg(player, ent, static_cast<int>(oldVis), static_cast<int>(newVis));
|
||||
GetSimContext().GetComponentManager().PostMessage(ent, msg);
|
||||
}
|
||||
|
||||
@ -1909,8 +1916,8 @@ public:
|
||||
if (LosIsOffWorld(i,j))
|
||||
continue;
|
||||
u32 &explored = m_ExploredVertices.at(p);
|
||||
explored += !(m_LosState[i + j*m_TerrainVerticesPerSide] & (LOS_EXPLORED << (2*(p-1))));
|
||||
m_LosState[i + j*m_TerrainVerticesPerSide] |= (LOS_EXPLORED << (2*(p-1)));
|
||||
explored += !(m_LosState.get(i, j) & ((u32)LosState::EXPLORED << (2*(p-1))));
|
||||
m_LosState.get(i, j) |= ((u32)LosState::EXPLORED << (2*(p-1)));
|
||||
}
|
||||
|
||||
SeeExploredEntities(p);
|
||||
@ -1951,11 +1958,11 @@ public:
|
||||
if (LosIsOffWorld(ti, tj))
|
||||
continue;
|
||||
|
||||
u32& losState = m_LosState[ti + tj * m_TerrainVerticesPerSide];
|
||||
if (!(losState & (LOS_EXPLORED << (2*(p-1)))))
|
||||
u32& losState = m_LosState.get(ti, tj);
|
||||
if (!(losState & ((u32)LosState::EXPLORED << (2*(p-1)))))
|
||||
{
|
||||
++explored;
|
||||
losState |= (LOS_EXPLORED << (2*(p-1)));
|
||||
losState |= ((u32)LosState::EXPLORED << (2*(p-1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2018,9 +2025,8 @@ public:
|
||||
const Grid<u16>& shoreGrid = cmpPathfinder->ComputeShoreGrid(true);
|
||||
ENSURE(shoreGrid.m_W == m_TerrainVerticesPerSide-1 && shoreGrid.m_H == m_TerrainVerticesPerSide-1);
|
||||
|
||||
std::vector<u16>& counts = m_LosPlayerCounts.at(p);
|
||||
ENSURE(!counts.empty());
|
||||
u16* countsData = &counts[0];
|
||||
Grid<u16>& counts = m_LosPlayerCounts.at(p);
|
||||
ENSURE(!counts.blank());
|
||||
|
||||
for (u16 j = 0; j < shoreGrid.m_H; ++j)
|
||||
for (u16 i = 0; i < shoreGrid.m_W; ++i)
|
||||
@ -2031,9 +2037,9 @@ public:
|
||||
|
||||
// Maybe we could be more clever and don't add dummy strips of one tile
|
||||
if (enable)
|
||||
LosAddStripHelper(p, i, i, j, countsData);
|
||||
LosAddStripHelper(p, i, i, j, counts);
|
||||
else
|
||||
LosRemoveStripHelper(p, i, i, j, countsData);
|
||||
LosRemoveStripHelper(p, i, i, j, counts);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2069,56 +2075,50 @@ public:
|
||||
/**
|
||||
* Update the LOS state of tiles within a given horizontal strip (i0,j) to (i1,j) (inclusive).
|
||||
*/
|
||||
inline void LosAddStripHelper(u8 owner, i32 i0, i32 i1, i32 j, u16* counts)
|
||||
inline void LosAddStripHelper(u8 owner, i32 i0, i32 i1, i32 j, Grid<u16>& counts)
|
||||
{
|
||||
if (i1 < i0)
|
||||
return;
|
||||
|
||||
i32 idx0 = j*m_TerrainVerticesPerSide + i0;
|
||||
i32 idx1 = j*m_TerrainVerticesPerSide + i1;
|
||||
u32 &explored = m_ExploredVertices.at(owner);
|
||||
for (i32 idx = idx0; idx <= idx1; ++idx)
|
||||
for (i32 i = i0; i <= i1; ++i)
|
||||
{
|
||||
// Increasing from zero to non-zero - move from unexplored/explored to visible+explored
|
||||
if (counts[idx] == 0)
|
||||
if (counts.get(i, j) == 0)
|
||||
{
|
||||
i32 i = i0 + idx - idx0;
|
||||
if (!LosIsOffWorld(i, j))
|
||||
{
|
||||
explored += !(m_LosState[idx] & (LOS_EXPLORED << (2*(owner-1))));
|
||||
m_LosState[idx] |= ((LOS_VISIBLE | LOS_EXPLORED) << (2*(owner-1)));
|
||||
explored += !(m_LosState.get(i, j) & ((u32)LosState::EXPLORED << (2*(owner-1))));
|
||||
m_LosState.get(i, j) |= (((int)LosState::VISIBLE | (u32)LosState::EXPLORED) << (2*(owner-1)));
|
||||
}
|
||||
|
||||
MarkVisibilityDirtyAroundTile(owner, i, j);
|
||||
}
|
||||
|
||||
ASSERT(counts[idx] < 65535);
|
||||
counts[idx] = (u16)(counts[idx] + 1); // ignore overflow; the player should never have 64K units
|
||||
ENSURE(counts.get(i, j) < std::numeric_limits<u16>::max());
|
||||
counts.get(i, j) = (u16)(counts.get(i, j) + 1); // ignore overflow; the player should never have 64K units
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the LOS state of tiles within a given horizontal strip (i0,j) to (i1,j) (inclusive).
|
||||
*/
|
||||
inline void LosRemoveStripHelper(u8 owner, i32 i0, i32 i1, i32 j, u16* counts)
|
||||
inline void LosRemoveStripHelper(u8 owner, i32 i0, i32 i1, i32 j, Grid<u16>& counts)
|
||||
{
|
||||
if (i1 < i0)
|
||||
return;
|
||||
|
||||
i32 idx0 = j*m_TerrainVerticesPerSide + i0;
|
||||
i32 idx1 = j*m_TerrainVerticesPerSide + i1;
|
||||
for (i32 idx = idx0; idx <= idx1; ++idx)
|
||||
for (i32 i = i0; i <= i1; ++i)
|
||||
{
|
||||
ASSERT(counts[idx] > 0);
|
||||
counts[idx] = (u16)(counts[idx] - 1);
|
||||
ASSERT(counts.get(i, j) > 0);
|
||||
counts.get(i, j) = (u16)(counts.get(i, j) - 1);
|
||||
|
||||
// Decreasing from non-zero to zero - move from visible+explored to explored
|
||||
if (counts[idx] == 0)
|
||||
if (counts.get(i, j) == 0)
|
||||
{
|
||||
// (If LosIsOffWorld then this is a no-op, so don't bother doing the check)
|
||||
m_LosState[idx] &= ~(LOS_VISIBLE << (2*(owner-1)));
|
||||
m_LosState.get(i, j) &= ~((int)LosState::VISIBLE << (2*(owner-1)));
|
||||
|
||||
i32 i = i0 + idx - idx0;
|
||||
MarkVisibilityDirtyAroundTile(owner, i, j);
|
||||
}
|
||||
}
|
||||
@ -2132,10 +2132,10 @@ public:
|
||||
|
||||
// Mark the LoS tiles around the updated vertex
|
||||
// 1: left-up, 2: right-up, 3: left-down, 4: right-down
|
||||
int n1 = ((j-1)/LOS_TILES_RATIO)*m_LosTilesPerSide + (i-1)/LOS_TILES_RATIO;
|
||||
int n2 = ((j-1)/LOS_TILES_RATIO)*m_LosTilesPerSide + i/LOS_TILES_RATIO;
|
||||
int n3 = (j/LOS_TILES_RATIO)*m_LosTilesPerSide + (i-1)/LOS_TILES_RATIO;
|
||||
int n4 = (j/LOS_TILES_RATIO)*m_LosTilesPerSide + i/LOS_TILES_RATIO;
|
||||
LosTile n1 = PosToLosTilesHelper(i-1, j-1);
|
||||
LosTile n2 = PosToLosTilesHelper(i-1, j);
|
||||
LosTile n3 = PosToLosTilesHelper(i, j-1);
|
||||
LosTile n4 = PosToLosTilesHelper(i, j);
|
||||
|
||||
u16 sharedDirtyVisibilityMask = m_SharedDirtyVisibilityMasks[owner];
|
||||
|
||||
@ -2162,13 +2162,11 @@ public:
|
||||
|
||||
PROFILE("LosUpdateHelper");
|
||||
|
||||
std::vector<u16>& counts = m_LosPlayerCounts.at(owner);
|
||||
Grid<u16>& counts = m_LosPlayerCounts.at(owner);
|
||||
|
||||
// Lazy initialisation of counts:
|
||||
if (counts.empty())
|
||||
counts.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide);
|
||||
|
||||
u16* countsData = &counts[0];
|
||||
if (counts.blank())
|
||||
counts.resize(m_TerrainVerticesPerSide, m_TerrainVerticesPerSide);
|
||||
|
||||
// Compute the circular region as a series of strips.
|
||||
// Rather than quantise pos to vertexes, we do more precise sub-tile computations
|
||||
@ -2233,9 +2231,9 @@ public:
|
||||
i32 i0clamp = std::max(i0, 1);
|
||||
i32 i1clamp = std::min(i1, m_TerrainVerticesPerSide-2);
|
||||
if (adding)
|
||||
LosAddStripHelper(owner, i0clamp, i1clamp, j, countsData);
|
||||
LosAddStripHelper(owner, i0clamp, i1clamp, j, counts);
|
||||
else
|
||||
LosRemoveStripHelper(owner, i0clamp, i1clamp, j, countsData);
|
||||
LosRemoveStripHelper(owner, i0clamp, i1clamp, j, counts);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2251,13 +2249,11 @@ public:
|
||||
|
||||
PROFILE("LosUpdateHelperIncremental");
|
||||
|
||||
std::vector<u16>& counts = m_LosPlayerCounts.at(owner);
|
||||
Grid<u16>& counts = m_LosPlayerCounts.at(owner);
|
||||
|
||||
// Lazy initialisation of counts:
|
||||
if (counts.empty())
|
||||
counts.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide);
|
||||
|
||||
u16* countsData = &counts[0];
|
||||
if (counts.blank())
|
||||
counts.resize(m_TerrainVerticesPerSide, m_TerrainVerticesPerSide);
|
||||
|
||||
// See comments in LosUpdateHelper.
|
||||
// This does exactly the same, except computing the strips for
|
||||
@ -2343,11 +2339,11 @@ public:
|
||||
// and we can just add/remove the entire other strip
|
||||
if (i1clamp_from < i0clamp_from)
|
||||
{
|
||||
LosAddStripHelper(owner, i0clamp_to, i1clamp_to, j, countsData);
|
||||
LosAddStripHelper(owner, i0clamp_to, i1clamp_to, j, counts);
|
||||
}
|
||||
else if (i1clamp_to < i0clamp_to)
|
||||
{
|
||||
LosRemoveStripHelper(owner, i0clamp_from, i1clamp_from, j, countsData);
|
||||
LosRemoveStripHelper(owner, i0clamp_from, i1clamp_from, j, counts);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2360,10 +2356,10 @@ public:
|
||||
// movement speeds), the region between them will be both added and removed,
|
||||
// so we have to do the add first to avoid overflowing to -1 and triggering
|
||||
// assertion failures.)
|
||||
LosAddStripHelper(owner, i0clamp_to, i0clamp_from-1, j, countsData);
|
||||
LosAddStripHelper(owner, i1clamp_from+1, i1clamp_to, j, countsData);
|
||||
LosRemoveStripHelper(owner, i0clamp_from, i0clamp_to-1, j, countsData);
|
||||
LosRemoveStripHelper(owner, i1clamp_to+1, i1clamp_from, j, countsData);
|
||||
LosAddStripHelper(owner, i0clamp_to, i0clamp_from-1, j, counts);
|
||||
LosAddStripHelper(owner, i1clamp_from+1, i1clamp_to, j, counts);
|
||||
LosRemoveStripHelper(owner, i0clamp_from, i0clamp_to-1, j, counts);
|
||||
LosRemoveStripHelper(owner, i1clamp_to+1, i1clamp_from, j, counts);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2448,7 +2444,7 @@ public:
|
||||
continue;
|
||||
|
||||
for (playerIt = players.begin(); playerIt != players.end(); ++playerIt)
|
||||
if (m_LosState[j*m_TerrainVerticesPerSide + i] & (LOS_EXPLORED << (2*((*playerIt)-1))))
|
||||
if (m_LosState.get(i, j) & ((u32)LosState::EXPLORED << (2*((*playerIt)-1))))
|
||||
{
|
||||
exploredVertices += 1;
|
||||
break;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2018 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -68,7 +68,7 @@ public:
|
||||
int currentPlayer = GetSimContext().GetCurrentDisplayedPlayer();
|
||||
|
||||
CmpPtr<ICmpRangeManager> cmpRangeManager(GetSystemEntity());
|
||||
if (!cmpRangeManager || (cmpRangeManager->GetLosVisibility(source, currentPlayer) != ICmpRangeManager::VIS_VISIBLE))
|
||||
if (!cmpRangeManager || (cmpRangeManager->GetLosVisibility(source, currentPlayer) != LosVisibility::VISIBLE))
|
||||
return;
|
||||
|
||||
CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), source);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -88,7 +88,7 @@ public:
|
||||
/**
|
||||
* Cached LOS visibility status.
|
||||
*/
|
||||
ICmpRangeManager::ELosVisibility visibility;
|
||||
LosVisibility visibility;
|
||||
bool visibilityDirty;
|
||||
|
||||
/**
|
||||
@ -404,7 +404,7 @@ void CCmpUnitRenderer::RenderSubmit(SceneCollector& collector, const CFrustum& f
|
||||
if (unit.visibilityDirty)
|
||||
UpdateVisibility(unit);
|
||||
|
||||
if (unit.visibility == ICmpRangeManager::VIS_HIDDEN)
|
||||
if (unit.visibility == LosVisibility::HIDDEN)
|
||||
continue;
|
||||
|
||||
if (!g_AtlasGameLoop->running && !g_RenderingOptions.GetRenderActors() && (unit.flags & ACTOR_ONLY))
|
||||
@ -451,7 +451,7 @@ void CCmpUnitRenderer::UpdateVisibility(SUnit& unit) const
|
||||
// (regardless of whether the LOS system thinks it's visible)
|
||||
CmpPtr<ICmpVisibility> cmpVisibility(unit.entity);
|
||||
if (cmpVisibility && cmpVisibility->GetAlwaysVisible())
|
||||
unit.visibility = ICmpRangeManager::VIS_VISIBLE;
|
||||
unit.visibility = LosVisibility::VISIBLE;
|
||||
else
|
||||
{
|
||||
CmpPtr<ICmpRangeManager> cmpRangeManager(GetSystemEntity());
|
||||
@ -460,12 +460,12 @@ void CCmpUnitRenderer::UpdateVisibility(SUnit& unit) const
|
||||
}
|
||||
}
|
||||
else
|
||||
unit.visibility = ICmpRangeManager::VIS_HIDDEN;
|
||||
unit.visibility = LosVisibility::HIDDEN;
|
||||
|
||||
// Change the visibility of the visual actor's selectable if it has one.
|
||||
CmpPtr<ICmpSelectable> cmpSelectable(unit.entity);
|
||||
if (cmpSelectable)
|
||||
cmpSelectable->SetVisibility(unit.visibility != ICmpRangeManager::VIS_HIDDEN);
|
||||
cmpSelectable->SetVisibility(unit.visibility != LosVisibility::HIDDEN);
|
||||
|
||||
unit.visibilityDirty = false;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -22,13 +22,13 @@
|
||||
#include "simulation2/system/InterfaceScripted.h"
|
||||
|
||||
namespace {
|
||||
std::string VisibilityToString(ICmpRangeManager::ELosVisibility visibility)
|
||||
std::string VisibilityToString(LosVisibility visibility)
|
||||
{
|
||||
switch (visibility)
|
||||
{
|
||||
case ICmpRangeManager::VIS_HIDDEN: return "hidden";
|
||||
case ICmpRangeManager::VIS_FOGGED: return "fogged";
|
||||
case ICmpRangeManager::VIS_VISIBLE: return "visible";
|
||||
case LosVisibility::HIDDEN: return "hidden";
|
||||
case LosVisibility::FOGGED: return "fogged";
|
||||
case LosVisibility::VISIBLE: return "visible";
|
||||
default: return "error"; // should never happen
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -22,6 +22,7 @@
|
||||
#include "maths/FixedVector2D.h"
|
||||
|
||||
#include "simulation2/system/Interface.h"
|
||||
#include "simulation2/helpers/Grid.h"
|
||||
#include "simulation2/helpers/Position.h"
|
||||
#include "simulation2/helpers/Player.h"
|
||||
|
||||
@ -29,6 +30,27 @@
|
||||
|
||||
class FastSpatialSubdivision;
|
||||
|
||||
/**
|
||||
* Since GetVisibility queries are run by the range manager
|
||||
* other code using these must include ICmpRangeManager.h anyways,
|
||||
* so define this enum here (Ideally, it'd be in its own header file,
|
||||
* but adding header file does incur its own compilation time increase).
|
||||
*/
|
||||
enum class LosVisibility : u8
|
||||
{
|
||||
HIDDEN = 0,
|
||||
FOGGED = 1,
|
||||
VISIBLE = 2
|
||||
};
|
||||
|
||||
enum class LosState : u8
|
||||
{
|
||||
UNEXPLORED = 0,
|
||||
EXPLORED = 1,
|
||||
VISIBLE = 2,
|
||||
MASK = 3
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides efficient range-based queries of the game world,
|
||||
* and also LOS-based effects (fog of war).
|
||||
@ -221,22 +243,6 @@ public:
|
||||
*/
|
||||
virtual void SetEntityFlag(entity_id_t ent, const std::string& identifier, bool value) = 0;
|
||||
|
||||
// LOS interface:
|
||||
|
||||
enum ELosState
|
||||
{
|
||||
LOS_UNEXPLORED = 0,
|
||||
LOS_EXPLORED = 1,
|
||||
LOS_VISIBLE = 2,
|
||||
LOS_MASK = 3
|
||||
};
|
||||
|
||||
enum ELosVisibility
|
||||
{
|
||||
VIS_HIDDEN = 0,
|
||||
VIS_FOGGED = 1,
|
||||
VIS_VISIBLE = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* Object providing efficient abstracted access to the LOS state.
|
||||
@ -250,8 +256,8 @@ public:
|
||||
friend class CCmpRangeManager;
|
||||
friend class TestLOSTexture;
|
||||
|
||||
CLosQuerier(u32 playerMask, const std::vector<u32>& data, ssize_t verticesPerSide) :
|
||||
m_Data(&data[0]), m_PlayerMask(playerMask), m_VerticesPerSide(verticesPerSide)
|
||||
CLosQuerier(u32 playerMask, const Grid<u32>& data, ssize_t verticesPerSide) :
|
||||
m_Data(data), m_PlayerMask(playerMask), m_VerticesPerSide(verticesPerSide)
|
||||
{
|
||||
}
|
||||
|
||||
@ -267,7 +273,7 @@ public:
|
||||
return false;
|
||||
|
||||
// Check high bit of each bit-pair
|
||||
if ((m_Data[j*m_VerticesPerSide + i] & m_PlayerMask) & 0xAAAAAAAAu)
|
||||
if ((m_Data.get(i, j) & m_PlayerMask) & 0xAAAAAAAAu)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
@ -282,7 +288,7 @@ public:
|
||||
return false;
|
||||
|
||||
// Check low bit of each bit-pair
|
||||
if ((m_Data[j*m_VerticesPerSide + i] & m_PlayerMask) & 0x55555555u)
|
||||
if ((m_Data.get(i, j) & m_PlayerMask) & 0x55555555u)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
@ -298,7 +304,7 @@ public:
|
||||
ENSURE(i >= 0 && j >= 0 && i < m_VerticesPerSide && j < m_VerticesPerSide);
|
||||
#endif
|
||||
// Check high bit of each bit-pair
|
||||
if ((m_Data[j*m_VerticesPerSide + i] & m_PlayerMask) & 0xAAAAAAAAu)
|
||||
if ((m_Data.get(i, j) & m_PlayerMask) & 0xAAAAAAAAu)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
@ -314,7 +320,7 @@ public:
|
||||
ENSURE(i >= 0 && j >= 0 && i < m_VerticesPerSide && j < m_VerticesPerSide);
|
||||
#endif
|
||||
// Check low bit of each bit-pair
|
||||
if ((m_Data[j*m_VerticesPerSide + i] & m_PlayerMask) & 0x55555555u)
|
||||
if ((m_Data.get(i, j) & m_PlayerMask) & 0x55555555u)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
@ -322,9 +328,12 @@ public:
|
||||
|
||||
private:
|
||||
u32 m_PlayerMask;
|
||||
const u32* m_Data;
|
||||
const Grid<u32>& m_Data;
|
||||
ssize_t m_VerticesPerSide;
|
||||
};
|
||||
//////////////////////////////////////////////////////////////////
|
||||
//// LOS interface below this line ////
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Returns a CLosQuerier for checking whether vertex positions are visible to the given player
|
||||
@ -339,17 +348,17 @@ public:
|
||||
|
||||
/**
|
||||
* Returns the visibility status of the given entity, with respect to the given player.
|
||||
* Returns VIS_HIDDEN if the entity doesn't exist or is not in the world.
|
||||
* Returns LosVisibility::HIDDEN if the entity doesn't exist or is not in the world.
|
||||
* This respects the GetLosRevealAll flag.
|
||||
*/
|
||||
virtual ELosVisibility GetLosVisibility(CEntityHandle ent, player_id_t player) const = 0;
|
||||
virtual ELosVisibility GetLosVisibility(entity_id_t ent, player_id_t player) const = 0;
|
||||
virtual LosVisibility GetLosVisibility(CEntityHandle ent, player_id_t player) const = 0;
|
||||
virtual LosVisibility GetLosVisibility(entity_id_t ent, player_id_t player) const = 0;
|
||||
|
||||
/**
|
||||
* Returns the visibility status of the given position, with respect to the given player.
|
||||
* This respects the GetLosRevealAll flag.
|
||||
*/
|
||||
virtual ELosVisibility GetLosVisibilityPosition(entity_pos_t x, entity_pos_t z, player_id_t player) const = 0;
|
||||
virtual LosVisibility GetLosVisibilityPosition(entity_pos_t x, entity_pos_t z, player_id_t player) const = 0;
|
||||
|
||||
/**
|
||||
* Request the update of the visibility cache of ent at next turn.
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2015 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -35,21 +35,21 @@ public:
|
||||
return m_Script.Call<bool>("IsActivated");
|
||||
}
|
||||
|
||||
virtual ICmpRangeManager::ELosVisibility GetVisibility(player_id_t player, bool isVisible, bool isExplored)
|
||||
virtual LosVisibility GetVisibility(player_id_t player, bool isVisible, bool isExplored)
|
||||
{
|
||||
int visibility = m_Script.Call<int, player_id_t, bool, bool>("GetVisibility", player, isVisible, isExplored);
|
||||
|
||||
switch (visibility)
|
||||
{
|
||||
case ICmpRangeManager::VIS_HIDDEN:
|
||||
return ICmpRangeManager::VIS_HIDDEN;
|
||||
case ICmpRangeManager::VIS_FOGGED:
|
||||
return ICmpRangeManager::VIS_FOGGED;
|
||||
case ICmpRangeManager::VIS_VISIBLE:
|
||||
return ICmpRangeManager::VIS_VISIBLE;
|
||||
case static_cast<int>(LosVisibility::HIDDEN):
|
||||
return LosVisibility::HIDDEN;
|
||||
case static_cast<int>(LosVisibility::FOGGED):
|
||||
return LosVisibility::FOGGED;
|
||||
case static_cast<int>(LosVisibility::VISIBLE):
|
||||
return LosVisibility::VISIBLE;
|
||||
default:
|
||||
LOGERROR("Received the invalid visibility value %d from the Visibility scripted component!", visibility);
|
||||
return ICmpRangeManager::VIS_HIDDEN;
|
||||
return LosVisibility::HIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2015 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -42,7 +42,7 @@ public:
|
||||
*/
|
||||
virtual bool IsActivated() = 0;
|
||||
|
||||
virtual ICmpRangeManager::ELosVisibility GetVisibility(player_id_t player, bool isVisible, bool isExplored) = 0;
|
||||
virtual LosVisibility GetVisibility(player_id_t player, bool isVisible, bool isExplored) = 0;
|
||||
|
||||
virtual bool GetRetainInFog() = 0;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -20,12 +20,19 @@
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "simulation2/serialization/IDeserializer.h"
|
||||
#include "simulation2/serialization/ISerializer.h"
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define GRID_BOUNDS_DEBUG 0
|
||||
#else
|
||||
#define GRID_BOUNDS_DEBUG 1
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
struct SerializedGridCompressed;
|
||||
|
||||
/**
|
||||
* Basic 2D array, intended for storing tile data, plus support for lazy updates
|
||||
* by ICmpObstructionManager.
|
||||
@ -34,32 +41,54 @@
|
||||
template<typename T>
|
||||
class Grid
|
||||
{
|
||||
friend struct SerializedGridCompressed<T>;
|
||||
protected:
|
||||
// Tag-dispatching internal utilities for convenience.
|
||||
struct default_type{};
|
||||
struct is_pod { operator default_type() { return default_type{}; }};
|
||||
struct is_container { operator default_type() { return default_type{}; }};
|
||||
|
||||
// helper to detect value_type
|
||||
template <typename U, typename = int> struct has_value_type : std::false_type { };
|
||||
template <typename U> struct has_value_type <U, decltype(std::declval<typename U::value_type>(), 0)> : std::true_type { };
|
||||
|
||||
template <typename U, typename A, typename B> using if_ = typename std::conditional<U::value, A, B>::type;
|
||||
|
||||
template<typename U>
|
||||
using dispatch = if_< std::is_pod<U>, is_pod,
|
||||
if_<has_value_type<U>, is_container,
|
||||
default_type>>;
|
||||
|
||||
public:
|
||||
Grid() : m_W(0), m_H(0), m_Data(NULL), m_DirtyID(0)
|
||||
Grid() : m_W(0), m_H(0), m_Data(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Grid(u16 w, u16 h) : m_W(w), m_H(h), m_Data(NULL), m_DirtyID(0)
|
||||
Grid(u16 w, u16 h) : m_W(w), m_H(h), m_Data(NULL)
|
||||
{
|
||||
if (m_W || m_H)
|
||||
m_Data = new T[m_W * m_H];
|
||||
reset();
|
||||
resize(w, h);
|
||||
}
|
||||
|
||||
Grid(const Grid& g) : m_W(0), m_H(0), m_Data(NULL), m_DirtyID(0)
|
||||
Grid(const Grid& g) : m_W(0), m_H(0), m_Data(NULL)
|
||||
{
|
||||
*this = g;
|
||||
}
|
||||
|
||||
using value_type = T;
|
||||
public:
|
||||
|
||||
// Ensure that o and this are the same size before calling.
|
||||
void copy_data(T* o, default_type) { std::copy(o, o + m_H*m_W, &m_Data[0]); }
|
||||
void copy_data(T* o, is_pod) { memcpy(m_Data, o, m_W*m_H*sizeof(T)); }
|
||||
|
||||
Grid& operator=(const Grid& g)
|
||||
{
|
||||
if (this == &g)
|
||||
return *this;
|
||||
|
||||
m_DirtyID = g.m_DirtyID;
|
||||
if (m_W == g.m_W && m_H == g.m_H)
|
||||
{
|
||||
memcpy(m_Data, g.m_Data, m_W*m_H*sizeof(T));
|
||||
copy_data(g.m_Data, dispatch<T>{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -69,7 +98,7 @@ public:
|
||||
if (g.m_Data)
|
||||
{
|
||||
m_Data = new T[m_W * m_H];
|
||||
memcpy(m_Data, g.m_Data, m_W*m_H*sizeof(T));
|
||||
copy_data(g.m_Data, dispatch<T>{});
|
||||
}
|
||||
else
|
||||
m_Data = NULL;
|
||||
@ -78,7 +107,6 @@ public:
|
||||
|
||||
void swap(Grid& g)
|
||||
{
|
||||
std::swap(m_DirtyID, g.m_DirtyID);
|
||||
std::swap(m_Data, g.m_Data);
|
||||
std::swap(m_H, g.m_H);
|
||||
std::swap(m_W, g.m_W);
|
||||
@ -89,24 +117,38 @@ public:
|
||||
delete[] m_Data;
|
||||
}
|
||||
|
||||
// Ensure that o and this are the same size before calling.
|
||||
bool compare_data(T* o, default_type) const { return std::equal(&m_Data[0], &m_Data[m_W*m_H], o); }
|
||||
bool compare_data(T* o, is_pod) const { return memcmp(m_Data, o, m_W*m_H*sizeof(T)) == 0; }
|
||||
|
||||
bool operator==(const Grid& g) const
|
||||
{
|
||||
if (!compare_sizes(&g) || m_DirtyID != g.m_DirtyID)
|
||||
if (!compare_sizes(&g))
|
||||
return false;
|
||||
|
||||
return memcmp(m_Data, g.m_Data, m_W*m_H*sizeof(T)) == 0;
|
||||
return compare_data(g.m_Data, dispatch<T>{});
|
||||
}
|
||||
bool operator!=(const Grid& g) const { return !(*this==g); }
|
||||
|
||||
bool blank() const
|
||||
{
|
||||
return m_W == 0 && m_H == 0;
|
||||
}
|
||||
|
||||
bool any_set_in_square(int i0, int j0, int i1, int j1) const
|
||||
u16 width() const { return m_W; };
|
||||
u16 height() const { return m_H; };
|
||||
|
||||
|
||||
bool _any_set_in_square(int, int, int, int, default_type) const
|
||||
{
|
||||
#if GRID_BOUNDS_DEBUG
|
||||
static_assert(!std::is_same<T, T>::value, "Not implemented.");
|
||||
return false; // Fix warnings.
|
||||
}
|
||||
bool _any_set_in_square(int i0, int j0, int i1, int j1, is_pod) const
|
||||
{
|
||||
#if GRID_BOUNDS_DEBUG
|
||||
ENSURE(i0 >= 0 && j0 >= 0 && i1 <= m_W && j1 <= m_H);
|
||||
#endif
|
||||
#endif
|
||||
for (int j = j0; j < j1; ++j)
|
||||
{
|
||||
int sum = 0;
|
||||
@ -118,10 +160,30 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool any_set_in_square(int i0, int j0, int i1, int j1) const
|
||||
{
|
||||
return _any_set_in_square(i0, j0, i1, j1, dispatch<T>{});
|
||||
}
|
||||
|
||||
void reset_data(default_type) { std::fill(&m_Data[0], &m_Data[m_H*m_W], T{}); }
|
||||
void reset_data(is_pod) { memset(m_Data, 0, m_W*m_H*sizeof(T)); }
|
||||
|
||||
void reset()
|
||||
{
|
||||
if (m_Data)
|
||||
memset(m_Data, 0, m_W*m_H*sizeof(T));
|
||||
reset_data(dispatch<T>{});
|
||||
}
|
||||
|
||||
void resize(u16 w, u16 h)
|
||||
{
|
||||
if (m_Data)
|
||||
delete[] m_Data;
|
||||
m_W = w;
|
||||
m_H = h;
|
||||
if (m_W || m_H)
|
||||
m_Data = new T[m_W * m_H];
|
||||
ENSURE(m_Data);
|
||||
reset();
|
||||
}
|
||||
|
||||
// Add two grids of the same size
|
||||
@ -154,6 +216,20 @@ public:
|
||||
m_Data[j*m_W + i] = value;
|
||||
}
|
||||
|
||||
T& operator[](std::pair<u16, u16> coords) { return get(coords.first, coords.second); }
|
||||
T& get(std::pair<u16, u16> coords) { return get(coords.first, coords.second); }
|
||||
|
||||
T& operator[](std::pair<u16, u16> coords) const { return get(coords.first, coords.second); }
|
||||
T& get(std::pair<u16, u16> coords) const { return get(coords.first, coords.second); }
|
||||
|
||||
T& get(int i, int j)
|
||||
{
|
||||
#if GRID_BOUNDS_DEBUG
|
||||
ENSURE(0 <= i && i < m_W && 0 <= j && j < m_H);
|
||||
#endif
|
||||
return m_Data[j*m_W + i];
|
||||
}
|
||||
|
||||
T& get(int i, int j) const
|
||||
{
|
||||
#if GRID_BOUNDS_DEBUG
|
||||
@ -170,10 +246,62 @@ public:
|
||||
|
||||
u16 m_W, m_H;
|
||||
T* m_Data;
|
||||
|
||||
size_t m_DirtyID; // if this is < the id maintained by ICmpObstructionManager then it needs to be updated
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serialize a grid, applying a simple RLE compression that is assumed efficient.
|
||||
*/
|
||||
template<typename ELEM>
|
||||
struct SerializedGridCompressed
|
||||
{
|
||||
template<typename T>
|
||||
void operator()(ISerializer& serialize, const char* name, Grid<T>& value)
|
||||
{
|
||||
size_t len = value.m_H * value.m_W;
|
||||
serialize.NumberU16_Unbounded("width", value.m_W);
|
||||
serialize.NumberU16_Unbounded("height", value.m_H);
|
||||
if (len == 0)
|
||||
return;
|
||||
u32 count = 1;
|
||||
T prevVal = value.m_Data[0];
|
||||
for (size_t i = 1; i < len; ++i)
|
||||
{
|
||||
if (prevVal == value.m_Data[i])
|
||||
{
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
serialize.NumberU32_Unbounded("#", count);
|
||||
ELEM()(serialize, name, prevVal);
|
||||
count = 1;
|
||||
prevVal = value.m_Data[i];
|
||||
}
|
||||
serialize.NumberU32_Unbounded("#", count);
|
||||
ELEM()(serialize, name, prevVal);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void operator()(IDeserializer& deserialize, const char* name, Grid<T>& value)
|
||||
{
|
||||
u16 w, h;
|
||||
deserialize.NumberU16_Unbounded("width", w);
|
||||
deserialize.NumberU16_Unbounded("height", h);
|
||||
u32 len = h * w;
|
||||
value.resize(w, h);
|
||||
for (size_t i = 0; i < len;)
|
||||
{
|
||||
u32 count;
|
||||
deserialize.NumberU32_Unbounded("#", count);
|
||||
T el;
|
||||
ELEM()(deserialize, name, el);
|
||||
std::fill(&value.m_Data[i], &value.m_Data[i+count], el);
|
||||
i += count;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Similar to Grid, except optimised for sparse usage (the grid is subdivided into
|
||||
* buckets whose contents are only initialised on demand, to save on memset cost).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -79,7 +79,7 @@ entity_id_t EntitySelection::PickEntityAtPoint(CSimulation2& simulation, const C
|
||||
continue;
|
||||
|
||||
// Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
|
||||
if (cmpRangeManager->GetLosVisibility(handle, player) == ICmpRangeManager::VIS_HIDDEN)
|
||||
if (cmpRangeManager->GetLosVisibility(handle, player) == LosVisibility::HIDDEN)
|
||||
continue;
|
||||
|
||||
return handle.GetId();
|
||||
@ -126,7 +126,7 @@ bool CheckEntityInRect(CEntityHandle handle, const CCamera& camera, int sx0, int
|
||||
static bool CheckEntityVisibleAndInRect(CEntityHandle handle, CmpPtr<ICmpRangeManager> cmpRangeManager, const CCamera& camera, int sx0, int sy0, int sx1, int sy1, player_id_t player, bool allowEditorSelectables)
|
||||
{
|
||||
// Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
|
||||
if (cmpRangeManager->GetLosVisibility(handle, player) == ICmpRangeManager::VIS_HIDDEN)
|
||||
if (cmpRangeManager->GetLosVisibility(handle, player) == LosVisibility::HIDDEN)
|
||||
return false;
|
||||
|
||||
return CheckEntityInRect(handle, camera, sx0, sy0, sx1, sy1, allowEditorSelectables);
|
||||
@ -224,7 +224,7 @@ std::vector<entity_id_t> EntitySelection::PickSimilarEntities(CSimulation2& simu
|
||||
|
||||
// Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
|
||||
// In this case, the checking is done to avoid selecting garrisoned units
|
||||
if (cmpRangeManager->GetLosVisibility(handle, owner) == ICmpRangeManager::VIS_HIDDEN)
|
||||
if (cmpRangeManager->GetLosVisibility(handle, owner) == LosVisibility::HIDDEN)
|
||||
continue;
|
||||
|
||||
// Ignore entities not owned by 'owner'
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -30,6 +30,24 @@
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
template<typename ELEM>
|
||||
struct SerializeArray
|
||||
{
|
||||
template<typename T, size_t N>
|
||||
void operator()(ISerializer& serialize, const char* name, std::array<T, N>& value)
|
||||
{
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
ELEM()(serialize, name, value[i]);
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
void operator()(IDeserializer& deserialize, const char* name, std::array<T, N>& value)
|
||||
{
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
ELEM()(deserialize, name, value[i]);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ELEM>
|
||||
struct SerializeVector
|
||||
{
|
||||
@ -53,54 +71,7 @@ struct SerializeVector
|
||||
{
|
||||
T el;
|
||||
ELEM()(deserialize, name, el);
|
||||
value.push_back(el);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ELEM>
|
||||
struct SerializeRepetitiveVector
|
||||
{
|
||||
template<typename T>
|
||||
void operator()(ISerializer& serialize, const char* name, std::vector<T>& value)
|
||||
{
|
||||
size_t len = value.size();
|
||||
serialize.NumberU32_Unbounded("length", (u32)len);
|
||||
if (len == 0)
|
||||
return;
|
||||
u32 count = 1;
|
||||
T prevVal = value[0];
|
||||
for (size_t i = 1; i < len; ++i)
|
||||
{
|
||||
if (prevVal == value[i])
|
||||
{
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
serialize.NumberU32_Unbounded("#", count);
|
||||
ELEM()(serialize, name, prevVal);
|
||||
count = 1;
|
||||
prevVal = value[i];
|
||||
}
|
||||
serialize.NumberU32_Unbounded("#", count);
|
||||
ELEM()(serialize, name, prevVal);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void operator()(IDeserializer& deserialize, const char* name, std::vector<T>& value)
|
||||
{
|
||||
value.clear();
|
||||
u32 len;
|
||||
deserialize.NumberU32_Unbounded("length", len);
|
||||
value.reserve(len); // TODO: watch out for out-of-memory
|
||||
for (size_t i = 0; i < len;)
|
||||
{
|
||||
u32 count;
|
||||
deserialize.NumberU32_Unbounded("#", count);
|
||||
T el;
|
||||
ELEM()(deserialize, name, el);
|
||||
i += count;
|
||||
value.insert(value.end(), count, el);
|
||||
value.emplace_back(el);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -18,6 +18,7 @@
|
||||
#include "lib/self_test.h"
|
||||
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
#include "simulation2/helpers/Grid.h"
|
||||
#include "simulation2/serialization/DebugSerializer.h"
|
||||
#include "simulation2/serialization/SerializeTemplates.h"
|
||||
|
||||
@ -28,6 +29,19 @@
|
||||
class TestSerializeTemplates : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test_Debug_array()
|
||||
{
|
||||
ScriptInterface script("Test", "Test", g_ScriptRuntime);
|
||||
std::stringstream stream;
|
||||
|
||||
CDebugSerializer serialize(script, stream);
|
||||
std::array<u32, 6> value = {
|
||||
3, 0, 1, 4, 1, 5
|
||||
};
|
||||
SerializeArray<SerializeU32_Unbounded>()(serialize, "E", value);
|
||||
TS_ASSERT_STR_EQUALS(stream.str(), "E: 3\nE: 0\nE: 1\nE: 4\nE: 1\nE: 5\n");
|
||||
}
|
||||
|
||||
void test_Debug_vector()
|
||||
{
|
||||
ScriptInterface script("Test", "Test", g_ScriptRuntime);
|
||||
@ -53,4 +67,23 @@ public:
|
||||
SerializeSet<SerializeU32_Unbounded>()(serialize, "E", value);
|
||||
TS_ASSERT_STR_EQUALS(stream.str(), "size: 5\nE: 0\nE: 1\nE: 3\nE: 4\nE: 5\n");
|
||||
}
|
||||
|
||||
void test_Debug_grid()
|
||||
{
|
||||
ScriptInterface script("Test", "Test", g_ScriptRuntime);
|
||||
std::stringstream stream;
|
||||
|
||||
CDebugSerializer serialize(script, stream);
|
||||
Grid<u16> value;
|
||||
value.resize(3,2);
|
||||
// Checkerboard pattern.
|
||||
for (u8 j = 0; j < value.height(); ++j)
|
||||
for (u8 i = 0; i < value.width(); ++i)
|
||||
value.set(i, j, ((i % 2) + (j % 2)) % 2);
|
||||
|
||||
SerializedGridCompressed<SerializeU16_Unbounded>()(serialize, "E", value);
|
||||
TS_ASSERT_STR_EQUALS(stream.str(), "width: 3\nheight: 2\n"
|
||||
"#: 1\nE: 0\n#: 1\nE: 1\n#: 1\nE: 0\n"
|
||||
"#: 1\nE: 1\n#: 1\nE: 0\n#: 1\nE: 1\n");
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user