SpawnTable.java 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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.datatables;
  20. import java.sql.Connection;
  21. import java.sql.PreparedStatement;
  22. import java.sql.ResultSet;
  23. import java.sql.Statement;
  24. import java.util.Collections;
  25. import java.util.Map;
  26. import java.util.Set;
  27. import java.util.logging.Level;
  28. import java.util.logging.Logger;
  29. import javolution.util.FastMap;
  30. import javolution.util.FastSet;
  31. import com.l2jserver.Config;
  32. import com.l2jserver.L2DatabaseFactory;
  33. import com.l2jserver.gameserver.instancemanager.DayNightSpawnManager;
  34. import com.l2jserver.gameserver.model.L2Spawn;
  35. import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
  36. import com.l2jserver.gameserver.model.interfaces.IL2Procedure;
  37. /**
  38. * Spawn data retriever.
  39. * @author Zoey76
  40. */
  41. public final class SpawnTable
  42. {
  43. private static final Logger _log = Logger.getLogger(SpawnTable.class.getName());
  44. // SQL
  45. private static final String SELECT_SPAWNS = "SELECT count, npc_templateid, locx, locy, locz, heading, respawn_delay, respawn_random, loc_id, periodOfDay FROM spawnlist";
  46. private static final String SELECT_CUSTOM_SPAWNS = "SELECT count, npc_templateid, locx, locy, locz, heading, respawn_delay, respawn_random, loc_id, periodOfDay FROM custom_spawnlist";
  47. private static final Map<Integer, Set<L2Spawn>> _spawnTable = new FastMap<Integer, Set<L2Spawn>>().shared();
  48. protected SpawnTable()
  49. {
  50. load();
  51. }
  52. /**
  53. * Wrapper to load all spawns.
  54. */
  55. public void load()
  56. {
  57. if (!Config.ALT_DEV_NO_SPAWNS)
  58. {
  59. fillSpawnTable(false);
  60. final int spawnCount = _spawnTable.size();
  61. _log.info(getClass().getSimpleName() + ": Loaded " + spawnCount + " npc spawns.");
  62. if (Config.CUSTOM_SPAWNLIST_TABLE)
  63. {
  64. fillSpawnTable(true);
  65. _log.info(getClass().getSimpleName() + ": Loaded " + (_spawnTable.size() - spawnCount) + " custom npc spawns.");
  66. }
  67. }
  68. }
  69. /**
  70. * Retrieves spawn data from database.
  71. * @param isCustom if {@code true} the spawns are loaded as custom from custom spawn table
  72. * @return the spawn count
  73. */
  74. private int fillSpawnTable(boolean isCustom)
  75. {
  76. int npcSpawnCount = 0;
  77. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  78. Statement s = con.createStatement();
  79. ResultSet rs = s.executeQuery(isCustom ? SELECT_CUSTOM_SPAWNS : SELECT_SPAWNS))
  80. {
  81. L2Spawn spawn;
  82. L2NpcTemplate npcTemplate;
  83. int npcId;
  84. while (rs.next())
  85. {
  86. npcId = rs.getInt("npc_templateid");
  87. npcTemplate = NpcTable.getInstance().getTemplate(npcId);
  88. if (npcTemplate == null)
  89. {
  90. _log.warning(getClass().getSimpleName() + ": Data missing in NPC table for ID: " + npcId + ".");
  91. continue;
  92. }
  93. if (npcTemplate.isType("L2SiegeGuard") || npcTemplate.isType("L2RaidBoss") || (!Config.ALLOW_CLASS_MASTERS && npcTemplate.isType("L2ClassMaster")))
  94. {
  95. // Don't spawn
  96. continue;
  97. }
  98. spawn = new L2Spawn(npcTemplate);
  99. spawn.setAmount(rs.getInt("count"));
  100. spawn.setX(rs.getInt("locx"));
  101. spawn.setY(rs.getInt("locy"));
  102. spawn.setZ(rs.getInt("locz"));
  103. spawn.setHeading(rs.getInt("heading"));
  104. spawn.setRespawnDelay(rs.getInt("respawn_delay"), rs.getInt("respawn_random"));
  105. spawn.setCustom(isCustom);
  106. int loc_id = rs.getInt("loc_id");
  107. spawn.setLocationId(loc_id);
  108. switch (rs.getInt("periodOfDay"))
  109. {
  110. case 0: // default
  111. npcSpawnCount += spawn.init();
  112. break;
  113. case 1: // Day
  114. DayNightSpawnManager.getInstance().addDayCreature(spawn);
  115. npcSpawnCount++;
  116. break;
  117. case 2: // Night
  118. DayNightSpawnManager.getInstance().addNightCreature(spawn);
  119. npcSpawnCount++;
  120. break;
  121. }
  122. addSpawn(spawn);
  123. }
  124. }
  125. catch (Exception e)
  126. {
  127. _log.log(Level.WARNING, getClass().getSimpleName() + ": Spawn could not be initialized: " + e.getMessage(), e);
  128. }
  129. return npcSpawnCount;
  130. }
  131. public Map<Integer, Set<L2Spawn>> getSpawnTable()
  132. {
  133. return _spawnTable;
  134. }
  135. /**
  136. * Get the spawns for the NPC Id.
  137. * @param npcId the NPC Id
  138. * @return the spawn set for the given npcId
  139. */
  140. public Set<L2Spawn> getSpawns(int npcId)
  141. {
  142. return _spawnTable.containsKey(npcId) ? _spawnTable.get(npcId) : Collections.<L2Spawn> emptySet();
  143. }
  144. /**
  145. * Get the first NPC spawn.
  146. * @param npcId the NPC Id to search
  147. * @return the first not null spawn, if any
  148. */
  149. public L2Spawn getFirstSpawn(int npcId)
  150. {
  151. if (_spawnTable.containsKey(npcId))
  152. {
  153. for (L2Spawn spawn : _spawnTable.get(npcId))
  154. {
  155. if (spawn != null)
  156. {
  157. return spawn;
  158. }
  159. }
  160. }
  161. return null;
  162. }
  163. /**
  164. * Add a new spawn to the spawn table.
  165. * @param spawn the spawn to add
  166. * @param storeInDb if {@code true} it'll be saved in the database
  167. */
  168. public void addNewSpawn(L2Spawn spawn, boolean storeInDb)
  169. {
  170. addSpawn(spawn);
  171. if (storeInDb)
  172. {
  173. final String spawnTable = spawn.isCustom() && Config.CUSTOM_SPAWNLIST_TABLE ? "custom_spawnlist" : "spawnlist";
  174. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  175. PreparedStatement insert = con.prepareStatement("INSERT INTO " + spawnTable + "(count,npc_templateid,locx,locy,locz,heading,respawn_delay,respawn_random,loc_id) values(?,?,?,?,?,?,?,?,?)"))
  176. {
  177. insert.setInt(1, spawn.getAmount());
  178. insert.setInt(2, spawn.getId());
  179. insert.setInt(3, spawn.getX());
  180. insert.setInt(4, spawn.getY());
  181. insert.setInt(5, spawn.getZ());
  182. insert.setInt(6, spawn.getHeading());
  183. insert.setInt(7, spawn.getRespawnDelay() / 1000);
  184. insert.setInt(8, spawn.getRespawnMaxDelay() - spawn.getRespawnMinDelay());
  185. insert.setInt(9, spawn.getLocationId());
  186. insert.execute();
  187. }
  188. catch (Exception e)
  189. {
  190. _log.log(Level.WARNING, getClass().getSimpleName() + ": Could not store spawn in the DB:" + e.getMessage(), e);
  191. }
  192. }
  193. }
  194. /**
  195. * Delete an spawn from the spawn table.
  196. * @param spawn the spawn to delete
  197. * @param updateDb if {@code true} database will be updated
  198. */
  199. public void deleteSpawn(L2Spawn spawn, boolean updateDb)
  200. {
  201. if (!removeSpawn(spawn))
  202. {
  203. return;
  204. }
  205. if (updateDb)
  206. {
  207. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  208. PreparedStatement delete = con.prepareStatement("DELETE FROM " + (spawn.isCustom() ? "custom_spawnlist" : "spawnlist") + " WHERE locx=? AND locy=? AND locz=? AND npc_templateid=? AND heading=?"))
  209. {
  210. delete.setInt(1, spawn.getX());
  211. delete.setInt(2, spawn.getY());
  212. delete.setInt(3, spawn.getZ());
  213. delete.setInt(4, spawn.getId());
  214. delete.setInt(5, spawn.getHeading());
  215. delete.execute();
  216. }
  217. catch (Exception e)
  218. {
  219. _log.log(Level.WARNING, getClass().getSimpleName() + ": Spawn " + spawn + " could not be removed from DB: " + e.getMessage(), e);
  220. }
  221. }
  222. }
  223. /**
  224. * Add a spawn to the spawn set if present, otherwise add a spawn set and add the spawn to the newly created spawn set.
  225. * @param spawn the NPC spawn to add
  226. */
  227. private void addSpawn(L2Spawn spawn)
  228. {
  229. if (!_spawnTable.containsKey(spawn.getId()))
  230. {
  231. _spawnTable.put(spawn.getId(), new FastSet<L2Spawn>().shared());
  232. }
  233. _spawnTable.get(spawn.getId()).add(spawn);
  234. }
  235. /**
  236. * Remove a spawn from the spawn set, if the spawn set is empty, remove it as well.
  237. * @param spawn the NPC spawn to remove
  238. * @return {@code true} if the spawn was successfully removed, {@code false} otherwise
  239. */
  240. private boolean removeSpawn(L2Spawn spawn)
  241. {
  242. if (_spawnTable.containsKey(spawn.getId()))
  243. {
  244. final Set<L2Spawn> set = _spawnTable.get(spawn.getId());
  245. boolean removed = set.remove(spawn);
  246. if (set.isEmpty())
  247. {
  248. _spawnTable.remove(spawn.getId());
  249. }
  250. return removed;
  251. }
  252. return false;
  253. }
  254. /**
  255. * Execute a procedure over all spawns.<br>
  256. * <font size="4" color="red">Do not use it!</font>
  257. * @param procedure the procedure to execute
  258. * @return {@code true} if all procedures were executed, {@code false} otherwise
  259. */
  260. public boolean forEachSpawn(IL2Procedure<L2Spawn> procedure)
  261. {
  262. for (Set<L2Spawn> set : _spawnTable.values())
  263. {
  264. for (L2Spawn spawn : set)
  265. {
  266. if (!procedure.execute(spawn))
  267. {
  268. return false;
  269. }
  270. }
  271. }
  272. return true;
  273. }
  274. public static SpawnTable getInstance()
  275. {
  276. return SingletonHolder._instance;
  277. }
  278. private static class SingletonHolder
  279. {
  280. protected static final SpawnTable _instance = new SpawnTable();
  281. }
  282. }