ZoneManager.java 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. /*
  2. * Copyright (C) 2004-2015 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.instancemanager;
  20. import java.io.File;
  21. import java.lang.reflect.Constructor;
  22. import java.util.ArrayList;
  23. import java.util.Collection;
  24. import java.util.HashMap;
  25. import java.util.Iterator;
  26. import java.util.List;
  27. import java.util.Map;
  28. import org.w3c.dom.Document;
  29. import org.w3c.dom.NamedNodeMap;
  30. import org.w3c.dom.Node;
  31. import com.l2jserver.gameserver.model.L2Object;
  32. import com.l2jserver.gameserver.model.L2World;
  33. import com.l2jserver.gameserver.model.L2WorldRegion;
  34. import com.l2jserver.gameserver.model.actor.L2Character;
  35. import com.l2jserver.gameserver.model.items.instance.L2ItemInstance;
  36. import com.l2jserver.gameserver.model.zone.AbstractZoneSettings;
  37. import com.l2jserver.gameserver.model.zone.L2ZoneForm;
  38. import com.l2jserver.gameserver.model.zone.L2ZoneRespawn;
  39. import com.l2jserver.gameserver.model.zone.L2ZoneType;
  40. import com.l2jserver.gameserver.model.zone.form.ZoneCuboid;
  41. import com.l2jserver.gameserver.model.zone.form.ZoneCylinder;
  42. import com.l2jserver.gameserver.model.zone.form.ZoneNPoly;
  43. import com.l2jserver.gameserver.model.zone.type.L2ArenaZone;
  44. import com.l2jserver.gameserver.model.zone.type.L2OlympiadStadiumZone;
  45. import com.l2jserver.gameserver.model.zone.type.L2RespawnZone;
  46. import com.l2jserver.gameserver.model.zone.type.NpcSpawnTerritory;
  47. import com.l2jserver.util.data.xml.IXmlReader;
  48. /**
  49. * This class manages the zones
  50. * @author durgus
  51. */
  52. public final class ZoneManager implements IXmlReader
  53. {
  54. private static final Map<String, AbstractZoneSettings> _settings = new HashMap<>();
  55. private final Map<Class<? extends L2ZoneType>, Map<Integer, ? extends L2ZoneType>> _classZones = new HashMap<>();
  56. private final Map<String, NpcSpawnTerritory> _spawnTerritories = new HashMap<>();
  57. private int _lastDynamicId = 300000;
  58. private List<L2ItemInstance> _debugItems;
  59. /**
  60. * Instantiates a new zone manager.
  61. */
  62. protected ZoneManager()
  63. {
  64. load();
  65. }
  66. /**
  67. * Reload.
  68. */
  69. public void reload()
  70. {
  71. // Get the world regions
  72. int count = 0;
  73. final L2WorldRegion[][] worldRegions = L2World.getInstance().getWorldRegions();
  74. // Backup old zone settings
  75. for (Map<Integer, ? extends L2ZoneType> map : _classZones.values())
  76. {
  77. for (L2ZoneType zone : map.values())
  78. {
  79. if (zone.getSettings() != null)
  80. {
  81. _settings.put(zone.getName(), zone.getSettings());
  82. }
  83. }
  84. }
  85. // Clear zones
  86. for (L2WorldRegion[] worldRegion : worldRegions)
  87. {
  88. for (L2WorldRegion element : worldRegion)
  89. {
  90. element.getZones().clear();
  91. count++;
  92. }
  93. }
  94. GrandBossManager.getInstance().getZones().clear();
  95. LOGGER.info("{}: Removed zones in " + count + " regions.", getClass().getSimpleName());
  96. // Load the zones
  97. load();
  98. // Re-validate all characters in zones
  99. for (L2Object obj : L2World.getInstance().getVisibleObjects())
  100. {
  101. if (obj instanceof L2Character)
  102. {
  103. ((L2Character) obj).revalidateZone(true);
  104. }
  105. }
  106. _settings.clear();
  107. }
  108. @Override
  109. public void parseDocument(Document doc, File f)
  110. {
  111. // Get the world regions
  112. final L2WorldRegion[][] worldRegions = L2World.getInstance().getWorldRegions();
  113. NamedNodeMap attrs;
  114. Node attribute;
  115. String zoneName;
  116. int[][] coords;
  117. int zoneId, minZ, maxZ;
  118. String zoneType, zoneShape;
  119. final List<int[]> rs = new ArrayList<>();
  120. for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
  121. {
  122. if ("list".equalsIgnoreCase(n.getNodeName()))
  123. {
  124. attrs = n.getAttributes();
  125. attribute = attrs.getNamedItem("enabled");
  126. if ((attribute != null) && !Boolean.parseBoolean(attribute.getNodeValue()))
  127. {
  128. continue;
  129. }
  130. for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
  131. {
  132. if ("zone".equalsIgnoreCase(d.getNodeName()))
  133. {
  134. attrs = d.getAttributes();
  135. attribute = attrs.getNamedItem("type");
  136. if (attribute != null)
  137. {
  138. zoneType = attribute.getNodeValue();
  139. }
  140. else
  141. {
  142. LOGGER.warn("ZoneData: Missing type for zone in file {}", f.getName());
  143. continue;
  144. }
  145. attribute = attrs.getNamedItem("id");
  146. if (attribute != null)
  147. {
  148. zoneId = Integer.parseInt(attribute.getNodeValue());
  149. }
  150. else
  151. {
  152. zoneId = zoneType.equalsIgnoreCase("NpcSpawnTerritory") ? 0 : _lastDynamicId++;
  153. }
  154. attribute = attrs.getNamedItem("name");
  155. if (attribute != null)
  156. {
  157. zoneName = attribute.getNodeValue();
  158. }
  159. else
  160. {
  161. zoneName = null;
  162. }
  163. // Check zone name for NpcSpawnTerritory. Must exist and to be unique
  164. if (zoneType.equalsIgnoreCase("NpcSpawnTerritory"))
  165. {
  166. if (zoneName == null)
  167. {
  168. LOGGER.warn("ZoneData: Missing name for NpcSpawnTerritory in file: {}, skipping zone!", f.getName());
  169. continue;
  170. }
  171. else if (_spawnTerritories.containsKey(zoneName))
  172. {
  173. LOGGER.warn("ZoneData: Name {} already used for another zone, check file {}, skipping zone!", zoneName, f.getName());
  174. continue;
  175. }
  176. }
  177. minZ = parseInteger(attrs, "minZ");
  178. maxZ = parseInteger(attrs, "maxZ");
  179. zoneType = parseString(attrs, "type");
  180. zoneShape = parseString(attrs, "shape");
  181. // Get the zone shape from xml
  182. L2ZoneForm zoneForm = null;
  183. try
  184. {
  185. for (Node cd = d.getFirstChild(); cd != null; cd = cd.getNextSibling())
  186. {
  187. if ("node".equalsIgnoreCase(cd.getNodeName()))
  188. {
  189. attrs = cd.getAttributes();
  190. int[] point = new int[2];
  191. point[0] = parseInteger(attrs, "X");
  192. point[1] = parseInteger(attrs, "Y");
  193. rs.add(point);
  194. }
  195. }
  196. coords = rs.toArray(new int[rs.size()][2]);
  197. rs.clear();
  198. if ((coords == null) || (coords.length == 0))
  199. {
  200. LOGGER.warn("{}: ZoneData: missing data for zone: {} XML file {}!", getClass().getSimpleName(), zoneId, f.getName());
  201. continue;
  202. }
  203. // Create this zone. Parsing for cuboids is a bit different than for other polygons cuboids need exactly 2 points to be defined.
  204. // Other polygons need at least 3 (one per vertex)
  205. if (zoneShape.equalsIgnoreCase("Cuboid"))
  206. {
  207. if (coords.length == 2)
  208. {
  209. zoneForm = new ZoneCuboid(coords[0][0], coords[1][0], coords[0][1], coords[1][1], minZ, maxZ);
  210. }
  211. else
  212. {
  213. LOGGER.warn("{}: ZoneData: Missing cuboid vertex in sql data for zone: {} in file {}!", getClass().getSimpleName(), zoneId, f.getName());
  214. continue;
  215. }
  216. }
  217. else if (zoneShape.equalsIgnoreCase("NPoly"))
  218. {
  219. // nPoly needs to have at least 3 vertices
  220. if (coords.length > 2)
  221. {
  222. final int[] aX = new int[coords.length];
  223. final int[] aY = new int[coords.length];
  224. for (int i = 0; i < coords.length; i++)
  225. {
  226. aX[i] = coords[i][0];
  227. aY[i] = coords[i][1];
  228. }
  229. zoneForm = new ZoneNPoly(aX, aY, minZ, maxZ);
  230. }
  231. else
  232. {
  233. LOGGER.warn("{}: ZoneData: Bad data for zone: {} in file {}!", getClass().getSimpleName(), zoneId, f.getName());
  234. continue;
  235. }
  236. }
  237. else if (zoneShape.equalsIgnoreCase("Cylinder"))
  238. {
  239. // A Cylinder zone requires a center point
  240. // at x,y and a radius
  241. attrs = d.getAttributes();
  242. final int zoneRad = Integer.parseInt(attrs.getNamedItem("rad").getNodeValue());
  243. if ((coords.length == 1) && (zoneRad > 0))
  244. {
  245. zoneForm = new ZoneCylinder(coords[0][0], coords[0][1], minZ, maxZ, zoneRad);
  246. }
  247. else
  248. {
  249. LOGGER.warn("{}: ZoneData: Bad data for zone: {} in file {}!", getClass().getSimpleName(), zoneId, f.getName());
  250. continue;
  251. }
  252. }
  253. else
  254. {
  255. LOGGER.warn("{}: ZoneData: Unknown shape: {} for zone {} in file {}", getClass().getSimpleName(), zoneShape, zoneId, f.getName());
  256. continue;
  257. }
  258. }
  259. catch (Exception e)
  260. {
  261. LOGGER.warn("{}: ZoneData: Failed to load zone {} coordinates!", getClass().getSimpleName(), zoneId, e);
  262. }
  263. // No further parameters needed, if NpcSpawnTerritory is loading
  264. if (zoneType.equalsIgnoreCase("NpcSpawnTerritory"))
  265. {
  266. _spawnTerritories.put(zoneName, new NpcSpawnTerritory(zoneName, zoneForm));
  267. continue;
  268. }
  269. // Create the zone
  270. Class<?> newZone = null;
  271. Constructor<?> zoneConstructor = null;
  272. L2ZoneType temp;
  273. try
  274. {
  275. newZone = Class.forName("com.l2jserver.gameserver.model.zone.type.L2" + zoneType);
  276. zoneConstructor = newZone.getConstructor(int.class);
  277. temp = (L2ZoneType) zoneConstructor.newInstance(zoneId);
  278. temp.setZone(zoneForm);
  279. }
  280. catch (Exception e)
  281. {
  282. LOGGER.warn("{}: ZoneData: No such zone type: {} in file {}!", getClass().getSimpleName(), zoneType, f.getName());
  283. continue;
  284. }
  285. // Check for additional parameters
  286. for (Node cd = d.getFirstChild(); cd != null; cd = cd.getNextSibling())
  287. {
  288. if ("stat".equalsIgnoreCase(cd.getNodeName()))
  289. {
  290. attrs = cd.getAttributes();
  291. String name = attrs.getNamedItem("name").getNodeValue();
  292. String val = attrs.getNamedItem("val").getNodeValue();
  293. temp.setParameter(name, val);
  294. }
  295. else if ("spawn".equalsIgnoreCase(cd.getNodeName()) && (temp instanceof L2ZoneRespawn))
  296. {
  297. attrs = cd.getAttributes();
  298. int spawnX = Integer.parseInt(attrs.getNamedItem("X").getNodeValue());
  299. int spawnY = Integer.parseInt(attrs.getNamedItem("Y").getNodeValue());
  300. int spawnZ = Integer.parseInt(attrs.getNamedItem("Z").getNodeValue());
  301. Node val = attrs.getNamedItem("type");
  302. ((L2ZoneRespawn) temp).parseLoc(spawnX, spawnY, spawnZ, val == null ? null : val.getNodeValue());
  303. }
  304. else if ("race".equalsIgnoreCase(cd.getNodeName()) && (temp instanceof L2RespawnZone))
  305. {
  306. attrs = cd.getAttributes();
  307. String race = attrs.getNamedItem("name").getNodeValue();
  308. String point = attrs.getNamedItem("point").getNodeValue();
  309. ((L2RespawnZone) temp).addRaceRespawnPoint(race, point);
  310. }
  311. }
  312. if (checkId(zoneId))
  313. {
  314. LOGGER.debug("{}: Caution: Zone ({}) from file {} overrides previous definition.", getClass().getSimpleName(), zoneId, f.getName());
  315. }
  316. if ((zoneName != null) && !zoneName.isEmpty())
  317. {
  318. temp.setName(zoneName);
  319. }
  320. addZone(zoneId, temp);
  321. // Register the zone into any world region it intersects with...
  322. // currently 11136 test for each zone :>
  323. int ax, ay, bx, by;
  324. for (int x = 0; x < worldRegions.length; x++)
  325. {
  326. for (int y = 0; y < worldRegions[x].length; y++)
  327. {
  328. ax = (x - L2World.OFFSET_X) << L2World.SHIFT_BY;
  329. bx = ((x + 1) - L2World.OFFSET_X) << L2World.SHIFT_BY;
  330. ay = (y - L2World.OFFSET_Y) << L2World.SHIFT_BY;
  331. by = ((y + 1) - L2World.OFFSET_Y) << L2World.SHIFT_BY;
  332. if (temp.getZone().intersectsRectangle(ax, bx, ay, by))
  333. {
  334. worldRegions[x][y].addZone(temp);
  335. }
  336. }
  337. }
  338. }
  339. }
  340. }
  341. }
  342. }
  343. @Override
  344. public final void load()
  345. {
  346. _classZones.clear();
  347. _spawnTerritories.clear();
  348. parseDatapackDirectory("data/zones", false);
  349. parseDatapackDirectory("data/zones/npcSpawnTerritories", false);
  350. LOGGER.info("{}: Loaded {} zone classes and {} zones.", getClass().getSimpleName(), _classZones.size(), getSize());
  351. LOGGER.info("{}: Loaded {} NPC spawn territoriers.", getClass().getSimpleName(), _spawnTerritories.size());
  352. }
  353. /**
  354. * Gets the size.
  355. * @return the size
  356. */
  357. public int getSize()
  358. {
  359. int i = 0;
  360. for (Map<Integer, ? extends L2ZoneType> map : _classZones.values())
  361. {
  362. i += map.size();
  363. }
  364. return i;
  365. }
  366. /**
  367. * Check id.
  368. * @param id the id
  369. * @return true, if successful
  370. */
  371. public boolean checkId(int id)
  372. {
  373. for (Map<Integer, ? extends L2ZoneType> map : _classZones.values())
  374. {
  375. if (map.containsKey(id))
  376. {
  377. return true;
  378. }
  379. }
  380. return false;
  381. }
  382. /**
  383. * Add new zone.
  384. * @param <T> the generic type
  385. * @param id the id
  386. * @param zone the zone
  387. */
  388. @SuppressWarnings("unchecked")
  389. public <T extends L2ZoneType> void addZone(Integer id, T zone)
  390. {
  391. Map<Integer, T> map = (Map<Integer, T>) _classZones.get(zone.getClass());
  392. if (map == null)
  393. {
  394. map = new HashMap<>();
  395. map.put(id, zone);
  396. _classZones.put(zone.getClass(), map);
  397. }
  398. else
  399. {
  400. map.put(id, zone);
  401. }
  402. }
  403. /**
  404. * Returns all zones registered with the ZoneManager. To minimize iteration processing retrieve zones from L2WorldRegion for a specific location instead.
  405. * @return zones
  406. * @see #getAllZones(Class)
  407. */
  408. @Deprecated
  409. public Collection<L2ZoneType> getAllZones()
  410. {
  411. final List<L2ZoneType> zones = new ArrayList<>();
  412. for (Map<Integer, ? extends L2ZoneType> map : _classZones.values())
  413. {
  414. zones.addAll(map.values());
  415. }
  416. return zones;
  417. }
  418. /**
  419. * Return all zones by class type.
  420. * @param <T> the generic type
  421. * @param zoneType Zone class
  422. * @return Collection of zones
  423. */
  424. @SuppressWarnings("unchecked")
  425. public <T extends L2ZoneType> Collection<T> getAllZones(Class<T> zoneType)
  426. {
  427. return (Collection<T>) _classZones.get(zoneType).values();
  428. }
  429. /**
  430. * Get zone by ID.
  431. * @param id the id
  432. * @return the zone by id
  433. * @see #getZoneById(int, Class)
  434. */
  435. public L2ZoneType getZoneById(int id)
  436. {
  437. for (Map<Integer, ? extends L2ZoneType> map : _classZones.values())
  438. {
  439. if (map.containsKey(id))
  440. {
  441. return map.get(id);
  442. }
  443. }
  444. return null;
  445. }
  446. /**
  447. * Get zone by ID and zone class.
  448. * @param <T> the generic type
  449. * @param id the id
  450. * @param zoneType the zone type
  451. * @return zone
  452. */
  453. @SuppressWarnings("unchecked")
  454. public <T extends L2ZoneType> T getZoneById(int id, Class<T> zoneType)
  455. {
  456. return (T) _classZones.get(zoneType).get(id);
  457. }
  458. /**
  459. * Returns all zones from where the object is located.
  460. * @param object the object
  461. * @return zones
  462. */
  463. public List<L2ZoneType> getZones(L2Object object)
  464. {
  465. return getZones(object.getX(), object.getY(), object.getZ());
  466. }
  467. /**
  468. * Gets the zone.
  469. * @param <T> the generic type
  470. * @param object the object
  471. * @param type the type
  472. * @return zone from where the object is located by type
  473. */
  474. public <T extends L2ZoneType> T getZone(L2Object object, Class<T> type)
  475. {
  476. if (object == null)
  477. {
  478. return null;
  479. }
  480. return getZone(object.getX(), object.getY(), object.getZ(), type);
  481. }
  482. /**
  483. * Returns all zones from given coordinates (plane).
  484. * @param x the x
  485. * @param y the y
  486. * @return zones
  487. */
  488. public List<L2ZoneType> getZones(int x, int y)
  489. {
  490. final L2WorldRegion region = L2World.getInstance().getRegion(x, y);
  491. final List<L2ZoneType> temp = new ArrayList<>();
  492. for (L2ZoneType zone : region.getZones())
  493. {
  494. if (zone.isInsideZone(x, y))
  495. {
  496. temp.add(zone);
  497. }
  498. }
  499. return temp;
  500. }
  501. /**
  502. * Returns all zones from given coordinates.
  503. * @param x the x
  504. * @param y the y
  505. * @param z the z
  506. * @return zones
  507. */
  508. public List<L2ZoneType> getZones(int x, int y, int z)
  509. {
  510. final L2WorldRegion region = L2World.getInstance().getRegion(x, y);
  511. final List<L2ZoneType> temp = new ArrayList<>();
  512. for (L2ZoneType zone : region.getZones())
  513. {
  514. if (zone.isInsideZone(x, y, z))
  515. {
  516. temp.add(zone);
  517. }
  518. }
  519. return temp;
  520. }
  521. /**
  522. * Gets the zone.
  523. * @param <T> the generic type
  524. * @param x the x
  525. * @param y the y
  526. * @param z the z
  527. * @param type the type
  528. * @return zone from given coordinates
  529. */
  530. @SuppressWarnings("unchecked")
  531. public <T extends L2ZoneType> T getZone(int x, int y, int z, Class<T> type)
  532. {
  533. final L2WorldRegion region = L2World.getInstance().getRegion(x, y);
  534. for (L2ZoneType zone : region.getZones())
  535. {
  536. if (zone.isInsideZone(x, y, z) && type.isInstance(zone))
  537. {
  538. return (T) zone;
  539. }
  540. }
  541. return null;
  542. }
  543. /**
  544. * Get spawm territory by name
  545. * @param name name of territory to search
  546. * @return link to zone form
  547. */
  548. public NpcSpawnTerritory getSpawnTerritory(String name)
  549. {
  550. return _spawnTerritories.containsKey(name) ? _spawnTerritories.get(name) : null;
  551. }
  552. /**
  553. * Returns all spawm territories from where the object is located
  554. * @param object
  555. * @return zones
  556. */
  557. public List<NpcSpawnTerritory> getSpawnTerritories(L2Object object)
  558. {
  559. List<NpcSpawnTerritory> temp = new ArrayList<>();
  560. for (NpcSpawnTerritory territory : _spawnTerritories.values())
  561. {
  562. if (territory.isInsideZone(object.getX(), object.getY(), object.getZ()))
  563. {
  564. temp.add(territory);
  565. }
  566. }
  567. return temp;
  568. }
  569. /**
  570. * Gets the arena.
  571. * @param character the character
  572. * @return the arena
  573. */
  574. public final L2ArenaZone getArena(L2Character character)
  575. {
  576. if (character == null)
  577. {
  578. return null;
  579. }
  580. for (L2ZoneType temp : ZoneManager.getInstance().getZones(character.getX(), character.getY(), character.getZ()))
  581. {
  582. if ((temp instanceof L2ArenaZone) && temp.isCharacterInZone(character))
  583. {
  584. return ((L2ArenaZone) temp);
  585. }
  586. }
  587. return null;
  588. }
  589. /**
  590. * Gets the olympiad stadium.
  591. * @param character the character
  592. * @return the olympiad stadium
  593. */
  594. public final L2OlympiadStadiumZone getOlympiadStadium(L2Character character)
  595. {
  596. if (character == null)
  597. {
  598. return null;
  599. }
  600. for (L2ZoneType temp : ZoneManager.getInstance().getZones(character.getX(), character.getY(), character.getZ()))
  601. {
  602. if ((temp instanceof L2OlympiadStadiumZone) && temp.isCharacterInZone(character))
  603. {
  604. return ((L2OlympiadStadiumZone) temp);
  605. }
  606. }
  607. return null;
  608. }
  609. /**
  610. * For testing purposes only.
  611. * @param <T> the generic type
  612. * @param obj the obj
  613. * @param type the type
  614. * @return the closest zone
  615. */
  616. @SuppressWarnings("unchecked")
  617. public <T extends L2ZoneType> T getClosestZone(L2Object obj, Class<T> type)
  618. {
  619. T zone = getZone(obj, type);
  620. if (zone == null)
  621. {
  622. double closestdis = Double.MAX_VALUE;
  623. for (T temp : (Collection<T>) _classZones.get(type).values())
  624. {
  625. double distance = temp.getDistanceToZone(obj);
  626. if (distance < closestdis)
  627. {
  628. closestdis = distance;
  629. zone = temp;
  630. }
  631. }
  632. }
  633. return zone;
  634. }
  635. /**
  636. * General storage for debug items used for visualizing zones.
  637. * @return list of items
  638. */
  639. public List<L2ItemInstance> getDebugItems()
  640. {
  641. if (_debugItems == null)
  642. {
  643. _debugItems = new ArrayList<>();
  644. }
  645. return _debugItems;
  646. }
  647. /**
  648. * Remove all debug items from l2world.
  649. */
  650. public void clearDebugItems()
  651. {
  652. if (_debugItems != null)
  653. {
  654. final Iterator<L2ItemInstance> it = _debugItems.iterator();
  655. while (it.hasNext())
  656. {
  657. final L2ItemInstance item = it.next();
  658. if (item != null)
  659. {
  660. item.decayMe();
  661. }
  662. it.remove();
  663. }
  664. }
  665. }
  666. /**
  667. * Gets the settings.
  668. * @param name the name
  669. * @return the settings
  670. */
  671. public static AbstractZoneSettings getSettings(String name)
  672. {
  673. return _settings.get(name);
  674. }
  675. /**
  676. * Gets the single instance of ZoneManager.
  677. * @return single instance of ZoneManager
  678. */
  679. public static final ZoneManager getInstance()
  680. {
  681. return SingletonHolder._instance;
  682. }
  683. private static class SingletonHolder
  684. {
  685. protected static final ZoneManager _instance = new ZoneManager();
  686. }
  687. }