SQLDatabaseManager.java 62 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640
  1. package com.gmail.nossr50.database;
  2. import java.sql.Connection;
  3. import java.sql.PreparedStatement;
  4. import java.sql.ResultSet;
  5. import java.sql.ResultSetMetaData;
  6. import java.sql.SQLException;
  7. import java.sql.Statement;
  8. import java.util.ArrayList;
  9. import java.util.Collection;
  10. import java.util.HashMap;
  11. import java.util.List;
  12. import java.util.Map;
  13. import java.util.Properties;
  14. import java.util.UUID;
  15. import com.gmail.nossr50.mcMMO;
  16. import com.gmail.nossr50.config.Config;
  17. import com.gmail.nossr50.datatypes.MobHealthbarType;
  18. import com.gmail.nossr50.datatypes.database.DatabaseType;
  19. import com.gmail.nossr50.datatypes.database.PlayerStat;
  20. import com.gmail.nossr50.datatypes.database.UpgradeType;
  21. import com.gmail.nossr50.datatypes.player.PlayerProfile;
  22. import com.gmail.nossr50.datatypes.skills.AbilityType;
  23. import com.gmail.nossr50.datatypes.skills.SkillType;
  24. import com.gmail.nossr50.runnables.database.UUIDUpdateAsyncTask;
  25. import com.gmail.nossr50.util.Misc;
  26. import snaq.db.ConnectionPool;
  27. public final class SQLDatabaseManager implements DatabaseManager {
  28. private static final String ALL_QUERY_VERSION = "taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy";
  29. private String connectionString;
  30. private String tablePrefix = Config.getInstance().getMySQLTablePrefix();
  31. private final int POOL_FETCH_TIMEOUT = 0; // How long a method will wait for a connection. Since none are on main thread, we can safely say wait for as long as you like.
  32. private final Map<UUID, Integer> cachedUserIDs = new HashMap<UUID, Integer>();
  33. private final Map<String, Integer> cachedUserIDsByName = new HashMap<String, Integer>();
  34. private ConnectionPool connectionPool;
  35. protected SQLDatabaseManager() {
  36. connectionString = "jdbc:mysql://" + Config.getInstance().getMySQLServerName() + ":" + Config.getInstance().getMySQLServerPort() + "/" + Config.getInstance().getMySQLDatabaseName();
  37. try {
  38. // Force driver to load if not yet loaded
  39. Class.forName("com.mysql.jdbc.Driver");
  40. Properties connectionProperties = new Properties();
  41. connectionProperties.put("user", Config.getInstance().getMySQLUserName());
  42. connectionProperties.put("password", Config.getInstance().getMySQLUserPassword());
  43. connectionProperties.put("autoReconnect", "false");
  44. connectionPool = new ConnectionPool("mcMMO-Pool",
  45. 1 /*Minimum of one*/,
  46. 10 /*max pool size */, // TODO Configurable?
  47. 10 /*max num connections*/, // TODO Configurable?
  48. 0 /* idle timeout of connections */,
  49. connectionString,
  50. connectionProperties);
  51. connectionPool.init(); // Init first connection
  52. connectionPool.registerShutdownHook(); // Auto release on jvm exit just in case
  53. }
  54. catch (ClassNotFoundException e) {
  55. // TODO tft do something here everything will blow up
  56. e.printStackTrace();
  57. }
  58. checkStructure();
  59. }
  60. public void purgePowerlessUsers() {
  61. mcMMO.p.getLogger().info("Purging powerless users...");
  62. Connection connection = null;
  63. Statement statement = null;
  64. ResultSet resultSet = null;
  65. List<String> usernames = new ArrayList<String>();
  66. try {
  67. connection = connectionPool.getConnection(POOL_FETCH_TIMEOUT);
  68. statement = connection.createStatement();
  69. resultSet = statement.executeQuery("SELECT u.user FROM " + tablePrefix + "skills AS s, " + tablePrefix + "users AS u WHERE s.user_id = u.id AND (s.taming+s.mining+s.woodcutting+s.repair+s.unarmed+s.herbalism+s.excavation+s.archery+s.swords+s.axes+s.acrobatics+s.fishing) = 0");
  70. while (resultSet.next()) {
  71. usernames.add(resultSet.getString("user"));
  72. }
  73. resultSet.close();
  74. statement.executeUpdate("DELETE FROM u, e, h, s, c USING " + tablePrefix + "users u " +
  75. "JOIN " + tablePrefix + "experience e ON (u.id = e.user_id) " +
  76. "JOIN " + tablePrefix + "huds h ON (u.id = h.user_id) " +
  77. "JOIN " + tablePrefix + "skills s ON (u.id = s.user_id) " +
  78. "JOIN " + tablePrefix + "cooldowns c ON (u.id = c.user_id) " +
  79. "WHERE (s.taming+s.mining+s.woodcutting+s.repair+s.unarmed+s.herbalism+s.excavation+s.archery+s.swords+s.axes+s.acrobatics+s.fishing) = 0");
  80. }
  81. catch (SQLException ex) {
  82. printErrors(ex);
  83. }
  84. finally {
  85. if (resultSet != null) {
  86. try {
  87. resultSet.close();
  88. }
  89. catch (SQLException e) {
  90. // Ignore
  91. }
  92. }
  93. if (statement != null) {
  94. try {
  95. statement.close();
  96. }
  97. catch (SQLException e) {
  98. // Ignore
  99. }
  100. }
  101. if (connection != null) {
  102. try {
  103. connection.close();
  104. }
  105. catch (SQLException e) {
  106. // Ignore
  107. }
  108. }
  109. }
  110. if (!usernames.isEmpty()) {
  111. processPurge(usernames);
  112. }
  113. mcMMO.p.getLogger().info("Purged " + usernames.size() + " users from the database.");
  114. }
  115. public void purgeOldUsers() {
  116. mcMMO.p.getLogger().info("Purging old users...");
  117. Connection connection = null;
  118. Statement statement = null;
  119. ResultSet resultSet = null;
  120. List<String> usernames = new ArrayList<String>();
  121. try {
  122. connection = connectionPool.getConnection(POOL_FETCH_TIMEOUT);
  123. statement = connection.createStatement();
  124. resultSet = statement.executeQuery("SELECT user FROM " + tablePrefix + "users WHERE ((NOW() - lastlogin * " + Misc.TIME_CONVERSION_FACTOR + ") > " + PURGE_TIME + ")");
  125. while (resultSet.next()) {
  126. usernames.add(resultSet.getString("user"));
  127. }
  128. resultSet.close();
  129. statement.executeUpdate("DELETE FROM u, e, h, s, c USING " + tablePrefix + "users u " +
  130. "JOIN " + tablePrefix + "experience e ON (u.id = e.user_id) " +
  131. "JOIN " + tablePrefix + "huds h ON (u.id = h.user_id) " +
  132. "JOIN " + tablePrefix + "skills s ON (u.id = s.user_id) " +
  133. "JOIN " + tablePrefix + "cooldowns c ON (u.id = c.user_id) " +
  134. "WHERE ((NOW() - lastlogin * " + Misc.TIME_CONVERSION_FACTOR + ") > " + PURGE_TIME + ")");
  135. }
  136. catch (SQLException ex) {
  137. printErrors(ex);
  138. }
  139. finally {
  140. if (resultSet != null) {
  141. try {
  142. resultSet.close();
  143. }
  144. catch (SQLException e) {
  145. // Ignore
  146. }
  147. }
  148. if (statement != null) {
  149. try {
  150. statement.close();
  151. }
  152. catch (SQLException e) {
  153. // Ignore
  154. }
  155. }
  156. if (connection != null) {
  157. try {
  158. connection.close();
  159. }
  160. catch (SQLException e) {
  161. // Ignore
  162. }
  163. }
  164. }
  165. if (!usernames.isEmpty()) {
  166. processPurge(usernames);
  167. }
  168. mcMMO.p.getLogger().info("Purged " + usernames.size() + " users from the database.");
  169. }
  170. public boolean removeUser(String playerName) {
  171. boolean success = false;
  172. Connection connection = null;
  173. PreparedStatement statement = null;
  174. try {
  175. connection = connectionPool.getConnection(POOL_FETCH_TIMEOUT);
  176. statement = connection.prepareStatement("DELETE FROM u, e, h, s, c " +
  177. "USING " + tablePrefix + "users u " +
  178. "JOIN " + tablePrefix + "experience e ON (u.id = e.user_id) " +
  179. "JOIN " + tablePrefix + "huds h ON (u.id = h.user_id) " +
  180. "JOIN " + tablePrefix + "skills s ON (u.id = s.user_id) " +
  181. "JOIN " + tablePrefix + "cooldowns c ON (u.id = c.user_id) " +
  182. "WHERE u.user = ?");
  183. statement.setString(1, playerName);
  184. success = statement.executeUpdate() != 0;
  185. }
  186. catch (SQLException ex) {
  187. printErrors(ex);
  188. }
  189. finally {
  190. if (statement != null) {
  191. try {
  192. statement.close();
  193. }
  194. catch (SQLException e) {
  195. // Ignore
  196. }
  197. }
  198. if (connection != null) {
  199. try {
  200. connection.close();
  201. }
  202. catch (SQLException e) {
  203. // Ignore
  204. }
  205. }
  206. }
  207. if (success) {
  208. Misc.profileCleanup(playerName);
  209. }
  210. return success;
  211. }
  212. public boolean saveUser(PlayerProfile profile) {
  213. boolean success = true;
  214. PreparedStatement statement = null;
  215. Connection connection = null;
  216. try {
  217. connection = connectionPool.getConnection(POOL_FETCH_TIMEOUT);
  218. int id = getUserID(connection, profile.getUniqueId());
  219. if (id == -1) {
  220. newUser(profile.getPlayerName(), profile.getUniqueId().toString());
  221. id = getUserID(connection, profile.getUniqueId());
  222. if (id == -1) {
  223. return false;
  224. }
  225. }
  226. statement = connection.prepareStatement("UPDATE " + tablePrefix + "users SET lastlogin = UNIX_TIMESTAMP() WHERE uuid = ?");
  227. statement.setString(1, profile.getUniqueId().toString());
  228. success &= (statement.executeUpdate() != 0);
  229. statement.close();
  230. statement = connection.prepareStatement("UPDATE " + tablePrefix + "skills SET "
  231. + " taming = ?, mining = ?, repair = ?, woodcutting = ?"
  232. + ", unarmed = ?, herbalism = ?, excavation = ?"
  233. + ", archery = ?, swords = ?, axes = ?, acrobatics = ?"
  234. + ", fishing = ?, alchemy = ? WHERE user_id = ?");
  235. statement.setInt(1, profile.getSkillLevel(SkillType.TAMING));
  236. statement.setInt(2, profile.getSkillLevel(SkillType.MINING));
  237. statement.setInt(3, profile.getSkillLevel(SkillType.REPAIR));
  238. statement.setInt(4, profile.getSkillLevel(SkillType.WOODCUTTING));
  239. statement.setInt(5, profile.getSkillLevel(SkillType.UNARMED));
  240. statement.setInt(6, profile.getSkillLevel(SkillType.HERBALISM));
  241. statement.setInt(7, profile.getSkillLevel(SkillType.EXCAVATION));
  242. statement.setInt(8, profile.getSkillLevel(SkillType.ARCHERY));
  243. statement.setInt(9, profile.getSkillLevel(SkillType.SWORDS));
  244. statement.setInt(10, profile.getSkillLevel(SkillType.AXES));
  245. statement.setInt(11, profile.getSkillLevel(SkillType.ACROBATICS));
  246. statement.setInt(12, profile.getSkillLevel(SkillType.FISHING));
  247. statement.setInt(13, profile.getSkillLevel(SkillType.ALCHEMY));
  248. statement.setInt(14, id);
  249. success &= (statement.executeUpdate() != 0);
  250. statement.close();
  251. statement = connection.prepareStatement("UPDATE " + tablePrefix + "experience SET "
  252. + " taming = ?, mining = ?, repair = ?, woodcutting = ?"
  253. + ", unarmed = ?, herbalism = ?, excavation = ?"
  254. + ", archery = ?, swords = ?, axes = ?, acrobatics = ?"
  255. + ", fishing = ?, alchemy = ? WHERE user_id = ?");
  256. statement.setInt(1, profile.getSkillXpLevel(SkillType.TAMING));
  257. statement.setInt(2, profile.getSkillXpLevel(SkillType.MINING));
  258. statement.setInt(3, profile.getSkillXpLevel(SkillType.REPAIR));
  259. statement.setInt(4, profile.getSkillXpLevel(SkillType.WOODCUTTING));
  260. statement.setInt(5, profile.getSkillXpLevel(SkillType.UNARMED));
  261. statement.setInt(6, profile.getSkillXpLevel(SkillType.HERBALISM));
  262. statement.setInt(7, profile.getSkillXpLevel(SkillType.EXCAVATION));
  263. statement.setInt(8, profile.getSkillXpLevel(SkillType.ARCHERY));
  264. statement.setInt(9, profile.getSkillXpLevel(SkillType.SWORDS));
  265. statement.setInt(10, profile.getSkillXpLevel(SkillType.AXES));
  266. statement.setInt(11, profile.getSkillXpLevel(SkillType.ACROBATICS));
  267. statement.setInt(12, profile.getSkillXpLevel(SkillType.FISHING));
  268. statement.setInt(13, profile.getSkillXpLevel(SkillType.ALCHEMY));
  269. statement.setInt(14, id);
  270. success &= (statement.executeUpdate() != 0);
  271. statement.close();
  272. statement = connection.prepareStatement("UPDATE " + tablePrefix + "cooldowns SET "
  273. + " mining = ?, woodcutting = ?, unarmed = ?"
  274. + ", herbalism = ?, excavation = ?, swords = ?"
  275. + ", axes = ?, blast_mining = ? WHERE user_id = ?");
  276. statement.setLong(1, profile.getAbilityDATS(AbilityType.SUPER_BREAKER));
  277. statement.setLong(2, profile.getAbilityDATS(AbilityType.TREE_FELLER));
  278. statement.setLong(3, profile.getAbilityDATS(AbilityType.BERSERK));
  279. statement.setLong(4, profile.getAbilityDATS(AbilityType.GREEN_TERRA));
  280. statement.setLong(5, profile.getAbilityDATS(AbilityType.GIGA_DRILL_BREAKER));
  281. statement.setLong(6, profile.getAbilityDATS(AbilityType.SERRATED_STRIKES));
  282. statement.setLong(7, profile.getAbilityDATS(AbilityType.SKULL_SPLITTER));
  283. statement.setLong(8, profile.getAbilityDATS(AbilityType.BLAST_MINING));
  284. statement.setInt(9, id);
  285. success = (statement.executeUpdate() != 0);
  286. statement.close();
  287. statement = connection.prepareStatement("UPDATE " + tablePrefix + "huds SET mobhealthbar = ? WHERE user_id = ?");
  288. statement.setString(1, profile.getMobHealthbarType() == null ? Config.getInstance().getMobHealthbarDefault().name() : profile.getMobHealthbarType().name());
  289. statement.setInt(2, id);
  290. success = (statement.executeUpdate() != 0);
  291. }
  292. catch (SQLException ex) {
  293. printErrors(ex);
  294. }
  295. finally {
  296. if (statement != null) {
  297. try {
  298. statement.close();
  299. }
  300. catch (SQLException e) {
  301. // Ignore
  302. }
  303. }
  304. if (connection != null) {
  305. try {
  306. connection.close();
  307. }
  308. catch (SQLException e) {
  309. // Ignore
  310. }
  311. }
  312. }
  313. return success;
  314. }
  315. public List<PlayerStat> readLeaderboard(SkillType skill, int pageNumber, int statsPerPage) {
  316. List<PlayerStat> stats = new ArrayList<PlayerStat>();
  317. String query = skill == null ? ALL_QUERY_VERSION : skill.name().toLowerCase();
  318. ResultSet resultSet = null;
  319. PreparedStatement statement = null;
  320. Connection connection = null;
  321. try {
  322. connection = connectionPool.getConnection(POOL_FETCH_TIMEOUT);
  323. statement = connection.prepareStatement("SELECT " + query + ", user, NOW() FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON (user_id = id) WHERE " + query + " > 0 ORDER BY " + query + " DESC, user LIMIT ?, ?");
  324. statement.setInt(1, (pageNumber * statsPerPage) - statsPerPage);
  325. statement.setInt(2, statsPerPage);
  326. resultSet = statement.executeQuery();
  327. while (resultSet.next()) {
  328. ArrayList<String> column = new ArrayList<String>();
  329. for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) {
  330. column.add(resultSet.getString(i));
  331. }
  332. stats.add(new PlayerStat(column.get(1), Integer.valueOf(column.get(0))));
  333. }
  334. }
  335. catch (SQLException ex) {
  336. printErrors(ex);
  337. }
  338. finally {
  339. if (resultSet != null) {
  340. try {
  341. resultSet.close();
  342. }
  343. catch (SQLException e) {
  344. // Ignore
  345. }
  346. }
  347. if (statement != null) {
  348. try {
  349. statement.close();
  350. }
  351. catch (SQLException e) {
  352. // Ignore
  353. }
  354. }
  355. if (connection != null) {
  356. try {
  357. connection.close();
  358. }
  359. catch (SQLException e) {
  360. // Ignore
  361. }
  362. }
  363. }
  364. return stats;
  365. }
  366. public Map<SkillType, Integer> readRank(String playerName) {
  367. Map<SkillType, Integer> skills = new HashMap<SkillType, Integer>();
  368. ResultSet resultSet = null;
  369. PreparedStatement statement = null;
  370. Connection connection = null;
  371. try {
  372. connection = connectionPool.getConnection(POOL_FETCH_TIMEOUT);
  373. for (SkillType skillType : SkillType.NON_CHILD_SKILLS) {
  374. String skillName = skillType.name().toLowerCase();
  375. String sql = "SELECT COUNT(*) AS rank FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE " + skillName + " > 0 " +
  376. "AND " + skillName + " > (SELECT " + skillName + " FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " +
  377. "WHERE user = ?)";
  378. statement = connection.prepareStatement(sql);
  379. statement.setString(1, playerName);
  380. resultSet = statement.executeQuery();
  381. resultSet.next();
  382. int rank = resultSet.getInt("rank");
  383. sql = "SELECT user, " + skillName + " FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE " + skillName + " > 0 " +
  384. "AND " + skillName + " = (SELECT " + skillName + " FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " +
  385. "WHERE user = '" + playerName + "') ORDER BY user";
  386. resultSet.close();
  387. statement.close();
  388. statement = connection.prepareStatement(sql);
  389. resultSet = statement.executeQuery();
  390. while (resultSet.next()) {
  391. if (resultSet.getString("user").equalsIgnoreCase(playerName)) {
  392. skills.put(skillType, rank + resultSet.getRow());
  393. break;
  394. }
  395. }
  396. resultSet.close();
  397. statement.close();
  398. }
  399. String sql = "SELECT COUNT(*) AS rank FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " +
  400. "WHERE " + ALL_QUERY_VERSION + " > 0 " +
  401. "AND " + ALL_QUERY_VERSION + " > " +
  402. "(SELECT " + ALL_QUERY_VERSION + " " +
  403. "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE user = ?)";
  404. statement = connection.prepareStatement(sql);
  405. statement.setString(1, playerName);
  406. resultSet = statement.executeQuery();
  407. resultSet.next();
  408. int rank = resultSet.getInt("rank");
  409. resultSet.close();
  410. statement.close();
  411. sql = "SELECT user, " + ALL_QUERY_VERSION + " " +
  412. "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " +
  413. "WHERE " + ALL_QUERY_VERSION + " > 0 " +
  414. "AND " + ALL_QUERY_VERSION + " = " +
  415. "(SELECT " + ALL_QUERY_VERSION + " " +
  416. "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE user = ?) ORDER BY user";
  417. statement = connection.prepareStatement(sql);
  418. statement.setString(1, playerName);
  419. resultSet = statement.executeQuery();
  420. while (resultSet.next()) {
  421. if (resultSet.getString("user").equalsIgnoreCase(playerName)) {
  422. skills.put(null, rank + resultSet.getRow());
  423. break;
  424. }
  425. }
  426. resultSet.close();
  427. statement.close();
  428. }
  429. catch (SQLException ex) {
  430. printErrors(ex);
  431. }
  432. finally {
  433. if (resultSet != null) {
  434. try {
  435. resultSet.close();
  436. }
  437. catch (SQLException e) {
  438. // Ignore
  439. }
  440. }
  441. if (statement != null) {
  442. try {
  443. statement.close();
  444. }
  445. catch (SQLException e) {
  446. // Ignore
  447. }
  448. }
  449. if (connection != null) {
  450. try {
  451. connection.close();
  452. }
  453. catch (SQLException e) {
  454. // Ignore
  455. }
  456. }
  457. }
  458. return skills;
  459. }
  460. public void newUser(String playerName, String uuid) {
  461. Connection connection = null;
  462. try {
  463. connection = connectionPool.getConnection(POOL_FETCH_TIMEOUT);
  464. newUser(connection, playerName, uuid);
  465. }
  466. catch (SQLException ex) {
  467. printErrors(ex);
  468. }
  469. finally {
  470. if (connection != null) {
  471. try {
  472. connection.close();
  473. }
  474. catch (SQLException e) {
  475. // Ignore
  476. }
  477. }
  478. }
  479. }
  480. private void newUser(Connection connection, String playerName, String uuid) {
  481. ResultSet resultSet = null;
  482. PreparedStatement statement = null;
  483. try {
  484. statement = connection.prepareStatement("INSERT INTO " + tablePrefix + "users (user, uuid, lastlogin) VALUES (?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
  485. statement.setString(1, playerName);
  486. statement.setString(2, uuid);
  487. statement.setLong(3, System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR);
  488. statement.executeUpdate();
  489. resultSet = statement.getGeneratedKeys();
  490. if (!resultSet.next()) {
  491. return;
  492. }
  493. writeMissingRows(connection, resultSet.getInt(1));
  494. }
  495. catch (SQLException ex) {
  496. printErrors(ex);
  497. }
  498. finally {
  499. if (resultSet != null) {
  500. try {
  501. resultSet.close();
  502. }
  503. catch (SQLException e) {
  504. // Ignore
  505. }
  506. }
  507. if (statement != null) {
  508. try {
  509. statement.close();
  510. }
  511. catch (SQLException e) {
  512. // Ignore
  513. }
  514. }
  515. }
  516. }
  517. /**
  518. * This is a fallback method to provide the old way of getting a
  519. * PlayerProfile in case there is no UUID match found
  520. */
  521. private PlayerProfile loadPlayerNameProfile(String playerName, String uuid, boolean create, boolean retry) {
  522. PreparedStatement statement = null;
  523. Connection connection = null;
  524. ResultSet resultSet = null;
  525. try {
  526. connection = connectionPool.getConnection(POOL_FETCH_TIMEOUT);
  527. int id = getUserID(connection, playerName);
  528. if (id == -1) {
  529. // There is no such user
  530. if (create) {
  531. newUser(playerName, uuid);
  532. return loadPlayerNameProfile(playerName, uuid, false, false);
  533. }
  534. // Return unloaded profile if can't create
  535. return new PlayerProfile(playerName, false);
  536. }
  537. // There is such a user
  538. writeMissingRows(connection, id);
  539. statement = connection.prepareStatement(
  540. "SELECT "
  541. + "s.taming, s.mining, s.repair, s.woodcutting, s.unarmed, s.herbalism, s.excavation, s.archery, s.swords, s.axes, s.acrobatics, s.fishing, s.alchemy, "
  542. + "e.taming, e.mining, e.repair, e.woodcutting, e.unarmed, e.herbalism, e.excavation, e.archery, e.swords, e.axes, e.acrobatics, e.fishing, e.alchemy, "
  543. + "c.taming, c.mining, c.repair, c.woodcutting, c.unarmed, c.herbalism, c.excavation, c.archery, c.swords, c.axes, c.acrobatics, c.blast_mining, "
  544. + "h.mobhealthbar, u.uuid "
  545. + "FROM " + tablePrefix + "users u "
  546. + "JOIN " + tablePrefix + "skills s ON (u.id = s.user_id) "
  547. + "JOIN " + tablePrefix + "experience e ON (u.id = e.user_id) "
  548. + "JOIN " + tablePrefix + "cooldowns c ON (u.id = c.user_id) "
  549. + "JOIN " + tablePrefix + "huds h ON (u.id = h.user_id) "
  550. + "WHERE u.user = ?");
  551. statement.setString(1, playerName);
  552. resultSet = statement.executeQuery();
  553. if (resultSet.next()) {
  554. try {
  555. PlayerProfile ret = loadFromResult(playerName, resultSet);
  556. return ret;
  557. }
  558. catch (SQLException e) {
  559. }
  560. }
  561. }
  562. catch (SQLException ex) {
  563. printErrors(ex);
  564. }
  565. finally {
  566. if (resultSet != null) {
  567. try {
  568. resultSet.close();
  569. }
  570. catch (SQLException e) {
  571. // Ignore
  572. }
  573. }
  574. if (statement != null) {
  575. try {
  576. statement.close();
  577. }
  578. catch (SQLException e) {
  579. // Ignore
  580. }
  581. }
  582. if (connection != null) {
  583. try {
  584. connection.close();
  585. }
  586. catch (SQLException e) {
  587. // Ignore
  588. }
  589. }
  590. }
  591. // Problem, nothing was returned
  592. // Quit if this is second time around
  593. if (!retry) {
  594. return new PlayerProfile(playerName, false);
  595. }
  596. // Retry, and abort on re-failure
  597. return loadPlayerNameProfile(playerName, uuid, create, false);
  598. }
  599. @Deprecated
  600. public PlayerProfile loadPlayerProfile(String playerName, boolean create) {
  601. return loadPlayerProfile(playerName, "", false, true);
  602. }
  603. public PlayerProfile loadPlayerProfile(UUID uuid) {
  604. return loadPlayerProfile("", uuid.toString(), false, true);
  605. }
  606. public PlayerProfile loadPlayerProfile(String playerName, UUID uuid, boolean create) {
  607. return loadPlayerProfile(playerName, uuid.toString(), create, true);
  608. }
  609. private PlayerProfile loadPlayerProfile(String playerName, String uuid, boolean create, boolean retry) {
  610. PreparedStatement statement = null;
  611. Connection connection = null;
  612. ResultSet resultSet = null;
  613. try {
  614. connection = connectionPool.getConnection(POOL_FETCH_TIMEOUT);
  615. int id = getUserID(connection, playerName);
  616. if (id == -1) {
  617. // There is no such user
  618. if (create) {
  619. newUser(playerName, uuid);
  620. return loadPlayerNameProfile(playerName, uuid, false, false);
  621. }
  622. // Return unloaded profile if can't create
  623. return new PlayerProfile(playerName, false);
  624. }
  625. // There is such a user
  626. writeMissingRows(connection, id);
  627. statement = connection.prepareStatement(
  628. "SELECT "
  629. + "s.taming, s.mining, s.repair, s.woodcutting, s.unarmed, s.herbalism, s.excavation, s.archery, s.swords, s.axes, s.acrobatics, s.fishing, s.alchemy, "
  630. + "e.taming, e.mining, e.repair, e.woodcutting, e.unarmed, e.herbalism, e.excavation, e.archery, e.swords, e.axes, e.acrobatics, e.fishing, e.alchemy, "
  631. + "c.taming, c.mining, c.repair, c.woodcutting, c.unarmed, c.herbalism, c.excavation, c.archery, c.swords, c.axes, c.acrobatics, c.blast_mining, "
  632. + "h.mobhealthbar, u.uuid "
  633. + "FROM " + tablePrefix + "users u "
  634. + "JOIN " + tablePrefix + "skills s ON (u.id = s.user_id) "
  635. + "JOIN " + tablePrefix + "experience e ON (u.id = e.user_id) "
  636. + "JOIN " + tablePrefix + "cooldowns c ON (u.id = c.user_id) "
  637. + "JOIN " + tablePrefix + "huds h ON (u.id = h.user_id) "
  638. + "WHERE u.UUID = ?");
  639. statement.setString(1, uuid);
  640. resultSet = statement.executeQuery();
  641. if (resultSet.next()) {
  642. try {
  643. PlayerProfile profile = loadFromResult(playerName, resultSet);
  644. resultSet.close();
  645. statement.close();
  646. if (!playerName.isEmpty() && !profile.getPlayerName().isEmpty()) {
  647. statement = connection.prepareStatement(
  648. "UPDATE `" + tablePrefix + "users` "
  649. + "SET user = ? "
  650. + "WHERE UUID = ?");
  651. statement.setString(1, playerName);
  652. statement.setString(2, uuid);
  653. statement.executeUpdate();
  654. statement.close();
  655. }
  656. return profile;
  657. }
  658. catch (SQLException e) {
  659. }
  660. }
  661. resultSet.close();
  662. }
  663. catch (SQLException ex) {
  664. printErrors(ex);
  665. }
  666. finally {
  667. if (resultSet != null) {
  668. try {
  669. resultSet.close();
  670. }
  671. catch (SQLException e) {
  672. // Ignore
  673. }
  674. }
  675. if (statement != null) {
  676. try {
  677. statement.close();
  678. }
  679. catch (SQLException e) {
  680. // Ignore
  681. }
  682. }
  683. if (connection != null) {
  684. try {
  685. connection.close();
  686. }
  687. catch (SQLException e) {
  688. // Ignore
  689. }
  690. }
  691. }
  692. // Problem, nothing was returned
  693. // Retry the old fashioned way if this is second time around
  694. if (!retry) {
  695. return loadPlayerNameProfile(playerName, uuid, create, true);
  696. }
  697. // Retry, and abort on re-failure
  698. return loadPlayerProfile(playerName, uuid, create, false);
  699. }
  700. public void convertUsers(DatabaseManager destination) {
  701. PreparedStatement statement = null;
  702. Connection connection = null;
  703. ResultSet resultSet = null;
  704. try {
  705. connection = connectionPool.getConnection(POOL_FETCH_TIMEOUT);
  706. statement = connection.prepareStatement(
  707. "SELECT "
  708. + "s.taming, s.mining, s.repair, s.woodcutting, s.unarmed, s.herbalism, s.excavation, s.archery, s.swords, s.axes, s.acrobatics, s.fishing, s.alchemy, "
  709. + "e.taming, e.mining, e.repair, e.woodcutting, e.unarmed, e.herbalism, e.excavation, e.archery, e.swords, e.axes, e.acrobatics, e.fishing, e.alchemy, "
  710. + "c.taming, c.mining, c.repair, c.woodcutting, c.unarmed, c.herbalism, c.excavation, c.archery, c.swords, c.axes, c.acrobatics, c.blast_mining, "
  711. + "h.mobhealthbar, u.uuid "
  712. + "FROM " + tablePrefix + "users u "
  713. + "JOIN " + tablePrefix + "skills s ON (u.id = s.user_id) "
  714. + "JOIN " + tablePrefix + "experience e ON (u.id = e.user_id) "
  715. + "JOIN " + tablePrefix + "cooldowns c ON (u.id = c.user_id) "
  716. + "JOIN " + tablePrefix + "huds h ON (u.id = h.user_id) "
  717. + "WHERE u.user = ?");
  718. List<String> usernames = getStoredUsers();
  719. int convertedUsers = 0;
  720. long startMillis = System.currentTimeMillis();
  721. for (String playerName : usernames) {
  722. statement.setString(1, playerName);
  723. try {
  724. resultSet = statement.executeQuery();
  725. resultSet.next();
  726. destination.saveUser(loadFromResult(playerName, resultSet));
  727. resultSet.close();
  728. }
  729. catch (SQLException e) {
  730. // Ignore
  731. }
  732. convertedUsers++;
  733. Misc.printProgress(convertedUsers, progressInterval, startMillis);
  734. }
  735. }
  736. catch (SQLException e) {
  737. printErrors(e);
  738. }
  739. finally {
  740. if (resultSet != null) {
  741. try {
  742. resultSet.close();
  743. }
  744. catch (SQLException e) {
  745. // Ignore
  746. }
  747. }
  748. if (statement != null) {
  749. try {
  750. statement.close();
  751. }
  752. catch (SQLException e) {
  753. // Ignore
  754. }
  755. }
  756. if (connection != null) {
  757. try {
  758. connection.close();
  759. }
  760. catch (SQLException e) {
  761. // Ignore
  762. }
  763. }
  764. }
  765. }
  766. public boolean saveUserUUID(String userName, UUID uuid) {
  767. PreparedStatement statement = null;
  768. Connection connection = null;
  769. try {
  770. connection = connectionPool.getConnection(POOL_FETCH_TIMEOUT);
  771. statement = connection.prepareStatement(
  772. "UPDATE `" + tablePrefix + "users` SET "
  773. + " uuid = ? WHERE user = ?");
  774. statement.setString(1, uuid.toString());
  775. statement.setString(2, userName);
  776. statement.execute();
  777. return true;
  778. }
  779. catch (SQLException ex) {
  780. printErrors(ex);
  781. return false;
  782. }
  783. finally {
  784. if (statement != null) {
  785. try {
  786. statement.close();
  787. }
  788. catch (SQLException e) {
  789. // Ignore
  790. }
  791. }
  792. if (connection != null) {
  793. try {
  794. connection.close();
  795. }
  796. catch (SQLException e) {
  797. // Ignore
  798. }
  799. }
  800. }
  801. }
  802. public boolean saveUserUUIDs(Map<String, UUID> fetchedUUIDs) {
  803. PreparedStatement statement = null;
  804. int count = 0;
  805. Connection connection = null;
  806. try {
  807. connection = connectionPool.getConnection(POOL_FETCH_TIMEOUT);
  808. statement = connection.prepareStatement("UPDATE " + tablePrefix + "users SET uuid = ? WHERE user = ?");
  809. for (Map.Entry<String, UUID> entry : fetchedUUIDs.entrySet()) {
  810. statement.setString(1, entry.getValue().toString());
  811. statement.setString(2, entry.getKey());
  812. statement.addBatch();
  813. count++;
  814. if ((count % 500) == 0) {
  815. statement.executeBatch();
  816. count = 0;
  817. }
  818. }
  819. if (count != 0) {
  820. statement.executeBatch();
  821. }
  822. return true;
  823. }
  824. catch (SQLException ex) {
  825. printErrors(ex);
  826. return false;
  827. }
  828. finally {
  829. if (statement != null) {
  830. try {
  831. statement.close();
  832. }
  833. catch (SQLException e) {
  834. // Ignore
  835. }
  836. }
  837. if (connection != null) {
  838. try {
  839. connection.close();
  840. }
  841. catch (SQLException e) {
  842. // Ignore
  843. }
  844. }
  845. }
  846. }
  847. public List<String> getStoredUsers() {
  848. ArrayList<String> users = new ArrayList<String>();
  849. Statement statement = null;
  850. Connection connection = null;
  851. ResultSet resultSet = null;
  852. try {
  853. connection = connectionPool.getConnection(POOL_FETCH_TIMEOUT);
  854. statement = connection.createStatement();
  855. resultSet = statement.executeQuery("SELECT user FROM " + tablePrefix + "users");
  856. while (resultSet.next()) {
  857. users.add(resultSet.getString("user"));
  858. }
  859. }
  860. catch (SQLException e) {
  861. printErrors(e);
  862. }
  863. finally {
  864. if (resultSet != null) {
  865. try {
  866. resultSet.close();
  867. }
  868. catch (SQLException e) {
  869. // Ignore
  870. }
  871. }
  872. if (statement != null) {
  873. try {
  874. statement.close();
  875. }
  876. catch (SQLException e) {
  877. // Ignore
  878. }
  879. }
  880. if (connection != null) {
  881. try {
  882. connection.close();
  883. }
  884. catch (SQLException e) {
  885. // Ignore
  886. }
  887. }
  888. }
  889. return users;
  890. }
  891. /**
  892. * Checks that the database structure is present and correct
  893. */
  894. private void checkStructure() {
  895. Statement statement = null;
  896. Connection connection = null;
  897. try {
  898. connection = connectionPool.getConnection(POOL_FETCH_TIMEOUT);
  899. statement = connection.createStatement();
  900. statement.executeUpdate("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "users` ("
  901. + "`id` int(10) unsigned NOT NULL AUTO_INCREMENT,"
  902. + "`user` varchar(40) NOT NULL,"
  903. + "`uuid` varchar(36) NULL DEFAULT NULL,"
  904. + "`lastlogin` int(32) unsigned NOT NULL,"
  905. + "PRIMARY KEY (`id`),"
  906. + "UNIQUE KEY `user` (`user`),"
  907. + "UNIQUE KEY `uuid` (`uuid`)) DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;");
  908. statement.executeUpdate("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "huds` ("
  909. + "`user_id` int(10) unsigned NOT NULL,"
  910. + "`mobhealthbar` varchar(50) NOT NULL DEFAULT '" + Config.getInstance().getMobHealthbarDefault() + "',"
  911. + "PRIMARY KEY (`user_id`)) "
  912. + "DEFAULT CHARSET=latin1;");
  913. statement.executeUpdate("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "cooldowns` ("
  914. + "`user_id` int(10) unsigned NOT NULL,"
  915. + "`taming` int(32) unsigned NOT NULL DEFAULT '0',"
  916. + "`mining` int(32) unsigned NOT NULL DEFAULT '0',"
  917. + "`woodcutting` int(32) unsigned NOT NULL DEFAULT '0',"
  918. + "`repair` int(32) unsigned NOT NULL DEFAULT '0',"
  919. + "`unarmed` int(32) unsigned NOT NULL DEFAULT '0',"
  920. + "`herbalism` int(32) unsigned NOT NULL DEFAULT '0',"
  921. + "`excavation` int(32) unsigned NOT NULL DEFAULT '0',"
  922. + "`archery` int(32) unsigned NOT NULL DEFAULT '0',"
  923. + "`swords` int(32) unsigned NOT NULL DEFAULT '0',"
  924. + "`axes` int(32) unsigned NOT NULL DEFAULT '0',"
  925. + "`acrobatics` int(32) unsigned NOT NULL DEFAULT '0',"
  926. + "`blast_mining` int(32) unsigned NOT NULL DEFAULT '0',"
  927. + "PRIMARY KEY (`user_id`)) "
  928. + "DEFAULT CHARSET=latin1;");
  929. statement.executeUpdate("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "skills` ("
  930. + "`user_id` int(10) unsigned NOT NULL,"
  931. + "`taming` int(10) unsigned NOT NULL DEFAULT '0',"
  932. + "`mining` int(10) unsigned NOT NULL DEFAULT '0',"
  933. + "`woodcutting` int(10) unsigned NOT NULL DEFAULT '0',"
  934. + "`repair` int(10) unsigned NOT NULL DEFAULT '0',"
  935. + "`unarmed` int(10) unsigned NOT NULL DEFAULT '0',"
  936. + "`herbalism` int(10) unsigned NOT NULL DEFAULT '0',"
  937. + "`excavation` int(10) unsigned NOT NULL DEFAULT '0',"
  938. + "`archery` int(10) unsigned NOT NULL DEFAULT '0',"
  939. + "`swords` int(10) unsigned NOT NULL DEFAULT '0',"
  940. + "`axes` int(10) unsigned NOT NULL DEFAULT '0',"
  941. + "`acrobatics` int(10) unsigned NOT NULL DEFAULT '0',"
  942. + "`fishing` int(10) unsigned NOT NULL DEFAULT '0',"
  943. + "`alchemy` int(10) unsigned NOT NULL DEFAULT '0',"
  944. + "PRIMARY KEY (`user_id`)) "
  945. + "DEFAULT CHARSET=latin1;");
  946. statement.executeUpdate("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "experience` ("
  947. + "`user_id` int(10) unsigned NOT NULL,"
  948. + "`taming` int(10) unsigned NOT NULL DEFAULT '0',"
  949. + "`mining` int(10) unsigned NOT NULL DEFAULT '0',"
  950. + "`woodcutting` int(10) unsigned NOT NULL DEFAULT '0',"
  951. + "`repair` int(10) unsigned NOT NULL DEFAULT '0',"
  952. + "`unarmed` int(10) unsigned NOT NULL DEFAULT '0',"
  953. + "`herbalism` int(10) unsigned NOT NULL DEFAULT '0',"
  954. + "`excavation` int(10) unsigned NOT NULL DEFAULT '0',"
  955. + "`archery` int(10) unsigned NOT NULL DEFAULT '0',"
  956. + "`swords` int(10) unsigned NOT NULL DEFAULT '0',"
  957. + "`axes` int(10) unsigned NOT NULL DEFAULT '0',"
  958. + "`acrobatics` int(10) unsigned NOT NULL DEFAULT '0',"
  959. + "`fishing` int(10) unsigned NOT NULL DEFAULT '0',"
  960. + "`alchemy` int(10) unsigned NOT NULL DEFAULT '0',"
  961. + "PRIMARY KEY (`user_id`)) "
  962. + "DEFAULT CHARSET=latin1;");
  963. for (UpgradeType updateType : UpgradeType.values()) {
  964. checkDatabaseStructure(connection, updateType);
  965. }
  966. mcMMO.p.getLogger().info("Killing orphans");
  967. statement.executeUpdate("DELETE FROM `" + tablePrefix + "experience` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "users` `u` WHERE `" + tablePrefix + "experience`.`user_id` = `u`.`id`)");
  968. statement.executeUpdate("DELETE FROM `" + tablePrefix + "huds` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "users` `u` WHERE `" + tablePrefix + "huds`.`user_id` = `u`.`id`)");
  969. statement.executeUpdate("DELETE FROM `" + tablePrefix + "cooldowns` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "users` `u` WHERE `" + tablePrefix + "cooldowns`.`user_id` = `u`.`id`)");
  970. statement.executeUpdate("DELETE FROM `" + tablePrefix + "skills` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "users` `u` WHERE `" + tablePrefix + "skills`.`user_id` = `u`.`id`)");
  971. }
  972. catch (SQLException ex) {
  973. printErrors(ex);
  974. }
  975. finally {
  976. if (statement != null) {
  977. try {
  978. statement.close();
  979. }
  980. catch (SQLException e) {
  981. // Ignore
  982. }
  983. }
  984. if (connection != null) {
  985. try {
  986. connection.close();
  987. }
  988. catch (SQLException e) {
  989. // Ignore
  990. }
  991. }
  992. }
  993. }
  994. /**
  995. * Check database structure for necessary upgrades.
  996. *
  997. * @param upgrade Upgrade to attempt to apply
  998. */
  999. private void checkDatabaseStructure(Connection connection, UpgradeType upgrade) {
  1000. if (!mcMMO.getUpgradeManager().shouldUpgrade(upgrade)) {
  1001. mcMMO.p.debug("Skipping " + upgrade.name() + " upgrade (unneeded)");
  1002. return;
  1003. }
  1004. Statement statement = null;
  1005. try {
  1006. statement = connection.createStatement();
  1007. switch (upgrade) {
  1008. case ADD_FISHING:
  1009. checkUpgradeAddFishing(statement);
  1010. break;
  1011. case ADD_BLAST_MINING_COOLDOWN:
  1012. checkUpgradeAddBlastMiningCooldown(statement);
  1013. break;
  1014. case ADD_SQL_INDEXES:
  1015. checkUpgradeAddSQLIndexes(statement);
  1016. break;
  1017. case ADD_MOB_HEALTHBARS:
  1018. checkUpgradeAddMobHealthbars(statement);
  1019. break;
  1020. case DROP_SQL_PARTY_NAMES:
  1021. checkUpgradeDropPartyNames(statement);
  1022. break;
  1023. case DROP_SPOUT:
  1024. checkUpgradeDropSpout(statement);
  1025. break;
  1026. case ADD_ALCHEMY:
  1027. checkUpgradeAddAlchemy(statement);
  1028. break;
  1029. case ADD_UUIDS:
  1030. checkUpgradeAddUUIDs(statement);
  1031. return;
  1032. default:
  1033. break;
  1034. }
  1035. mcMMO.getUpgradeManager().setUpgradeCompleted(upgrade);
  1036. }
  1037. catch (SQLException ex) {
  1038. printErrors(ex);
  1039. }
  1040. finally {
  1041. if (statement != null) {
  1042. try {
  1043. statement.close();
  1044. }
  1045. catch (SQLException e) {
  1046. // Ignore
  1047. }
  1048. }
  1049. }
  1050. }
  1051. private void writeMissingRows(Connection connection, int id) {
  1052. PreparedStatement statement = null;
  1053. try {
  1054. statement = connection.prepareStatement("INSERT IGNORE INTO " + tablePrefix + "experience (user_id) VALUES (?)");
  1055. statement.setInt(1, id);
  1056. statement.execute();
  1057. statement.close();
  1058. statement = connection.prepareStatement("INSERT IGNORE INTO " + tablePrefix + "skills (user_id) VALUES (?)");
  1059. statement.setInt(1, id);
  1060. statement.execute();
  1061. statement.close();
  1062. statement = connection.prepareStatement("INSERT IGNORE INTO " + tablePrefix + "cooldowns (user_id) VALUES (?)");
  1063. statement.setInt(1, id);
  1064. statement.execute();
  1065. statement.close();
  1066. statement = connection.prepareStatement("INSERT IGNORE INTO " + tablePrefix + "huds (user_id, mobhealthbar) VALUES (?, ?)");
  1067. statement.setInt(1, id);
  1068. statement.setString(2, Config.getInstance().getMobHealthbarDefault().name());
  1069. statement.execute();
  1070. statement.close();
  1071. }
  1072. catch (SQLException ex) {
  1073. printErrors(ex);
  1074. }
  1075. finally {
  1076. if (statement != null) {
  1077. try {
  1078. statement.close();
  1079. }
  1080. catch (SQLException e) {
  1081. // Ignore
  1082. }
  1083. }
  1084. }
  1085. }
  1086. private void processPurge(Collection<String> usernames) {
  1087. for (String user : usernames) {
  1088. Misc.profileCleanup(user);
  1089. }
  1090. }
  1091. private PlayerProfile loadFromResult(String playerName, ResultSet result) throws SQLException {
  1092. Map<SkillType, Integer> skills = new HashMap<SkillType, Integer>(); // Skill & Level
  1093. Map<SkillType, Float> skillsXp = new HashMap<SkillType, Float>(); // Skill & XP
  1094. Map<AbilityType, Integer> skillsDATS = new HashMap<AbilityType, Integer>(); // Ability & Cooldown
  1095. MobHealthbarType mobHealthbarType;
  1096. UUID uuid;
  1097. final int OFFSET_SKILLS = 0; // TODO update these numbers when the query
  1098. // changes (a new skill is added)
  1099. final int OFFSET_XP = 13;
  1100. final int OFFSET_DATS = 26;
  1101. final int OFFSET_OTHER = 38;
  1102. skills.put(SkillType.TAMING, result.getInt(OFFSET_SKILLS + 1));
  1103. skills.put(SkillType.MINING, result.getInt(OFFSET_SKILLS + 2));
  1104. skills.put(SkillType.REPAIR, result.getInt(OFFSET_SKILLS + 3));
  1105. skills.put(SkillType.WOODCUTTING, result.getInt(OFFSET_SKILLS + 4));
  1106. skills.put(SkillType.UNARMED, result.getInt(OFFSET_SKILLS + 5));
  1107. skills.put(SkillType.HERBALISM, result.getInt(OFFSET_SKILLS + 6));
  1108. skills.put(SkillType.EXCAVATION, result.getInt(OFFSET_SKILLS + 7));
  1109. skills.put(SkillType.ARCHERY, result.getInt(OFFSET_SKILLS + 8));
  1110. skills.put(SkillType.SWORDS, result.getInt(OFFSET_SKILLS + 9));
  1111. skills.put(SkillType.AXES, result.getInt(OFFSET_SKILLS + 10));
  1112. skills.put(SkillType.ACROBATICS, result.getInt(OFFSET_SKILLS + 11));
  1113. skills.put(SkillType.FISHING, result.getInt(OFFSET_SKILLS + 12));
  1114. skills.put(SkillType.ALCHEMY, result.getInt(OFFSET_SKILLS + 13));
  1115. skillsXp.put(SkillType.TAMING, result.getFloat(OFFSET_XP + 1));
  1116. skillsXp.put(SkillType.MINING, result.getFloat(OFFSET_XP + 2));
  1117. skillsXp.put(SkillType.REPAIR, result.getFloat(OFFSET_XP + 3));
  1118. skillsXp.put(SkillType.WOODCUTTING, result.getFloat(OFFSET_XP + 4));
  1119. skillsXp.put(SkillType.UNARMED, result.getFloat(OFFSET_XP + 5));
  1120. skillsXp.put(SkillType.HERBALISM, result.getFloat(OFFSET_XP + 6));
  1121. skillsXp.put(SkillType.EXCAVATION, result.getFloat(OFFSET_XP + 7));
  1122. skillsXp.put(SkillType.ARCHERY, result.getFloat(OFFSET_XP + 8));
  1123. skillsXp.put(SkillType.SWORDS, result.getFloat(OFFSET_XP + 9));
  1124. skillsXp.put(SkillType.AXES, result.getFloat(OFFSET_XP + 10));
  1125. skillsXp.put(SkillType.ACROBATICS, result.getFloat(OFFSET_XP + 11));
  1126. skillsXp.put(SkillType.FISHING, result.getFloat(OFFSET_XP + 12));
  1127. skillsXp.put(SkillType.ALCHEMY, result.getFloat(OFFSET_XP + 13));
  1128. // Taming - Unused - result.getInt(OFFSET_DATS + 1)
  1129. skillsDATS.put(AbilityType.SUPER_BREAKER, result.getInt(OFFSET_DATS + 2));
  1130. // Repair - Unused - result.getInt(OFFSET_DATS + 3)
  1131. skillsDATS.put(AbilityType.TREE_FELLER, result.getInt(OFFSET_DATS + 4));
  1132. skillsDATS.put(AbilityType.BERSERK, result.getInt(OFFSET_DATS + 5));
  1133. skillsDATS.put(AbilityType.GREEN_TERRA, result.getInt(OFFSET_DATS + 6));
  1134. skillsDATS.put(AbilityType.GIGA_DRILL_BREAKER, result.getInt(OFFSET_DATS + 7));
  1135. // Archery - Unused - result.getInt(OFFSET_DATS + 8)
  1136. skillsDATS.put(AbilityType.SERRATED_STRIKES, result.getInt(OFFSET_DATS + 9));
  1137. skillsDATS.put(AbilityType.SKULL_SPLITTER, result.getInt(OFFSET_DATS + 10));
  1138. // Acrobatics - Unused - result.getInt(OFFSET_DATS + 11)
  1139. skillsDATS.put(AbilityType.BLAST_MINING, result.getInt(OFFSET_DATS + 12));
  1140. try {
  1141. mobHealthbarType = MobHealthbarType.valueOf(result.getString(OFFSET_OTHER + 2));
  1142. }
  1143. catch (Exception e) {
  1144. mobHealthbarType = Config.getInstance().getMobHealthbarDefault();
  1145. }
  1146. try {
  1147. uuid = UUID.fromString(result.getString(OFFSET_OTHER + 3));
  1148. }
  1149. catch (Exception e) {
  1150. uuid = null;
  1151. }
  1152. return new PlayerProfile(playerName, uuid, skills, skillsXp, skillsDATS, mobHealthbarType);
  1153. }
  1154. private void printErrors(SQLException ex) {
  1155. mcMMO.p.getLogger().severe("SQLException: " + ex.getMessage());
  1156. mcMMO.p.getLogger().severe("SQLState: " + ex.getSQLState());
  1157. mcMMO.p.getLogger().severe("VendorError: " + ex.getErrorCode());
  1158. }
  1159. public DatabaseType getDatabaseType() {
  1160. return DatabaseType.SQL;
  1161. }
  1162. private void checkUpgradeAddAlchemy(final Statement statement) throws SQLException {
  1163. try {
  1164. statement.executeQuery("SELECT `alchemy` FROM `" + tablePrefix + "skills` LIMIT 1");
  1165. }
  1166. catch (SQLException ex) {
  1167. mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Alchemy...");
  1168. statement.executeUpdate("ALTER TABLE `" + tablePrefix + "skills` ADD `alchemy` int(10) NOT NULL DEFAULT '0'");
  1169. statement.executeUpdate("ALTER TABLE `" + tablePrefix + "experience` ADD `alchemy` int(10) NOT NULL DEFAULT '0'");
  1170. }
  1171. }
  1172. private void checkUpgradeAddBlastMiningCooldown(final Statement statement) throws SQLException {
  1173. try {
  1174. statement.executeQuery("SELECT `blast_mining` FROM `" + tablePrefix + "cooldowns` LIMIT 1");
  1175. }
  1176. catch (SQLException ex) {
  1177. mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Blast Mining...");
  1178. statement.executeUpdate("ALTER TABLE `" + tablePrefix + "cooldowns` ADD `blast_mining` int(32) NOT NULL DEFAULT '0'");
  1179. }
  1180. }
  1181. private void checkUpgradeAddFishing(final Statement statement) throws SQLException {
  1182. try {
  1183. statement.executeQuery("SELECT `fishing` FROM `" + tablePrefix + "skills` LIMIT 1");
  1184. }
  1185. catch (SQLException ex) {
  1186. mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Fishing...");
  1187. statement.executeUpdate("ALTER TABLE `" + tablePrefix + "skills` ADD `fishing` int(10) NOT NULL DEFAULT '0'");
  1188. statement.executeUpdate("ALTER TABLE `" + tablePrefix + "experience` ADD `fishing` int(10) NOT NULL DEFAULT '0'");
  1189. }
  1190. }
  1191. private void checkUpgradeAddMobHealthbars(final Statement statement) throws SQLException {
  1192. try {
  1193. statement.executeQuery("SELECT `mobhealthbar` FROM `" + tablePrefix + "huds` LIMIT 1");
  1194. }
  1195. catch (SQLException ex) {
  1196. mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for mob healthbars...");
  1197. statement.executeUpdate("ALTER TABLE `" + tablePrefix + "huds` ADD `mobhealthbar` varchar(50) NOT NULL DEFAULT '" + Config.getInstance().getMobHealthbarDefault() + "'");
  1198. }
  1199. }
  1200. private void checkUpgradeAddSQLIndexes(final Statement statement) throws SQLException {
  1201. ResultSet resultSet = null;
  1202. try {
  1203. resultSet = statement.executeQuery("SHOW INDEX FROM `" + tablePrefix + "skills` WHERE `Key_name` LIKE 'idx\\_%'");
  1204. resultSet.last();
  1205. if (resultSet.getRow() != SkillType.NON_CHILD_SKILLS.size()) {
  1206. mcMMO.p.getLogger().info("Indexing tables, this may take a while on larger databases");
  1207. for (SkillType skill : SkillType.NON_CHILD_SKILLS) {
  1208. String skill_name = skill.name().toLowerCase();
  1209. try {
  1210. statement.executeUpdate("ALTER TABLE `" + tablePrefix + "skills` ADD INDEX `idx_" + skill_name + "` (`" + skill_name + "`) USING BTREE");
  1211. }
  1212. catch (SQLException ex) {
  1213. // Ignore
  1214. }
  1215. }
  1216. }
  1217. }
  1218. catch (SQLException ex) {
  1219. printErrors(ex);
  1220. }
  1221. finally {
  1222. if (resultSet != null) {
  1223. try {
  1224. resultSet.close();
  1225. }
  1226. catch (SQLException e) {
  1227. // Ignore
  1228. }
  1229. }
  1230. }
  1231. }
  1232. private void checkUpgradeAddUUIDs(final Statement statement) {
  1233. List<String> names = new ArrayList<String>();
  1234. ResultSet resultSet = null;
  1235. try {
  1236. resultSet = statement.executeQuery("SELECT * FROM `" + tablePrefix + "users` LIMIT 1");
  1237. ResultSetMetaData rsmeta = resultSet.getMetaData();
  1238. boolean column_exists = false;
  1239. for (int i = 1; i <= rsmeta.getColumnCount(); i++) {
  1240. if (rsmeta.getColumnName(i).equalsIgnoreCase("uuid")) {
  1241. column_exists = true;
  1242. break;
  1243. }
  1244. }
  1245. if (!column_exists) {
  1246. mcMMO.p.getLogger().info("Adding UUIDs to mcMMO MySQL user table...");
  1247. statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` ADD `uuid` varchar(36) NULL DEFAULT NULL");
  1248. statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` ADD UNIQUE INDEX `uuid` (`uuid`) USING BTREE");
  1249. }
  1250. }
  1251. catch (SQLException ex) {
  1252. printErrors(ex);
  1253. }
  1254. finally {
  1255. if (resultSet != null) {
  1256. try {
  1257. resultSet.close();
  1258. }
  1259. catch (SQLException e) {
  1260. // Ignore
  1261. }
  1262. }
  1263. }
  1264. try {
  1265. resultSet = statement.executeQuery("SELECT `user` FROM `" + tablePrefix + "users` WHERE `uuid` IS NULL");
  1266. while (resultSet.next()) {
  1267. names.add(resultSet.getString("user"));
  1268. }
  1269. }
  1270. catch (SQLException ex) {
  1271. printErrors(ex);
  1272. }
  1273. finally {
  1274. if (resultSet != null) {
  1275. try {
  1276. resultSet.close();
  1277. }
  1278. catch (SQLException e) {
  1279. // Ignore
  1280. }
  1281. }
  1282. }
  1283. if (!names.isEmpty()) {
  1284. new UUIDUpdateAsyncTask(mcMMO.p, names).runTaskAsynchronously(mcMMO.p);
  1285. }
  1286. }
  1287. private void checkUpgradeDropPartyNames(final Statement statement) {
  1288. ResultSet resultSet = null;
  1289. try {
  1290. resultSet = statement.executeQuery("SELECT * FROM `" + tablePrefix + "users` LIMIT 1");
  1291. ResultSetMetaData rsmeta = resultSet.getMetaData();
  1292. boolean column_exists = false;
  1293. for (int i = 1; i <= rsmeta.getColumnCount(); i++) {
  1294. if (rsmeta.getColumnName(i).equalsIgnoreCase("party")) {
  1295. column_exists = true;
  1296. break;
  1297. }
  1298. }
  1299. if (column_exists) {
  1300. mcMMO.p.getLogger().info("Removing party name from users table...");
  1301. statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` DROP COLUMN `party`");
  1302. }
  1303. }
  1304. catch (SQLException ex) {
  1305. printErrors(ex);
  1306. }
  1307. finally {
  1308. if (resultSet != null) {
  1309. try {
  1310. resultSet.close();
  1311. }
  1312. catch (SQLException e) {
  1313. // Ignore
  1314. }
  1315. }
  1316. }
  1317. }
  1318. private void checkUpgradeDropSpout(final Statement statement) {
  1319. ResultSet resultSet = null;
  1320. try {
  1321. resultSet = statement.executeQuery("SELECT * FROM `" + tablePrefix + "huds` LIMIT 1");
  1322. ResultSetMetaData rsmeta = resultSet.getMetaData();
  1323. boolean column_exists = false;
  1324. for (int i = 1; i <= rsmeta.getColumnCount(); i++) {
  1325. if (rsmeta.getColumnName(i).equalsIgnoreCase("hudtype")) {
  1326. column_exists = true;
  1327. break;
  1328. }
  1329. }
  1330. if (column_exists) {
  1331. mcMMO.p.getLogger().info("Removing Spout HUD type from huds table...");
  1332. statement.executeUpdate("ALTER TABLE `" + tablePrefix + "huds` DROP COLUMN `hudtype`");
  1333. }
  1334. }
  1335. catch (SQLException ex) {
  1336. printErrors(ex);
  1337. }
  1338. finally {
  1339. if (resultSet != null) {
  1340. try {
  1341. resultSet.close();
  1342. }
  1343. catch (SQLException e) {
  1344. // Ignore
  1345. }
  1346. }
  1347. }
  1348. }
  1349. private int getUserID(final Connection connection, final String playerName) {
  1350. Integer id = cachedUserIDsByName.get(playerName.toLowerCase());
  1351. if (id != null) {
  1352. return id;
  1353. }
  1354. ResultSet resultSet = null;
  1355. PreparedStatement statement = null;
  1356. try {
  1357. statement = connection.prepareStatement("SELECT id, uuid FROM " + tablePrefix + "users WHERE user = ?");
  1358. statement.setString(1, playerName);
  1359. resultSet = statement.executeQuery();
  1360. if (resultSet.next()) {
  1361. id = resultSet.getInt("id");
  1362. cachedUserIDsByName.put(playerName.toLowerCase(), id);
  1363. try {
  1364. cachedUserIDs.put(UUID.fromString(resultSet.getString("uuid")), id);
  1365. }
  1366. catch (Exception e) {
  1367. }
  1368. return id;
  1369. }
  1370. }
  1371. catch (SQLException ex) {
  1372. printErrors(ex);
  1373. }
  1374. finally {
  1375. if (resultSet != null) {
  1376. try {
  1377. resultSet.close();
  1378. }
  1379. catch (SQLException e) {
  1380. // Ignore
  1381. }
  1382. }
  1383. if (statement != null) {
  1384. try {
  1385. statement.close();
  1386. }
  1387. catch (SQLException e) {
  1388. // Ignore
  1389. }
  1390. }
  1391. }
  1392. return -1;
  1393. }
  1394. private int getUserID(final Connection connection, final UUID uuid) {
  1395. if (cachedUserIDs.containsKey(uuid)) {
  1396. return cachedUserIDs.get(uuid);
  1397. }
  1398. ResultSet resultSet = null;
  1399. PreparedStatement statement = null;
  1400. try {
  1401. statement = connection.prepareStatement("SELECT id, user FROM " + tablePrefix + "users WHERE uuid = ?");
  1402. statement.setString(1, uuid.toString());
  1403. resultSet = statement.executeQuery();
  1404. if (resultSet.next()) {
  1405. int id = resultSet.getInt("id");
  1406. cachedUserIDs.put(uuid, id);
  1407. cachedUserIDsByName.put(resultSet.getString("user").toLowerCase(), id);
  1408. return id;
  1409. }
  1410. }
  1411. catch (SQLException ex) {
  1412. printErrors(ex);
  1413. }
  1414. finally {
  1415. if (resultSet != null) {
  1416. try {
  1417. resultSet.close();
  1418. }
  1419. catch (SQLException e) {
  1420. // Ignore
  1421. }
  1422. }
  1423. if (statement != null) {
  1424. try {
  1425. statement.close();
  1426. }
  1427. catch (SQLException e) {
  1428. // Ignore
  1429. }
  1430. }
  1431. }
  1432. return -1;
  1433. }
  1434. @Override
  1435. public void onDisable() {
  1436. connectionPool.release();
  1437. }
  1438. }