Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cache pathfinding results to speed up calculations #1541

Merged
merged 40 commits into from
Sep 9, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
875ddd5
Add new files
idshibanov Aug 26, 2020
0da1c0b
Convert to class
idshibanov Aug 26, 2020
71a24c0
Move world files into new folder
idshibanov Aug 26, 2020
a8e1699
Update node structure
idshibanov Aug 26, 2020
2678b21
Add VS include directory
idshibanov Aug 26, 2020
91e15ec
Plug in pathfinder
idshibanov Aug 27, 2020
5155a28
Instant distance prediction
idshibanov Aug 27, 2020
c3a62e4
Test new pathfinding
idshibanov Sep 4, 2020
944ab10
Share tile passable call
idshibanov Sep 4, 2020
cd3fdc7
Fix move cost
idshibanov Sep 4, 2020
bf23401
Move passability rules to World class
idshibanov Sep 5, 2020
ec117e8
Fix the destination object logic
idshibanov Sep 5, 2020
706278e
Merge branch 'master' of https://github.com/ihhub/fheroes2.git into p…
idshibanov Sep 5, 2020
a8e635a
Remove unused code
idshibanov Sep 6, 2020
e4e3be7
Code style correction
ihhub Sep 7, 2020
bbcbb8b
Make clang-format happy
ihhub Sep 7, 2020
f5cf3d4
Address feedback
idshibanov Sep 7, 2020
cd4d988
Fix pathing bugs
idshibanov Sep 8, 2020
47046fd
Fix monster protection logic
idshibanov Sep 8, 2020
c0dfd18
Remove old code
idshibanov Sep 8, 2020
7ac6b19
Remove unused variable
ihhub Sep 8, 2020
1b2868d
Remove unused parameter
idshibanov Sep 8, 2020
5aa1683
Merge branch 'pathfinding-array' of git@github.com:idshibanov/fheroes…
idshibanov Sep 8, 2020
7bc5f9c
Fix boat check
idshibanov Sep 8, 2020
7be946c
Small speedup
ihhub Sep 8, 2020
27ebac8
Speed up monster protection logic
idshibanov Sep 9, 2020
023c775
Merge branch 'pathfinding-array' of git@github.com:idshibanov/fheroes…
idshibanov Sep 9, 2020
42482c2
Simplify old road logic
idshibanov Sep 9, 2020
af4d5cc
Don't need direction for road calculation
idshibanov Sep 9, 2020
aaf3a73
Set road boolean
idshibanov Sep 9, 2020
7e9a94f
Replace Direction::Get with faster Maps::GetDirection
idshibanov Sep 9, 2020
65ecebf
Add optimized version of Maps::isValidDirection
idshibanov Sep 9, 2020
eb9ee13
Unwrap loop in Maps::GetTilesUnderProtection
idshibanov Sep 9, 2020
c16e125
Optimize World::isValidPath
idshibanov Sep 9, 2020
6f66b8b
Cache direction offset
idshibanov Sep 9, 2020
03f10d3
Fix first step move cost
idshibanov Sep 9, 2020
2b417c0
Remove unused limit param
idshibanov Sep 9, 2020
f3237e8
Revert to use passable_disable
idshibanov Sep 9, 2020
1ce26fd
Formatting
idshibanov Sep 9, 2020
7b6a5ba
Use parent class method
ihhub Sep 9, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Move passability rules to World class
  • Loading branch information
idshibanov committed Sep 5, 2020
commit bf234019226347f2b05c97602bdff890f7dd31f7
2 changes: 0 additions & 2 deletions src/fheroes2/heroes/route.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,6 @@ namespace Route
bool hide;
};

bool PassableFromToTile( s32 from, s32 to, int direct, s32 dst, bool fromWater );

StreamBase & operator<<( StreamBase &, const Step & );
StreamBase & operator<<( StreamBase &, const Path & );
StreamBase & operator>>( StreamBase &, Step & );
Expand Down
2 changes: 1 addition & 1 deletion src/fheroes2/heroes/route_pathfind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ bool PassableToTile( const Maps::Tiles & toTile, int direct, s32 dst, bool fromW
return true;
}

