Advertisement
Guest User

Untitled

a guest
Oct 1st, 2016
118
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 46.80 KB | None | 0 0
  1. /*
  2. * L2jFrozen Project - www.l2jfrozen.com
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2, or (at your option)
  7. * any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  17. * 02111-1307, USA.
  18. *
  19. * http://www.gnu.org/copyleft/gpl.html
  20. */
  21. package com.l2jfrozen.gameserver.geo;
  22.  
  23. import java.io.BufferedOutputStream;
  24. import java.io.BufferedReader;
  25. import java.io.File;
  26. import java.io.FileOutputStream;
  27. import java.io.FileReader;
  28. import java.io.RandomAccessFile;
  29. import java.nio.ByteBuffer;
  30. import java.nio.ByteOrder;
  31. import java.nio.IntBuffer;
  32. import java.nio.MappedByteBuffer;
  33. import java.nio.channels.FileChannel;
  34. import java.util.StringTokenizer;
  35.  
  36. import com.l2jfrozen.Config;
  37. import com.l2jfrozen.gameserver.datatables.FenceTable;
  38. import com.l2jfrozen.gameserver.datatables.csv.DoorTable;
  39. import com.l2jfrozen.gameserver.geo.pathfinding.Node;
  40. import com.l2jfrozen.gameserver.geo.pathfinding.cellnodes.CellPathFinding;
  41. import com.l2jfrozen.gameserver.geo.util.L2Arrays;
  42. import com.l2jfrozen.gameserver.geo.util.LookupTable;
  43. import com.l2jfrozen.gameserver.model.L2Object;
  44. import com.l2jfrozen.gameserver.model.L2World;
  45. import com.l2jfrozen.gameserver.model.Location;
  46. import com.l2jfrozen.gameserver.model.actor.instance.L2DoorInstance;
  47. import com.l2jfrozen.gameserver.model.actor.instance.L2PcInstance;
  48. import com.l2jfrozen.gameserver.model.actor.instance.L2SiegeGuardInstance;
  49. import com.l2jfrozen.util.Point3D;
  50.  
  51. public final class GeoEngine extends GeoData
  52. {
  53. private final static byte _e = 1;
  54. private final static byte _w = 2;
  55. private final static byte _s = 4;
  56. private final static byte _n = 8;
  57.  
  58. private static final class SingletonHolder
  59. {
  60. protected static final GeoEngine INSTANCE = new GeoEngine();
  61. }
  62.  
  63. public static GeoEngine getInstance()
  64. {
  65. return SingletonHolder.INSTANCE;
  66. }
  67.  
  68. private final LookupTable<MappedByteBuffer> _geodata = new LookupTable<>();
  69. private final LookupTable<IntBuffer> _geodataIndex = new LookupTable<>();
  70. private BufferedOutputStream _geoBugsOut;
  71.  
  72. protected GeoEngine()
  73. {
  74. nInitGeodata();
  75. }
  76.  
  77. @Override
  78. public short getType(final int x, final int y)
  79. {
  80. return nGetType((x - L2World.MAP_MIN_X) >> 4, (y - L2World.MAP_MIN_Y) >> 4);
  81. }
  82.  
  83. @Override
  84. public short getHeight(final int x, final int y, final int z)
  85. {
  86. return nGetHeight((x - L2World.MAP_MIN_X) >> 4, (y - L2World.MAP_MIN_Y) >> 4, z);
  87. }
  88.  
  89. @Override
  90. public short getSpawnHeight(final int x, final int y, final int zmin, final int zmax, final int spawnid)
  91. {
  92. return nGetSpawnHeight((x - L2World.MAP_MIN_X) >> 4, (y - L2World.MAP_MIN_Y) >> 4, zmin, zmax, spawnid);
  93. }
  94.  
  95. @Override
  96. public String geoPosition(final int x, final int y)
  97. {
  98. final int gx = (x - L2World.MAP_MIN_X) >> 4;
  99. final int gy = (y - L2World.MAP_MIN_Y) >> 4;
  100. return "bx: " + getBlock(gx) + " by: " + getBlock(gy) + " cx: " + getCell(gx) + " cy: " + getCell(gy) + " region offset: " + getRegionOffset(gx, gy);
  101. }
  102.  
  103. @Override
  104. public boolean canSeeTarget(final L2Object cha, final Point3D target)
  105. {
  106. if (DoorTable.getInstance().checkIfDoorsBetween(cha.getX(), cha.getY(), cha.getZ(), target.getX(), target.getY(), target.getZ()))
  107. return false;
  108. if (!FenceTable.canSeeTarget(cha, target.getX(), target.getY()))
  109. return false;
  110.  
  111. if (cha.getZ() >= target.getZ())
  112. return canSeeTarget(cha.getX(), cha.getY(), cha.getZ(), target.getX(), target.getY(), target.getZ());
  113. return canSeeTarget(target.getX(), target.getY(), target.getZ(), cha.getX(), cha.getY(), cha.getZ());
  114. }
  115.  
  116. @Override
  117. public boolean canSeeTarget(final L2Object cha, final L2Object target)
  118. {
  119. // To be able to see over fences and give the player the viewpoint
  120. // game client has, all coordinates are lifted 45 from ground.
  121. // Because of layer selection in LOS algorithm (it selects -45 there
  122. // and some layers can be very close...) do not change this without
  123. // changing the LOS code.
  124. // Basically the +45 is character height. Raid bosses are naturally higher,
  125. // dwarves shorter, but this should work relatively well.
  126. // If this is going to be improved, use e.g.
  127. // ((L2Character)cha).getTemplate().collisionHeight
  128. int z = cha.getZ() + 45;
  129. if (cha instanceof L2SiegeGuardInstance)
  130. z += 30; // well they don't move closer to balcony fence at the moment :(
  131. int z2 = target.getZ() + 45;
  132. if (target instanceof L2DoorInstance)
  133. return true; // door coordinates are hinge coords..
  134. if (DoorTable.getInstance().checkIfDoorsBetween(cha.getX(), cha.getY(), z, target.getX(), target.getY(), z2))
  135. return false;
  136. if (target instanceof L2SiegeGuardInstance)
  137. z2 += 30; // well they don't move closer to balcony fence at the moment :(
  138. if (z >= z2)
  139. return canSeeTarget(cha.getX(), cha.getY(), z, target.getX(), target.getY(), z2);
  140. return canSeeTarget(target.getX(), target.getY(), z2, cha.getX(), cha.getY(), z);
  141. }
  142.  
  143. @Override
  144. public boolean canSeeTargetDebug(final L2PcInstance gm, final L2Object target)
  145. {
  146. if (!FenceTable.canSeeTarget(gm, target.getX(), target.getY()))
  147. return false;
  148.  
  149. // comments: see above
  150. final int z = gm.getZ() + 45;
  151. final int z2 = target.getZ() + 45;
  152. if (target instanceof L2DoorInstance)
  153. {
  154. gm.sendMessage("door always true");
  155. return true; // door coordinates are hinge coords..
  156. }
  157.  
  158. if (z >= z2)
  159. return canSeeDebug(gm, (gm.getX() - L2World.MAP_MIN_X) >> 4, (gm.getY() - L2World.MAP_MIN_Y) >> 4, z, (target.getX() - L2World.MAP_MIN_X) >> 4, (target.getY() - L2World.MAP_MIN_Y) >> 4, z2);
  160. return canSeeDebug(gm, (target.getX() - L2World.MAP_MIN_X) >> 4, (target.getY() - L2World.MAP_MIN_Y) >> 4, z2, (gm.getX() - L2World.MAP_MIN_X) >> 4, (gm.getY() - L2World.MAP_MIN_Y) >> 4, z);
  161. }
  162.  
  163. @Override
  164. public short getNSWE(final int x, final int y, final int z)
  165. {
  166. return nGetNSWE((x - L2World.MAP_MIN_X) >> 4, (y - L2World.MAP_MIN_Y) >> 4, z);
  167. }
  168.  
  169. @Override
  170. public boolean canMoveFromToTarget(final int x, final int y, final int z, final int tx, final int ty, final int tz)
  171. {
  172. final Location destiny = moveCheck(x, y, z, tx, ty, tz);
  173. return (destiny.getX() == tx && destiny.getY() == ty && destiny.getZ() == tz);
  174. }
  175.  
  176. @Override
  177. public Location moveCheck(final int x, final int y, final int z, final int tx, final int ty, final int tz)
  178. {
  179. final Location startpoint = new Location(x, y, z);
  180. if (DoorTable.getInstance().checkIfDoorsBetween(x, y, z, tx, ty, tz))
  181. return startpoint;
  182. if (!FenceTable.canSeeTarget(x,y, tx, ty))
  183. return startpoint;
  184.  
  185. final Location destiny = new Location(tx, ty, tz);
  186. return moveCheck(startpoint, destiny, (x - L2World.MAP_MIN_X) >> 4, (y - L2World.MAP_MIN_Y) >> 4, z, (tx - L2World.MAP_MIN_X) >> 4, (ty - L2World.MAP_MIN_Y) >> 4, tz);
  187. }
  188.  
  189. @Override
  190. public void addGeoDataBug(final L2PcInstance gm, final String comment)
  191. {
  192. final int gx = (gm.getX() - L2World.MAP_MIN_X) >> 4;
  193. final int gy = (gm.getY() - L2World.MAP_MIN_Y) >> 4;
  194. final int bx = getBlock(gx);
  195. final int by = getBlock(gy);
  196. final int cx = getCell(gx);
  197. final int cy = getCell(gy);
  198. final int rx = (gx >> 11) + 10;
  199. final int ry = (gy >> 11) + 10;
  200. final String out = rx + ";" + ry + ";" + bx + ";" + by + ";" + cx + ";" + cy + ";" + gm.getZ() + ";" + comment + "\n";
  201. try
  202. {
  203. _geoBugsOut.write(out.getBytes());
  204. _geoBugsOut.flush();
  205. gm.sendMessage("GeoData bug saved!");
  206. }
  207. catch (final Exception e)
  208. {
  209. e.printStackTrace();
  210. gm.sendMessage("GeoData bug save Failed!");
  211. }
  212. }
  213.  
  214. @Override
  215. public boolean canSeeTarget(final int x, final int y, final int z, final int tx, final int ty, final int tz)
  216. {
  217. return canSee((x - L2World.MAP_MIN_X) >> 4, (y - L2World.MAP_MIN_Y) >> 4, z, (tx - L2World.MAP_MIN_X) >> 4, (ty - L2World.MAP_MIN_Y) >> 4, tz);
  218. }
  219.  
  220. @Override
  221. public boolean hasGeo(final int x, final int y)
  222. {
  223. final int gx = (x - L2World.MAP_MIN_X) >> 4;
  224. final int gy = (y - L2World.MAP_MIN_Y) >> 4;
  225. final short region = getRegionOffset(gx, gy);
  226.  
  227. return _geodata.get(region) != null;
  228. }
  229.  
  230. private boolean canSee(int x, int y, double z, final int tx, final int ty, final int tz)
  231. {
  232. int dx = (tx - x);
  233. int dy = (ty - y);
  234. final double dz = (tz - z);
  235. final int distance2 = dx * dx + dy * dy;
  236.  
  237. if (distance2 > 90000) // (300*300) 300*16 = 4800 in world coord
  238. {
  239. // Avoid too long check
  240. return false;
  241. }
  242. // very short checks: 9 => 144 world distance
  243. // this ensures NLOS function has enough points to calculate,
  244. // it might not work when distance is small and path vertical
  245. else if (distance2 < 82)
  246. {
  247. // 150 should be too deep/high.
  248. if (dz * dz > 22500)
  249. {
  250. final short region = getRegionOffset(x, y);
  251. // geodata is loaded for region and mobs should have correct Z coordinate...
  252. // so there would likely be a floor in between the two
  253. if (_geodata.get(region) != null)
  254. return false;
  255. }
  256. return true;
  257. }
  258.  
  259. // Increment in Z coordinate when moving along X or Y axis
  260. // and not straight to the target. This is done because
  261. // calculation moves either in X or Y direction.
  262. final int inc_x = sign(dx);
  263. final int inc_y = sign(dy);
  264. dx = Math.abs(dx);
  265. dy = Math.abs(dy);
  266. final double inc_z_directionx = dz * dx / (distance2);
  267. final double inc_z_directiony = dz * dy / (distance2);
  268.  
  269. // next_* are used in NLOS check from x,y
  270. int next_x = x;
  271. int next_y = y;
  272.  
  273. // creates path to the target
  274. // calculation stops when next_* == target
  275. if (dx >= dy)// dy/dx <= 1
  276. {
  277. final int delta_A = 2 * dy;
  278. int d = delta_A - dx;
  279. final int delta_B = delta_A - 2 * dx;
  280.  
  281. for (int i = 0; i < dx; i++)
  282. {
  283. x = next_x;
  284. y = next_y;
  285. if (d > 0)
  286. {
  287. d += delta_B;
  288. next_x += inc_x;
  289. z += inc_z_directionx;
  290. if (!nLOS(x, y, (int) z, inc_x, 0, inc_z_directionx, tz, false))
  291. return false;
  292. next_y += inc_y;
  293. z += inc_z_directiony;
  294. // LOGGER.warn("1: next_x:"+next_x+" next_y"+next_y);
  295. if (!nLOS(next_x, y, (int) z, 0, inc_y, inc_z_directiony, tz, false))
  296. return false;
  297. }
  298. else
  299. {
  300. d += delta_A;
  301. next_x += inc_x;
  302. // LOGGER.warn("2: next_x:"+next_x+" next_y"+next_y);
  303. z += inc_z_directionx;
  304. if (!nLOS(x, y, (int) z, inc_x, 0, inc_z_directionx, tz, false))
  305. return false;
  306. }
  307. }
  308. }
  309. else
  310. {
  311. final int delta_A = 2 * dx;
  312. int d = delta_A - dy;
  313. final int delta_B = delta_A - 2 * dy;
  314. for (int i = 0; i < dy; i++)
  315. {
  316. x = next_x;
  317. y = next_y;
  318. if (d > 0)
  319. {
  320. d += delta_B;
  321. next_y += inc_y;
  322. z += inc_z_directiony;
  323. if (!nLOS(x, y, (int) z, 0, inc_y, inc_z_directiony, tz, false))
  324. return false;
  325. next_x += inc_x;
  326. z += inc_z_directionx;
  327. // LOGGER.warn("3: next_x:"+next_x+" next_y"+next_y);
  328. if (!nLOS(x, next_y, (int) z, inc_x, 0, inc_z_directionx, tz, false))
  329. return false;
  330. }
  331. else
  332. {
  333. d += delta_A;
  334. next_y += inc_y;
  335. // LOGGER.warn("4: next_x:"+next_x+" next_y"+next_y);
  336. z += inc_z_directiony;
  337. if (!nLOS(x, y, (int) z, 0, inc_y, inc_z_directiony, tz, false))
  338. return false;
  339. }
  340. }
  341. }
  342. return true;
  343. }
  344.  
  345. /*
  346. * Debug function for checking if there's a line of sight between two coordinates. Creates points for line of sight check (x,y,z towards target) and in each point, layer and movement checks are made with NLOS function. Coordinates here are geodata x,y but z coordinate is world coordinate
  347. */
  348. private boolean canSeeDebug(final L2PcInstance gm, int x, int y, double z, final int tx, final int ty, final int tz)
  349. {
  350. int dx = (tx - x);
  351. int dy = (ty - y);
  352. final double dz = (tz - z);
  353. final int distance2 = dx * dx + dy * dy;
  354.  
  355. if (distance2 > 90000) // (300*300) 300*16 = 4800 in world coord
  356. {
  357. // Avoid too long check
  358. gm.sendMessage("dist > 300");
  359. return false;
  360. }
  361. // very short checks: 9 => 144 world distance
  362. // this ensures NLOS function has enough points to calculate,
  363. // it might not work when distance is small and path vertical
  364. else if (distance2 < 82)
  365. {
  366. // 150 should be too deep/high.
  367. if (dz * dz > 22500)
  368. {
  369. final short region = getRegionOffset(x, y);
  370. // geodata is loaded for region and mobs should have correct Z coordinate...
  371. // so there would likely be a floor in between the two
  372. if (_geodata.get(region) != null)
  373. return false;
  374. }
  375. return true;
  376. }
  377.  
  378. // Increment in Z coordinate when moving along X or Y axis
  379. // and not straight to the target. This is done because
  380. // calculation moves either in X or Y direction.
  381. final int inc_x = sign(dx);
  382. final int inc_y = sign(dy);
  383. dx = Math.abs(dx);
  384. dy = Math.abs(dy);
  385. final double inc_z_directionx = dz * dx / (distance2);
  386. final double inc_z_directiony = dz * dy / (distance2);
  387.  
  388. gm.sendMessage("Los: from X: " + x + "Y: " + y + "--->> X: " + tx + " Y: " + ty);
  389.  
  390. // next_* are used in NLOS check from x,y
  391. int next_x = x;
  392. int next_y = y;
  393.  
  394. // creates path to the target
  395. // calculation stops when next_* == target
  396. if (dx >= dy)// dy/dx <= 1
  397. {
  398. final int delta_A = 2 * dy;
  399. int d = delta_A - dx;
  400. final int delta_B = delta_A - 2 * dx;
  401.  
  402. for (int i = 0; i < dx; i++)
  403. {
  404. x = next_x;
  405. y = next_y;
  406. if (d > 0)
  407. {
  408. d += delta_B;
  409. next_x += inc_x;
  410. z += inc_z_directionx;
  411. if (!nLOS(x, y, (int) z, inc_x, 0, inc_z_directionx, tz, true))
  412. return false;
  413. next_y += inc_y;
  414. z += inc_z_directiony;
  415. // LOGGER.warn( "1: next_x:"+next_x+" next_y"+next_y);
  416. if (!nLOS(next_x, y, (int) z, 0, inc_y, inc_z_directiony, tz, true))
  417. return false;
  418. }
  419. else
  420. {
  421. d += delta_A;
  422. next_x += inc_x;
  423. // LOGGER.warn( "2: next_x:"+next_x+" next_y"+next_y);
  424. z += inc_z_directionx;
  425. if (!nLOS(x, y, (int) z, inc_x, 0, inc_z_directionx, tz, true))
  426. return false;
  427. }
  428. }
  429. }
  430. else
  431. {
  432. final int delta_A = 2 * dx;
  433. int d = delta_A - dy;
  434. final int delta_B = delta_A - 2 * dy;
  435. for (int i = 0; i < dy; i++)
  436. {
  437. x = next_x;
  438. y = next_y;
  439. if (d > 0)
  440. {
  441. d += delta_B;
  442. next_y += inc_y;
  443. z += inc_z_directiony;
  444. if (!nLOS(x, y, (int) z, 0, inc_y, inc_z_directiony, tz, true))
  445. return false;
  446. next_x += inc_x;
  447. z += inc_z_directionx;
  448. // LOGGER.warn( "3: next_x:"+next_x+" next_y"+next_y);
  449. if (!nLOS(x, next_y, (int) z, inc_x, 0, inc_z_directionx, tz, true))
  450. return false;
  451. }
  452. else
  453. {
  454. d += delta_A;
  455. next_y += inc_y;
  456. // LOGGER.warn( "4: next_x:"+next_x+" next_y"+next_y);
  457. z += inc_z_directiony;
  458. if (!nLOS(x, y, (int) z, 0, inc_y, inc_z_directiony, tz, true))
  459. return false;
  460. }
  461. }
  462. }
  463. return true;
  464. }
  465.  
  466. /*
  467. * MoveCheck
  468. */
  469. private Location moveCheck(final Location startpoint, final Location destiny, int x, int y, double z, int tx, int ty, int tz)
  470. {
  471. int dx = (tx - x);
  472. int dy = (ty - y);
  473. final int distance2 = dx * dx + dy * dy;
  474.  
  475. if (distance2 == 0)
  476. return destiny;
  477. if (distance2 > 36100) // 190*190*16 = 3040 world coord
  478. {
  479. // Avoid too long check
  480. // Currently we calculate a middle point
  481. // for wyvern users and otherwise for comfort
  482. final double divider = Math.sqrt((double) 30000 / distance2);
  483. tx = x + (int) (divider * dx);
  484. ty = y + (int) (divider * dy);
  485. final int dz = (tz - startpoint.getZ());
  486. tz = startpoint.getZ() + (int) (divider * dz);
  487. dx = (tx - x);
  488. dy = (ty - y);
  489. // return startpoint;
  490. }
  491.  
  492. // Increment in Z coordinate when moving along X or Y axis
  493. // and not straight to the target. This is done because
  494. // calculation moves either in X or Y direction.
  495. final int inc_x = sign(dx);
  496. final int inc_y = sign(dy);
  497. dx = Math.abs(dx);
  498. dy = Math.abs(dy);
  499.  
  500. // gm.sendMessage("MoveCheck: from X: "+x+ "Y: "+y+ "--->> X: "+tx+" Y: "+ty);
  501.  
  502. // next_* are used in NcanMoveNext check from x,y
  503. int next_x = x;
  504. int next_y = y;
  505. double tempz = z;
  506.  
  507. // creates path to the target, using only x or y direction
  508. // calculation stops when next_* == target
  509. if (dx >= dy)// dy/dx <= 1
  510. {
  511. final int delta_A = 2 * dy;
  512. int d = delta_A - dx;
  513. final int delta_B = delta_A - 2 * dx;
  514.  
  515. for (int i = 0; i < dx; i++)
  516. {
  517. x = next_x;
  518. y = next_y;
  519. if (d > 0)
  520. {
  521. d += delta_B;
  522. next_x += inc_x;
  523. tempz = nCanMoveNext(x, y, (int) z, next_x, next_y, tz);
  524. if (tempz == Double.MIN_VALUE)
  525. return new Location((x << 4) + L2World.MAP_MIN_X, (y << 4) + L2World.MAP_MIN_Y, (int) z);
  526. z = tempz;
  527. next_y += inc_y;
  528. // LOGGER.warn("2: next_x:"+next_x+" next_y"+next_y);
  529. tempz = nCanMoveNext(next_x, y, (int) z, next_x, next_y, tz);
  530. if (tempz == Double.MIN_VALUE)
  531. return new Location((x << 4) + L2World.MAP_MIN_X, (y << 4) + L2World.MAP_MIN_Y, (int) z);
  532. z = tempz;
  533. }
  534. else
  535. {
  536. d += delta_A;
  537. next_x += inc_x;
  538. // LOGGER.warn("3: next_x:"+next_x+" next_y"+next_y);
  539. tempz = nCanMoveNext(x, y, (int) z, next_x, next_y, tz);
  540. if (tempz == Double.MIN_VALUE)
  541. return new Location((x << 4) + L2World.MAP_MIN_X, (y << 4) + L2World.MAP_MIN_Y, (int) z);
  542. z = tempz;
  543. }
  544. }
  545. }
  546. else
  547. {
  548. final int delta_A = 2 * dx;
  549. int d = delta_A - dy;
  550. final int delta_B = delta_A - 2 * dy;
  551. for (int i = 0; i < dy; i++)
  552. {
  553. x = next_x;
  554. y = next_y;
  555. if (d > 0)
  556. {
  557. d += delta_B;
  558. next_y += inc_y;
  559. tempz = nCanMoveNext(x, y, (int) z, next_x, next_y, tz);
  560. if (tempz == Double.MIN_VALUE)
  561. return new Location((x << 4) + L2World.MAP_MIN_X, (y << 4) + L2World.MAP_MIN_Y, (int) z);
  562. z = tempz;
  563. next_x += inc_x;
  564. // LOGGER.warn("5: next_x:"+next_x+" next_y"+next_y);
  565. tempz = nCanMoveNext(x, next_y, (int) z, next_x, next_y, tz);
  566. if (tempz == Double.MIN_VALUE)
  567. return new Location((x << 4) + L2World.MAP_MIN_X, (y << 4) + L2World.MAP_MIN_Y, (int) z);
  568. z = tempz;
  569. }
  570. else
  571. {
  572. d += delta_A;
  573. next_y += inc_y;
  574. // LOGGER.warn("6: next_x:"+next_x+" next_y"+next_y);
  575. tempz = nCanMoveNext(x, y, (int) z, next_x, next_y, tz);
  576. if (tempz == Double.MIN_VALUE)
  577. return new Location((x << 4) + L2World.MAP_MIN_X, (y << 4) + L2World.MAP_MIN_Y, (int) z);
  578. z = tempz;
  579. }
  580. }
  581. }
  582. if (z == startpoint.getZ()) // geodata hasn't modified Z in any coordinate, i.e. doesn't exist
  583. return destiny;
  584. return new Location(destiny.getX(), destiny.getY(), (int) z);
  585. }
  586.  
  587. private byte sign(final int x)
  588. {
  589. if (x >= 0)
  590. return +1;
  591. return -1;
  592. }
  593.  
  594. // GeoEngine
  595. private void nInitGeodata()
  596. {
  597. LOGGER.info("Geo Engine: - Loading Geodata...");
  598. final File Data = new File(Config.DATAPACK_ROOT, "data/geodata/geo_index.txt");
  599. if (!Data.exists())
  600. return;
  601.  
  602. BufferedReader lnr = null;
  603. FileReader reader = null;
  604. try
  605. {
  606. reader = new FileReader(Data);
  607. lnr = new BufferedReader(reader);
  608.  
  609. String line;
  610. while ((line = lnr.readLine()) != null)
  611. {
  612.  
  613. if (line.trim().length() == 0)
  614. continue;
  615.  
  616. final StringTokenizer st = new StringTokenizer(line, "_");
  617. final byte rx = Byte.parseByte(st.nextToken());
  618. final byte ry = Byte.parseByte(st.nextToken());
  619. loadGeodataFile(rx, ry);
  620. }
  621.  
  622. }
  623. catch (final Exception e)
  624. {
  625. e.printStackTrace();
  626. }
  627. finally
  628. {
  629.  
  630. if (lnr != null)
  631. try
  632. {
  633. lnr.close();
  634. }
  635. catch (final Exception e)
  636. {
  637. e.printStackTrace();
  638. }
  639.  
  640. if (reader != null)
  641. try
  642. {
  643. reader.close();
  644. }
  645. catch (final Exception e)
  646. {
  647. e.printStackTrace();
  648. }
  649. }
  650.  
  651. final File geo_bugs = new File(Config.DATAPACK_ROOT, "data/geodata/geo_bugs.txt");
  652. FileOutputStream out = null;
  653. try
  654. {
  655. out = new FileOutputStream(geo_bugs, true);
  656. _geoBugsOut = new BufferedOutputStream(out);
  657. }
  658. catch (final Exception e)
  659. {
  660. e.printStackTrace();
  661.  
  662. }
  663.  
  664. }
  665.  
  666. @Override
  667. public void unloadGeodata(final byte rx, final byte ry)
  668. {
  669. final short regionoffset = (short) ((rx << 5) + ry);
  670. _geodataIndex.set(regionoffset, null);
  671. _geodata.set(regionoffset, null);
  672. }
  673.  
  674. @Override
  675. public boolean loadGeodataFile(final byte rx, final byte ry)
  676. {
  677. boolean output = false;
  678. final String fname = "data/geodata/" + rx + "_" + ry + ".l2j";
  679. final short regionoffset = (short) ((rx << 5) + ry);
  680. LOGGER.info("Geo Engine: - Loading: " + fname + " -> region offset: " + regionoffset + "X: " + rx + " Y: " + ry);
  681. final File Geo = new File(Config.DATAPACK_ROOT, fname);
  682. int size, index = 0, block = 0, flor = 0;
  683. FileChannel roChannel = null;
  684. RandomAccessFile raf = null;
  685. try
  686. {
  687. // Create a read-only memory-mapped file
  688. raf = new RandomAccessFile(Geo, "r");
  689. roChannel = raf.getChannel();
  690. size = (int) roChannel.size();
  691. MappedByteBuffer geo;
  692. if (Config.FORCE_GEODATA) // Force O/S to Loads this buffer's content into physical memory.
  693. // it is not guarantee, because the underlying operating system may have paged out some of the buffer's data
  694. geo = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, size).load();
  695. else
  696. geo = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, size);
  697. geo.order(ByteOrder.LITTLE_ENDIAN);
  698.  
  699. if (size > 196608)
  700. {
  701. // Indexing geo files, so we will know where each block starts
  702. final IntBuffer indexs = IntBuffer.allocate(65536);
  703. while (block < 65536)
  704. {
  705. final byte type = geo.get(index);
  706. indexs.put(block, index);
  707. block++;
  708. index++;
  709. if (type == 0)
  710. index += 2; // 1x short
  711. else if (type == 1)
  712. index += 128; // 64 x short
  713. else
  714. {
  715. for (int b = 0; b < 64; b++)
  716. {
  717. final byte layers = geo.get(index);
  718. index += (layers << 1) + 1;
  719. if (layers > flor)
  720. flor = layers;
  721. }
  722. }
  723. }
  724. _geodataIndex.set(regionoffset, indexs);
  725. }
  726. _geodata.set(regionoffset, geo);
  727.  
  728. output = true;
  729. LOGGER.info("Geo Engine: - Max Layers: " + flor + " Size: " + size + " Loaded: " + index);
  730. }
  731. catch (final Exception e)
  732. {
  733. e.printStackTrace();
  734. LOGGER.warn("Failed to Load GeoFile at block: " + block + "\n");
  735.  
  736. }
  737. finally
  738. {
  739. if (roChannel != null)
  740. try
  741. {
  742. roChannel.close();
  743. }
  744. catch (final Exception e1)
  745. {
  746. e1.printStackTrace();
  747. }
  748.  
  749. if (raf != null)
  750. try
  751. {
  752. raf.close();
  753. }
  754. catch (final Exception e1)
  755. {
  756. e1.printStackTrace();
  757. }
  758.  
  759. }
  760. return output;
  761. }
  762.  
  763. // Geodata Methods
  764. /**
  765. * @param x
  766. * @param y
  767. * @return Region Offset
  768. */
  769. private short getRegionOffset(final int x, final int y)
  770. {
  771. final int rx = x >> 11; // =/(256 * 8)
  772. final int ry = y >> 11;
  773. return (short) (((rx + 16) << 5) + (ry + 10));
  774. }
  775.  
  776. /**
  777. * @param geo_pos
  778. * @return Block Index: 0-255
  779. */
  780. private int getBlock(final int geo_pos)
  781. {
  782. return (geo_pos >> 3) % 256;
  783. }
  784.  
  785. /**
  786. * @param geo_pos
  787. * @return Cell Index: 0-7
  788. */
  789. private int getCell(final int geo_pos)
  790. {
  791. return geo_pos % 8;
  792. }
  793.  
  794. // Geodata Functions
  795.  
  796. /**
  797. * @param x
  798. * @param y
  799. * @return Type of geo_block: 0-2
  800. */
  801. private short nGetType(final int x, final int y)
  802. {
  803. final short region = getRegionOffset(x, y);
  804. final int blockX = getBlock(x);
  805. final int blockY = getBlock(y);
  806. int index = 0;
  807. // Geodata without index - it is just empty so index can be calculated on the fly
  808. if (_geodataIndex.get(region) == null)
  809. index = ((blockX << 8) + blockY) * 3;
  810. // Get Index for current block of current geodata region
  811. else
  812. index = _geodataIndex.get(region).get((blockX << 8) + blockY);
  813. // Buffer that Contains current Region GeoData
  814. final ByteBuffer geo = _geodata.get(region);
  815. if (geo == null)
  816. {
  817. if (Config.DEBUG)
  818. LOGGER.warn("Geo Region - Region Offset: " + region + " dosnt exist!!");
  819. return 0;
  820. }
  821. return geo.get(index);
  822. }
  823.  
  824. /**
  825. * @param geox
  826. * @param geoy
  827. * @param z
  828. * @return Nearest Z
  829. */
  830. private short nGetHeight(final int geox, final int geoy, final int z)
  831. {
  832. final short region = getRegionOffset(geox, geoy);
  833. final int blockX = getBlock(geox);
  834. final int blockY = getBlock(geoy);
  835. int cellX, cellY, index;
  836. // Geodata without index - it is just empty so index can be calculated on the fly
  837. if (_geodataIndex.get(region) == null)
  838. index = ((blockX << 8) + blockY) * 3;
  839. // Get Index for current block of current region geodata
  840. else
  841. index = _geodataIndex.get(region).get((blockX << 8) + blockY);
  842. // Buffer that Contains current Region GeoData
  843. final ByteBuffer geo = _geodata.get(region);
  844. if (geo == null)
  845. {
  846. if (Config.DEBUG)
  847. LOGGER.warn("Geo Region - Region Offset: " + region + " dosnt exist!!");
  848. return (short) z;
  849. }
  850. // Read current block type: 0-flat,1-complex,2-multilevel
  851. final byte type = geo.get(index);
  852. index++;
  853. if (type == 0)// flat
  854. return geo.getShort(index);
  855. else if (type == 1)// complex
  856. {
  857. cellX = getCell(geox);
  858. cellY = getCell(geoy);
  859. index += ((cellX << 3) + cellY) << 1;
  860. short height = geo.getShort(index);
  861. height = (short) (height & 0x0fff0);
  862. height = (short) (height >> 1); // height / 2
  863. return height;
  864. }
  865. else
  866. // multilevel
  867. {
  868. cellX = getCell(geox);
  869. cellY = getCell(geoy);
  870. int offset = (cellX << 3) + cellY;
  871. while (offset > 0)
  872. {
  873. final byte lc = geo.get(index);
  874. index += (lc << 1) + 1;
  875. offset--;
  876. }
  877. byte layers = geo.get(index);
  878. index++;
  879. short height = -1;
  880. if (layers <= 0 || layers > 125)
  881. {
  882. if (Config.DEBUG)
  883. LOGGER.warn("Broken geofile (case1), region: " + region + " - invalid layer count: " + layers + " at: " + geox + " " + geoy);
  884. return (short) z;
  885. }
  886. short temph = Short.MIN_VALUE;
  887. while (layers > 0)
  888. {
  889. height = geo.getShort(index);
  890. height = (short) (height & 0x0fff0);
  891. height = (short) (height >> 1); // height / 2
  892. if ((z - temph) * (z - temph) > (z - height) * (z - height))
  893. temph = height;
  894. layers--;
  895. index += 2;
  896. }
  897. return temph;
  898. }
  899. }
  900.  
  901. /**
  902. * @param geox
  903. * @param geoy
  904. * @param z
  905. * @return One layer higher Z than parameter Z
  906. */
  907. private short nGetUpperHeight(final int geox, final int geoy, final int z)
  908. {
  909. final short region = getRegionOffset(geox, geoy);
  910. final int blockX = getBlock(geox);
  911. final int blockY = getBlock(geoy);
  912. int cellX, cellY, index;
  913. // Geodata without index - it is just empty so index can be calculated on the fly
  914. if (_geodataIndex.get(region) == null)
  915. index = ((blockX << 8) + blockY) * 3;
  916. // Get Index for current block of current region geodata
  917. else
  918. index = _geodataIndex.get(region).get((blockX << 8) + blockY);
  919. // Buffer that Contains current Region GeoData
  920. final ByteBuffer geo = _geodata.get(region);
  921. if (geo == null)
  922. {
  923. if (Config.DEBUG)
  924. LOGGER.warn("Geo Region - Region Offset: " + region + " dosnt exist!!");
  925. return (short) z;
  926. }
  927. // Read current block type: 0-flat,1-complex,2-multilevel
  928. final byte type = geo.get(index);
  929. index++;
  930. if (type == 0)// flat
  931. return geo.getShort(index);
  932. else if (type == 1)// complex
  933. {
  934. cellX = getCell(geox);
  935. cellY = getCell(geoy);
  936. index += ((cellX << 3) + cellY) << 1;
  937. short height = geo.getShort(index);
  938. height = (short) (height & 0x0fff0);
  939. height = (short) (height >> 1); // height / 2
  940. return height;
  941. }
  942. else
  943. // multilevel
  944. {
  945. cellX = getCell(geox);
  946. cellY = getCell(geoy);
  947. int offset = (cellX << 3) + cellY;
  948. while (offset > 0)
  949. {
  950. final byte lc = geo.get(index);
  951. index += (lc << 1) + 1;
  952. offset--;
  953. }
  954. byte layers = geo.get(index);
  955. index++;
  956. short height = -1;
  957. if (layers <= 0 || layers > 125)
  958. {
  959. if (Config.DEBUG)
  960. LOGGER.warn("Broken geofile (case1), region: " + region + " - invalid layer count: " + layers + " at: " + geox + " " + geoy);
  961. return (short) z;
  962. }
  963. short temph = Short.MAX_VALUE;
  964. while (layers > 0) // from higher to lower
  965. {
  966. height = geo.getShort(index);
  967. height = (short) (height & 0x0fff0);
  968. height = (short) (height >> 1); // height / 2
  969. if (height < z)
  970. return temph;
  971. temph = height;
  972. layers--;
  973. index += 2;
  974. }
  975. return temph;
  976. }
  977. }
  978.  
  979. /**
  980. * @param geox
  981. * @param geoy
  982. * @param zmin
  983. * @param zmax
  984. * @param spawnid
  985. * @return Z betwen zmin and zmax
  986. */
  987. private short nGetSpawnHeight(final int geox, final int geoy, final int zmin, final int zmax, final int spawnid)
  988. {
  989. final short region = getRegionOffset(geox, geoy);
  990. final int blockX = getBlock(geox);
  991. final int blockY = getBlock(geoy);
  992. int cellX, cellY, index;
  993. short temph = Short.MIN_VALUE;
  994. // Geodata without index - it is just empty so index can be calculated on the fly
  995. if (_geodataIndex.get(region) == null)
  996. index = ((blockX << 8) + blockY) * 3;
  997. // Get Index for current block of current region geodata
  998. else
  999. index = _geodataIndex.get(region).get((blockX << 8) + blockY);
  1000. // Buffer that Contains current Region GeoData
  1001. final ByteBuffer geo = _geodata.get(region);
  1002. if (geo == null)
  1003. {
  1004. if (Config.DEBUG)
  1005. LOGGER.warn("Geo Region - Region Offset: " + region + " dosnt exist!!");
  1006. return (short) zmin;
  1007. }
  1008. // Read current block type: 0-flat,1-complex,2-multilevel
  1009. final byte type = geo.get(index);
  1010. index++;
  1011. if (type == 0)// flat
  1012. temph = geo.getShort(index);
  1013. else if (type == 1)// complex
  1014. {
  1015. cellX = getCell(geox);
  1016. cellY = getCell(geoy);
  1017. index += ((cellX << 3) + cellY) << 1;
  1018. short height = geo.getShort(index);
  1019. height = (short) (height & 0x0fff0);
  1020. height = (short) (height >> 1); // height / 2
  1021. temph = height;
  1022. }
  1023. else
  1024. // multilevel
  1025. {
  1026. cellX = getCell(geox);
  1027. cellY = getCell(geoy);
  1028. short height;
  1029. int offset = (cellX << 3) + cellY;
  1030. while (offset > 0)
  1031. {
  1032. final byte lc = geo.get(index);
  1033. index += (lc << 1) + 1;
  1034. offset--;
  1035. }
  1036. // Read current block type: 0-flat,1-complex,2-multilevel
  1037. byte layers = geo.get(index);
  1038. index++;
  1039. if (layers <= 0 || layers > 125)
  1040. {
  1041. if (Config.DEBUG)
  1042. LOGGER.warn("Broken geofile (case2), region: " + region + " - invalid layer count: " + layers + " at: " + geox + " " + geoy);
  1043. return (short) zmin;
  1044. }
  1045. while (layers > 0)
  1046. {
  1047. height = geo.getShort(index);
  1048. height = (short) (height & 0x0fff0);
  1049. height = (short) (height >> 1); // height / 2
  1050. if ((zmin - temph) * (zmin - temph) > (zmin - height) * (zmin - height))
  1051. temph = height;
  1052. layers--;
  1053. index += 2;
  1054. }
  1055. if (temph > zmax + 200 || temph < zmin - 200)
  1056. {
  1057. if (Config.DEBUG)
  1058. LOGGER.warn("SpawnHeight Error - Couldnt find correct layer to spawn NPC - GeoData or Spawnlist Bug!: zmin: " + zmin + " zmax: " + zmax + " value: " + temph + " SpawnId: " + spawnid + " at: " + geox + " : " + geoy);
  1059. return (short) zmin;
  1060. }
  1061. }
  1062. if (temph > zmax + 1000 || temph < zmin - 1000)
  1063. {
  1064. if (Config.DEBUG)
  1065. LOGGER.warn("SpawnHeight Error - Spawnlist z value is wrong or GeoData error: zmin: " + zmin + " zmax: " + zmax + " value: " + temph + " SpawnId: " + spawnid + " at: " + geox + " : " + geoy);
  1066. return (short) zmin;
  1067. }
  1068. return temph;
  1069. }
  1070.  
  1071. /**
  1072. * @param x
  1073. * @param y
  1074. * @param z
  1075. * @param tx
  1076. * @param ty
  1077. * @param tz
  1078. * @return True if char can move to (tx,ty,tz)
  1079. */
  1080. private double nCanMoveNext(final int x, final int y, final int z, final int tx, final int ty, final int tz)
  1081. {
  1082. final short region = getRegionOffset(x, y);
  1083. final int blockX = getBlock(x);
  1084. final int blockY = getBlock(y);
  1085. int cellX, cellY;
  1086. short NSWE = 0;
  1087.  
  1088. int index = 0;
  1089. // Geodata without index - it is just empty so index can be calculated on the fly
  1090. if (_geodataIndex.get(region) == null)
  1091. index = ((blockX << 8) + blockY) * 3;
  1092. // Get Index for current block of current region geodata
  1093. else
  1094. index = _geodataIndex.get(region).get((blockX << 8) + blockY);
  1095. // Buffer that Contains current Region GeoData
  1096. final ByteBuffer geo = _geodata.get(region);
  1097. if (geo == null)
  1098. {
  1099. if (Config.DEBUG)
  1100. LOGGER.warn("Geo Region - Region Offset: " + region + " dosnt exist!!");
  1101. return z;
  1102. }
  1103. // Read current block type: 0-flat,1-complex,2-multilevel
  1104. final byte type = geo.get(index);
  1105. index++;
  1106. if (type == 0) // flat
  1107. return geo.getShort(index);
  1108. else if (type == 1) // complex
  1109. {
  1110. cellX = getCell(x);
  1111. cellY = getCell(y);
  1112. index += ((cellX << 3) + cellY) << 1;
  1113. short height = geo.getShort(index);
  1114. NSWE = (short) (height & 0x0F);
  1115. height = (short) (height & 0x0fff0);
  1116. height = (short) (height >> 1); // height / 2
  1117. if (checkNSWE(NSWE, x, y, tx, ty))
  1118. return height;
  1119. return Double.MIN_VALUE;
  1120. }
  1121. else
  1122. // multilevel, type == 2
  1123. {
  1124. cellX = getCell(x);
  1125. cellY = getCell(y);
  1126. int offset = (cellX << 3) + cellY;
  1127. while (offset > 0) // iterates (too many times?) to get to layer count
  1128. {
  1129. final byte lc = geo.get(index);
  1130. index += (lc << 1) + 1;
  1131. offset--;
  1132. }
  1133. byte layers = geo.get(index);
  1134. // LOGGER.warn( "layers"+layers);
  1135. index++;
  1136. short height = -1;
  1137. if (layers <= 0 || layers > 125)
  1138. {
  1139. if (Config.DEBUG)
  1140. LOGGER.warn("Broken geofile (case3), region: " + region + " - invalid layer count: " + layers + " at: " + x + " " + y);
  1141. return z;
  1142. }
  1143. short tempz = Short.MIN_VALUE;
  1144. while (layers > 0)
  1145. {
  1146. height = geo.getShort(index);
  1147. height = (short) (height & 0x0fff0);
  1148. height = (short) (height >> 1); // height / 2
  1149.  
  1150. // searches the closest layer to current z coordinate
  1151. if ((z - tempz) * (z - tempz) > (z - height) * (z - height))
  1152. {
  1153. // layercurr = layers;
  1154. tempz = height;
  1155. NSWE = geo.getShort(index);
  1156. NSWE = (short) (NSWE & 0x0F);
  1157. }
  1158. layers--;
  1159. index += 2;
  1160. }
  1161. if (checkNSWE(NSWE, x, y, tx, ty))
  1162. return tempz;
  1163. return Double.MIN_VALUE;
  1164. }
  1165. }
  1166.  
  1167. /**
  1168. * @param x
  1169. * @param y
  1170. * @param z
  1171. * @param inc_x
  1172. * @param inc_y
  1173. * @param inc_z
  1174. * @param tz
  1175. * @param debug
  1176. * @return True if Char can see target
  1177. */
  1178. private boolean nLOS(final int x, final int y, final int z, final int inc_x, final int inc_y, final double inc_z, final int tz, final boolean debug)
  1179. {
  1180. final short region = getRegionOffset(x, y);
  1181. final int blockX = getBlock(x);
  1182. final int blockY = getBlock(y);
  1183. int cellX, cellY;
  1184. short NSWE = 0;
  1185.  
  1186. int index;
  1187. // Geodata without index - it is just empty so index can be calculated on the fly
  1188. if (_geodataIndex.get(region) == null)
  1189. index = ((blockX << 8) + blockY) * 3;
  1190. // Get Index for current block of current region geodata
  1191. else
  1192. index = _geodataIndex.get(region).get((blockX << 8) + blockY);
  1193. // Buffer that Contains current Region GeoData
  1194. final ByteBuffer geo = _geodata.get(region);
  1195. if (geo == null)
  1196. {
  1197. if (Config.DEBUG)
  1198. LOGGER.warn("Geo Region - Region Offset: " + region + " dosnt exist!!");
  1199. return true;
  1200. }
  1201. // Read current block type: 0-flat,1-complex,2-multilevel
  1202. final byte type = geo.get(index);
  1203. index++;
  1204. if (type == 0) // flat, movement and sight always possible
  1205. {
  1206. final short height = geo.getShort(index);
  1207. if (debug)
  1208. LOGGER.warn("flatheight:" + height);
  1209. if (z > height)
  1210. return inc_z > height;
  1211. return inc_z < height;
  1212. }
  1213. else if (type == 1) // complex
  1214. {
  1215. cellX = getCell(x);
  1216. cellY = getCell(y);
  1217. index += ((cellX << 3) + cellY) << 1;
  1218. short height = geo.getShort(index);
  1219. NSWE = (short) (height & 0x0F);
  1220. height = (short) (height & 0x0fff0);
  1221. height = (short) (height >> 1); // height / 2
  1222. if (!checkNSWE(NSWE, x, y, x + inc_x, y + inc_y))
  1223. {
  1224. if (debug)
  1225. LOGGER.warn("height:" + height + " z" + z);
  1226.  
  1227. return z >= nGetUpperHeight(x + inc_x, y + inc_y, height);
  1228. }
  1229. return true;
  1230. }
  1231. else
  1232. // multilevel, type == 2
  1233. {
  1234. cellX = getCell(x);
  1235. cellY = getCell(y);
  1236.  
  1237. int offset = (cellX << 3) + cellY;
  1238. while (offset > 0) // iterates (too many times?) to get to layer count
  1239. {
  1240. final byte lc = geo.get(index);
  1241. index += (lc << 1) + 1;
  1242. offset--;
  1243. }
  1244. final byte layers = geo.get(index);
  1245.  
  1246. index++;
  1247. short tempZ = -1;
  1248. if (layers <= 0 || layers > 125)
  1249. {
  1250. if (Config.DEBUG)
  1251. LOGGER.warn("Broken geofile (case4), region: " + region + " - invalid layer count: " + layers + " at: " + x + " " + y);
  1252. return false;
  1253. }
  1254. short upperHeight = Short.MAX_VALUE; // big positive value
  1255. short lowerHeight = Short.MIN_VALUE; // big negative value
  1256. byte temp_layers = layers;
  1257. boolean highestlayer = false;
  1258. while (temp_layers > 0) // from higher to lower
  1259. {
  1260. // reads tempZ for current layer, result in world z coordinate
  1261. tempZ = geo.getShort(index);
  1262. tempZ = (short) (tempZ & 0x0fff0);
  1263. tempZ = (short) (tempZ >> 1); // tempZ / 2
  1264.  
  1265. if (z > tempZ)
  1266. {
  1267. lowerHeight = tempZ;
  1268. NSWE = geo.getShort(index);
  1269. NSWE = (short) (NSWE & 0x0F);
  1270. break;
  1271. }
  1272. highestlayer = false;
  1273. upperHeight = tempZ;
  1274.  
  1275. temp_layers--;
  1276. index += 2;
  1277. }
  1278. if (debug)
  1279. LOGGER.warn("z:" + z + " x: " + cellX + " y:" + cellY + " la " + layers + " lo:" + lowerHeight + " up:" + upperHeight);
  1280. // Check if LOS goes under a layer/floor
  1281. // clearly under layer but not too much under
  1282. // lowerheight here only for geodata bug checking, layers very close? maybe could be removed
  1283. if ((z - upperHeight) < -10 && (z - upperHeight) > inc_z - 10 && (z - lowerHeight) > 40)
  1284. {
  1285. if (debug)
  1286. LOGGER.warn("false, incz" + inc_z);
  1287. return false;
  1288. }
  1289.  
  1290. // or there's a fence/wall ahead when we're not on highest layer
  1291. if (!highestlayer)
  1292. {
  1293. // a probable wall, there's movement block and layers above you
  1294. if (!checkNSWE(NSWE, x, y, x + inc_x, y + inc_y)) // cannot move
  1295. {
  1296. if (debug)
  1297. LOGGER.warn("block and next in x" + inc_x + " y" + inc_y + " is:" + nGetUpperHeight(x + inc_x, y + inc_y, lowerHeight));
  1298. // check one inc_x inc_y further, for the height there
  1299. return z >= nGetUpperHeight(x + inc_x, y + inc_y, lowerHeight);
  1300. }
  1301. return true;
  1302. }
  1303. if (!checkNSWE(NSWE, x, y, x + inc_x, y + inc_y))
  1304. {
  1305. // check one inc_x inc_y further, for the height there
  1306. return z >= nGetUpperHeight(x + inc_x, y + inc_y, lowerHeight);
  1307. }
  1308. return true;
  1309. }
  1310. }
  1311.  
  1312. /**
  1313. * @param x
  1314. * @param y
  1315. * @param z
  1316. * @return NSWE: 0-15
  1317. */
  1318. private short nGetNSWE(final int x, final int y, final int z)
  1319. {
  1320. final short region = getRegionOffset(x, y);
  1321. final int blockX = getBlock(x);
  1322. final int blockY = getBlock(y);
  1323. int cellX, cellY;
  1324. short NSWE = 0;
  1325.  
  1326. int index = 0;
  1327. // Geodata without index - it is just empty so index can be calculated on the fly
  1328. if (_geodataIndex.get(region) == null)
  1329. index = ((blockX << 8) + blockY) * 3;
  1330. // Get Index for current block of current region geodata
  1331. else
  1332. index = _geodataIndex.get(region).get((blockX << 8) + blockY);
  1333. // Buffer that Contains current Region GeoData
  1334. final ByteBuffer geo = _geodata.get(region);
  1335. if (geo == null)
  1336. {
  1337. if (Config.DEBUG)
  1338. LOGGER.warn("Geo Region - Region Offset: " + region + " dosnt exist!!");
  1339. return 15;
  1340. }
  1341. // Read current block type: 0-flat,1-complex,2-multilevel
  1342. final byte type = geo.get(index);
  1343. index++;
  1344. if (type == 0)// flat
  1345. return 15;
  1346. else if (type == 1)// complex
  1347. {
  1348. cellX = getCell(x);
  1349. cellY = getCell(y);
  1350. index += ((cellX << 3) + cellY) << 1;
  1351. final short height = geo.getShort(index);
  1352. NSWE = (short) (height & 0x0F);
  1353. }
  1354. else
  1355. // multilevel
  1356. {
  1357. cellX = getCell(x);
  1358. cellY = getCell(y);
  1359. int offset = (cellX << 3) + cellY;
  1360. while (offset > 0)
  1361. {
  1362. final byte lc = geo.get(index);
  1363. index += (lc << 1) + 1;
  1364. offset--;
  1365. }
  1366. byte layers = geo.get(index);
  1367. index++;
  1368. short height = -1;
  1369. if (layers <= 0 || layers > 125)
  1370. {
  1371. if (Config.DEBUG)
  1372. LOGGER.warn("Broken geofile (case5), region: " + region + " - invalid layer count: " + layers + " at: " + x + " " + y);
  1373. return 15;
  1374. }
  1375. short tempz = Short.MIN_VALUE;
  1376. while (layers > 0)
  1377. {
  1378. height = geo.getShort(index);
  1379. height = (short) (height & 0x0fff0);
  1380. height = (short) (height >> 1); // height / 2
  1381.  
  1382. if ((z - tempz) * (z - tempz) > (z - height) * (z - height))
  1383. {
  1384. tempz = height;
  1385. NSWE = geo.get(index);
  1386. NSWE = (short) (NSWE & 0x0F);
  1387. }
  1388. layers--;
  1389. index += 2;
  1390. }
  1391. }
  1392. return NSWE;
  1393. }
  1394.  
  1395. /**
  1396. * @param n
  1397. * @return NSWE: 0-15
  1398. */
  1399. @Override
  1400. public Node[] getNeighbors(final Node n)
  1401. {
  1402. Node newNode;
  1403. final int x = n.getNodeX();
  1404. final int y = n.getNodeY();
  1405. int parentdirection = 0;
  1406. if (n.getParent() != null) // check for not adding parent again
  1407. {
  1408. if (n.getParent().getNodeX() > x)
  1409. parentdirection = 1;
  1410. if (n.getParent().getNodeX() < x)
  1411. parentdirection = -1;
  1412. if (n.getParent().getNodeY() > y)
  1413. parentdirection = 2;
  1414. if (n.getParent().getNodeY() < y)
  1415. parentdirection = -2;
  1416. }
  1417. final short z = n.getZ();
  1418. final short region = getRegionOffset(x, y);
  1419. final int blockX = getBlock(x);
  1420. final int blockY = getBlock(y);
  1421. int cellX, cellY;
  1422. short NSWE = 0;
  1423. int index = 0;
  1424. // Geodata without index - it is just empty so index can be calculated on the fly
  1425. if (_geodataIndex.get(region) == null)
  1426. index = ((blockX << 8) + blockY) * 3;
  1427. // Get Index for current block of current region geodata
  1428. else
  1429. index = _geodataIndex.get(region).get((blockX << 8) + blockY);
  1430. // Buffer that Contains current Region GeoData
  1431. final ByteBuffer geo = _geodata.get(region);
  1432. if (geo == null)
  1433. {
  1434. if (Config.DEBUG)
  1435. LOGGER.warn("Geo Region - Region Offset: " + region + " dosnt exist!!");
  1436. return null;
  1437. }
  1438.  
  1439. final Node[] Neighbors = new Node[4];
  1440. int arrayIndex = 0;
  1441.  
  1442. // Read current block type: 0-flat,1-complex,2-multilevel
  1443. final byte type = geo.get(index);
  1444. index++;
  1445. if (type == 0)// flat
  1446. {
  1447. final short height = geo.getShort(index);
  1448. n.setZ(height);
  1449. if (parentdirection != 1)
  1450. {
  1451. newNode = CellPathFinding.getInstance().readNode(x + 1, y, height);
  1452. // newNode.setCost(0);
  1453. Neighbors[arrayIndex++] = newNode;
  1454. }
  1455. if (parentdirection != 2)
  1456. {
  1457. newNode = CellPathFinding.getInstance().readNode(x, y + 1, height);
  1458. Neighbors[arrayIndex++] = newNode;
  1459. }
  1460. if (parentdirection != -2)
  1461. {
  1462. newNode = CellPathFinding.getInstance().readNode(x, y - 1, height);
  1463. Neighbors[arrayIndex++] = newNode;
  1464. }
  1465. if (parentdirection != -1)
  1466. {
  1467. newNode = CellPathFinding.getInstance().readNode(x - 1, y, height);
  1468. Neighbors[arrayIndex++] = newNode;
  1469. }
  1470. }
  1471. else if (type == 1)// complex
  1472. {
  1473. cellX = getCell(x);
  1474. cellY = getCell(y);
  1475. index += ((cellX << 3) + cellY) << 1;
  1476. short height = geo.getShort(index);
  1477. NSWE = (short) (height & 0x0F);
  1478. height = (short) (height & 0x0fff0);
  1479. height = (short) (height >> 1); // height / 2
  1480. n.setZ(height);
  1481. if (NSWE != 15 && parentdirection != 0)
  1482. return null; // no node with a block will be used
  1483. if (parentdirection != 1 && checkNSWE(NSWE, x, y, x + 1, y))
  1484. {
  1485. newNode = CellPathFinding.getInstance().readNode(x + 1, y, height);
  1486. // newNode.setCost(basecost+50);
  1487. Neighbors[arrayIndex++] = newNode;
  1488. }
  1489. if (parentdirection != 2 && checkNSWE(NSWE, x, y, x, y + 1))
  1490. {
  1491. newNode = CellPathFinding.getInstance().readNode(x, y + 1, height);
  1492. Neighbors[arrayIndex++] = newNode;
  1493. }
  1494. if (parentdirection != -2 && checkNSWE(NSWE, x, y, x, y - 1))
  1495. {
  1496. newNode = CellPathFinding.getInstance().readNode(x, y - 1, height);
  1497. Neighbors[arrayIndex++] = newNode;
  1498. }
  1499. if (parentdirection != -1 && checkNSWE(NSWE, x, y, x - 1, y))
  1500. {
  1501. newNode = CellPathFinding.getInstance().readNode(x - 1, y, height);
  1502. Neighbors[arrayIndex++] = newNode;
  1503. }
  1504. }
  1505. else
  1506. // multilevel
  1507. {
  1508. cellX = getCell(x);
  1509. cellY = getCell(y);
  1510. int offset = (cellX << 3) + cellY;
  1511. while (offset > 0)
  1512. {
  1513. final byte lc = geo.get(index);
  1514. index += (lc << 1) + 1;
  1515. offset--;
  1516. }
  1517. byte layers = geo.get(index);
  1518. index++;
  1519. short height = -1;
  1520. if (layers <= 0 || layers > 125)
  1521. {
  1522. if (Config.DEBUG)
  1523. LOGGER.warn("Broken geofile (case5), region: " + region + " - invalid layer count: " + layers + " at: " + x + " " + y);
  1524. return null;
  1525. }
  1526. short tempz = Short.MIN_VALUE;
  1527. while (layers > 0)
  1528. {
  1529. height = geo.getShort(index);
  1530. height = (short) (height & 0x0fff0);
  1531. height = (short) (height >> 1); // height / 2
  1532.  
  1533. if ((z - tempz) * (z - tempz) > (z - height) * (z - height))
  1534. {
  1535. tempz = height;
  1536. NSWE = geo.get(index);
  1537. NSWE = (short) (NSWE & 0x0F);
  1538. }
  1539. layers--;
  1540. index += 2;
  1541. }
  1542. n.setZ(tempz);
  1543. if (NSWE != 15 && parentdirection != 0)
  1544. return null; // no node with a block will be used
  1545. if (parentdirection != 1 && checkNSWE(NSWE, x, y, x + 1, y))
  1546. {
  1547. newNode = CellPathFinding.getInstance().readNode(x + 1, y, tempz);
  1548. // newNode.setCost(basecost+50);
  1549. Neighbors[arrayIndex++] = newNode;
  1550. }
  1551. if (parentdirection != 2 && checkNSWE(NSWE, x, y, x, y + 1))
  1552. {
  1553. newNode = CellPathFinding.getInstance().readNode(x, y + 1, tempz);
  1554. Neighbors[arrayIndex++] = newNode;
  1555. }
  1556. if (parentdirection != -2 && checkNSWE(NSWE, x, y, x, y - 1))
  1557. {
  1558. newNode = CellPathFinding.getInstance().readNode(x, y - 1, tempz);
  1559. Neighbors[arrayIndex++] = newNode;
  1560. }
  1561. if (parentdirection != -1 && checkNSWE(NSWE, x, y, x - 1, y))
  1562. {
  1563. newNode = CellPathFinding.getInstance().readNode(x - 1, y, tempz);
  1564. Neighbors[arrayIndex++] = newNode;
  1565. }
  1566. }
  1567.  
  1568. return L2Arrays.compact(Neighbors);
  1569. }
  1570.  
  1571. /**
  1572. * @param NSWE
  1573. * @param x
  1574. * @param y
  1575. * @param tx
  1576. * @param ty
  1577. * @return True if NSWE dont block given direction
  1578. */
  1579. private boolean checkNSWE(final short NSWE, final int x, final int y, final int tx, final int ty)
  1580. {
  1581. // Check NSWE
  1582. if (NSWE == 15)
  1583. return true;
  1584. if (tx > x)// E
  1585. {
  1586. if ((NSWE & _e) == 0)
  1587. return false;
  1588. }
  1589. else if (tx < x)// W
  1590. {
  1591. if ((NSWE & _w) == 0)
  1592. return false;
  1593. }
  1594. if (ty > y)// S
  1595. {
  1596. if ((NSWE & _s) == 0)
  1597. return false;
  1598. }
  1599. else if (ty < y)// N
  1600. {
  1601. if ((NSWE & _n) == 0)
  1602. return false;
  1603. }
  1604. return true;
  1605. }
  1606. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement