GeoPathFinding.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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 com.l2jserver.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 com.l2jserver.Config;
  30. import com.l2jserver.gameserver.GeoData;
  31. import com.l2jserver.gameserver.model.L2World;
  32. import com.l2jserver.gameserver.model.Location;
  33. import com.l2jserver.gameserver.pathfinding.AbstractNodeLoc;
  34. import com.l2jserver.gameserver.pathfinding.Node;
  35. import com.l2jserver.gameserver.pathfinding.PathFinding;
  36. import javolution.util.FastList;
  37. import javolution.util.FastMap;
  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 Map<Short, ByteBuffer> _pathNodes = new FastMap<Short, ByteBuffer>();
  46. private static Map<Short, IntBuffer> _pathNodesIndex = new FastMap<Short, IntBuffer>();
  47. public static GeoPathFinding getInstance()
  48. {
  49. return SingletonHolder._instance;
  50. }
  51. /**
  52. * @see com.l2jserver.gameserver.pathfinding.PathFinding#PathNodesExist(short)
  53. */
  54. @Override
  55. public boolean pathNodesExist(short regionoffset)
  56. {
  57. return _pathNodesIndex.containsKey(regionoffset);
  58. }
  59. /**
  60. * @see com.l2jserver.gameserver.pathfinding.PathFinding#FindPath(int, int, short, int, int, short)
  61. */
  62. @Override
  63. public List<AbstractNodeLoc> findPath(int x, int y, int z, int tx, int ty, int tz, int instanceId)
  64. {
  65. int gx = (x - L2World.MAP_MIN_X) >> 4;
  66. int gy = (y - L2World.MAP_MIN_Y) >> 4;
  67. short gz = (short) z;
  68. int gtx = (tx - L2World.MAP_MIN_X) >> 4;
  69. int gty = (ty - L2World.MAP_MIN_Y) >> 4;
  70. short gtz = (short) tz;
  71. Node start = readNode(gx, gy, gz);
  72. Node end = readNode(gtx, gty, gtz);
  73. if (start == null || end == null)
  74. return null;
  75. if (Math.abs(start.getLoc().getZ() - z) > 55)
  76. return null; // not correct layer
  77. if (Math.abs(end.getLoc().getZ() - tz) > 55)
  78. return null; // not correct layer
  79. if (start == end)
  80. return null;
  81. // TODO: Find closest path node we CAN access. Now only checks if we can not reach the closest
  82. Location temp = GeoData.getInstance().moveCheck(x, y, z, start.getLoc().getX(), start.getLoc().getY(), start.getLoc().getZ(), instanceId);
  83. if ((temp.getX() != start.getLoc().getX()) || (temp.getY() != start.getLoc().getY()))
  84. return null; // cannot reach closest...
  85. // TODO: Find closest path node around target, now only checks if final location can be reached
  86. temp = GeoData.getInstance().moveCheck(tx, ty, tz, end.getLoc().getX(), end.getLoc().getY(), end.getLoc().getZ(), instanceId);
  87. if ((temp.getX() != end.getLoc().getX()) || (temp.getY() != end.getLoc().getY()))
  88. return null; // cannot reach closest...
  89. //return searchAStar(start, end);
  90. return searchByClosest2(start, end);
  91. }
  92. /**
  93. * @see com.l2jserver.gameserver.pathfinding.PathFinding#ReadNeighbors(short, short)
  94. */
  95. @Override
  96. public Node[] readNeighbors(Node n, int idx)
  97. {
  98. int node_x = n.getLoc().getNodeX();
  99. int node_y = n.getLoc().getNodeY();
  100. //short node_z = n.getLoc().getZ();
  101. short regoffset = getRegionOffset(getRegionX(node_x), getRegionY(node_y));
  102. ByteBuffer pn = _pathNodes.get(regoffset);
  103. List<Node> Neighbors = new FastList<Node>(8);
  104. Node newNode;
  105. short new_node_x, new_node_y;
  106. //Region for sure will change, we must read from correct file
  107. byte neighbor = pn.get(idx++); //N
  108. if (neighbor > 0)
  109. {
  110. neighbor--;
  111. new_node_x = (short) node_x;
  112. new_node_y = (short) (node_y - 1);
  113. newNode = readNode(new_node_x, new_node_y, neighbor);
  114. if (newNode != null)
  115. Neighbors.add(newNode);
  116. }
  117. neighbor = pn.get(idx++); //NE
  118. if (neighbor > 0)
  119. {
  120. neighbor--;
  121. new_node_x = (short) (node_x + 1);
  122. new_node_y = (short) (node_y - 1);
  123. newNode = readNode(new_node_x, new_node_y, neighbor);
  124. if (newNode != null)
  125. Neighbors.add(newNode);
  126. }
  127. neighbor = pn.get(idx++); //E
  128. if (neighbor > 0)
  129. {
  130. neighbor--;
  131. new_node_x = (short) (node_x + 1);
  132. new_node_y = (short) node_y;
  133. newNode = readNode(new_node_x, new_node_y, neighbor);
  134. if (newNode != null)
  135. Neighbors.add(newNode);
  136. }
  137. neighbor = pn.get(idx++); //SE
  138. if (neighbor > 0)
  139. {
  140. neighbor--;
  141. new_node_x = (short) (node_x + 1);
  142. new_node_y = (short) (node_y + 1);
  143. newNode = readNode(new_node_x, new_node_y, neighbor);
  144. if (newNode != null)
  145. Neighbors.add(newNode);
  146. }
  147. neighbor = pn.get(idx++); //S
  148. if (neighbor > 0)
  149. {
  150. neighbor--;
  151. new_node_x = (short) node_x;
  152. new_node_y = (short) (node_y + 1);
  153. newNode = readNode(new_node_x, new_node_y, neighbor);
  154. if (newNode != null)
  155. Neighbors.add(newNode);
  156. }
  157. neighbor = pn.get(idx++); //SW
  158. if (neighbor > 0)
  159. {
  160. neighbor--;
  161. new_node_x = (short) (node_x - 1);
  162. new_node_y = (short) (node_y + 1);
  163. newNode = readNode(new_node_x, new_node_y, neighbor);
  164. if (newNode != null)
  165. Neighbors.add(newNode);
  166. }
  167. neighbor = pn.get(idx++); //W
  168. if (neighbor > 0)
  169. {
  170. neighbor--;
  171. new_node_x = (short) (node_x - 1);
  172. new_node_y = (short) node_y;
  173. newNode = readNode(new_node_x, new_node_y, neighbor);
  174. if (newNode != null)
  175. Neighbors.add(newNode);
  176. }
  177. neighbor = pn.get(idx++); //NW
  178. if (neighbor > 0)
  179. {
  180. neighbor--;
  181. new_node_x = (short) (node_x - 1);
  182. new_node_y = (short) (node_y - 1);
  183. newNode = readNode(new_node_x, new_node_y, neighbor);
  184. if (newNode != null)
  185. Neighbors.add(newNode);
  186. }
  187. Node[] result = new Node[Neighbors.size()];
  188. return Neighbors.toArray(result);
  189. }
  190. //Private
  191. private Node readNode(short node_x, short node_y, byte layer)
  192. {
  193. short regoffset = getRegionOffset(getRegionX(node_x), getRegionY(node_y));
  194. if (!this.pathNodesExist(regoffset))
  195. 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))
  217. return null;
  218. short nbx = getNodeBlock(node_x);
  219. short nby = getNodeBlock(node_y);
  220. int idx = _pathNodesIndex.get(regoffset).get((nby << 8) + nbx);
  221. ByteBuffer pn = _pathNodes.get(regoffset);
  222. //reading
  223. byte nodes = pn.get(idx++);
  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. }
  250. catch (Exception e)
  251. {
  252. e.printStackTrace();
  253. throw new Error("Failed to Load pn_index File.");
  254. }
  255. String line;
  256. try
  257. {
  258. while ((line = lnr.readLine()) != null)
  259. {
  260. if (line.trim().length() == 0)
  261. continue;
  262. StringTokenizer st = new StringTokenizer(line, "_");
  263. byte rx = Byte.parseByte(st.nextToken());
  264. byte ry = Byte.parseByte(st.nextToken());
  265. LoadPathNodeFile(rx, ry);
  266. }
  267. }
  268. catch (Exception e)
  269. {
  270. e.printStackTrace();
  271. throw new Error("Failed to Read pn_index File.");
  272. }
  273. finally
  274. {
  275. try
  276. {
  277. lnr.close();
  278. }
  279. catch (Exception e)
  280. {
  281. }
  282. }
  283. }
  284. private void LoadPathNodeFile(byte rx, byte ry)
  285. {
  286. String fname = "./data/pathnode/" + rx + "_" + ry + ".pn";
  287. short regionoffset = getRegionOffset(rx, ry);
  288. _log.info("PathFinding Engine: - Loading: " + fname + " -> region offset: " + regionoffset + "X: " + rx + " Y: " + ry);
  289. File Pn = new File(fname);
  290. int node = 0, size, index = 0;
  291. FileChannel roChannel = null;
  292. try
  293. {
  294. // Create a read-only memory-mapped file
  295. roChannel = new RandomAccessFile(Pn, "r").getChannel();
  296. size = (int) roChannel.size();
  297. MappedByteBuffer nodes;
  298. if (Config.FORCE_GEODATA) //Force O/S to Loads this buffer's content into physical memory.
  299. //it is not guarantee, because the underlying operating system may have paged out some of the buffer's data
  300. nodes = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, size).load();
  301. else
  302. nodes = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, size);
  303. // Indexing pathnode files, so we will know where each block starts
  304. IntBuffer indexs = IntBuffer.allocate(65536);
  305. while (node < 65536)
  306. {
  307. byte layer = nodes.get(index);
  308. indexs.put(node++, index);
  309. index += layer * 10 + 1;
  310. }
  311. _pathNodesIndex.put(regionoffset, indexs);
  312. _pathNodes.put(regionoffset, nodes);
  313. }
  314. catch (Exception e)
  315. {
  316. e.printStackTrace();
  317. _log.warning("Failed to Load PathNode File: " + fname + "\n");
  318. }
  319. finally
  320. {
  321. try
  322. {
  323. roChannel.close();
  324. }
  325. catch (Exception e)
  326. {
  327. }
  328. }
  329. }
  330. @SuppressWarnings("synthetic-access")
  331. private static class SingletonHolder
  332. {
  333. protected static final GeoPathFinding _instance = new GeoPathFinding();
  334. }
  335. }