5 #include "../command/common.qh"
7 void pathlib_deletepath(entity start)
9 FOREACH_ENTITY_ENT(owner, start,
11 setthink(it, SUB_Remove);
16 //#define PATHLIB_NODEEXPIRE 0.05
17 const float PATHLIB_NODEEXPIRE = 20;
19 void dumpnode(entity n)
21 n.is_path_node = false;
22 setthink(n, SUB_Remove);
27 void pathlib_showpath(entity start);
28 void pathlib_showpath2(entity path);
29 void pathlib_showsquare(vector where,float goodsquare,float _lifetime);
33 entity pathlib_mknode(vector where,entity parent)
37 node = pathlib_nodeatpoint(where);
41 mark_error(where, 60);
48 setthink(node, SUB_Remove);
49 node.nextthink = time + PATHLIB_NODEEXPIRE;
50 node.is_path_node = true;
51 node.owner = openlist;
52 node.path_prev = parent;
55 setsize(node, '0 0 0', '0 0 0');
57 setorigin(node, where);
58 node.medium = pointcontents(where);
60 pathlib_showsquare(where, 1 ,15);
68 float pathlib_makenode_adaptive(entity parent,vector start, vector to, vector goal,float cost)
71 float h,g,f,doedge = 0;
74 ++pathlib_searched_cnt;
76 if(inwater(parent.origin))
78 LOG_TRACE("FromWater");
79 pathlib_expandnode = pathlib_expandnode_box;
80 pathlib_movenode = pathlib_swimnode;
87 pathlib_expandnode = pathlib_expandnode_box;
88 pathlib_movenode = pathlib_walknode;
92 LOG_TRACE("LandToLoand");
93 //if(edge_check(parent.origin))
96 pathlib_expandnode = pathlib_expandnode_star;
97 pathlib_movenode = pathlib_walknode;
102 node = pathlib_nodeatpoint(to);
105 LOG_TRACE("NodeAtPoint");
108 if(node.owner == openlist)
110 h = pathlib_heuristic(node.origin,goal);
111 g = pathlib_cost(parent,node.origin,cost);
114 if(node.pathlib_node_g > g)
116 node.pathlib_node_h = h;
117 node.pathlib_node_g = g;
118 node.pathlib_node_f = f;
120 node.path_prev = parent;
124 best_open_node = node;
125 else if(best_open_node.pathlib_node_f > node.pathlib_node_f)
126 best_open_node = node;
132 where = pathlib_movenode(parent, parent.origin, to, 0);
134 if (!pathlib_movenode_goodnode)
136 //pathlib_showsquare(where, 0 ,30);
137 //pathlib_showsquare(parent.origin, 1 ,30);
138 LOG_TRACE("pathlib_movenode_goodnode = 0");
142 //pathlib_showsquare(where, 1 ,30);
144 if(pathlib_nodeatpoint(where))
146 LOG_TRACE("NAP WHERE :",vtos(where));
147 LOG_TRACE("not NAP TO:",vtos(to));
148 LOG_TRACE("NAP-NNAP:",ftos(vlen(to-where)));
154 if (!tile_check(parent, where))
156 LOG_TRACE("tile_check fail");
158 pathlib_showsquare(where, 0 ,30);
164 h = pathlib_heuristic(where,goal);
165 g = pathlib_cost(parent,where,cost);
169 node = findradius(where,pathlib_gridsize * 0.5);
172 if(node.is_path_node == true)
175 if(node.owner == openlist)
177 if(node.pathlib_node_g > g)
179 //pathlib_movenode(node, where,node.origin,0);
180 //if(pathlib_movenode_goodnode)
182 //mark_error(node.origin + '0 0 128',30);
183 node.pathlib_node_h = h;
184 node.pathlib_node_g = g;
185 node.pathlib_node_f = f;
186 node.path_prev = parent;
191 best_open_node = node;
192 else if(best_open_node.pathlib_node_f > node.pathlib_node_f)
193 best_open_node = node;
202 node = pathlib_mknode(where, parent);
203 node.pathlib_node_h = h;
204 node.pathlib_node_g = g;
205 node.pathlib_node_f = f;
208 best_open_node = node;
209 else if(best_open_node.pathlib_node_f > node.pathlib_node_f)
210 best_open_node = node;
215 entity pathlib_getbestopen()
219 ++pathlib_bestcash_hits;
220 pathlib_bestcash_saved += pathlib_open_cnt;
222 return best_open_node;
225 entity bestnode = NULL;
226 FOREACH_ENTITY_ENT(owner, openlist,
228 ++pathlib_bestopen_searched;
230 if(!bestnode || it.pathlib_node_f < bestnode.pathlib_node_f)
237 void pathlib_close_node(entity node,vector goal)
240 if(node.owner == closedlist)
242 LOG_TRACE("Pathlib: Tried to close a closed node!");
246 if(node == best_open_node)
247 best_open_node = NULL;
249 ++pathlib_closed_cnt;
252 node.owner = closedlist;
254 if(vdist(node.origin - goal, <=, pathlib_gridsize))
258 goalmove = pathlib_walknode(node, node.origin, goal, 1);
259 if(pathlib_movenode_goodnode)
262 pathlib_foundgoal = true;
267 void pathlib_cleanup()
269 best_open_node = NULL;
275 node = findfloat(NULL,is_path_node, true);
279 node.owner = openlist;
280 node.pathlib_node_g = 0;
281 node.pathlib_node_h = 0;
282 node.pathlib_node_f = 0;
283 node.path_prev = NULL;
287 node = findfloat(node,is_path_node, true);
301 float Cosine_Interpolate(float a, float b, float x)
306 f = (1 - cos(ft)) * 0.5;
308 return a*(1-f) + b*f;
311 float buildpath_nodefilter_directional(vector n,vector c,vector p)
315 d2 = normalize(p - c);
316 d1 = normalize(c - n);
318 if(vdist(d1 - d2, <, 0.25))
327 float buildpath_nodefilter_moveskip(entity this, vector n,vector c,vector p)
329 pathlib_walknode(this, p, n, 1);
330 if(pathlib_movenode_goodnode)
336 float buildpath_nodefilter_none(vector n,vector c,vector p)
341 entity path_build(entity next, vector where, entity prev, entity start)
346 if(buildpath_nodefilter)
347 if(buildpath_nodefilter(next.origin,where,prev.origin))
353 path.path_next = next;
355 setorigin(path, where);
358 path.classname = "path_end";
362 path.classname = "path_start";
364 path.classname = "path_node";
370 entity pathlib_astar(entity this, vector from,vector to)
372 entity path, start, end, open, n, ln;
373 float ptime, ftime, ctime;
375 ptime = gettime(GETTIME_REALTIME);
376 pathlib_starttime = ptime;
380 // Select water<->land capable node make/link
381 pathlib_makenode = pathlib_makenode_adaptive;
383 // Select XYZ cost estimate
384 //pathlib_heuristic = pathlib_h_diagonal3;
385 pathlib_heuristic = pathlib_h_diagonal;
387 // Select distance + waterfactor cost
388 pathlib_cost = pathlib_g_euclidean_water;
390 // Select star expander
391 pathlib_expandnode = pathlib_expandnode_star;
393 // Select walk simulation movement test
394 pathlib_movenode = pathlib_walknode;
396 // Filter final nodes by direction
397 buildpath_nodefilter = buildpath_nodefilter_directional;
399 // Filter tiles with cross pattern
400 tile_check = tile_check_cross;
402 // If the start is in water we need diffrent settings
405 // Select volumetric node expaner
406 pathlib_expandnode = pathlib_expandnode_box;
408 // Water movement test
409 pathlib_movenode = pathlib_swimnode;
416 closedlist = spawn();
418 pathlib_closed_cnt = 0;
419 pathlib_open_cnt = 0;
420 pathlib_made_cnt = 0;
421 pathlib_merge_cnt = 0;
422 pathlib_searched_cnt = 0;
423 pathlib_bestopen_searched = 0;
424 pathlib_bestcash_hits = 0;
425 pathlib_bestcash_saved = 0;
427 pathlib_gridsize = 128;
428 pathlib_movecost = pathlib_gridsize;
429 pathlib_movecost_diag = vlen(('1 1 0' * pathlib_gridsize));
430 pathlib_movecost_waterfactor = 25000000;
431 pathlib_foundgoal = 0;
433 movenode_boxmax = this.maxs * 1.1;
434 movenode_boxmin = this.mins * 1.1;
436 movenode_stepsize = pathlib_gridsize * 0.25;
438 tile_check_size = pathlib_gridsize * 0.5;
439 tile_check_up = '0 0 2' * pathlib_gridsize;
440 tile_check_up = '0 0 128';
441 tile_check_down = '0 0 3' * pathlib_gridsize;
442 tile_check_down = '0 0 256';
444 //movenode_stepup = '0 0 128';
445 movenode_stepup = '0 0 36';
446 movenode_maxdrop = '0 0 512';
447 //movenode_maxdrop = '0 0 512';
448 movenode_boxup = '0 0 72';
450 from.x = fsnap(from.x, pathlib_gridsize);
451 from.y = fsnap(from.y, pathlib_gridsize);
454 to.x = fsnap(to.x, pathlib_gridsize);
455 to.y = fsnap(to.y, pathlib_gridsize);
458 LOG_TRACE("AStar init");
459 path = pathlib_mknode(from, NULL);
460 pathlib_close_node(path, to);
461 if(pathlib_foundgoal)
463 LOG_TRACE("AStar: Goal found on first node!");
465 open = new(path_end);
467 setorigin(open, path.origin);
474 if(pathlib_expandnode(path, from, to) <= 0)
476 LOG_TRACE("AStar path fail.");
482 best_open_node = pathlib_getbestopen();
484 pathlib_close_node(best_open_node, to);
485 if(inwater(n.origin))
486 pathlib_expandnode_box(n, from, to);
488 pathlib_expandnode_star(n, from, to);
490 while(pathlib_open_cnt)
492 if((gettime(GETTIME_REALTIME) - pathlib_starttime) > pathlib_maxtime)
494 LOG_TRACE("Path took to long to compute!");
495 LOG_TRACE("Nodes - created: ", ftos(pathlib_made_cnt));
496 LOG_TRACE("Nodes - open: ", ftos(pathlib_open_cnt));
497 LOG_TRACE("Nodes - merged: ", ftos(pathlib_merge_cnt));
498 LOG_TRACE("Nodes - closed: ", ftos(pathlib_closed_cnt));
504 best_open_node = pathlib_getbestopen();
506 pathlib_close_node(best_open_node,to);
508 if(inwater(n.origin))
509 pathlib_expandnode_box(n,from,to);
511 pathlib_expandnode(n,from,to);
513 if(pathlib_foundgoal)
515 LOG_TRACE("Target found. Rebuilding and filtering path...");
516 ftime = gettime(GETTIME_REALTIME);
517 ptime = ftime - ptime;
519 start = path_build(NULL,path.origin,NULL,NULL);
520 end = path_build(NULL,goal_node.origin,NULL,start);
524 for(open = goal_node; open.path_prev != path; open = open.path_prev)
526 n = path_build(ln,open.origin,open.path_prev,start);
532 ftime = gettime(GETTIME_REALTIME) - ftime;
534 ctime = gettime(GETTIME_REALTIME);
536 ctime = gettime(GETTIME_REALTIME) - ctime;
540 pathlib_showpath2(start);
542 LOG_TRACE("Time used - pathfinding: ", ftos(ptime));
543 LOG_TRACE("Time used - rebuild & filter: ", ftos(ftime));
544 LOG_TRACE("Time used - cleanup: ", ftos(ctime));
545 LOG_TRACE("Time used - total: ", ftos(ptime + ftime + ctime));
546 LOG_TRACE("Time used - # frames: ", ftos(ceil((ptime + ftime + ctime) / sys_frametime)));
547 LOG_TRACE("Nodes - created: ", ftos(pathlib_made_cnt));
548 LOG_TRACE("Nodes - open: ", ftos(pathlib_open_cnt));
549 LOG_TRACE("Nodes - merged: ", ftos(pathlib_merge_cnt));
550 LOG_TRACE("Nodes - closed: ", ftos(pathlib_closed_cnt));
551 LOG_TRACE("Nodes - searched: ", ftos(pathlib_searched_cnt));
552 LOG_TRACE("Nodes bestopen searched: ", ftos(pathlib_bestopen_searched));
553 LOG_TRACE("Nodes bestcash - hits: ", ftos(pathlib_bestcash_hits));
554 LOG_TRACE("Nodes bestcash - save: ", ftos(pathlib_bestcash_saved));
555 LOG_TRACE("AStar done.");
561 LOG_TRACE("A* Faild to find a path! Try a smaller gridsize.");