Util.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. /*
  2. * Copyright (C) 2004-2013 L2J Server
  3. *
  4. * This file is part of L2J Server.
  5. *
  6. * L2J Server is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * L2J Server is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. package com.l2jserver.gameserver.util;
  20. import java.io.File;
  21. import java.text.DateFormat;
  22. import java.text.DecimalFormat;
  23. import java.text.DecimalFormatSymbols;
  24. import java.text.NumberFormat;
  25. import java.text.SimpleDateFormat;
  26. import java.util.Collection;
  27. import java.util.Date;
  28. import java.util.List;
  29. import java.util.Locale;
  30. import javolution.text.TextBuilder;
  31. import javolution.util.FastList;
  32. import com.l2jserver.Config;
  33. import com.l2jserver.gameserver.GeoData;
  34. import com.l2jserver.gameserver.ThreadPoolManager;
  35. import com.l2jserver.gameserver.model.L2Object;
  36. import com.l2jserver.gameserver.model.actor.L2Character;
  37. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  38. import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
  39. import com.l2jserver.gameserver.network.serverpackets.ShowBoard;
  40. import com.l2jserver.util.file.filter.ExtFilter;
  41. /**
  42. * General Utility functions related to game server.
  43. */
  44. public final class Util
  45. {
  46. private static final NumberFormat ADENA_FORMATTER = NumberFormat.getIntegerInstance(Locale.ENGLISH);
  47. public static void handleIllegalPlayerAction(L2PcInstance actor, String message, int punishment)
  48. {
  49. ThreadPoolManager.getInstance().scheduleGeneral(new IllegalPlayerAction(actor, message, punishment), 5000);
  50. }
  51. public static String getRelativePath(File base, File file)
  52. {
  53. return file.toURI().getPath().substring(base.toURI().getPath().length());
  54. }
  55. /**
  56. * @param obj1
  57. * @param obj2
  58. * @return degree value of object 2 to the horizontal line with object 1 being the origin.
  59. */
  60. public static double calculateAngleFrom(L2Object obj1, L2Object obj2)
  61. {
  62. return calculateAngleFrom(obj1.getX(), obj1.getY(), obj2.getX(), obj2.getY());
  63. }
  64. /**
  65. * @param obj1X
  66. * @param obj1Y
  67. * @param obj2X
  68. * @param obj2Y
  69. * @return degree value of object 2 to the horizontal line with object 1 being the origin
  70. */
  71. public static final double calculateAngleFrom(int obj1X, int obj1Y, int obj2X, int obj2Y)
  72. {
  73. double angleTarget = Math.toDegrees(Math.atan2(obj2Y - obj1Y, obj2X - obj1X));
  74. if (angleTarget < 0)
  75. {
  76. angleTarget = 360 + angleTarget;
  77. }
  78. return angleTarget;
  79. }
  80. public static final double convertHeadingToDegree(int clientHeading)
  81. {
  82. double degree = clientHeading / 182.044444444;
  83. return degree;
  84. }
  85. public static final int convertDegreeToClientHeading(double degree)
  86. {
  87. if (degree < 0)
  88. {
  89. degree = 360 + degree;
  90. }
  91. return (int) (degree * 182.044444444);
  92. }
  93. public static final int calculateHeadingFrom(L2Object obj1, L2Object obj2)
  94. {
  95. return calculateHeadingFrom(obj1.getX(), obj1.getY(), obj2.getX(), obj2.getY());
  96. }
  97. public static final int calculateHeadingFrom(int obj1X, int obj1Y, int obj2X, int obj2Y)
  98. {
  99. double angleTarget = Math.toDegrees(Math.atan2(obj2Y - obj1Y, obj2X - obj1X));
  100. if (angleTarget < 0)
  101. {
  102. angleTarget = 360 + angleTarget;
  103. }
  104. return (int) (angleTarget * 182.044444444);
  105. }
  106. public static final int calculateHeadingFrom(double dx, double dy)
  107. {
  108. double angleTarget = Math.toDegrees(Math.atan2(dy, dx));
  109. if (angleTarget < 0)
  110. {
  111. angleTarget = 360 + angleTarget;
  112. }
  113. return (int) (angleTarget * 182.044444444);
  114. }
  115. /**
  116. * @param x1
  117. * @param y1
  118. * @param x2
  119. * @param y2
  120. * @return the distance between the two coordinates in 2D plane
  121. */
  122. public static double calculateDistance(int x1, int y1, int x2, int y2)
  123. {
  124. return calculateDistance(x1, y1, 0, x2, y2, 0, false);
  125. }
  126. /**
  127. * @param x1
  128. * @param y1
  129. * @param z1
  130. * @param x2
  131. * @param y2
  132. * @param z2
  133. * @param includeZAxis - if true, includes also the Z axis in the calculation
  134. * @return the distance between the two coordinates
  135. */
  136. public static double calculateDistance(int x1, int y1, int z1, int x2, int y2, int z2, boolean includeZAxis)
  137. {
  138. double dx = (double) x1 - x2;
  139. double dy = (double) y1 - y2;
  140. if (includeZAxis)
  141. {
  142. double dz = z1 - z2;
  143. return Math.sqrt((dx * dx) + (dy * dy) + (dz * dz));
  144. }
  145. return Math.sqrt((dx * dx) + (dy * dy));
  146. }
  147. /**
  148. * @param obj1
  149. * @param obj2
  150. * @param includeZAxis - if true, includes also the Z axis in the calculation
  151. * @return the distance between the two objects
  152. */
  153. public static double calculateDistance(L2Object obj1, L2Object obj2, boolean includeZAxis)
  154. {
  155. if ((obj1 == null) || (obj2 == null))
  156. {
  157. return 1000000;
  158. }
  159. return calculateDistance(obj1.getX(), obj1.getY(), obj1.getZ(), obj2.getX(), obj2.getY(), obj2.getZ(), includeZAxis);
  160. }
  161. /**
  162. * @param str - the string whose first letter to capitalize
  163. * @return a string with the first letter of the {@code str} capitalized
  164. */
  165. public static String capitalizeFirst(String str)
  166. {
  167. if ((str == null) || str.isEmpty())
  168. {
  169. return str;
  170. }
  171. final char[] arr = str.toCharArray();
  172. final char c = arr[0];
  173. if (Character.isLetter(c))
  174. {
  175. arr[0] = Character.toUpperCase(c);
  176. }
  177. return new String(arr);
  178. }
  179. /**
  180. * (Based on ucwords() function of PHP)<br>
  181. * DrHouse: still functional but must be rewritten to avoid += to concat strings
  182. * @param str - the string to capitalize
  183. * @return a string with the first letter of every word in {@code str} capitalized
  184. */
  185. @Deprecated
  186. public static String capitalizeWords(String str)
  187. {
  188. if ((str == null) || str.isEmpty())
  189. {
  190. return str;
  191. }
  192. char[] charArray = str.toCharArray();
  193. StringBuilder result = new StringBuilder();
  194. // Capitalize the first letter in the given string!
  195. charArray[0] = Character.toUpperCase(charArray[0]);
  196. for (int i = 0; i < charArray.length; i++)
  197. {
  198. if (Character.isWhitespace(charArray[i]))
  199. {
  200. charArray[i + 1] = Character.toUpperCase(charArray[i + 1]);
  201. }
  202. result.append(charArray[i]);
  203. }
  204. return result.toString();
  205. }
  206. /**
  207. * @param range
  208. * @param obj1
  209. * @param obj2
  210. * @param includeZAxis
  211. * @return {@code true} if the two objects are within specified range between each other, {@code false} otherwise
  212. */
  213. public static boolean checkIfInRange(int range, L2Object obj1, L2Object obj2, boolean includeZAxis)
  214. {
  215. if ((obj1 == null) || (obj2 == null))
  216. {
  217. return false;
  218. }
  219. if (obj1.getInstanceId() != obj2.getInstanceId())
  220. {
  221. return false;
  222. }
  223. if (range == -1)
  224. {
  225. return true; // not limited
  226. }
  227. int rad = 0;
  228. if (obj1 instanceof L2Character)
  229. {
  230. rad += ((L2Character) obj1).getTemplate().getCollisionRadius();
  231. }
  232. if (obj2 instanceof L2Character)
  233. {
  234. rad += ((L2Character) obj2).getTemplate().getCollisionRadius();
  235. }
  236. double dx = obj1.getX() - obj2.getX();
  237. double dy = obj1.getY() - obj2.getY();
  238. double d = (dx * dx) + (dy * dy);
  239. if (includeZAxis)
  240. {
  241. double dz = obj1.getZ() - obj2.getZ();
  242. d += (dz * dz);
  243. }
  244. return d <= ((range * range) + (2 * range * rad) + (rad * rad));
  245. }
  246. /**
  247. * Checks if object is within short (sqrt(int.max_value)) radius, not using collisionRadius. Faster calculation than checkIfInRange if distance is short and collisionRadius isn't needed. Not for long distance checks (potential teleports, far away castles etc).
  248. * @param radius
  249. * @param obj1
  250. * @param obj2
  251. * @param includeZAxis if true, check also Z axis (3-dimensional check), otherwise only 2D
  252. * @return {@code true} if objects are within specified range between each other, {@code false} otherwise
  253. */
  254. public static boolean checkIfInShortRadius(int radius, L2Object obj1, L2Object obj2, boolean includeZAxis)
  255. {
  256. if ((obj1 == null) || (obj2 == null))
  257. {
  258. return false;
  259. }
  260. if (radius == -1)
  261. {
  262. return true; // not limited
  263. }
  264. int dx = obj1.getX() - obj2.getX();
  265. int dy = obj1.getY() - obj2.getY();
  266. if (includeZAxis)
  267. {
  268. int dz = obj1.getZ() - obj2.getZ();
  269. return ((dx * dx) + (dy * dy) + (dz * dz)) <= (radius * radius);
  270. }
  271. return ((dx * dx) + (dy * dy)) <= (radius * radius);
  272. }
  273. /**
  274. * @param str - the String to count
  275. * @return the number of "words" in a given string.
  276. */
  277. public static int countWords(String str)
  278. {
  279. return str.trim().split("\\s+").length;
  280. }
  281. /**
  282. * (Based on implode() in PHP)
  283. * @param strArray - an array of strings to concatenate
  284. * @param strDelim - the delimiter to put between the strings
  285. * @return a delimited string for a given array of string elements.
  286. */
  287. public static String implodeString(Iterable<String> strArray, String strDelim)
  288. {
  289. final TextBuilder sbString = TextBuilder.newInstance();
  290. for (String strValue : strArray)
  291. {
  292. sbString.append(strValue);
  293. sbString.append(strDelim);
  294. }
  295. String result = sbString.toString();
  296. TextBuilder.recycle(sbString);
  297. return result;
  298. }
  299. /**
  300. * Based on implode() in PHP
  301. * @param <T>
  302. * @param array
  303. * @param delim
  304. * @return a delimited string for a given array of string elements.
  305. */
  306. public static <T> String implode(T[] array, String delim)
  307. {
  308. String result = "";
  309. for (T val : array)
  310. {
  311. result += val.toString() + delim;
  312. }
  313. if (!result.isEmpty())
  314. {
  315. result = result.substring(0, result.length() - 1);
  316. }
  317. return result;
  318. }
  319. /**
  320. * (Based on round() in PHP)
  321. * @param number - the number to round
  322. * @param numPlaces - how many digits after decimal point to leave intact
  323. * @return the value of {@code number} rounded to specified number of digits after the decimal point.
  324. */
  325. public static float roundTo(float number, int numPlaces)
  326. {
  327. if (numPlaces <= 1)
  328. {
  329. return Math.round(number);
  330. }
  331. float exponent = (float) Math.pow(10, numPlaces);
  332. return Math.round(number * exponent) / exponent;
  333. }
  334. /**
  335. * @param text - the text to check
  336. * @return {@code true} if {@code text} contains only numbers, {@code false} otherwise
  337. */
  338. public static boolean isDigit(String text)
  339. {
  340. if ((text == null) || text.isEmpty())
  341. {
  342. return false;
  343. }
  344. for (char c : text.toCharArray())
  345. {
  346. if (!Character.isDigit(c))
  347. {
  348. return false;
  349. }
  350. }
  351. return true;
  352. }
  353. /**
  354. * @param text - the text to check
  355. * @return {@code true} if {@code text} contains only letters and/or numbers, {@code false} otherwise
  356. */
  357. public static boolean isAlphaNumeric(String text)
  358. {
  359. if ((text == null) || text.isEmpty())
  360. {
  361. return false;
  362. }
  363. for (char c : text.toCharArray())
  364. {
  365. if (!Character.isLetterOrDigit(c))
  366. {
  367. return false;
  368. }
  369. }
  370. return true;
  371. }
  372. /**
  373. * Format the specified digit using the digit grouping symbol "," (comma).<br>
  374. * For example, 123456789 becomes 123,456,789.
  375. * @param amount - the amount of adena
  376. * @return the formatted adena amount
  377. */
  378. public static String formatAdena(long amount)
  379. {
  380. synchronized (ADENA_FORMATTER)
  381. {
  382. return ADENA_FORMATTER.format(amount);
  383. }
  384. }
  385. /**
  386. * @param val
  387. * @param format
  388. * @return formatted double value by specified format.
  389. */
  390. public static String formatDouble(double val, String format)
  391. {
  392. final DecimalFormat formatter = new DecimalFormat(format, new DecimalFormatSymbols(Locale.ENGLISH));
  393. return formatter.format(val);
  394. }
  395. /**
  396. * Format the given date on the given format
  397. * @param date : the date to format.
  398. * @param format : the format to correct by.
  399. * @return a string representation of the formatted date.
  400. */
  401. public static String formatDate(Date date, String format)
  402. {
  403. if (date == null)
  404. {
  405. return null;
  406. }
  407. final DateFormat dateFormat = new SimpleDateFormat(format);
  408. return dateFormat.format(date);
  409. }
  410. /**
  411. * @param <T>
  412. * @param array - the array to look into
  413. * @param obj - the object to search for
  414. * @return {@code true} if the {@code array} contains the {@code obj}, {@code false} otherwise.
  415. */
  416. public static <T> boolean contains(T[] array, T obj)
  417. {
  418. for (T element : array)
  419. {
  420. if (element == obj)
  421. {
  422. return true;
  423. }
  424. }
  425. return false;
  426. }
  427. /**
  428. * @param array - the array to look into
  429. * @param obj - the integer to search for
  430. * @return {@code true} if the {@code array} contains the {@code obj}, {@code false} otherwise
  431. */
  432. public static boolean contains(int[] array, int obj)
  433. {
  434. for (int element : array)
  435. {
  436. if (element == obj)
  437. {
  438. return true;
  439. }
  440. }
  441. return false;
  442. }
  443. public static File[] getDatapackFiles(String dirname, String extention)
  444. {
  445. File dir = new File(Config.DATAPACK_ROOT, "data/" + dirname);
  446. if (!dir.exists())
  447. {
  448. return null;
  449. }
  450. return dir.listFiles(new ExtFilter(extention));
  451. }
  452. public static String getDateString(Date date)
  453. {
  454. SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
  455. return dateFormat.format(date.getTime());
  456. }
  457. /**
  458. * Sends the given html to the player.
  459. * @param activeChar
  460. * @param html
  461. */
  462. public static void sendHtml(L2PcInstance activeChar, String html)
  463. {
  464. NpcHtmlMessage npcHtml = new NpcHtmlMessage(0);
  465. npcHtml.setHtml(html);
  466. activeChar.sendPacket(npcHtml);
  467. }
  468. /**
  469. * Sends the html using the community board window.
  470. * @param activeChar
  471. * @param html
  472. */
  473. public static void sendCBHtml(L2PcInstance activeChar, String html)
  474. {
  475. sendCBHtml(activeChar, html, "");
  476. }
  477. /**
  478. * Sends the html using the community board window.
  479. * @param activeChar
  480. * @param html
  481. * @param fillMultiEdit fills the multiedit window (if any) inside the community board.
  482. */
  483. public static void sendCBHtml(L2PcInstance activeChar, String html, String fillMultiEdit)
  484. {
  485. if (activeChar == null)
  486. {
  487. return;
  488. }
  489. if (html != null)
  490. {
  491. activeChar.clearBypass();
  492. int len = html.length();
  493. for (int i = 0; i < len; i++)
  494. {
  495. int start = html.indexOf("\"bypass ", i);
  496. int finish = html.indexOf("\"", start + 1);
  497. if ((start < 0) || (finish < 0))
  498. {
  499. break;
  500. }
  501. if (html.substring(start + 8, start + 10).equals("-h"))
  502. {
  503. start += 11;
  504. }
  505. else
  506. {
  507. start += 8;
  508. }
  509. i = finish;
  510. int finish2 = html.indexOf("$", start);
  511. if ((finish2 < finish) && (finish2 > 0))
  512. {
  513. activeChar.addBypass2(html.substring(start, finish2).trim());
  514. }
  515. else
  516. {
  517. activeChar.addBypass(html.substring(start, finish).trim());
  518. }
  519. }
  520. }
  521. if (fillMultiEdit != null)
  522. {
  523. activeChar.sendPacket(new ShowBoard(html, "1001"));
  524. fillMultiEditContent(activeChar, fillMultiEdit);
  525. }
  526. else
  527. {
  528. activeChar.sendPacket(new ShowBoard(null, "101"));
  529. activeChar.sendPacket(new ShowBoard(html, "101"));
  530. activeChar.sendPacket(new ShowBoard(null, "102"));
  531. activeChar.sendPacket(new ShowBoard(null, "103"));
  532. }
  533. }
  534. /**
  535. * Fills the community board's multiedit window with text. Must send after sendCBHtml
  536. * @param activeChar
  537. * @param text
  538. */
  539. public static void fillMultiEditContent(L2PcInstance activeChar, String text)
  540. {
  541. text = text.replaceAll("<br>", Config.EOL);
  542. List<String> arg = new FastList<>();
  543. arg.add("0");
  544. arg.add("0");
  545. arg.add("0");
  546. arg.add("0");
  547. arg.add("0");
  548. arg.add("0");
  549. arg.add(activeChar.getName());
  550. arg.add(Integer.toString(activeChar.getObjectId()));
  551. arg.add(activeChar.getAccountName());
  552. arg.add("9");
  553. arg.add(" ");
  554. arg.add(" ");
  555. arg.add(text);
  556. arg.add("0");
  557. arg.add("0");
  558. arg.add("0");
  559. arg.add("0");
  560. activeChar.sendPacket(new ShowBoard(arg));
  561. }
  562. /**
  563. * Return the number of playable characters in a defined radius around the specified object.
  564. * @param range : the radius in which to look for players
  565. * @param npc : the object whose knownlist to check
  566. * @param playable : if {@code true}, count summons and pets aswell
  567. * @param invisible : if {@code true}, count invisible characters aswell
  568. * @return the number of targets found
  569. */
  570. public static int getPlayersCountInRadius(int range, L2Object npc, boolean playable, boolean invisible)
  571. {
  572. int count = 0;
  573. final Collection<L2Object> objs = npc.getKnownList().getKnownObjects().values();
  574. for (L2Object obj : objs)
  575. {
  576. if ((obj != null) && ((obj.isPlayable() && playable) || obj.isPet()))
  577. {
  578. if (obj.isPlayer() && !invisible && obj.getActingPlayer().getAppearance().getInvisible())
  579. {
  580. continue;
  581. }
  582. final L2Character cha = (L2Character) obj;
  583. if (((cha.getZ() < (npc.getZ() - 100)) && (cha.getZ() > (npc.getZ() + 100))) || !(GeoData.getInstance().canSeeTarget(cha.getX(), cha.getY(), cha.getZ(), npc.getX(), npc.getY(), npc.getZ())))
  584. {
  585. continue;
  586. }
  587. if (Util.checkIfInRange(range, npc, obj, true) && !cha.isDead())
  588. {
  589. count++;
  590. }
  591. }
  592. }
  593. return count;
  594. }
  595. }