Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Index: source/simulation2/components/CCmpTerritoryManager.cpp
- ===================================================================
- --- source/simulation2/components/CCmpTerritoryManager.cpp (revision 14692)
- +++ source/simulation2/components/CCmpTerritoryManager.cpp (working copy)
- @@ -59,6 +59,8 @@
- virtual void ProcessTile(ssize_t i, ssize_t j);
- };
- +static const int FALLOFF = 256;
- +
- class CCmpTerritoryManager : public ICmpTerritoryManager
- {
- public:
- @@ -84,6 +86,7 @@
- float m_BorderThickness;
- float m_BorderSeparation;
- +
- // Player ID in bits 0-5 (TERRITORY_PLAYER_MASK);
- // connected flag in bit 6 (TERRITORY_CONNECTED_MASK);
- // processed flag in bit 7 (TERRITORY_PROCESSED_MASK)
- @@ -279,26 +282,52 @@
- typedef PriorityQueueHeap<std::pair<u16, u16>, u32, std::greater<u32> > OpenQueue;
- -static void ProcessNeighbour(u32 falloff, u16 i, u16 j, u32 pg, bool diagonal,
- - Grid<u32>& grid, OpenQueue& queue, const Grid<u8>& costGrid)
- +/**
- + * Compute the tile indexes on the grid nearest to a given point
- + */
- +static void NearestTile(entity_pos_t x, entity_pos_t z, u16& i, u16& j, u16 w, u16 h)
- {
- - u32 dg = falloff * costGrid.get(i, j);
- + i = (u16)clamp((x / (int)TERRAIN_TILE_SIZE).ToInt_RoundToZero(), 0, w-1);
- + j = (u16)clamp((z / (int)TERRAIN_TILE_SIZE).ToInt_RoundToZero(), 0, h-1);
- +}
- +
- +/**
- + * Returns the position of the center of the given tile
- + */
- +static void TileCenter(u16 i, u16 j, entity_pos_t& x, entity_pos_t& z)
- +{
- + x = entity_pos_t::FromInt(i*(int)TERRAIN_TILE_SIZE + (int)TERRAIN_TILE_SIZE/2);
- + z = entity_pos_t::FromInt(j*(int)TERRAIN_TILE_SIZE + (int)TERRAIN_TILE_SIZE/2);
- +}
- +
- +static void ProcessNeighbour(u16 i, u16 j, u32 pg, bool diagonal,
- + Grid<u32>& grid, OpenQueue& queue, const Grid<u8>& costGrid, Grid<u32>& territoryExtenderGrid)
- +{
- + u32 dg = FALLOFF * costGrid.get(i, j);
- if (diagonal)
- dg = (dg * 362) / 256;
- + u32 g;
- // Stop if new cost g=pg-dg is not better than previous value for that tile
- // (arranged to avoid underflow if pg < dg)
- if (pg <= grid.get(i, j) + dg)
- - return;
- + {
- + if (!territoryExtenderGrid.get(i, j))
- + return;
- + // the tile was set by another entity. Add it to the queue anyway, but with the current weight
- + g = territoryExtenderGrid.get(i, j);
- + }
- + else
- + {
- + g = pg - dg; // cost to this tile = cost to predecessor - falloff from predecessor
- + }
- - u32 g = pg - dg; // cost to this tile = cost to predecessor - falloff from predecessor
- -
- grid.set(i, j, g);
- OpenQueue::Item tile = { std::make_pair(i, j), g };
- queue.push(tile);
- }
- -static void FloodFill(Grid<u32>& grid, Grid<u8>& costGrid, OpenQueue& openTiles, u32 falloff)
- +static void FloodFill(Grid<u32>& grid, Grid<u8>& costGrid, OpenQueue& openTiles, Grid<u32>& territoryExtenderGrid)
- {
- u16 tilesW = grid.m_W;
- u16 tilesH = grid.m_H;
- @@ -311,21 +340,21 @@
- u16 x = tile.id.first;
- u16 z = tile.id.second;
- if (x > 0)
- - ProcessNeighbour(falloff, (u16)(x-1), z, tile.rank, false, grid, openTiles, costGrid);
- + ProcessNeighbour((u16)(x-1), z, tile.rank, false, grid, openTiles, costGrid, territoryExtenderGrid);
- if (x < tilesW-1)
- - ProcessNeighbour(falloff, (u16)(x+1), z, tile.rank, false, grid, openTiles, costGrid);
- + ProcessNeighbour((u16)(x+1), z, tile.rank, false, grid, openTiles, costGrid, territoryExtenderGrid);
- if (z > 0)
- - ProcessNeighbour(falloff, x, (u16)(z-1), tile.rank, false, grid, openTiles, costGrid);
- + ProcessNeighbour(x, (u16)(z-1), tile.rank, false, grid, openTiles, costGrid, territoryExtenderGrid);
- if (z < tilesH-1)
- - ProcessNeighbour(falloff, x, (u16)(z+1), tile.rank, false, grid, openTiles, costGrid);
- + ProcessNeighbour(x, (u16)(z+1), tile.rank, false, grid, openTiles, costGrid, territoryExtenderGrid);
- if (x > 0 && z > 0)
- - ProcessNeighbour(falloff, (u16)(x-1), (u16)(z-1), tile.rank, true, grid, openTiles, costGrid);
- + ProcessNeighbour((u16)(x-1), (u16)(z-1), tile.rank, true, grid, openTiles, costGrid, territoryExtenderGrid);
- if (x > 0 && z < tilesH-1)
- - ProcessNeighbour(falloff, (u16)(x-1), (u16)(z+1), tile.rank, true, grid, openTiles, costGrid);
- + ProcessNeighbour((u16)(x-1), (u16)(z+1), tile.rank, true, grid, openTiles, costGrid, territoryExtenderGrid);
- if (x < tilesW-1 && z > 0)
- - ProcessNeighbour(falloff, (u16)(x+1), (u16)(z-1), tile.rank, true, grid, openTiles, costGrid);
- + ProcessNeighbour((u16)(x+1), (u16)(z-1), tile.rank, true, grid, openTiles, costGrid, territoryExtenderGrid);
- if (x < tilesW-1 && z < tilesH-1)
- - ProcessNeighbour(falloff, (u16)(x+1), (u16)(z+1), tile.rank, true, grid, openTiles, costGrid);
- + ProcessNeighbour((u16)(x+1), (u16)(z+1), tile.rank, true, grid, openTiles, costGrid, territoryExtenderGrid);
- }
- }
- @@ -380,7 +409,6 @@
- // Split influence entities into per-player lists, ignoring any with invalid properties
- std::map<player_id_t, std::vector<entity_id_t> > influenceEntities;
- - std::vector<entity_id_t> rootInfluenceEntities;
- for (CComponentManager::InterfaceList::iterator it = influences.begin(); it != influences.end(); ++it)
- {
- // Ignore any with no weight or radius (to avoid divide-by-zero later)
- @@ -401,25 +429,20 @@
- if (owner > TERRITORY_PLAYER_MASK)
- continue;
- - // Ignore if invalid position
- + // check valid position
- CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), it->first);
- - if (!cmpPosition || !cmpPosition->IsInWorld())
- - continue;
- -
- - influenceEntities[owner].push_back(it->first);
- -
- - if (cmpTerritoryInfluence->IsRoot())
- - rootInfluenceEntities.push_back(it->first);
- + if (cmpPosition && cmpPosition->IsInWorld())
- + influenceEntities[owner].push_back(it->first);
- }
- // For each player, store the sum of influences on each tile
- std::vector<std::pair<player_id_t, Grid<u32> > > playerGrids;
- - // TODO: this is a large waste of memory; we don't really need to store
- - // all the intermediate grids
- for (std::map<player_id_t, std::vector<entity_id_t> >::iterator it = influenceEntities.begin(); it != influenceEntities.end(); ++it)
- {
- Grid<u32> playerGrid(tilesW, tilesH);
- + Grid<u32> territoryExtenderGrid(tilesW, tilesH);
- + OpenQueue openTiles;
- std::vector<entity_id_t>& ents = it->second;
- for (std::vector<entity_id_t>::iterator eit = ents.begin(); eit != ents.end(); ++eit)
- @@ -426,33 +449,32 @@
- {
- // Compute the influence map of the current entity, then add it to the player grid
- - Grid<u32> entityGrid(tilesW, tilesH);
- -
- CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), *eit);
- CFixedVector2D pos = cmpPosition->GetPosition2D();
- - u16 i = (u16)clamp((pos.X / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity(), 0, tilesW-1);
- - u16 j = (u16)clamp((pos.Y / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity(), 0, tilesH-1);
- + u16 i, j;
- + NearestTile(pos.X, pos.Y, i, j, tilesW, tilesH);
- CmpPtr<ICmpTerritoryInfluence> cmpTerritoryInfluence(GetSimContext(), *eit);
- - u32 weight = cmpTerritoryInfluence->GetWeight();
- - u32 radius = cmpTerritoryInfluence->GetRadius() / TERRAIN_TILE_SIZE;
- - u32 falloff = weight / radius; // earlier check for GetRadius() == 0 prevents divide-by-zero
- + u32 radius = cmpTerritoryInfluence->GetRadius() * FALLOFF / TERRAIN_TILE_SIZE;
- - // TODO: we should have some maximum value on weight, to avoid overflow
- + // TODO: we should have some maximum value on radius, to avoid overflow
- // when doing all the sums
- // Initialise the tile under the entity
- - entityGrid.set(i, j, weight);
- - OpenQueue openTiles;
- - OpenQueue::Item tile = { std::make_pair((u16)i, (i16)j), weight };
- - openTiles.push(tile);
- -
- - // Expand influences outwards
- - FloodFill(entityGrid, influenceGrid, openTiles, falloff);
- -
- - // TODO: we should do a sparse grid and only add the non-zero regions, for performance
- - playerGrid.add(entityGrid);
- + if (cmpTerritoryInfluence->IsRoot())
- + {
- + playerGrid.set(i, j, radius);
- + OpenQueue::Item tile = { std::make_pair((u16)i, (i16)j), radius };
- + openTiles.push(tile);
- + }
- + else
- + {
- + // if it's only a territory extender, store it in a separate grid
- + // and don't visit the tiles by default
- + territoryExtenderGrid.set(i, j, radius);
- + }
- }
- + FloodFill(playerGrid, influenceGrid, openTiles, territoryExtenderGrid);
- playerGrids.push_back(std::make_pair(it->first, playerGrid));
- }
- @@ -469,90 +491,15 @@
- if (w > bestWeight)
- {
- player_id_t id = playerGrids[k].first;
- - m_Territories->set(i, j, (u8)id);
- + m_Territories->set(i, j, (u8)id | TERRITORY_CONNECTED_MASK);
- bestWeight = w;
- }
- }
- }
- }
- -
- - // Detect territories connected to a 'root' influence (typically a civ center)
- - // belonging to their player, and mark them with the connected flag
- - for (std::vector<entity_id_t>::iterator it = rootInfluenceEntities.begin(); it != rootInfluenceEntities.end(); ++it)
- - {
- - // (These components must be valid else the entities wouldn't be added to this list)
- - CmpPtr<ICmpOwnership> cmpOwnership(GetSimContext(), *it);
- - CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), *it);
- -
- - CFixedVector2D pos = cmpPosition->GetPosition2D();
- - u16 i = (u16)clamp((pos.X / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity(), 0, tilesW-1);
- - u16 j = (u16)clamp((pos.Y / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity(), 0, tilesH-1);
- -
- - u8 owner = (u8)cmpOwnership->GetOwner();
- -
- - if (m_Territories->get(i, j) != owner)
- - continue;
- -
- - // TODO: would be nice to refactor some of the many flood fill
- - // algorithms in this component
- -
- - Grid<u8>& grid = *m_Territories;
- -
- - u16 maxi = (u16)(grid.m_W-1);
- - u16 maxj = (u16)(grid.m_H-1);
- -
- - std::vector<std::pair<u16, u16> > tileStack;
- -
- -#define MARK_AND_PUSH(i, j) STMT(grid.set(i, j, owner | TERRITORY_CONNECTED_MASK); tileStack.push_back(std::make_pair(i, j)); )
- -
- - MARK_AND_PUSH(i, j);
- - while (!tileStack.empty())
- - {
- - int ti = tileStack.back().first;
- - int tj = tileStack.back().second;
- - tileStack.pop_back();
- -
- - if (ti > 0 && grid.get(ti-1, tj) == owner)
- - MARK_AND_PUSH(ti-1, tj);
- - if (ti < maxi && grid.get(ti+1, tj) == owner)
- - MARK_AND_PUSH(ti+1, tj);
- - if (tj > 0 && grid.get(ti, tj-1) == owner)
- - MARK_AND_PUSH(ti, tj-1);
- - if (tj < maxj && grid.get(ti, tj+1) == owner)
- - MARK_AND_PUSH(ti, tj+1);
- -
- - if (ti > 0 && tj > 0 && grid.get(ti-1, tj-1) == owner)
- - MARK_AND_PUSH(ti-1, tj-1);
- - if (ti > 0 && tj < maxj && grid.get(ti-1, tj+1) == owner)
- - MARK_AND_PUSH(ti-1, tj+1);
- - if (ti < maxi && tj > 0 && grid.get(ti+1, tj-1) == owner)
- - MARK_AND_PUSH(ti+1, tj-1);
- - if (ti < maxi && tj < maxj && grid.get(ti+1, tj+1) == owner)
- - MARK_AND_PUSH(ti+1, tj+1);
- - }
- -
- -#undef MARK_AND_PUSH
- - }
- }
- -/**
- - * Compute the tile indexes on the grid nearest to a given point
- - */
- -static void NearestTile(entity_pos_t x, entity_pos_t z, u16& i, u16& j, u16 w, u16 h)
- -{
- - i = (u16)clamp((x / (int)TERRAIN_TILE_SIZE).ToInt_RoundToZero(), 0, w-1);
- - j = (u16)clamp((z / (int)TERRAIN_TILE_SIZE).ToInt_RoundToZero(), 0, h-1);
- -}
- -/**
- - * Returns the position of the center of the given tile
- - */
- -static void TileCenter(u16 i, u16 j, entity_pos_t& x, entity_pos_t& z)
- -{
- - x = entity_pos_t::FromInt(i*(int)TERRAIN_TILE_SIZE + (int)TERRAIN_TILE_SIZE/2);
- - z = entity_pos_t::FromInt(j*(int)TERRAIN_TILE_SIZE + (int)TERRAIN_TILE_SIZE/2);
- -}
- -
- // TODO: would be nice not to duplicate those two functions from CCmpObstructionManager.cpp
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement