CrestTable.java 9.1 KB

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