CrestTable.java 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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.data.sql.impl;
  20. import java.io.File;
  21. import java.nio.file.Files;
  22. import java.sql.Connection;
  23. import java.sql.PreparedStatement;
  24. import java.sql.ResultSet;
  25. import java.sql.SQLException;
  26. import java.sql.Statement;
  27. import java.util.HashSet;
  28. import java.util.Map;
  29. import java.util.Set;
  30. import java.util.concurrent.ConcurrentHashMap;
  31. import java.util.concurrent.atomic.AtomicInteger;
  32. import java.util.logging.Level;
  33. import java.util.logging.Logger;
  34. import com.l2jserver.Config;
  35. import com.l2jserver.commons.database.pool.impl.ConnectionFactory;
  36. import com.l2jserver.gameserver.model.L2Clan;
  37. import com.l2jserver.gameserver.model.L2Crest;
  38. import com.l2jserver.gameserver.model.L2Crest.CrestType;
  39. import com.l2jserver.util.file.filter.BMPFilter;
  40. /**
  41. * Loads and saves crests from database.
  42. * @author NosBit
  43. */
  44. public final class CrestTable
  45. {
  46. private static final Logger LOGGER = Logger.getLogger(CrestTable.class.getName());
  47. private final Map<Integer, L2Crest> _crests = new ConcurrentHashMap<>();
  48. private final AtomicInteger _nextId = new AtomicInteger(1);
  49. protected CrestTable()
  50. {
  51. load();
  52. }
  53. public synchronized void load()
  54. {
  55. _crests.clear();
  56. Set<Integer> crestsInUse = new HashSet<>();
  57. for (L2Clan clan : ClanTable.getInstance().getClans())
  58. {
  59. if (clan.getCrestId() != 0)
  60. {
  61. crestsInUse.add(clan.getCrestId());
  62. }
  63. if (clan.getCrestLargeId() != 0)
  64. {
  65. crestsInUse.add(clan.getCrestLargeId());
  66. }
  67. if (clan.getAllyCrestId() != 0)
  68. {
  69. crestsInUse.add(clan.getAllyCrestId());
  70. }
  71. }
  72. try (Connection con = ConnectionFactory.getInstance().getConnection();
  73. Statement statement = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
  74. ResultSet rs = statement.executeQuery("SELECT `crest_id`, `data`, `type` FROM `crests` ORDER BY `crest_id` DESC"))
  75. {
  76. while (rs.next())
  77. {
  78. int id = rs.getInt("crest_id");
  79. if (_nextId.get() <= id)
  80. {
  81. _nextId.set(id + 1);
  82. }
  83. // delete all unused crests except the last one we dont want to reuse
  84. // a crest id because client will display wrong crest if its reused
  85. if (!crestsInUse.contains(id) && (id != (_nextId.get() - 1)))
  86. {
  87. rs.deleteRow();
  88. continue;
  89. }
  90. byte[] data = rs.getBytes("data");
  91. CrestType crestType = CrestType.getById(rs.getInt("type"));
  92. if (crestType != null)
  93. {
  94. _crests.put(id, new L2Crest(id, data, crestType));
  95. }
  96. else
  97. {
  98. LOGGER.warning("Unknown crest type found in database. Type:" + rs.getInt("type"));
  99. }
  100. }
  101. }
  102. catch (SQLException e)
  103. {
  104. LOGGER.log(Level.WARNING, "There was an error while loading crests from database:", e);
  105. }
  106. moveOldCrestsToDb(crestsInUse);
  107. LOGGER.info(getClass().getSimpleName() + ": Loaded " + _crests.size() + " Crests.");
  108. for (L2Clan clan : ClanTable.getInstance().getClans())
  109. {
  110. if (clan.getCrestId() != 0)
  111. {
  112. if (getCrest(clan.getCrestId()) == null)
  113. {
  114. LOGGER.info("Removing non-existent crest for clan " + clan.getName() + " [" + clan.getId() + "], crestId:" + clan.getCrestId());
  115. clan.setCrestId(0);
  116. clan.changeClanCrest(0);
  117. }
  118. }
  119. if (clan.getCrestLargeId() != 0)
  120. {
  121. if (getCrest(clan.getCrestLargeId()) == null)
  122. {
  123. LOGGER.info("Removing non-existent large crest for clan " + clan.getName() + " [" + clan.getId() + "], crestLargeId:" + clan.getCrestLargeId());
  124. clan.setCrestLargeId(0);
  125. clan.changeLargeCrest(0);
  126. }
  127. }
  128. if (clan.getAllyCrestId() != 0)
  129. {
  130. if (getCrest(clan.getAllyCrestId()) == null)
  131. {
  132. LOGGER.info("Removing non-existent ally crest for clan " + clan.getName() + " [" + clan.getId() + "], allyCrestId:" + clan.getAllyCrestId());
  133. clan.setAllyCrestId(0);
  134. clan.changeAllyCrest(0, true);
  135. }
  136. }
  137. }
  138. }
  139. /**
  140. * Moves old crests from data/crests folder to database and deletes crest folder<br>
  141. * <b>TODO:</b> remove it after some time
  142. * @param crestsInUse the set of crests in use
  143. */
  144. private void moveOldCrestsToDb(Set<Integer> crestsInUse)
  145. {
  146. final File crestDir = new File(Config.DATAPACK_ROOT, "data/crests/");
  147. if (crestDir.exists())
  148. {
  149. final File[] files = crestDir.listFiles(new BMPFilter());
  150. if (files == null)
  151. {
  152. return;
  153. }
  154. for (File file : files)
  155. {
  156. try
  157. {
  158. final byte[] data = Files.readAllBytes(file.toPath());
  159. if (file.getName().startsWith("Crest_Large_"))
  160. {
  161. final int crestId = Integer.parseInt(file.getName().substring(12, file.getName().length() - 4));
  162. if (crestsInUse.contains(crestId))
  163. {
  164. final L2Crest crest = createCrest(data, CrestType.PLEDGE_LARGE);
  165. if (crest != null)
  166. {
  167. for (L2Clan clan : ClanTable.getInstance().getClans())
  168. {
  169. if (clan.getCrestLargeId() == crestId)
  170. {
  171. clan.setCrestLargeId(0);
  172. clan.changeLargeCrest(crest.getId());
  173. }
  174. }
  175. }
  176. }
  177. }
  178. else if (file.getName().startsWith("Crest_"))
  179. {
  180. final int crestId = Integer.parseInt(file.getName().substring(6, file.getName().length() - 4));
  181. if (crestsInUse.contains(crestId))
  182. {
  183. final L2Crest crest = createCrest(data, CrestType.PLEDGE);
  184. if (crest != null)
  185. {
  186. for (L2Clan clan : ClanTable.getInstance().getClans())
  187. {
  188. if (clan.getCrestId() == crestId)
  189. {
  190. clan.setCrestId(0);
  191. clan.changeClanCrest(crest.getId());
  192. }
  193. }
  194. }
  195. }
  196. }
  197. else if (file.getName().startsWith("AllyCrest_"))
  198. {
  199. final int crestId = Integer.parseInt(file.getName().substring(10, file.getName().length() - 4));
  200. if (crestsInUse.contains(crestId))
  201. {
  202. final L2Crest crest = createCrest(data, CrestType.ALLY);
  203. if (crest != null)
  204. {
  205. for (L2Clan clan : ClanTable.getInstance().getClans())
  206. {
  207. if (clan.getAllyCrestId() == crestId)
  208. {
  209. clan.setAllyCrestId(0);
  210. clan.changeAllyCrest(crest.getId(), false);
  211. }
  212. }
  213. }
  214. }
  215. }
  216. file.delete();
  217. }
  218. catch (Exception e)
  219. {
  220. LOGGER.log(Level.WARNING, "There was an error while moving crest file " + file.getName() + " to database:", e);
  221. }
  222. }
  223. crestDir.delete();
  224. }
  225. }
  226. /**
  227. * @param crestId The crest id
  228. * @return {@code L2Crest} if crest is found, {@code null} if crest was not found.
  229. */
  230. public L2Crest getCrest(int crestId)
  231. {
  232. return _crests.get(crestId);
  233. }
  234. /**
  235. * Creates a {@code L2Crest} object and inserts it in database and cache.
  236. * @param data
  237. * @param crestType
  238. * @return {@code L2Crest} on success, {@code null} on failure.
  239. */
  240. public L2Crest createCrest(byte[] data, CrestType crestType)
  241. {
  242. try (Connection con = ConnectionFactory.getInstance().getConnection();
  243. PreparedStatement statement = con.prepareStatement("INSERT INTO `crests`(`crest_id`, `data`, `type`) VALUES(?, ?, ?)"))
  244. {
  245. final L2Crest crest = new L2Crest(getNextId(), data, crestType);
  246. statement.setInt(1, crest.getId());
  247. statement.setBytes(2, crest.getData());
  248. statement.setInt(3, crest.getType().getId());
  249. statement.executeUpdate();
  250. _crests.put(crest.getId(), crest);
  251. return crest;
  252. }
  253. catch (SQLException e)
  254. {
  255. LOGGER.log(Level.WARNING, "There was an error while saving crest in database:", e);
  256. }
  257. return null;
  258. }
  259. /**
  260. * Removes crest from database and cache.
  261. * @param crestId the id of crest to be removed.
  262. */
  263. public void removeCrest(int crestId)
  264. {
  265. _crests.remove(crestId);
  266. // avoid removing last crest id we dont want to lose index...
  267. // because client will display wrong crest if its reused
  268. if (crestId == (_nextId.get() - 1))
  269. {
  270. return;
  271. }
  272. try (Connection con = ConnectionFactory.getInstance().getConnection();
  273. PreparedStatement statement = con.prepareStatement("DELETE FROM `crests` WHERE `crest_id` = ?"))
  274. {
  275. statement.setInt(1, crestId);
  276. statement.executeUpdate();
  277. }
  278. catch (SQLException e)
  279. {
  280. LOGGER.log(Level.WARNING, "There was an error while deleting crest from database:", e);
  281. }
  282. }
  283. /**
  284. * @return The next crest id.
  285. */
  286. public int getNextId()
  287. {
  288. return _nextId.getAndIncrement();
  289. }
  290. public static CrestTable getInstance()
  291. {
  292. return SingletonHolder._instance;
  293. }
  294. private static class SingletonHolder
  295. {
  296. protected static final CrestTable _instance = new CrestTable();
  297. }
  298. }