GeoPathFinding.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. * This program is free software: you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation, either version 3 of the License, or (at your option) any later
  5. * version.
  6. *
  7. * This program is distributed in the hope that it will be useful, but WITHOUT
  8. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  10. * details.
  11. *
  12. * You should have received a copy of the GNU General Public License along with
  13. * this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. package net.sf.l2j.gameserver.pathfinding.geonodes;
  16. import java.io.BufferedReader;
  17. import java.io.File;
  18. import java.io.FileReader;
  19. import java.io.LineNumberReader;
  20. import java.io.RandomAccessFile;
  21. import java.nio.ByteBuffer;
  22. import java.nio.IntBuffer;
  23. import java.nio.MappedByteBuffer;
  24. import java.nio.channels.FileChannel;
  25. import java.util.List;
  26. import java.util.Map;
  27. import java.util.StringTokenizer;
  28. import java.util.logging.Logger;
  29. import javolution.util.FastList;
  30. import javolution.util.FastMap;
  31. import net.sf.l2j.Config;
  32. import net.sf.l2j.gameserver.GeoData;
  33. import net.sf.l2j.gameserver.model.L2World;
  34. import net.sf.l2j.gameserver.model.Location;
  35. import net.sf.l2j.gameserver.pathfinding.AbstractNodeLoc;
  36. import net.sf.l2j.gameserver.pathfinding.Node;
  37. import net.sf.l2j.gameserver.pathfinding.PathFinding;
  38. /**
  39. *
  40. * @author -Nemesiss-
  41. */
  42. public class GeoPathFinding extends PathFinding
  43. {
  44. private static Logger _log = Logger.getLogger(GeoPathFinding.class.getName());
  45. private static GeoPathFinding _instance;
  46. private static Map<Short, ByteBuffer> _pathNodes = new FastMap<Short, ByteBuffer>();
  47. private static Map<Short, IntBuffer> _pathNodesIndex = new FastMap<Short, IntBuffer>();
  48. public static GeoPathFinding getInstance()
  49. {
  50. if (_instance == null)
  51. _instance = new GeoPathFinding();
  52. return _instance;
  53. }
  54. /**
  55. * @see net.sf.l2j.gameserver.pathfinding.PathFinding#PathNodesExist(short)
  56. */
  57. @Override
  58. public boolean pathNodesExist(short regionoffset)
  59. {
  60. return _pathNodesIndex.containsKey(regionoffset);
  61. }
  62. /**
  63. * @see net.sf.l2j.gameserver.pathfinding.PathFinding#FindPath(int, int, short, int, int, short)
  64. */
  65. @Override
  66. public List<AbstractNodeLoc> findPath(int x, int y, int z, int tx, int ty, int tz)
  67. {
  68. int gx = (x - L2World.MAP_MIN_X) >> 4;
  69. int gy = (y - L2World.MAP_MIN_Y) >> 4;
  70. short gz = (short)z;
  71. int gtx = (tx - L2World.MAP_MIN_X) >> 4;
  72. int gty = (ty - L2World.MAP_MIN_Y) >> 4;
  73. short gtz = (short)tz;
  74. Node start = readNode(gx,gy,gz);
  75. Node end = readNode(gtx,gty,gtz);
  76. if (start == null || end == null)
  77. return null;
  78. if (Math.abs(start.getLoc().getZ() - z) > 55) return null; // not correct layer
  79. if (Math.abs(end.getLoc().getZ() - tz) > 55) return null; // not correct layer
  80. if (start == end)
  81. return null;
  82. // TODO: Find closest path node we CAN access. Now only checks if we can not reach the closest
  83. Location temp = GeoData.getInstance().moveCheck(x, y, z, start.getLoc().getX(), start.getLoc().getY(), start.getLoc().getZ());
  84. if ((temp.getX() != start.getLoc().getX()) || (temp.getY() != start.getLoc().getY()))
  85. return null; // cannot reach closest...
  86. // TODO: Find closest path node around target, now only checks if final location can be reached
  87. temp = GeoData.getInstance().moveCheck(tx, ty, tz, end.getLoc().getX(), end.getLoc().getY(), end.getLoc().getZ());
  88. if ((temp.getX() != end.getLoc().getX()) || (temp.getY() != end.getLoc().getY()))
  89. return null; // cannot reach closest...
  90. //return searchAStar(start, end);
  91. return searchByClosest2(start, end);
  92. }
  93. /**
  94. * @see net.sf.l2j.gameserver.pathfinding.PathFinding#ReadNeighbors(short, short)
  95. */
  96. @Override
  97. public Node[] readNeighbors(Node n, int idx)
  98. {
  99. int node_x = n.getLoc().getNodeX();
  100. int node_y = n.getLoc().getNodeY();
  101. //short node_z = n.getLoc().getZ();
  102. short regoffset = getRegionOffset(getRegionX(node_x),getRegionY(node_y));
  103. ByteBuffer pn = _pathNodes.get(regoffset);
  104. List<Node> Neighbors = new FastList<Node>(8);
  105. Node newNode;
  106. short new_node_x, new_node_y;
  107. //Region for sure will change, we must read from correct file
  108. byte neighbor = pn.get(idx); //N
  109. idx++;
  110. if(neighbor > 0)
  111. {
  112. neighbor--;
  113. new_node_x = (short)node_x;
  114. new_node_y = (short)(node_y-1);
  115. newNode = readNode(new_node_x,new_node_y,neighbor);
  116. if (newNode != null) Neighbors.add(newNode);
  117. }
  118. neighbor = pn.get(idx); //NE
  119. idx++;
  120. if(neighbor > 0)
  121. {
  122. neighbor--;
  123. new_node_x = (short)(node_x+1);
  124. new_node_y = (short)(node_y-1);
  125. newNode = readNode(new_node_x,new_node_y,neighbor);
  126. if (newNode != null) Neighbors.add(newNode);
  127. }
  128. neighbor = pn.get(idx); //E
  129. idx++;
  130. if(neighbor > 0)
  131. {
  132. neighbor--;
  133. new_node_x = (short)(node_x+1);
  134. new_node_y = (short)node_y;
  135. newNode = readNode(new_node_x,new_node_y,neighbor);
  136. if (newNode != null) Neighbors.add(newNode);
  137. }
  138. neighbor = pn.get(idx); //SE
  139. idx++;
  140. if(neighbor > 0)
  141. {
  142. neighbor--;
  143. new_node_x = (short)(node_x+1);
  144. new_node_y = (short)(node_y+1);
  145. newNode = readNode(new_node_x,new_node_y,neighbor);
  146. if (newNode != null) Neighbors.add(newNode);
  147. }
  148. neighbor = pn.get(idx); //S
  149. idx++;
  150. if(neighbor > 0)
  151. {
  152. neighbor--;
  153. new_node_x = (short)node_x;
  154. new_node_y = (short)(node_y+1);
  155. newNode = readNode(new_node_x,new_node_y,neighbor);
  156. if (newNode != null) Neighbors.add(newNode);
  157. }
  158. neighbor = pn.get(idx); //SW
  159. idx++;
  160. if(neighbor > 0)
  161. {
  162. neighbor--;
  163. new_node_x = (short)(node_x-1);
  164. new_node_y = (short)(node_y+1);
  165. newNode = readNode(new_node_x,new_node_y,neighbor);
  166. if (newNode != null) Neighbors.add(newNode);
  167. }
  168. neighbor = pn.get(idx); //W
  169. idx++;
  170. if(neighbor > 0)
  171. {
  172. neighbor--;
  173. new_node_x = (short)(node_x-1);
  174. new_node_y = (short)node_y;
  175. newNode = readNode(new_node_x,new_node_y,neighbor);
  176. if (newNode != null) Neighbors.add(newNode);
  177. }
  178. neighbor = pn.get(idx); //NW
  179. idx++;
  180. if(neighbor > 0)
  181. {
  182. neighbor--;
  183. new_node_x = (short)(node_x-1);
  184. new_node_y = (short)(node_y-1);
  185. newNode = readNode(new_node_x,new_node_y,neighbor);
  186. if (newNode != null) Neighbors.add(newNode);
  187. }
  188. Node[] result = new Node[Neighbors.size()];
  189. return Neighbors.toArray(result);
  190. }
  191. //Private
  192. private Node readNode(short node_x, short node_y, byte layer)
  193. {
  194. short regoffset = getRegionOffset(getRegionX(node_x),getRegionY(node_y));
  195. if (!this.pathNodesExist(regoffset)) return null;
  196. short nbx = getNodeBlock(node_x);
  197. short nby = getNodeBlock(node_y);
  198. int idx = _pathNodesIndex.get(regoffset).get((nby << 8)+nbx);
  199. ByteBuffer pn = _pathNodes.get(regoffset);
  200. //reading
  201. byte nodes = pn.get(idx);
  202. idx += layer*10+1;//byte + layer*10byte
  203. if (nodes < layer)
  204. {
  205. _log.warning("SmthWrong!");
  206. }
  207. short node_z = pn.getShort(idx);
  208. idx += 2;
  209. return new Node(new GeoNodeLoc(node_x,node_y,node_z), idx);
  210. }
  211. private Node readNode(int gx, int gy, short z)
  212. {
  213. short node_x = getNodePos(gx);
  214. short node_y = getNodePos(gy);
  215. short regoffset = getRegionOffset(getRegionX(node_x),getRegionY(node_y));
  216. if (!this.pathNodesExist(regoffset)) return null;
  217. short nbx = getNodeBlock(node_x);
  218. short nby = getNodeBlock(node_y);
  219. int idx = _pathNodesIndex.get(regoffset).get((nby << 8)+nbx);
  220. ByteBuffer pn = _pathNodes.get(regoffset);
  221. //reading
  222. byte nodes = pn.get(idx);
  223. idx++;//byte
  224. int idx2 = 0; //create index to nearlest node by z
  225. short last_z = Short.MIN_VALUE;
  226. while (nodes > 0)
  227. {
  228. short node_z = pn.getShort(idx);
  229. if (Math.abs(last_z - z) > Math.abs(node_z -z))
  230. {
  231. last_z = node_z;
  232. idx2 = idx+2;
  233. }
  234. idx += 10; //short + 8 byte
  235. nodes--;
  236. }
  237. return new Node(new GeoNodeLoc(node_x,node_y,last_z), idx2);
  238. }
  239. private GeoPathFinding()
  240. {
  241. LineNumberReader lnr = null;
  242. try
  243. {
  244. _log.info("PathFinding Engine: - Loading Path Nodes...");
  245. File Data = new File("./data/pathnode/pn_index.txt");
  246. if (!Data.exists())
  247. return;
  248. lnr = new LineNumberReader(new BufferedReader(new FileReader(Data)));
  249. } catch (Exception e) {
  250. e.printStackTrace();
  251. throw new Error("Failed to Load pn_index File.");
  252. }
  253. String line;
  254. try
  255. {
  256. while ((line = lnr.readLine()) != null) {
  257. if (line.trim().length() == 0)
  258. continue;
  259. StringTokenizer st = new StringTokenizer(line, "_");
  260. byte rx = Byte.parseByte(st.nextToken());
  261. byte ry = Byte.parseByte(st.nextToken());
  262. LoadPathNodeFile(rx,ry);
  263. }
  264. } catch (Exception e) {
  265. e.printStackTrace();
  266. throw new Error("Failed to Read pn_index File.");
  267. }
  268. finally
  269. {
  270. try
  271. {
  272. lnr.close();
  273. }
  274. catch (Exception e)
  275. {
  276. }
  277. }
  278. }
  279. private void LoadPathNodeFile(byte rx,byte ry)
  280. {
  281. String fname = "./data/pathnode/"+rx+"_"+ry+".pn";
  282. short regionoffset = getRegionOffset(rx,ry);
  283. _log.info("PathFinding Engine: - Loading: "+fname+" -> region offset: "+regionoffset+"X: "+rx+" Y: "+ry);
  284. File Pn = new File(fname);
  285. int node = 0,size, index = 0;
  286. FileChannel roChannel = null;
  287. try {
  288. // Create a read-only memory-mapped file
  289. roChannel = new RandomAccessFile(Pn, "r").getChannel();
  290. size = (int)roChannel.size();
  291. MappedByteBuffer nodes;
  292. if (Config.FORCE_GEODATA) //Force O/S to Loads this buffer's content into physical memory.
  293. //it is not guarantee, because the underlying operating system may have paged out some of the buffer's data
  294. nodes = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, size).load();
  295. else
  296. nodes = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, size);
  297. // Indexing pathnode files, so we will know where each block starts
  298. IntBuffer indexs = IntBuffer.allocate(65536);
  299. while(node < 65536)
  300. {
  301. byte layer = nodes.get(index);
  302. indexs.put(node, index);
  303. node++;
  304. index += layer*10+1;
  305. }
  306. _pathNodesIndex.put(regionoffset, indexs);
  307. _pathNodes.put(regionoffset, nodes);
  308. } catch (Exception e)
  309. {
  310. e.printStackTrace();
  311. _log.warning("Failed to Load PathNode File: "+fname+"\n");
  312. }
  313. finally
  314. {
  315. try
  316. {
  317. roChannel.close();
  318. }
  319. catch (Exception e)
  320. {
  321. }
  322. }
  323. }
  324. }