Merge pull request #1241 from wilkemeyer/optimize/pathsearch-memallocations
Optimized path_search() by reducing amount of allocations per call. Thanks to @wilkemeyer!
This commit is contained in:
commit
0da7136ae7
@ -1338,6 +1338,15 @@ void linkdb_foreach (struct linkdb_node** head, LinkDBFunc func, ...);
|
||||
}while(0)
|
||||
|
||||
|
||||
/// Resets the length and clears content, so the vector is empty
|
||||
///
|
||||
/// @param __vec Vector
|
||||
#define VECTOR_RESET(__vec) \
|
||||
if( VECTOR_LENGTH(__vec) > 0 ) { \
|
||||
memset(VECTOR_DATA(__vec), 0, (VECTOR_LENGTH(__vec)*sizeof(VECTOR_FIRST(__vec)))); /* clear data */ \
|
||||
} \
|
||||
VECTOR_LENGTH(__vec) = 0; /* clear current length */
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Binary heap library based on defines. (uses the vector defines above)
|
||||
@ -1622,6 +1631,11 @@ void linkdb_foreach (struct linkdb_node** head, LinkDBFunc func, ...);
|
||||
#define BHEAP_CLEAR(__heap) VECTOR_CLEAR(__heap)
|
||||
|
||||
|
||||
/// Resets the binary heap and clears content so it can be treated as empty
|
||||
///
|
||||
/// @parm __heap Binary heap
|
||||
#define BHEAP_RESET(__heap) VECTOR_RESET(__heap)
|
||||
|
||||
|
||||
/// Generic comparator for a min-heap. (minimum value at top)
|
||||
/// Returns -1 if v1 is smaller, 1 if v2 is smaller, 0 if equal.
|
||||
|
@ -4411,6 +4411,7 @@ void do_final(void)
|
||||
do_final_channel(); //should be called after final guild
|
||||
do_final_vending();
|
||||
do_final_buyingstore();
|
||||
do_final_path();
|
||||
|
||||
map_db->destroy(map_db, map_db_final);
|
||||
|
||||
@ -4716,6 +4717,7 @@ int do_init(int argc, char *argv[])
|
||||
add_timer_interval(gettick()+1000, map_freeblock_timer, 0, 0, 60*1000);
|
||||
|
||||
map_do_init_msg();
|
||||
do_init_path();
|
||||
do_init_atcommand();
|
||||
do_init_battle();
|
||||
do_init_instance();
|
||||
|
@ -39,6 +39,9 @@ struct path_node {
|
||||
|
||||
/// Binary heap of path nodes
|
||||
BHEAP_STRUCT_DECL(node_heap, struct path_node*);
|
||||
static BHEAP_STRUCT_VAR(node_heap, g_open_set); // use static heap for all path calculations
|
||||
// it get's initialized in do_init_path, freed in do_final_path.
|
||||
|
||||
|
||||
/// Comparator for binary heap of path nodes (minimum cost at top)
|
||||
#define NODE_MINTOPCMP(i,j) ((i)->f_cost - (j)->f_cost)
|
||||
@ -58,6 +61,16 @@ static const unsigned char walk_choices [3][3] =
|
||||
{DIR_SOUTHWEST,DIR_SOUTH,DIR_SOUTHEAST},
|
||||
};
|
||||
|
||||
|
||||
void do_init_path(){
|
||||
BHEAP_INIT(g_open_set); // [fwi]: BHEAP_STRUCT_VAR already initialized the heap, this is rudendant & just for code-conformance/readability
|
||||
}//
|
||||
|
||||
void do_final_path(){
|
||||
BHEAP_CLEAR(g_open_set);
|
||||
}//
|
||||
|
||||
|
||||
/*==========================================
|
||||
* Find the closest reachable cell, 'count' cells away from (x0,y0) in direction (dx,dy).
|
||||
* Income after the coordinates of the blow
|
||||
@ -249,6 +262,8 @@ static int add_path(struct node_heap *heap, struct path_node *tp, int16 x, int16
|
||||
* flag: &1 = easy path search only
|
||||
* flag: &2 = call path_search_long instead
|
||||
* cell: type of obstruction to check for
|
||||
*
|
||||
* Note: uses global g_open_set, therefore this method can't be called in parallel or recursivly.
|
||||
*------------------------------------------*/
|
||||
bool path_search(struct walkpath_data *wpd, int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int flag, cell_chk cell)
|
||||
{
|
||||
@ -313,8 +328,7 @@ bool path_search(struct walkpath_data *wpd, int16 m, int16 x0, int16 y0, int16 x
|
||||
// A* (A-star) pathfinding
|
||||
// We always use A* for finding walkpaths because it is what game client uses.
|
||||
// Easy pathfinding cuts corners of non-walkable cells, but client always walks around it.
|
||||
|
||||
BHEAP_STRUCT_VAR(node_heap, open_set); // 'Open' set
|
||||
BHEAP_RESET(g_open_set);
|
||||
|
||||
// FIXME: This array is too small to ensure all paths shorter than MAX_WALKPATH
|
||||
// can be found without node collision: calc_index(node1) = calc_index(node2).
|
||||
@ -337,7 +351,7 @@ bool path_search(struct walkpath_data *wpd, int16 m, int16 x0, int16 y0, int16 x
|
||||
tp[i].f_cost = heuristic(x0, y0, x1, y1);
|
||||
tp[i].flag = SET_OPEN;
|
||||
|
||||
heap_push_node(&open_set, &tp[i]); // Put start node to 'open' set
|
||||
heap_push_node(&g_open_set, &tp[i]); // Put start node to 'open' set
|
||||
|
||||
for(;;) {
|
||||
int e = 0; // error flag
|
||||
@ -352,13 +366,12 @@ bool path_search(struct walkpath_data *wpd, int16 m, int16 x0, int16 y0, int16 x
|
||||
|
||||
int g_cost;
|
||||
|
||||
if (BHEAP_LENGTH(open_set) == 0) {
|
||||
BHEAP_CLEAR(open_set);
|
||||
if (BHEAP_LENGTH(g_open_set) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
current = BHEAP_PEEK(open_set); // Look for the lowest f_cost node in the 'open' set
|
||||
BHEAP_POP2(open_set, NODE_MINTOPCMP, swap_ptr); // Remove it from 'open' set
|
||||
current = BHEAP_PEEK(g_open_set); // Look for the lowest f_cost node in the 'open' set
|
||||
BHEAP_POP2(g_open_set, NODE_MINTOPCMP, swap_ptr); // Remove it from 'open' set
|
||||
|
||||
x = current->x;
|
||||
y = current->y;
|
||||
@ -367,7 +380,6 @@ bool path_search(struct walkpath_data *wpd, int16 m, int16 x0, int16 y0, int16 x
|
||||
current->flag = SET_CLOSED; // Add current node to 'closed' set
|
||||
|
||||
if (x == x1 && y == y1) {
|
||||
BHEAP_CLEAR(open_set);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -379,24 +391,23 @@ bool path_search(struct walkpath_data *wpd, int16 m, int16 x0, int16 y0, int16 x
|
||||
#define chk_dir(d) ((allowed_dirs & (d)) == (d))
|
||||
// Process neighbors of current node
|
||||
if (chk_dir(PATH_DIR_SOUTH|PATH_DIR_EAST) && !map_getcellp(md, x+1, y-1, cell))
|
||||
e += add_path(&open_set, tp, x+1, y-1, g_cost + MOVE_DIAGONAL_COST, current, heuristic(x+1, y-1, x1, y1)); // (x+1, y-1) 5
|
||||
e += add_path(&g_open_set, tp, x+1, y-1, g_cost + MOVE_DIAGONAL_COST, current, heuristic(x+1, y-1, x1, y1)); // (x+1, y-1) 5
|
||||
if (chk_dir(PATH_DIR_EAST))
|
||||
e += add_path(&open_set, tp, x+1, y, g_cost + MOVE_COST, current, heuristic(x+1, y, x1, y1)); // (x+1, y) 6
|
||||
e += add_path(&g_open_set, tp, x+1, y, g_cost + MOVE_COST, current, heuristic(x+1, y, x1, y1)); // (x+1, y) 6
|
||||
if (chk_dir(PATH_DIR_NORTH|PATH_DIR_EAST) && !map_getcellp(md, x+1, y+1, cell))
|
||||
e += add_path(&open_set, tp, x+1, y+1, g_cost + MOVE_DIAGONAL_COST, current, heuristic(x+1, y+1, x1, y1)); // (x+1, y+1) 7
|
||||
e += add_path(&g_open_set, tp, x+1, y+1, g_cost + MOVE_DIAGONAL_COST, current, heuristic(x+1, y+1, x1, y1)); // (x+1, y+1) 7
|
||||
if (chk_dir(PATH_DIR_NORTH))
|
||||
e += add_path(&open_set, tp, x, y+1, g_cost + MOVE_COST, current, heuristic(x, y+1, x1, y1)); // (x, y+1) 0
|
||||
e += add_path(&g_open_set, tp, x, y+1, g_cost + MOVE_COST, current, heuristic(x, y+1, x1, y1)); // (x, y+1) 0
|
||||
if (chk_dir(PATH_DIR_NORTH|PATH_DIR_WEST) && !map_getcellp(md, x-1, y+1, cell))
|
||||
e += add_path(&open_set, tp, x-1, y+1, g_cost + MOVE_DIAGONAL_COST, current, heuristic(x-1, y+1, x1, y1)); // (x-1, y+1) 1
|
||||
e += add_path(&g_open_set, tp, x-1, y+1, g_cost + MOVE_DIAGONAL_COST, current, heuristic(x-1, y+1, x1, y1)); // (x-1, y+1) 1
|
||||
if (chk_dir(PATH_DIR_WEST))
|
||||
e += add_path(&open_set, tp, x-1, y, g_cost + MOVE_COST, current, heuristic(x-1, y, x1, y1)); // (x-1, y) 2
|
||||
e += add_path(&g_open_set, tp, x-1, y, g_cost + MOVE_COST, current, heuristic(x-1, y, x1, y1)); // (x-1, y) 2
|
||||
if (chk_dir(PATH_DIR_SOUTH|PATH_DIR_WEST) && !map_getcellp(md, x-1, y-1, cell))
|
||||
e += add_path(&open_set, tp, x-1, y-1, g_cost + MOVE_DIAGONAL_COST, current, heuristic(x-1, y-1, x1, y1)); // (x-1, y-1) 3
|
||||
e += add_path(&g_open_set, tp, x-1, y-1, g_cost + MOVE_DIAGONAL_COST, current, heuristic(x-1, y-1, x1, y1)); // (x-1, y-1) 3
|
||||
if (chk_dir(PATH_DIR_SOUTH))
|
||||
e += add_path(&open_set, tp, x, y-1, g_cost + MOVE_COST, current, heuristic(x, y-1, x1, y1)); // (x, y-1) 4
|
||||
e += add_path(&g_open_set, tp, x, y-1, g_cost + MOVE_COST, current, heuristic(x, y-1, x1, y1)); // (x, y-1) 4
|
||||
#undef chk_dir
|
||||
if (e) {
|
||||
BHEAP_CLEAR(open_set);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -66,4 +66,9 @@ unsigned int distance(int dx, int dy);
|
||||
bool check_distance_client(int dx, int dy, int distance);
|
||||
int distance_client(int dx, int dy);
|
||||
|
||||
//
|
||||
void do_init_path();
|
||||
void do_final_path();
|
||||
|
||||
|
||||
#endif /* _PATH_H_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user