bool Route::PassableFromToTile( s32 from, s32 to, int direct, s32 dst, bool fromWater )
bool PassableFromToTile( s32 from, s32 to, int direct, s32 dst, bool fromWater )
{
const Maps::Tiles & fromTile = world.GetTiles( from );
const Maps::Tiles & toTile = world.GetTiles( to );
Expand Down
6 changes: 2 additions & 4 deletions src/fheroes2/maps/maps_tiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1590,16 +1590,14 @@ void Maps::Tiles::RedrawPassable( Surface & dst ) const
const Point mp = Maps::GetPoint( GetIndex() );

if ( area.GetVisibleTileROI() & mp ) {
if ( 0 == tile_passable || DIRECTION_ALL != tile_passable ) {
Surface sf = PassableViewSurface( tile_passable );

if ( passable_disable ) {
Text text( GetString( passable_disable ), Font::SMALL );
if ( test_value ) {
Text text( GetString( test_value ), Font::SMALL );
text.Blit( 13, 13, sf );
}

area.BlitOnTile( dst, sf, 0, 0, mp );
}
}
#endif
}
Expand Down
2 changes: 2 additions & 0 deletions src/fheroes2/maps/maps_tiles.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,8 @@ namespace Maps
static void UpdateAbandoneMineSprite( Tiles & );
static void FixedPreload( Tiles & );

u16 test_value = 0;

private:
TilesAddon * FindFlags( void );
void CorrectFlags32( u32 index, bool );
Expand Down
3 changes: 3 additions & 0 deletions src/fheroes2/world/world.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,9 @@ class World : protected Size
MapObjectSimple * GetMapObject( u32 uid );
void RemoveMapObject( const MapObjectSimple * );

bool isTileUnderProtection( int to, int dst );
bool isFinalTile( const Maps::Tiles & toTile, bool fromWater ) const;
bool isValidPath( int index, int direction ) const;
uint32_t getDistance( int from, int to, uint32_t skill );
std::list<Route::Step> getPath( int from, int to, uint32_t skill, bool ignoreObjects = true );

Expand Down
102 changes: 96 additions & 6 deletions src/fheroes2/world/world_pathfinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,96 @@ std::list<Route::Step> Pathfinder::buildPath( int from, int target, uint8_t skil
return path;
}

bool World::isTileUnderProtection( int to, int dst )
{
const MapsIndexes & monsters = Maps::GetTilesUnderProtection( to );
return monsters.size() && monsters.end() == std::find( monsters.begin(), monsters.end(), dst );
}

bool World::isFinalTile( const Maps::Tiles & toTile, bool fromWater ) const
{
const bool toWater = toTile.isWater();
const int object = toTile.GetObject();

if ( object == MP2::OBJ_HEROES || object == MP2::OBJ_MONSTER )
return true;

if ( MP2::isPickupObject( object ) || MP2::isActionObject( object, fromWater ) )
return true;

if ( fromWater && !toTile.isWater() ) {
switch ( toTile.GetObject() ) {
case MP2::OBJ_BOAT:
case MP2::OBJ_MONSTER:
case MP2::OBJ_HEROES:
return false;

case MP2::OBJ_COAST:
return true;

default:
break;
}
}
else if ( !fromWater && toTile.isWater() ) {
switch ( toTile.GetObject() ) {
case MP2::OBJ_BOAT:
return true;

case MP2::OBJ_HEROES:
return true;

default:
break;
}
}
return false;
}

bool World::isValidPath(int index, int direction) const
{
const Maps::Tiles & fromTile = GetTiles( index );
const Maps::Tiles & toTile = GetTiles( Maps::GetDirectionIndex( index, direction ) );
const bool fromWater = fromTile.isWater();

// check corner water/coast
if ( fromWater ) {
switch ( direction ) {
case Direction::TOP_LEFT:
if ( !GetTiles( Maps::GetDirectionIndex( index, Direction::TOP ) ).isWater()
|| !GetTiles( Maps::GetDirectionIndex( index, Direction::LEFT ) ).isWater() )
return false;
break;

case Direction::TOP_RIGHT:
if ( !GetTiles( Maps::GetDirectionIndex( index, Direction::TOP ) ).isWater()
|| !GetTiles( Maps::GetDirectionIndex( index, Direction::RIGHT ) ).isWater() )
return false;
break;

case Direction::BOTTOM_RIGHT:
if ( !GetTiles( Maps::GetDirectionIndex( index, Direction::BOTTOM ) ).isWater()
|| !GetTiles( Maps::GetDirectionIndex( index, Direction::RIGHT ) ).isWater() )
return false;
break;

case Direction::BOTTOM_LEFT:
if ( !GetTiles( Maps::GetDirectionIndex( index, Direction::BOTTOM ) ).isWater()
|| !GetTiles( Maps::GetDirectionIndex( index, Direction::LEFT ) ).isWater() )
return false;
break;

default:
break;
}
}

if ( !fromTile.isPassable( direction, fromWater, false ) )
return false;

return toTile.isPassable( Direction::Reflect( direction ), fromWater, false );
}

bool Pathfinder::isBlockedByObject( int from, int target )
{
int currentNode = target;
Expand Down Expand Up @@ -127,6 +217,7 @@ uint32_t Pathfinder::getMovementPenalty( int from, int target, int direction, ui
// Destination is optional
void Pathfinder::evaluateMap( int start, uint8_t skill, int destination )
{
const Directions directions = Direction::All();
const bool fromWater = world.GetTiles( start ).isWater();
const int width = world.w();
const int height = world.h();
Expand All @@ -143,14 +234,13 @@ void Pathfinder::evaluateMap( int start, uint8_t skill, int destination )
size_t lastProcessedNode = 0;
while ( lastProcessedNode != nodesToExplore.size() ) {
const int currentNodeIdx = nodesToExplore[lastProcessedNode];
for ( uint8_t direction = 0; direction < 8; ++direction ) {
const int dirBitmask = GetDirectionBitmask( direction );
if ( Maps::isValidDirection( currentNodeIdx, dirBitmask ) ) {
const int newIndex = Maps::GetDirectionIndex( currentNodeIdx, dirBitmask );
for ( auto it = directions.begin(); it != directions.end(); ++it ) {
if ( Maps::isValidDirection( currentNodeIdx, *it ) ) {
const int newIndex = Maps::GetDirectionIndex( currentNodeIdx, *it );
Maps::Tiles & newTile = world.GetTiles( newIndex );

uint32_t moveCost = _cache[currentNodeIdx]._cost + getMovementPenalty( currentNodeIdx, newIndex, skill );
if ( Route::PassableFromToTile( currentNodeIdx, newIndex, dirBitmask, destination, fromWater ) ) {
uint32_t moveCost = _cache[currentNodeIdx]._cost + getMovementPenalty( currentNodeIdx, newIndex, *it, skill );
if ( world.isValidPath( currentNodeIdx, *it ) ) {
if ( _cache[newIndex]._from == -1 || _cache[newIndex]._cost > moveCost ) {
_cache[newIndex]._from = currentNodeIdx;
_cache[newIndex]._cost = moveCost;
Expand Down