Instance.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. package net.sf.l2j.gameserver.model.entity;
  2. import java.io.File;
  3. import java.io.FileNotFoundException;
  4. import java.io.IOException;
  5. import java.util.concurrent.ScheduledFuture;
  6. import java.util.logging.Logger;
  7. import javax.xml.parsers.DocumentBuilderFactory;
  8. import javolution.util.FastList;
  9. import javolution.util.FastSet;
  10. import org.w3c.dom.Document;
  11. import org.w3c.dom.Node;
  12. import net.sf.l2j.Config;
  13. import net.sf.l2j.gameserver.Announcements;
  14. import net.sf.l2j.gameserver.ThreadPoolManager;
  15. import net.sf.l2j.gameserver.datatables.DoorTable;
  16. import net.sf.l2j.gameserver.datatables.MapRegionTable;
  17. import net.sf.l2j.gameserver.datatables.NpcTable;
  18. import net.sf.l2j.gameserver.idfactory.IdFactory;
  19. import net.sf.l2j.gameserver.instancemanager.InstanceManager;
  20. import net.sf.l2j.gameserver.model.L2Spawn;
  21. import net.sf.l2j.gameserver.model.L2World;
  22. import net.sf.l2j.gameserver.model.L2WorldRegion;
  23. import net.sf.l2j.gameserver.model.actor.L2Npc;
  24. import net.sf.l2j.gameserver.model.actor.instance.L2DoorInstance;
  25. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  26. import net.sf.l2j.gameserver.network.SystemMessageId;
  27. import net.sf.l2j.gameserver.network.clientpackets.Say2;
  28. import net.sf.l2j.gameserver.network.serverpackets.CreatureSay;
  29. import net.sf.l2j.gameserver.network.serverpackets.SystemMessage;
  30. import net.sf.l2j.gameserver.templates.chars.L2NpcTemplate;
  31. /**
  32. * @author evill33t, GodKratos
  33. *
  34. */
  35. public class Instance
  36. {
  37. private final static Logger _log = Logger.getLogger(Instance.class.getName());
  38. private int _id;
  39. private String _name;
  40. private FastSet<Integer> _players = new FastSet<Integer>();
  41. private FastList<L2Npc> _npcs = new FastList<L2Npc>();
  42. private FastList<L2DoorInstance> _doors = new FastList<L2DoorInstance>();
  43. private int[] _spawnLoc = new int[3];
  44. private boolean _allowSummon = true;
  45. private long _emptyDestroyTime = -1;
  46. private long _lastLeft = -1;
  47. private long _instanceEndTime = -1;
  48. private boolean _isPvPInstance = false;
  49. protected ScheduledFuture<?> _CheckTimeUpTask = null;
  50. public Instance(int id)
  51. {
  52. _id = id;
  53. }
  54. /**
  55. * Returns the ID of this instance.
  56. */
  57. public int getId()
  58. {
  59. return _id;
  60. }
  61. /**
  62. * Returns the name of this instance
  63. */
  64. public String getName()
  65. {
  66. return _name;
  67. }
  68. public void setName(String name)
  69. {
  70. _name = name;
  71. }
  72. /**
  73. * Returns whether summon friend type skills are allowed for this instance
  74. */
  75. public boolean isSummonAllowed()
  76. {
  77. return _allowSummon;
  78. }
  79. /**
  80. * Sets the status for the instance for summon friend type skills
  81. */
  82. public void setAllowSummon(boolean b)
  83. {
  84. _allowSummon = b;
  85. }
  86. /*
  87. * Returns true if entire instance is PvP zone
  88. */
  89. public boolean isPvPInstance()
  90. {
  91. return _isPvPInstance;
  92. }
  93. /*
  94. * Sets PvP zone status of the instance
  95. */
  96. public void setPvPInstance(boolean b)
  97. {
  98. _isPvPInstance = b;
  99. }
  100. /**
  101. * Set the instance duration task
  102. * @param duration in minutes
  103. */
  104. public void setDuration(int duration)
  105. {
  106. if (_CheckTimeUpTask != null)
  107. _CheckTimeUpTask.cancel(true);
  108. _CheckTimeUpTask = ThreadPoolManager.getInstance().scheduleGeneral(new CheckTimeUp(duration), 500);
  109. }
  110. /**
  111. * Checks if the player exists within this instance
  112. * @param objectId
  113. * @return true if player exists in instance
  114. */
  115. public boolean containsPlayer(int objectId)
  116. {
  117. if (_players.contains(objectId))
  118. return true;
  119. return false;
  120. }
  121. /**
  122. * Adds the specified player to the instance
  123. * @param objectId Players object ID
  124. */
  125. public void addPlayer(int objectId)
  126. {
  127. if (!_players.contains(objectId))
  128. _players.add(objectId);
  129. }
  130. /**
  131. * Removes the specified player from the instance list
  132. * @param objectId Players object ID
  133. */
  134. public void removePlayer(int objectId)
  135. {
  136. if (_players.contains(objectId))
  137. _players.remove(objectId);
  138. if (_players.isEmpty() && _emptyDestroyTime >= 0)
  139. {
  140. _lastLeft = System.currentTimeMillis();
  141. setDuration((int) (_instanceEndTime - System.currentTimeMillis() - 1000));
  142. }
  143. }
  144. /**
  145. * Removes the player from the instance by setting InstanceId to 0 and teleporting to nearest town.
  146. * @param objectId
  147. */
  148. public void ejectPlayer(int objectId)
  149. {
  150. L2PcInstance player = (L2PcInstance) L2World.getInstance().findObject(objectId);
  151. if (player != null && player.getInstanceId() == this.getId())
  152. {
  153. player.setInstanceId(0);
  154. player.sendMessage("You were removed from the instance");
  155. if (getSpawnLoc()[0] != 0 && getSpawnLoc()[1] != 0 && getSpawnLoc()[2] != 0)
  156. player.teleToLocation(getSpawnLoc()[0], getSpawnLoc()[1], getSpawnLoc()[2]);
  157. else
  158. player.teleToLocation(MapRegionTable.TeleportWhereType.Town);
  159. }
  160. }
  161. public void addNpc(L2Npc npc)
  162. {
  163. _npcs.add(npc);
  164. }
  165. public void removeNpc(L2Spawn spawn)
  166. {
  167. _npcs.remove(spawn);
  168. }
  169. /**
  170. * Adds a door into the instance
  171. * @param doorId - from doors.csv
  172. * @param open - initial state of the door
  173. */
  174. public void addDoor(int doorId, boolean open)
  175. {
  176. for (L2DoorInstance door: _doors)
  177. {
  178. if (door.getDoorId() == doorId)
  179. {
  180. _log.warning("Door ID " + doorId + " already exists in instance " + this.getId());
  181. return;
  182. }
  183. }
  184. L2DoorInstance temp = DoorTable.getInstance().getDoor(doorId);
  185. L2DoorInstance newdoor = new L2DoorInstance(IdFactory.getInstance().getNextId(), temp.getTemplate(), temp.getDoorId(), temp.getName(), temp.isUnlockable());
  186. newdoor.setInstanceId(getId());
  187. newdoor.setRange(temp.getXMin(), temp.getYMin(), temp.getZMin(), temp.getXMax(), temp.getYMax(), temp.getZMax());
  188. try
  189. {
  190. newdoor.setMapRegion(MapRegionTable.getInstance().getMapRegion(temp.getX(), temp.getY()));
  191. }
  192. catch (Exception e)
  193. {
  194. _log.severe("Error in door data, ID:" + temp.getDoorId());
  195. }
  196. newdoor.getStatus().setCurrentHpMp(newdoor.getMaxHp(), newdoor.getMaxMp());
  197. newdoor.setOpen(open);
  198. newdoor.getPosition().setXYZInvisible(temp.getX(), temp.getY(), temp.getZ());
  199. newdoor.spawnMe(newdoor.getX(), newdoor.getY(), newdoor.getZ());
  200. _doors.add(newdoor);
  201. }
  202. public FastSet<Integer> getPlayers()
  203. {
  204. return _players;
  205. }
  206. public FastList<L2Npc> getNpcs()
  207. {
  208. return _npcs;
  209. }
  210. public FastList<L2DoorInstance> getDoors()
  211. {
  212. return _doors;
  213. }
  214. public L2DoorInstance getDoor(int id)
  215. {
  216. for (L2DoorInstance temp: getDoors())
  217. {
  218. if (temp.getDoorId() == id)
  219. return temp;
  220. }
  221. return null;
  222. }
  223. /**
  224. * Returns the spawn location for this instance to be used when leaving the instance
  225. * @return int[3]
  226. */
  227. public int[] getSpawnLoc()
  228. {
  229. return _spawnLoc;
  230. }
  231. public void removePlayers()
  232. {
  233. if (_players == null || _players.isEmpty())
  234. return;
  235. for (int objectId : _players)
  236. {
  237. ejectPlayer(objectId);
  238. }
  239. _players.clear();
  240. }
  241. public void removeNpcs()
  242. {
  243. if (_npcs == null || _npcs.isEmpty())
  244. return;
  245. for (L2Npc mob : _npcs)
  246. {
  247. if (mob != null)
  248. {
  249. mob.getSpawn().stopRespawn();
  250. mob.deleteMe();
  251. }
  252. }
  253. _npcs.clear();
  254. }
  255. public void removeDoors()
  256. {
  257. if (_doors == null || _doors.isEmpty())
  258. return;
  259. for (L2DoorInstance door: _doors)
  260. {
  261. if (door != null)
  262. {
  263. L2WorldRegion region = door.getWorldRegion();
  264. door.decayMe();
  265. if (region != null)
  266. region.removeVisibleObject(door);
  267. door.getKnownList().removeAllKnownObjects();
  268. L2World.getInstance().removeObject(door);
  269. }
  270. }
  271. _doors.clear();
  272. }
  273. public void loadInstanceTemplate(String filename) throws FileNotFoundException
  274. {
  275. Document doc = null;
  276. File xml = new File(Config.DATAPACK_ROOT, "data/instances/" + filename);
  277. try
  278. {
  279. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  280. factory.setValidating(false);
  281. factory.setIgnoringComments(true);
  282. doc = factory.newDocumentBuilder().parse(xml);
  283. for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
  284. {
  285. if ("instance".equalsIgnoreCase(n.getNodeName()))
  286. {
  287. parseInstance(n);
  288. }
  289. }
  290. }
  291. catch (IOException e)
  292. {
  293. _log.warning("Instance: can not find " + xml.getAbsolutePath() + " ! " + e);
  294. }
  295. catch (Exception e)
  296. {
  297. _log.warning("Instance: error while loading " + xml.getAbsolutePath() + " ! " + e);
  298. }
  299. }
  300. private void parseInstance(Node n) throws Exception
  301. {
  302. L2Spawn spawnDat;
  303. L2NpcTemplate npcTemplate;
  304. String name = null;
  305. name = n.getAttributes().getNamedItem("name").getNodeValue();
  306. setName(name);
  307. Node a;
  308. Node first = n.getFirstChild();
  309. for (n = first; n != null; n = n.getNextSibling())
  310. {
  311. if ("activityTime".equalsIgnoreCase(n.getNodeName()))
  312. {
  313. a = n.getAttributes().getNamedItem("val");
  314. if (a != null)
  315. {
  316. _CheckTimeUpTask = ThreadPoolManager.getInstance().scheduleGeneral(new CheckTimeUp(Integer.parseInt(a.getNodeValue()) * 60000), 15000);
  317. _instanceEndTime = System.currentTimeMillis() + Long.parseLong(a.getNodeValue()) * 60000 + 15000;
  318. }
  319. }
  320. /* else if ("timeDelay".equalsIgnoreCase(n.getNodeName()))
  321. {
  322. a = n.getAttributes().getNamedItem("val");
  323. if (a != null)
  324. instance.setTimeDelay(Integer.parseInt(a.getNodeValue()));
  325. }*/
  326. else if ("allowSummon".equalsIgnoreCase(n.getNodeName()))
  327. {
  328. a = n.getAttributes().getNamedItem("val");
  329. if (a != null)
  330. setAllowSummon(Boolean.parseBoolean(a.getNodeValue()));
  331. }
  332. else if ("emptyDestroyTime".equalsIgnoreCase(n.getNodeName()))
  333. {
  334. a = n.getAttributes().getNamedItem("val");
  335. if (a != null)
  336. _emptyDestroyTime = Long.parseLong(a.getNodeValue()) * 1000;
  337. }
  338. else if ("PvPInstance".equalsIgnoreCase(n.getNodeName()))
  339. {
  340. a = n.getAttributes().getNamedItem("val");
  341. if (a != null)
  342. setPvPInstance(Boolean.parseBoolean(a.getNodeValue()));
  343. }
  344. else if ("doorlist".equalsIgnoreCase(n.getNodeName()))
  345. {
  346. for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
  347. {
  348. int doorId = 0;
  349. boolean doorState = false;
  350. if ("door".equalsIgnoreCase(d.getNodeName()))
  351. {
  352. doorId = Integer.parseInt(d.getAttributes().getNamedItem("doorId").getNodeValue());
  353. if (d.getAttributes().getNamedItem("open") != null)
  354. doorState = Boolean.parseBoolean(d.getAttributes().getNamedItem("open").getNodeValue());
  355. addDoor(doorId, doorState);
  356. }
  357. }
  358. }
  359. else if ("spawnlist".equalsIgnoreCase(n.getNodeName()))
  360. {
  361. for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
  362. {
  363. int npcId = 0, x = 0, y = 0, z = 0, respawn = 0, heading = 0;
  364. if ("spawn".equalsIgnoreCase(d.getNodeName()))
  365. {
  366. npcId = Integer.parseInt(d.getAttributes().getNamedItem("npcId").getNodeValue());
  367. x = Integer.parseInt(d.getAttributes().getNamedItem("x").getNodeValue());
  368. y = Integer.parseInt(d.getAttributes().getNamedItem("y").getNodeValue());
  369. z = Integer.parseInt(d.getAttributes().getNamedItem("z").getNodeValue());
  370. heading = Integer.parseInt(d.getAttributes().getNamedItem("heading").getNodeValue());
  371. respawn = Integer.parseInt(d.getAttributes().getNamedItem("respawn").getNodeValue());
  372. npcTemplate = NpcTable.getInstance().getTemplate(npcId);
  373. if (npcTemplate != null)
  374. {
  375. spawnDat = new L2Spawn(npcTemplate);
  376. spawnDat.setLocx(x);
  377. spawnDat.setLocy(y);
  378. spawnDat.setLocz(z);
  379. spawnDat.setAmount(1);
  380. spawnDat.setHeading(heading);
  381. spawnDat.setRespawnDelay(respawn);
  382. if (respawn == 0)
  383. spawnDat.stopRespawn();
  384. else
  385. spawnDat.startRespawn();
  386. spawnDat.setInstanceId(getId());
  387. L2Npc newmob = spawnDat.doSpawn();
  388. _npcs.add(newmob);
  389. }
  390. else
  391. {
  392. _log.warning("Instance: Data missing in NPC table for ID: " + npcTemplate + " in Instance " + getId());
  393. }
  394. }
  395. }
  396. }
  397. else if ("spawnpoint".equalsIgnoreCase(n.getNodeName()))
  398. {
  399. try
  400. {
  401. _spawnLoc[0] = Integer.parseInt(n.getAttributes().getNamedItem("spawnX").getNodeValue());
  402. _spawnLoc[1] = Integer.parseInt(n.getAttributes().getNamedItem("spawnY").getNodeValue());
  403. _spawnLoc[2] = Integer.parseInt(n.getAttributes().getNamedItem("spawnZ").getNodeValue());
  404. }
  405. catch (Exception e)
  406. {
  407. _log.warning("Error parsing instance xml: " + e);
  408. _spawnLoc = new int[3];
  409. }
  410. }
  411. }
  412. if (Config.DEBUG)
  413. _log.info(name + " Instance Template for Instance " + getId() + " loaded");
  414. }
  415. protected void doCheckTimeUp(int remaining)
  416. {
  417. CreatureSay cs = null;
  418. int timeLeft;
  419. int interval;
  420. if (_players.isEmpty() && _emptyDestroyTime == 0)
  421. {
  422. remaining = 0;
  423. interval = 500;
  424. }
  425. else if (_players.isEmpty() && _emptyDestroyTime > 0)
  426. {
  427. Long emptyTimeLeft = _lastLeft + _emptyDestroyTime - System.currentTimeMillis();
  428. if (emptyTimeLeft <= 0)
  429. {
  430. interval = 0;
  431. remaining = 0;
  432. }
  433. else if (remaining > 300000 && emptyTimeLeft > 300000)
  434. {
  435. interval = 300000;
  436. remaining = remaining - 300000;
  437. }
  438. else if (remaining > 60000 && emptyTimeLeft > 60000)
  439. {
  440. interval = 60000;
  441. remaining = remaining - 60000;
  442. }
  443. else if (remaining > 30000 && emptyTimeLeft > 30000)
  444. {
  445. interval = 30000;
  446. remaining = remaining - 30000;
  447. }
  448. else
  449. {
  450. interval = 10000;
  451. remaining = remaining - 10000;
  452. }
  453. }
  454. else if (remaining > 300000)
  455. {
  456. timeLeft = remaining / 60000;
  457. interval = 300000;
  458. SystemMessage sm = new SystemMessage(SystemMessageId.DUNGEON_EXPIRES_IN_S1_MINUTES);
  459. sm.addString(Integer.toString(timeLeft));
  460. Announcements.getInstance().announceToInstance(sm, getId());
  461. remaining = remaining - 300000;
  462. }
  463. else if (remaining > 60000)
  464. {
  465. timeLeft = remaining / 60000;
  466. interval = 60000;
  467. SystemMessage sm = new SystemMessage(SystemMessageId.DUNGEON_EXPIRES_IN_S1_MINUTES);
  468. sm.addString(Integer.toString(timeLeft));
  469. Announcements.getInstance().announceToInstance(sm, getId());
  470. remaining = remaining - 60000;
  471. }
  472. else if (remaining > 30000)
  473. {
  474. timeLeft = remaining / 1000;
  475. interval = 30000;
  476. cs = new CreatureSay(0, Say2.ALLIANCE, "Notice", timeLeft + " seconds left.");
  477. remaining = remaining - 30000;
  478. }
  479. else
  480. {
  481. timeLeft = remaining / 1000;
  482. interval = 10000;
  483. cs = new CreatureSay(0, Say2.ALLIANCE, "Notice", timeLeft + " seconds left.");
  484. remaining = remaining - 10000;
  485. }
  486. if (cs != null)
  487. {
  488. for (int objectId : _players)
  489. {
  490. L2PcInstance player = (L2PcInstance) L2World.getInstance().findObject(objectId);
  491. if (player != null && player.getInstanceId() == getId())
  492. {
  493. player.sendPacket(cs);
  494. }
  495. }
  496. }
  497. cancelTimer();
  498. if (remaining >= 10000)
  499. _CheckTimeUpTask = ThreadPoolManager.getInstance().scheduleGeneral(new CheckTimeUp(remaining), interval);
  500. else
  501. _CheckTimeUpTask = ThreadPoolManager.getInstance().scheduleGeneral(new TimeUp(), interval);
  502. }
  503. public void cancelTimer()
  504. {
  505. if (_CheckTimeUpTask != null)
  506. _CheckTimeUpTask.cancel(true);
  507. }
  508. public class CheckTimeUp implements Runnable
  509. {
  510. private int _remaining;
  511. public CheckTimeUp(int remaining)
  512. {
  513. _remaining = remaining;
  514. }
  515. public void run()
  516. {
  517. doCheckTimeUp(_remaining);
  518. }
  519. }
  520. public class TimeUp implements Runnable
  521. {
  522. public void run()
  523. {
  524. InstanceManager.getInstance().destroyInstance(getId());
  525. }
  526. }
  527. }