5 #include "../command/common.qh"
7 void pathlib_deletepath(entity start)
11 e = findchainentity(owner, start);
20 //#define PATHLIB_NODEEXPIRE 0.05
21 const float PATHLIB_NODEEXPIRE = 20;
23 void dumpnode(entity n)
25 n.is_path_node = false;
30 entity pathlib_mknode(vector where,entity parent)
34 node = pathlib_nodeatpoint(where);
38 mark_error(where, 60);
45 node.think = SUB_Remove;
46 node.nextthink = time + PATHLIB_NODEEXPIRE;
47 node.is_path_node = true;
48 node.owner = openlist;
49 node.path_prev = parent;
52 setsize(node, '0 0 0', '0 0 0');
54 setorigin(node, where);
55 node.medium = pointcontents(where);
56 pathlib_showsquare(where, 1 ,15);
64 float pathlib_makenode_adaptive(entity parent,vector start, vector to, vector goal,float cost)
67 float h,g,f,doedge = 0;
70 ++pathlib_searched_cnt;
72 if(inwater(parent.origin))
74 LOG_TRACE("FromWater\n");
75 pathlib_expandnode = pathlib_expandnode_box;
76 pathlib_movenode = pathlib_swimnode;
82 LOG_TRACE("ToWater\n");
83 pathlib_expandnode = pathlib_expandnode_box;
84 pathlib_movenode = pathlib_walknode;
88 LOG_TRACE("LandToLoand\n");
89 //if(edge_check(parent.origin))
92 pathlib_expandnode = pathlib_expandnode_star;
93 pathlib_movenode = pathlib_walknode;
98 node = pathlib_nodeatpoint(to);
101 LOG_TRACE("NodeAtPoint\n");
104 if(node.owner == openlist)
106 h = pathlib_heuristic(node.origin,goal);
107 g = pathlib_cost(parent,node.origin,cost);
110 if(node.pathlib_node_g > g)
112 node.pathlib_node_h = h;
113 node.pathlib_node_g = g;
114 node.pathlib_node_f = f;
116 node.path_prev = parent;
120 best_open_node = node;
121 else if(best_open_node.pathlib_node_f > node.pathlib_node_f)
122 best_open_node = node;
128 where = pathlib_movenode(parent.origin, to, 0);
130 if (!pathlib_movenode_goodnode)
132 //pathlib_showsquare(where, 0 ,30);
133 //pathlib_showsquare(parent.origin, 1 ,30);
134 LOG_TRACE("pathlib_movenode_goodnode = 0\n");
138 //pathlib_showsquare(where, 1 ,30);
140 if(pathlib_nodeatpoint(where))
142 LOG_TRACE("NAP WHERE :",vtos(where),"\n");
143 LOG_TRACE("not NAP TO:",vtos(to),"\n");
144 LOG_TRACE("NAP-NNAP:",ftos(vlen(to-where)),"\n\n");
150 if (!tile_check(where))
152 LOG_TRACE("tile_check fail\n");
153 pathlib_showsquare(where, 0 ,30);
158 h = pathlib_heuristic(where,goal);
159 g = pathlib_cost(parent,where,cost);
163 node = findradius(where,pathlib_gridsize * 0.5);
166 if(node.is_path_node == true)
169 if(node.owner == openlist)
171 if(node.pathlib_node_g > g)
173 //pathlib_movenode(where,node.origin,0);
174 //if(pathlib_movenode_goodnode)
176 //mark_error(node.origin + '0 0 128',30);
177 node.pathlib_node_h = h;
178 node.pathlib_node_g = g;
179 node.pathlib_node_f = f;
180 node.path_prev = parent;
185 best_open_node = node;
186 else if(best_open_node.pathlib_node_f > node.pathlib_node_f)
187 best_open_node = node;
196 node = pathlib_mknode(where, parent);
197 node.pathlib_node_h = h;
198 node.pathlib_node_g = g;
199 node.pathlib_node_f = f;
202 best_open_node = node;
203 else if(best_open_node.pathlib_node_f > node.pathlib_node_f)
204 best_open_node = node;
209 entity pathlib_getbestopen()
216 ++pathlib_bestcash_hits;
217 pathlib_bestcash_saved += pathlib_open_cnt;
219 return best_open_node;
222 node = findchainentity(owner,openlist);
229 ++pathlib_bestopen_seached;
230 if(node.pathlib_node_f < bestnode.pathlib_node_f)
239 void pathlib_close_node(entity node,vector goal)
242 if(node.owner == closedlist)
244 LOG_TRACE("Pathlib: Tried to close a closed node!\n");
248 if(node == best_open_node)
249 best_open_node = world;
251 ++pathlib_closed_cnt;
254 node.owner = closedlist;
256 if(vlen(node.origin - goal) <= pathlib_gridsize)
260 goalmove = pathlib_walknode(node.origin,goal,1);
261 if(pathlib_movenode_goodnode)
264 pathlib_foundgoal = true;
269 void pathlib_cleanup()
271 best_open_node = world;
277 node = findfloat(world,is_path_node, true);
281 node.owner = openlist;
282 node.pathlib_node_g = 0;
283 node.pathlib_node_h = 0;
284 node.pathlib_node_f = 0;
285 node.path_prev = world;
289 node = findfloat(node,is_path_node, true);
303 float Cosine_Interpolate(float a, float b, float x)
308 f = (1 - cos(ft)) * 0.5;
310 return a*(1-f) + b*f;
313 float buildpath_nodefilter_directional(vector n,vector c,vector p)
317 d2 = normalize(p - c);
318 d1 = normalize(c - n);
320 if(vlen(d1-d2) < 0.25)
329 float buildpath_nodefilter_moveskip(vector n,vector c,vector p)
331 pathlib_walknode(p,n,1);
332 if(pathlib_movenode_goodnode)
338 float buildpath_nodefilter_none(vector n,vector c,vector p)
343 entity path_build(entity next, vector where, entity prev, entity start)
348 if(buildpath_nodefilter)
349 if(buildpath_nodefilter(next.origin,where,prev.origin))
355 path.path_next = next;
357 setorigin(path,where);
360 path.classname = "path_end";
364 path.classname = "path_start";
366 path.classname = "path_node";
372 entity pathlib_astar(vector from,vector to)
374 entity path, start, end, open, n, ln;
375 float ptime, ftime, ctime;
377 ptime = gettime(GETTIME_REALTIME);
378 pathlib_starttime = ptime;
382 // Select water<->land capable node make/link
383 pathlib_makenode = pathlib_makenode_adaptive;
385 // Select XYZ cost estimate
386 //pathlib_heuristic = pathlib_h_diagonal3;
387 pathlib_heuristic = pathlib_h_diagonal;
389 // Select distance + waterfactor cost
390 pathlib_cost = pathlib_g_euclidean_water;
392 // Select star expander
393 pathlib_expandnode = pathlib_expandnode_star;
395 // Select walk simulation movement test
396 pathlib_movenode = pathlib_walknode;
398 // Filter final nodes by direction
399 buildpath_nodefilter = buildpath_nodefilter_directional;
401 // Filter tiles with cross pattern
402 tile_check = tile_check_cross;
404 // If the start is in water we need diffrent settings
407 // Select volumetric node expaner
408 pathlib_expandnode = pathlib_expandnode_box;
410 // Water movement test
411 pathlib_movenode = pathlib_swimnode;
418 closedlist = spawn();
420 pathlib_closed_cnt = 0;
421 pathlib_open_cnt = 0;
422 pathlib_made_cnt = 0;
423 pathlib_merge_cnt = 0;
424 pathlib_searched_cnt = 0;
425 pathlib_bestopen_seached = 0;
426 pathlib_bestcash_hits = 0;
427 pathlib_bestcash_saved = 0;
429 pathlib_gridsize = 128;
430 pathlib_movecost = pathlib_gridsize;
431 pathlib_movecost_diag = vlen(('1 1 0' * pathlib_gridsize));
432 pathlib_movecost_waterfactor = 25000000;
433 pathlib_foundgoal = 0;
435 movenode_boxmax = self.maxs * 1.1;
436 movenode_boxmin = self.mins * 1.1;
438 movenode_stepsize = pathlib_gridsize * 0.25;
440 tile_check_size = pathlib_gridsize * 0.5;
441 tile_check_up = '0 0 2' * pathlib_gridsize;
442 tile_check_up = '0 0 128';
443 tile_check_down = '0 0 3' * pathlib_gridsize;
444 tile_check_down = '0 0 256';
446 //movenode_stepup = '0 0 128';
447 movenode_stepup = '0 0 36';
448 movenode_maxdrop = '0 0 512';
449 //movenode_maxdrop = '0 0 512';
450 movenode_boxup = '0 0 72';
452 from.x = fsnap(from.x, pathlib_gridsize);
453 from.y = fsnap(from.y, pathlib_gridsize);
456 to.x = fsnap(to.x, pathlib_gridsize);
457 to.y = fsnap(to.y, pathlib_gridsize);
460 LOG_TRACE("AStar init\n");
461 path = pathlib_mknode(from, world);
462 pathlib_close_node(path, to);
463 if(pathlib_foundgoal)
465 LOG_TRACE("AStar: Goal found on first node!\n");
469 open.classname = "path_end";
470 setorigin(open,path.origin);
477 if(pathlib_expandnode(path, from, to) <= 0)
479 LOG_TRACE("AStar path fail.\n");
485 best_open_node = pathlib_getbestopen();
487 pathlib_close_node(best_open_node, to);
488 if(inwater(n.origin))
489 pathlib_expandnode_box(n, from, to);
491 pathlib_expandnode_star(n, from, to);
493 while(pathlib_open_cnt)
495 if((gettime(GETTIME_REALTIME) - pathlib_starttime) > pathlib_maxtime)
497 LOG_TRACE("Path took to long to compute!\n");
498 LOG_TRACE("Nodes - created: ", ftos(pathlib_made_cnt),"\n");
499 LOG_TRACE("Nodes - open: ", ftos(pathlib_open_cnt),"\n");
500 LOG_TRACE("Nodes - merged: ", ftos(pathlib_merge_cnt),"\n");
501 LOG_TRACE("Nodes - closed: ", ftos(pathlib_closed_cnt),"\n");
507 best_open_node = pathlib_getbestopen();
509 pathlib_close_node(best_open_node,to);
511 if(inwater(n.origin))
512 pathlib_expandnode_box(n,from,to);
514 pathlib_expandnode(n,from,to);
516 if(pathlib_foundgoal)
518 LOG_TRACE("Target found. Rebuilding and filtering path...\n");
519 ftime = gettime(GETTIME_REALTIME);
520 ptime = ftime - ptime;
522 start = path_build(world,path.origin,world,world);
523 end = path_build(world,goal_node.origin,world,start);
527 for(open = goal_node; open.path_prev != path; open = open.path_prev)
529 n = path_build(ln,open.origin,open.path_prev,start);
535 ftime = gettime(GETTIME_REALTIME) - ftime;
537 ctime = gettime(GETTIME_REALTIME);
539 ctime = gettime(GETTIME_REALTIME) - ctime;
543 pathlib_showpath2(start);
545 LOG_TRACE("Time used - pathfinding: ", ftos(ptime),"\n");
546 LOG_TRACE("Time used - rebuild & filter: ", ftos(ftime),"\n");
547 LOG_TRACE("Time used - cleanup: ", ftos(ctime),"\n");
548 LOG_TRACE("Time used - total: ", ftos(ptime + ftime + ctime),"\n");
549 LOG_TRACE("Time used - # frames: ", ftos(ceil((ptime + ftime + ctime) / sys_frametime)),"\n\n");
550 LOG_TRACE("Nodes - created: ", ftos(pathlib_made_cnt),"\n");
551 LOG_TRACE("Nodes - open: ", ftos(pathlib_open_cnt),"\n");
552 LOG_TRACE("Nodes - merged: ", ftos(pathlib_merge_cnt),"\n");
553 LOG_TRACE("Nodes - closed: ", ftos(pathlib_closed_cnt),"\n");
554 LOG_TRACE("Nodes - searched: ", ftos(pathlib_searched_cnt),"\n");
555 LOG_TRACE("Nodes bestopen searched: ", ftos(pathlib_bestopen_seached),"\n");
556 LOG_TRACE("Nodes bestcash - hits: ", ftos(pathlib_bestcash_hits),"\n");
557 LOG_TRACE("Nodes bestcash - save: ", ftos(pathlib_bestcash_saved),"\n");
558 LOG_TRACE("AStar done.\n");
564 LOG_TRACE("A* Faild to find a path! Try a smaller gridsize.\n");