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)
|
}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)
|
// 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)
|
#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)
|
/// Generic comparator for a min-heap. (minimum value at top)
|
||||||
/// Returns -1 if v1 is smaller, 1 if v2 is smaller, 0 if equal.
|
/// 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_channel(); //should be called after final guild
|
||||||
do_final_vending();
|
do_final_vending();
|
||||||
do_final_buyingstore();
|
do_final_buyingstore();
|
||||||
|
do_final_path();
|
||||||
|
|
||||||
map_db->destroy(map_db, map_db_final);
|
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);
|
add_timer_interval(gettick()+1000, map_freeblock_timer, 0, 0, 60*1000);
|
||||||
|
|
||||||
map_do_init_msg();
|
map_do_init_msg();
|
||||||
|
do_init_path();
|
||||||
do_init_atcommand();
|
do_init_atcommand();
|
||||||
do_init_battle();
|
do_init_battle();
|
||||||
do_init_instance();
|
do_init_instance();
|
||||||
|
@ -39,6 +39,9 @@ struct path_node {
|
|||||||
|
|
||||||
/// Binary heap of path nodes
|
/// Binary heap of path nodes
|
||||||
BHEAP_STRUCT_DECL(node_heap, struct path_node*);
|
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)
|
/// Comparator for binary heap of path nodes (minimum cost at top)
|
||||||
#define NODE_MINTOPCMP(i,j) ((i)->f_cost - (j)->f_cost)
|
#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},
|
{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).
|
* Find the closest reachable cell, 'count' cells away from (x0,y0) in direction (dx,dy).
|
||||||
* Income after the coordinates of the blow
|
* 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: &1 = easy path search only
|
||||||
* flag: &2 = call path_search_long instead
|
* flag: &2 = call path_search_long instead
|
||||||
* cell: type of obstruction to check for
|
* 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)
|
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
|
// A* (A-star) pathfinding
|
||||||
// We always use A* for finding walkpaths because it is what game client uses.
|
// 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.
|
// Easy pathfinding cuts corners of non-walkable cells, but client always walks around it.
|
||||||
|
BHEAP_RESET(g_open_set);
|
||||||
BHEAP_STRUCT_VAR(node_heap, open_set); // 'Open' set
|
|
||||||
|
|
||||||
// FIXME: This array is too small to ensure all paths shorter than MAX_WALKPATH
|
// 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).
|
// 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].f_cost = heuristic(x0, y0, x1, y1);
|
||||||
tp[i].flag = SET_OPEN;
|
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(;;) {
|
for(;;) {
|
||||||
int e = 0; // error flag
|
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;
|
int g_cost;
|
||||||
|
|
||||||
if (BHEAP_LENGTH(open_set) == 0) {
|
if (BHEAP_LENGTH(g_open_set) == 0) {
|
||||||
BHEAP_CLEAR(open_set);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
current = BHEAP_PEEK(open_set); // Look for the lowest f_cost node in the 'open' set
|
current = BHEAP_PEEK(g_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
|
BHEAP_POP2(g_open_set, NODE_MINTOPCMP, swap_ptr); // Remove it from 'open' set
|
||||||
|
|
||||||
x = current->x;
|
x = current->x;
|
||||||
y = current->y;
|
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
|
current->flag = SET_CLOSED; // Add current node to 'closed' set
|
||||||
|
|
||||||
if (x == x1 && y == y1) {
|
if (x == x1 && y == y1) {
|
||||||
BHEAP_CLEAR(open_set);
|
|
||||||
break;
|
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))
|
#define chk_dir(d) ((allowed_dirs & (d)) == (d))
|
||||||
// Process neighbors of current node
|
// Process neighbors of current node
|
||||||
if (chk_dir(PATH_DIR_SOUTH|PATH_DIR_EAST) && !map_getcellp(md, x+1, y-1, cell))
|
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))
|
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))
|
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))
|
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))
|
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))
|
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))
|
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))
|
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
|
#undef chk_dir
|
||||||
if (e) {
|
if (e) {
|
||||||
BHEAP_CLEAR(open_set);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,4 +66,9 @@ unsigned int distance(int dx, int dy);
|
|||||||
bool check_distance_client(int dx, int dy, int distance);
|
bool check_distance_client(int dx, int dy, int distance);
|
||||||
int distance_client(int dx, int dy);
|
int distance_client(int dx, int dy);
|
||||||
|
|
||||||
|
//
|
||||||
|
void do_init_path();
|
||||||
|
void do_final_path();
|
||||||
|
|
||||||
|
|
||||||
#endif /* _PATH_H_ */
|
#endif /* _PATH_H_ */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user