FlatfileDatabaseManager.java 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559
  1. package com.gmail.nossr50.database;
  2. import com.gmail.nossr50.config.AdvancedConfig;
  3. import com.gmail.nossr50.config.Config;
  4. import com.gmail.nossr50.datatypes.MobHealthbarType;
  5. import com.gmail.nossr50.datatypes.database.DatabaseType;
  6. import com.gmail.nossr50.datatypes.database.PlayerStat;
  7. import com.gmail.nossr50.datatypes.database.UpgradeType;
  8. import com.gmail.nossr50.datatypes.player.PlayerProfile;
  9. import com.gmail.nossr50.datatypes.player.UniqueDataType;
  10. import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
  11. import com.gmail.nossr50.datatypes.skills.SuperAbilityType;
  12. import com.gmail.nossr50.mcMMO;
  13. import com.gmail.nossr50.runnables.database.UUIDUpdateAsyncTask;
  14. import com.gmail.nossr50.util.Misc;
  15. import com.gmail.nossr50.util.StringUtils;
  16. import com.gmail.nossr50.util.experience.ExperienceBarManager;
  17. import com.gmail.nossr50.util.skills.SkillUtils;
  18. import org.bukkit.OfflinePlayer;
  19. import java.io.*;
  20. import java.util.*;
  21. public final class FlatfileDatabaseManager implements DatabaseManager {
  22. private final HashMap<PrimarySkillType, List<PlayerStat>> playerStatHash = new HashMap<>();
  23. private final List<PlayerStat> powerLevels = new ArrayList<>();
  24. private long lastUpdate = 0;
  25. private final long UPDATE_WAIT_TIME = 600000L; // 10 minutes
  26. private final File usersFile;
  27. private static final Object fileWritingLock = new Object();
  28. protected FlatfileDatabaseManager() {
  29. usersFile = new File(mcMMO.getUsersFilePath());
  30. checkStructure();
  31. updateLeaderboards();
  32. if (mcMMO.getUpgradeManager().shouldUpgrade(UpgradeType.ADD_UUIDS)) {
  33. new UUIDUpdateAsyncTask(mcMMO.p, getStoredUsers()).start();
  34. }
  35. }
  36. public void purgePowerlessUsers() {
  37. int purgedUsers = 0;
  38. mcMMO.p.getLogger().info("Purging powerless users...");
  39. BufferedReader in = null;
  40. FileWriter out = null;
  41. String usersFilePath = mcMMO.getUsersFilePath();
  42. // This code is O(n) instead of O(n²)
  43. synchronized (fileWritingLock) {
  44. try {
  45. in = new BufferedReader(new FileReader(usersFilePath));
  46. StringBuilder writer = new StringBuilder();
  47. String line;
  48. while ((line = in.readLine()) != null) {
  49. String[] character = line.split(":");
  50. Map<PrimarySkillType, Integer> skills = getSkillMapFromLine(character);
  51. boolean powerless = true;
  52. for (int skill : skills.values()) {
  53. if (skill != 0) {
  54. powerless = false;
  55. break;
  56. }
  57. }
  58. // If they're still around, rewrite them to the file.
  59. if (!powerless) {
  60. writer.append(line).append("\r\n");
  61. }
  62. else {
  63. purgedUsers++;
  64. }
  65. }
  66. // Write the new file
  67. out = new FileWriter(usersFilePath);
  68. out.write(writer.toString());
  69. }
  70. catch (IOException e) {
  71. mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString());
  72. }
  73. finally {
  74. if (in != null) {
  75. try {
  76. in.close();
  77. }
  78. catch (IOException e) {
  79. // Ignore
  80. }
  81. }
  82. if (out != null) {
  83. try {
  84. out.close();
  85. }
  86. catch (IOException e) {
  87. // Ignore
  88. }
  89. }
  90. }
  91. }
  92. mcMMO.p.getLogger().info("Purged " + purgedUsers + " users from the database.");
  93. }
  94. public void purgeOldUsers() {
  95. int removedPlayers = 0;
  96. long currentTime = System.currentTimeMillis();
  97. mcMMO.p.getLogger().info("Purging old users...");
  98. BufferedReader in = null;
  99. FileWriter out = null;
  100. String usersFilePath = mcMMO.getUsersFilePath();
  101. // This code is O(n) instead of O(n²)
  102. synchronized (fileWritingLock) {
  103. try {
  104. in = new BufferedReader(new FileReader(usersFilePath));
  105. StringBuilder writer = new StringBuilder();
  106. String line;
  107. while ((line = in.readLine()) != null) {
  108. String[] character = line.split(":");
  109. String name = character[USERNAME];
  110. long lastPlayed = 0;
  111. boolean rewrite = false;
  112. try {
  113. lastPlayed = Long.parseLong(character[37]) * Misc.TIME_CONVERSION_FACTOR;
  114. }
  115. catch (NumberFormatException e) {
  116. e.printStackTrace();
  117. }
  118. if (lastPlayed == 0) {
  119. OfflinePlayer player = mcMMO.p.getServer().getOfflinePlayer(name);
  120. lastPlayed = player.getLastPlayed();
  121. rewrite = true;
  122. }
  123. if (currentTime - lastPlayed > PURGE_TIME) {
  124. removedPlayers++;
  125. }
  126. else {
  127. if (rewrite) {
  128. // Rewrite their data with a valid time
  129. character[37] = Long.toString(lastPlayed);
  130. String newLine = org.apache.commons.lang.StringUtils.join(character, ":");
  131. writer.append(newLine).append("\r\n");
  132. }
  133. else {
  134. writer.append(line).append("\r\n");
  135. }
  136. }
  137. }
  138. // Write the new file
  139. out = new FileWriter(usersFilePath);
  140. out.write(writer.toString());
  141. }
  142. catch (IOException e) {
  143. mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString());
  144. }
  145. finally {
  146. if (in != null) {
  147. try {
  148. in.close();
  149. }
  150. catch (IOException e) {
  151. // Ignore
  152. }
  153. }
  154. if (out != null) {
  155. try {
  156. out.close();
  157. }
  158. catch (IOException e) {
  159. // Ignore
  160. }
  161. }
  162. }
  163. }
  164. mcMMO.p.getLogger().info("Purged " + removedPlayers + " users from the database.");
  165. }
  166. public boolean removeUser(String playerName, UUID uuid) {
  167. //NOTE: UUID is unused for FlatFile for this interface implementation
  168. boolean worked = false;
  169. BufferedReader in = null;
  170. FileWriter out = null;
  171. String usersFilePath = mcMMO.getUsersFilePath();
  172. synchronized (fileWritingLock) {
  173. try {
  174. in = new BufferedReader(new FileReader(usersFilePath));
  175. StringBuilder writer = new StringBuilder();
  176. String line;
  177. while ((line = in.readLine()) != null) {
  178. // Write out the same file but when we get to the player we want to remove, we skip his line.
  179. if (!worked && line.split(":")[USERNAME].equalsIgnoreCase(playerName)) {
  180. mcMMO.p.getLogger().info("User found, removing...");
  181. worked = true;
  182. continue; // Skip the player
  183. }
  184. writer.append(line).append("\r\n");
  185. }
  186. out = new FileWriter(usersFilePath); // Write out the new file
  187. out.write(writer.toString());
  188. }
  189. catch (Exception e) {
  190. mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString());
  191. }
  192. finally {
  193. if (in != null) {
  194. try {
  195. in.close();
  196. }
  197. catch (IOException e) {
  198. // Ignore
  199. }
  200. }
  201. if (out != null) {
  202. try {
  203. out.close();
  204. }
  205. catch (IOException e) {
  206. // Ignore
  207. }
  208. }
  209. }
  210. }
  211. Misc.profileCleanup(playerName);
  212. return worked;
  213. }
  214. @Override
  215. public void cleanupUser(UUID uuid) {
  216. //Not used in FlatFile
  217. }
  218. public boolean saveUser(PlayerProfile profile) {
  219. String playerName = profile.getPlayerName();
  220. UUID uuid = profile.getUniqueId();
  221. BufferedReader in = null;
  222. FileWriter out = null;
  223. String usersFilePath = mcMMO.getUsersFilePath();
  224. synchronized (fileWritingLock) {
  225. try {
  226. // Open the file
  227. in = new BufferedReader(new FileReader(usersFilePath));
  228. StringBuilder writer = new StringBuilder();
  229. String line;
  230. boolean wroteUser = false;
  231. // While not at the end of the file
  232. while ((line = in.readLine()) != null) {
  233. // Read the line in and copy it to the output if it's not the player we want to edit
  234. String[] character = line.split(":");
  235. if (!(uuid != null && character[UUID_INDEX].equalsIgnoreCase(uuid.toString())) && !character[USERNAME].equalsIgnoreCase(playerName)) {
  236. writer.append(line).append("\r\n");
  237. }
  238. else {
  239. // Otherwise write the new player information
  240. writeUserToLine(profile, playerName, uuid, writer);
  241. wroteUser = true;
  242. }
  243. }
  244. /*
  245. * If we couldn't find the user in the DB we need to add him
  246. */
  247. if(!wroteUser)
  248. {
  249. writeUserToLine(profile, playerName, uuid, writer);
  250. }
  251. // Write the new file
  252. out = new FileWriter(usersFilePath);
  253. out.write(writer.toString());
  254. return true;
  255. }
  256. catch (Exception e) {
  257. e.printStackTrace();
  258. return false;
  259. }
  260. finally {
  261. if (in != null) {
  262. try {
  263. in.close();
  264. }
  265. catch (IOException e) {
  266. // Ignore
  267. }
  268. }
  269. if (out != null) {
  270. try {
  271. out.close();
  272. }
  273. catch (IOException e) {
  274. // Ignore
  275. }
  276. }
  277. }
  278. }
  279. }
  280. private void writeUserToLine(PlayerProfile profile, String playerName, UUID uuid, StringBuilder writer) {
  281. writer.append(playerName).append(":");
  282. writer.append(profile.getSkillLevel(PrimarySkillType.MINING)).append(":");
  283. writer.append(":");
  284. writer.append(":");
  285. writer.append(profile.getSkillXpLevel(PrimarySkillType.MINING)).append(":");
  286. writer.append(profile.getSkillLevel(PrimarySkillType.WOODCUTTING)).append(":");
  287. writer.append(profile.getSkillXpLevel(PrimarySkillType.WOODCUTTING)).append(":");
  288. writer.append(profile.getSkillLevel(PrimarySkillType.REPAIR)).append(":");
  289. writer.append(profile.getSkillLevel(PrimarySkillType.UNARMED)).append(":");
  290. writer.append(profile.getSkillLevel(PrimarySkillType.HERBALISM)).append(":");
  291. writer.append(profile.getSkillLevel(PrimarySkillType.EXCAVATION)).append(":");
  292. writer.append(profile.getSkillLevel(PrimarySkillType.ARCHERY)).append(":");
  293. writer.append(profile.getSkillLevel(PrimarySkillType.SWORDS)).append(":");
  294. writer.append(profile.getSkillLevel(PrimarySkillType.AXES)).append(":");
  295. writer.append(profile.getSkillLevel(PrimarySkillType.ACROBATICS)).append(":");
  296. writer.append(profile.getSkillXpLevel(PrimarySkillType.REPAIR)).append(":");
  297. writer.append(profile.getSkillXpLevel(PrimarySkillType.UNARMED)).append(":");
  298. writer.append(profile.getSkillXpLevel(PrimarySkillType.HERBALISM)).append(":");
  299. writer.append(profile.getSkillXpLevel(PrimarySkillType.EXCAVATION)).append(":");
  300. writer.append(profile.getSkillXpLevel(PrimarySkillType.ARCHERY)).append(":");
  301. writer.append(profile.getSkillXpLevel(PrimarySkillType.SWORDS)).append(":");
  302. writer.append(profile.getSkillXpLevel(PrimarySkillType.AXES)).append(":");
  303. writer.append(profile.getSkillXpLevel(PrimarySkillType.ACROBATICS)).append(":");
  304. writer.append(":");
  305. writer.append(profile.getSkillLevel(PrimarySkillType.TAMING)).append(":");
  306. writer.append(profile.getSkillXpLevel(PrimarySkillType.TAMING)).append(":");
  307. writer.append((int) profile.getAbilityDATS(SuperAbilityType.BERSERK)).append(":");
  308. writer.append((int) profile.getAbilityDATS(SuperAbilityType.GIGA_DRILL_BREAKER)).append(":");
  309. writer.append((int) profile.getAbilityDATS(SuperAbilityType.TREE_FELLER)).append(":");
  310. writer.append((int) profile.getAbilityDATS(SuperAbilityType.GREEN_TERRA)).append(":");
  311. writer.append((int) profile.getAbilityDATS(SuperAbilityType.SERRATED_STRIKES)).append(":");
  312. writer.append((int) profile.getAbilityDATS(SuperAbilityType.SKULL_SPLITTER)).append(":");
  313. writer.append((int) profile.getAbilityDATS(SuperAbilityType.SUPER_BREAKER)).append(":");
  314. writer.append(":");
  315. writer.append(profile.getSkillLevel(PrimarySkillType.FISHING)).append(":");
  316. writer.append(profile.getSkillXpLevel(PrimarySkillType.FISHING)).append(":");
  317. writer.append((int) profile.getAbilityDATS(SuperAbilityType.BLAST_MINING)).append(":");
  318. writer.append(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR).append(":");
  319. MobHealthbarType mobHealthbarType = profile.getMobHealthbarType();
  320. writer.append(mobHealthbarType == null ? Config.getInstance().getMobHealthbarDefault().toString() : mobHealthbarType.toString()).append(":");
  321. writer.append(profile.getSkillLevel(PrimarySkillType.ALCHEMY)).append(":");
  322. writer.append(profile.getSkillXpLevel(PrimarySkillType.ALCHEMY)).append(":");
  323. writer.append(uuid != null ? uuid.toString() : "NULL").append(":");
  324. writer.append(profile.getScoreboardTipsShown()).append(":");
  325. writer.append(profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS)).append(":");
  326. /*
  327. public static int SKILLS_TRIDENTS = 44;
  328. public static int EXP_TRIDENTS = 45;
  329. public static int SKILLS_CROSSBOWS = 46;
  330. public static int EXP_CROSSBOWS = 47;
  331. public static int BARSTATE_ACROBATICS = 48;
  332. public static int BARSTATE_ALCHEMY = 49;
  333. public static int BARSTATE_ARCHERY = 50;
  334. public static int BARSTATE_AXES = 51;
  335. public static int BARSTATE_EXCAVATION = 52;
  336. public static int BARSTATE_FISHING = 53;
  337. public static int BARSTATE_HERBALISM = 54;
  338. public static int BARSTATE_MINING = 55;
  339. public static int BARSTATE_REPAIR = 56;
  340. public static int BARSTATE_SALVAGE = 57;
  341. public static int BARSTATE_SMELTING = 58;
  342. public static int BARSTATE_SWORDS = 59;
  343. public static int BARSTATE_TAMING = 60;
  344. public static int BARSTATE_UNARMED = 61;
  345. public static int BARSTATE_WOODCUTTING = 62;
  346. public static int BARSTATE_TRIDENTS = 63;
  347. public static int BARSTATE_CROSSBOWS = 64;
  348. */
  349. writer.append(profile.getSkillLevel(PrimarySkillType.TRIDENTS)).append(":");
  350. writer.append(profile.getSkillXpLevel(PrimarySkillType.TRIDENTS)).append(":");
  351. writer.append(profile.getSkillLevel(PrimarySkillType.CROSSBOWS)).append(":");
  352. writer.append(profile.getSkillXpLevel(PrimarySkillType.CROSSBOWS)).append(":");
  353. //XPBar States
  354. writer.append(profile.getXpBarStateMap().get(PrimarySkillType.ACROBATICS).toString()).append(":");
  355. writer.append(profile.getXpBarStateMap().get(PrimarySkillType.ALCHEMY).toString()).append(":");
  356. writer.append(profile.getXpBarStateMap().get(PrimarySkillType.ARCHERY).toString()).append(":");
  357. writer.append(profile.getXpBarStateMap().get(PrimarySkillType.AXES).toString()).append(":");
  358. writer.append(profile.getXpBarStateMap().get(PrimarySkillType.EXCAVATION).toString()).append(":");
  359. writer.append(profile.getXpBarStateMap().get(PrimarySkillType.FISHING).toString()).append(":");
  360. writer.append(profile.getXpBarStateMap().get(PrimarySkillType.HERBALISM).toString()).append(":");
  361. writer.append(profile.getXpBarStateMap().get(PrimarySkillType.MINING).toString()).append(":");
  362. writer.append(profile.getXpBarStateMap().get(PrimarySkillType.REPAIR).toString()).append(":");
  363. writer.append(profile.getXpBarStateMap().get(PrimarySkillType.SALVAGE).toString()).append(":");
  364. writer.append(profile.getXpBarStateMap().get(PrimarySkillType.SMELTING).toString()).append(":");
  365. writer.append(profile.getXpBarStateMap().get(PrimarySkillType.SWORDS).toString()).append(":");
  366. writer.append(profile.getXpBarStateMap().get(PrimarySkillType.TAMING).toString()).append(":");
  367. writer.append(profile.getXpBarStateMap().get(PrimarySkillType.UNARMED).toString()).append(":");
  368. writer.append(profile.getXpBarStateMap().get(PrimarySkillType.WOODCUTTING).toString()).append(":");
  369. writer.append(profile.getXpBarStateMap().get(PrimarySkillType.TRIDENTS).toString()).append(":");
  370. writer.append(profile.getXpBarStateMap().get(PrimarySkillType.CROSSBOWS).toString()).append(":");
  371. writer.append("\r\n");
  372. }
  373. public List<PlayerStat> readLeaderboard(PrimarySkillType skill, int pageNumber, int statsPerPage) {
  374. updateLeaderboards();
  375. List<PlayerStat> statsList = skill == null ? powerLevels : playerStatHash.get(skill);
  376. int fromIndex = (Math.max(pageNumber, 1) - 1) * statsPerPage;
  377. return statsList.subList(Math.min(fromIndex, statsList.size()), Math.min(fromIndex + statsPerPage, statsList.size()));
  378. }
  379. public Map<PrimarySkillType, Integer> readRank(String playerName) {
  380. updateLeaderboards();
  381. Map<PrimarySkillType, Integer> skills = new HashMap<>();
  382. for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) {
  383. skills.put(skill, getPlayerRank(playerName, playerStatHash.get(skill)));
  384. }
  385. skills.put(null, getPlayerRank(playerName, powerLevels));
  386. return skills;
  387. }
  388. public void newUser(String playerName, UUID uuid) {
  389. BufferedWriter out = null;
  390. synchronized (fileWritingLock) {
  391. try {
  392. // Open the file to write the player
  393. out = new BufferedWriter(new FileWriter(mcMMO.getUsersFilePath(), true));
  394. String startingLevel = AdvancedConfig.getInstance().getStartingLevel() + ":";
  395. // Add the player to the end
  396. out.append(playerName).append(":");
  397. out.append(startingLevel); // Mining
  398. out.append(":");
  399. out.append(":");
  400. out.append("0:"); // Xp
  401. out.append(startingLevel); // Woodcutting
  402. out.append("0:"); // WoodCuttingXp
  403. out.append(startingLevel); // Repair
  404. out.append(startingLevel); // Unarmed
  405. out.append(startingLevel); // Herbalism
  406. out.append(startingLevel); // Excavation
  407. out.append(startingLevel); // Archery
  408. out.append(startingLevel); // Swords
  409. out.append(startingLevel); // Axes
  410. out.append(startingLevel); // Acrobatics
  411. out.append("0:"); // RepairXp
  412. out.append("0:"); // UnarmedXp
  413. out.append("0:"); // HerbalismXp
  414. out.append("0:"); // ExcavationXp
  415. out.append("0:"); // ArcheryXp
  416. out.append("0:"); // SwordsXp
  417. out.append("0:"); // AxesXp
  418. out.append("0:"); // AcrobaticsXp
  419. out.append(":");
  420. out.append(startingLevel); // Taming
  421. out.append("0:"); // TamingXp
  422. out.append("0:"); // DATS
  423. out.append("0:"); // DATS
  424. out.append("0:"); // DATS
  425. out.append("0:"); // DATS
  426. out.append("0:"); // DATS
  427. out.append("0:"); // DATS
  428. out.append("0:"); // DATS
  429. out.append(":");
  430. out.append(startingLevel); // Fishing
  431. out.append("0:"); // FishingXp
  432. out.append("0:"); // Blast Mining
  433. out.append(String.valueOf(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR)).append(":"); // LastLogin
  434. out.append(Config.getInstance().getMobHealthbarDefault().toString()).append(":"); // Mob Healthbar HUD
  435. out.append(startingLevel); // Alchemy
  436. out.append("0:"); // AlchemyXp
  437. out.append(uuid != null ? uuid.toString() : "NULL").append(":"); // UUID
  438. out.append("0:"); // Scoreboard tips shown
  439. out.append("0:"); // Chimaera Wing Dats
  440. //Barstates for the 15 currently existing skills by ordinal value
  441. out.append("NORMAL:"); // Acrobatics
  442. out.append("NORMAL:"); // Alchemy
  443. out.append("NORMAL:"); // Archery
  444. out.append("NORMAL:"); // Axes
  445. out.append("NORMAL:"); // Excavation
  446. out.append("NORMAL:"); // Fishing
  447. out.append("NORMAL:"); // Herbalism
  448. out.append("NORMAL:"); // Mining
  449. out.append("NORMAL:"); // Repair
  450. out.append("NORMAL:"); // Salvage
  451. out.append("NORMAL:"); // Smelting
  452. out.append("NORMAL:"); // Swords
  453. out.append("NORMAL:"); // Taming
  454. out.append("NORMAL:"); // Unarmed
  455. out.append("NORMAL:"); // Woodcutting
  456. out.append("NORMAL:"); // Tridents
  457. out.append("NORMAL:"); // Crossbows
  458. // Add more in the same format as the line above
  459. out.newLine();
  460. }
  461. catch (Exception e) {
  462. e.printStackTrace();
  463. }
  464. finally {
  465. if (out != null) {
  466. try {
  467. out.close();
  468. }
  469. catch (IOException e) {
  470. // Ignore
  471. }
  472. }
  473. }
  474. }
  475. }
  476. @Deprecated
  477. public PlayerProfile loadPlayerProfile(String playerName, boolean create) {
  478. return loadPlayerProfile(playerName, null, false);
  479. }
  480. public PlayerProfile loadPlayerProfile(UUID uuid) {
  481. return loadPlayerProfile("", uuid, false);
  482. }
  483. public PlayerProfile loadPlayerProfile(String playerName, UUID uuid, boolean create) {
  484. BufferedReader in = null;
  485. String usersFilePath = mcMMO.getUsersFilePath();
  486. synchronized (fileWritingLock) {
  487. try {
  488. // Open the user file
  489. in = new BufferedReader(new FileReader(usersFilePath));
  490. String line;
  491. while ((line = in.readLine()) != null) {
  492. // Find if the line contains the player we want.
  493. String[] character = line.split(":");
  494. // Compare names because we don't have a valid uuid for that player even
  495. // if input uuid is not null
  496. if (character[UUID_INDEX].equalsIgnoreCase("NULL")) {
  497. if (!character[USERNAME].equalsIgnoreCase(playerName)) {
  498. continue;
  499. }
  500. }
  501. // If input uuid is not null then we should compare uuids
  502. else if ((uuid != null && !character[UUID_INDEX].equalsIgnoreCase(uuid.toString())) || (uuid == null && !character[USERNAME].equalsIgnoreCase(playerName))) {
  503. continue;
  504. }
  505. // Update playerName in database after name change
  506. if (!character[USERNAME].equalsIgnoreCase(playerName)) {
  507. mcMMO.p.getLogger().info("Name change detected: " + character[USERNAME] + " => " + playerName);
  508. character[USERNAME] = playerName;
  509. }
  510. return loadFromLine(character);
  511. }
  512. // Didn't find the player, create a new one
  513. if (create) {
  514. if (uuid == null) {
  515. newUser(playerName, uuid);
  516. return new PlayerProfile(playerName, true);
  517. }
  518. newUser(playerName, uuid);
  519. return new PlayerProfile(playerName, uuid, true);
  520. }
  521. }
  522. catch (Exception e) {
  523. e.printStackTrace();
  524. }
  525. finally {
  526. // I have no idea why it's necessary to inline tryClose() here, but it removes
  527. // a resource leak warning, and I'm trusting the compiler on this one.
  528. if (in != null) {
  529. try {
  530. in.close();
  531. }
  532. catch (IOException e) {
  533. // Ignore
  534. }
  535. }
  536. }
  537. }
  538. // Return unloaded profile
  539. if (uuid == null) {
  540. return new PlayerProfile(playerName);
  541. }
  542. return new PlayerProfile(playerName, uuid);
  543. }
  544. public void convertUsers(DatabaseManager destination) {
  545. BufferedReader in = null;
  546. String usersFilePath = mcMMO.getUsersFilePath();
  547. int convertedUsers = 0;
  548. long startMillis = System.currentTimeMillis();
  549. synchronized (fileWritingLock) {
  550. try {
  551. // Open the user file
  552. in = new BufferedReader(new FileReader(usersFilePath));
  553. String line;
  554. while ((line = in.readLine()) != null) {
  555. String[] character = line.split(":");
  556. try {
  557. destination.saveUser(loadFromLine(character));
  558. }
  559. catch (Exception e) {
  560. e.printStackTrace();
  561. }
  562. convertedUsers++;
  563. Misc.printProgress(convertedUsers, progressInterval, startMillis);
  564. }
  565. }
  566. catch (Exception e) {
  567. e.printStackTrace();
  568. }
  569. finally {
  570. if (in != null) {
  571. try {
  572. in.close();
  573. }
  574. catch (IOException e) {
  575. // Ignore
  576. }
  577. }
  578. }
  579. }
  580. }
  581. public boolean saveUserUUID(String userName, UUID uuid) {
  582. boolean worked = false;
  583. int i = 0;
  584. BufferedReader in = null;
  585. FileWriter out = null;
  586. String usersFilePath = mcMMO.getUsersFilePath();
  587. synchronized (fileWritingLock) {
  588. try {
  589. in = new BufferedReader(new FileReader(usersFilePath));
  590. StringBuilder writer = new StringBuilder();
  591. String line;
  592. while ((line = in.readLine()) != null) {
  593. String[] character = line.split(":");
  594. if (!worked && character[USERNAME].equalsIgnoreCase(userName)) {
  595. if (character.length < 42) {
  596. mcMMO.p.getLogger().severe("Could not update UUID for " + userName + "!");
  597. mcMMO.p.getLogger().severe("Database entry is invalid.");
  598. continue;
  599. }
  600. line = line.replace(character[UUID_INDEX], uuid.toString());
  601. worked = true;
  602. }
  603. i++;
  604. writer.append(line).append("\r\n");
  605. }
  606. out = new FileWriter(usersFilePath); // Write out the new file
  607. out.write(writer.toString());
  608. }
  609. catch (Exception e) {
  610. mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString());
  611. }
  612. finally {
  613. mcMMO.p.getLogger().info(i + " entries written while saving UUID for " + userName);
  614. if (in != null) {
  615. try {
  616. in.close();
  617. }
  618. catch (IOException e) {
  619. // Ignore
  620. }
  621. }
  622. if (out != null) {
  623. try {
  624. out.close();
  625. }
  626. catch (IOException e) {
  627. // Ignore
  628. }
  629. }
  630. }
  631. }
  632. return worked;
  633. }
  634. public boolean saveUserUUIDs(Map<String, UUID> fetchedUUIDs) {
  635. BufferedReader in = null;
  636. FileWriter out = null;
  637. String usersFilePath = mcMMO.getUsersFilePath();
  638. int i = 0;
  639. synchronized (fileWritingLock) {
  640. try {
  641. in = new BufferedReader(new FileReader(usersFilePath));
  642. StringBuilder writer = new StringBuilder();
  643. String line;
  644. while (((line = in.readLine()) != null)) {
  645. String[] character = line.split(":");
  646. if (!fetchedUUIDs.isEmpty() && fetchedUUIDs.containsKey(character[USERNAME])) {
  647. if (character.length < 42) {
  648. mcMMO.p.getLogger().severe("Could not update UUID for " + character[USERNAME] + "!");
  649. mcMMO.p.getLogger().severe("Database entry is invalid.");
  650. continue;
  651. }
  652. character[UUID_INDEX] = fetchedUUIDs.remove(character[USERNAME]).toString();
  653. line = org.apache.commons.lang.StringUtils.join(character, ":") + ":";
  654. }
  655. i++;
  656. writer.append(line).append("\r\n");
  657. }
  658. out = new FileWriter(usersFilePath); // Write out the new file
  659. out.write(writer.toString());
  660. }
  661. catch (Exception e) {
  662. mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString());
  663. }
  664. finally {
  665. mcMMO.p.getLogger().info(i + " entries written while saving UUID batch");
  666. if (in != null) {
  667. try {
  668. in.close();
  669. }
  670. catch (IOException e) {
  671. // Ignore
  672. }
  673. }
  674. if (out != null) {
  675. try {
  676. out.close();
  677. }
  678. catch (IOException e) {
  679. // Ignore
  680. }
  681. }
  682. }
  683. }
  684. return true;
  685. }
  686. public List<String> getStoredUsers() {
  687. ArrayList<String> users = new ArrayList<>();
  688. BufferedReader in = null;
  689. String usersFilePath = mcMMO.getUsersFilePath();
  690. synchronized (fileWritingLock) {
  691. try {
  692. // Open the user file
  693. in = new BufferedReader(new FileReader(usersFilePath));
  694. String line;
  695. while ((line = in.readLine()) != null) {
  696. String[] character = line.split(":");
  697. users.add(character[USERNAME]);
  698. }
  699. }
  700. catch (Exception e) {
  701. e.printStackTrace();
  702. }
  703. finally {
  704. if (in != null) {
  705. try {
  706. in.close();
  707. }
  708. catch (IOException e) {
  709. // Ignore
  710. }
  711. }
  712. }
  713. }
  714. return users;
  715. }
  716. /**
  717. * Update the leader boards.
  718. */
  719. private void updateLeaderboards() {
  720. // Only update FFS leaderboards every 10 minutes.. this puts a lot of strain on the server (depending on the size of the database) and should not be done frequently
  721. if (System.currentTimeMillis() < lastUpdate + UPDATE_WAIT_TIME) {
  722. return;
  723. }
  724. String usersFilePath = mcMMO.getUsersFilePath();
  725. lastUpdate = System.currentTimeMillis(); // Log when the last update was run
  726. powerLevels.clear(); // Clear old values from the power levels
  727. // Initialize lists
  728. List<PlayerStat> mining = new ArrayList<>();
  729. List<PlayerStat> woodcutting = new ArrayList<>();
  730. List<PlayerStat> herbalism = new ArrayList<>();
  731. List<PlayerStat> excavation = new ArrayList<>();
  732. List<PlayerStat> acrobatics = new ArrayList<>();
  733. List<PlayerStat> repair = new ArrayList<>();
  734. List<PlayerStat> swords = new ArrayList<>();
  735. List<PlayerStat> axes = new ArrayList<>();
  736. List<PlayerStat> archery = new ArrayList<>();
  737. List<PlayerStat> unarmed = new ArrayList<>();
  738. List<PlayerStat> taming = new ArrayList<>();
  739. List<PlayerStat> fishing = new ArrayList<>();
  740. List<PlayerStat> alchemy = new ArrayList<>();
  741. BufferedReader in = null;
  742. String playerName = null;
  743. // Read from the FlatFile database and fill our arrays with information
  744. synchronized (fileWritingLock) {
  745. try {
  746. in = new BufferedReader(new FileReader(usersFilePath));
  747. String line;
  748. while ((line = in.readLine()) != null) {
  749. String[] data = line.split(":");
  750. playerName = data[USERNAME];
  751. int powerLevel = 0;
  752. Map<PrimarySkillType, Integer> skills = getSkillMapFromLine(data);
  753. powerLevel += putStat(acrobatics, playerName, skills.get(PrimarySkillType.ACROBATICS));
  754. powerLevel += putStat(alchemy, playerName, skills.get(PrimarySkillType.ALCHEMY));
  755. powerLevel += putStat(archery, playerName, skills.get(PrimarySkillType.ARCHERY));
  756. powerLevel += putStat(axes, playerName, skills.get(PrimarySkillType.AXES));
  757. powerLevel += putStat(excavation, playerName, skills.get(PrimarySkillType.EXCAVATION));
  758. powerLevel += putStat(fishing, playerName, skills.get(PrimarySkillType.FISHING));
  759. powerLevel += putStat(herbalism, playerName, skills.get(PrimarySkillType.HERBALISM));
  760. powerLevel += putStat(mining, playerName, skills.get(PrimarySkillType.MINING));
  761. powerLevel += putStat(repair, playerName, skills.get(PrimarySkillType.REPAIR));
  762. powerLevel += putStat(swords, playerName, skills.get(PrimarySkillType.SWORDS));
  763. powerLevel += putStat(taming, playerName, skills.get(PrimarySkillType.TAMING));
  764. powerLevel += putStat(unarmed, playerName, skills.get(PrimarySkillType.UNARMED));
  765. powerLevel += putStat(woodcutting, playerName, skills.get(PrimarySkillType.WOODCUTTING));
  766. putStat(powerLevels, playerName, powerLevel);
  767. }
  768. }
  769. catch (Exception e) {
  770. mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " during user " + playerName + " (Are you sure you formatted it correctly?) " + e.toString());
  771. }
  772. finally {
  773. if (in != null) {
  774. try {
  775. in.close();
  776. }
  777. catch (IOException e) {
  778. // Ignore
  779. }
  780. }
  781. }
  782. }
  783. SkillComparator c = new SkillComparator();
  784. mining.sort(c);
  785. woodcutting.sort(c);
  786. repair.sort(c);
  787. unarmed.sort(c);
  788. herbalism.sort(c);
  789. excavation.sort(c);
  790. archery.sort(c);
  791. swords.sort(c);
  792. axes.sort(c);
  793. acrobatics.sort(c);
  794. taming.sort(c);
  795. fishing.sort(c);
  796. alchemy.sort(c);
  797. powerLevels.sort(c);
  798. playerStatHash.put(PrimarySkillType.MINING, mining);
  799. playerStatHash.put(PrimarySkillType.WOODCUTTING, woodcutting);
  800. playerStatHash.put(PrimarySkillType.REPAIR, repair);
  801. playerStatHash.put(PrimarySkillType.UNARMED, unarmed);
  802. playerStatHash.put(PrimarySkillType.HERBALISM, herbalism);
  803. playerStatHash.put(PrimarySkillType.EXCAVATION, excavation);
  804. playerStatHash.put(PrimarySkillType.ARCHERY, archery);
  805. playerStatHash.put(PrimarySkillType.SWORDS, swords);
  806. playerStatHash.put(PrimarySkillType.AXES, axes);
  807. playerStatHash.put(PrimarySkillType.ACROBATICS, acrobatics);
  808. playerStatHash.put(PrimarySkillType.TAMING, taming);
  809. playerStatHash.put(PrimarySkillType.FISHING, fishing);
  810. playerStatHash.put(PrimarySkillType.ALCHEMY, alchemy);
  811. }
  812. /**
  813. * Checks that the file is present and valid
  814. */
  815. private void checkStructure() {
  816. if (usersFile.exists()) {
  817. BufferedReader in = null;
  818. FileWriter out = null;
  819. String usersFilePath = mcMMO.getUsersFilePath();
  820. synchronized (fileWritingLock) {
  821. try {
  822. in = new BufferedReader(new FileReader(usersFilePath));
  823. StringBuilder writer = new StringBuilder();
  824. String line;
  825. HashSet<String> usernames = new HashSet<>();
  826. HashSet<String> players = new HashSet<>();
  827. while ((line = in.readLine()) != null) {
  828. // Remove empty lines from the file
  829. if (line.isEmpty()) {
  830. continue;
  831. }
  832. // Length checks depend on last character being ':'
  833. if (line.charAt(line.length() - 1) != ':') {
  834. line = line.concat(":");
  835. }
  836. boolean updated = false;
  837. String[] character = line.split(":");
  838. // Prevent the same username from being present multiple times
  839. if (!usernames.add(character[USERNAME])) {
  840. character[USERNAME] = "_INVALID_OLD_USERNAME_'";
  841. updated = true;
  842. if (character.length < UUID_INDEX + 1 || character[UUID_INDEX].equals("NULL")) {
  843. continue;
  844. }
  845. }
  846. // Prevent the same player from being present multiple times
  847. if (character.length >= 42 && (!character[UUID_INDEX].isEmpty() && !character[UUID_INDEX].equals("NULL") && !players.add(character[UUID_INDEX]))) {
  848. continue;
  849. }
  850. if (character.length < 33) {
  851. // Before Version 1.0 - Drop
  852. mcMMO.p.getLogger().warning("Dropping malformed or before version 1.0 line from database - " + line);
  853. continue;
  854. }
  855. String oldVersion = null;
  856. if (character.length > 33 && !character[33].isEmpty()) {
  857. // Removal of Spout Support
  858. // Version 1.4.07-dev2
  859. // commit 7bac0e2ca5143bce84dc160617fed97f0b1cb968
  860. character[33] = "";
  861. if (oldVersion == null) {
  862. oldVersion = "1.4.07";
  863. }
  864. updated = true;
  865. }
  866. //TODO: If new skills are added this needs to be rewritten
  867. if (Config.getInstance().getTruncateSkills()) {
  868. for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) {
  869. int index = getSkillIndex(skill);
  870. if (index >= character.length) {
  871. continue;
  872. }
  873. int cap = Config.getInstance().getLevelCap(skill);
  874. if (Integer.parseInt(character[index]) > cap) {
  875. mcMMO.p.getLogger().warning("Truncating " + skill.getName() + " to configured max level for player " + character[USERNAME]);
  876. character[index] = cap + "";
  877. updated = true;
  878. }
  879. }
  880. }
  881. // If they're valid, rewrite them to the file.
  882. if (!updated && character.length == 43) {
  883. writer.append(line).append("\r\n");
  884. continue;
  885. }
  886. if (character.length <= 33) {
  887. // Introduction of HUDType
  888. // Version 1.1.06
  889. // commit 78f79213cdd7190cd11ae54526f3b4ea42078e8a
  890. character = Arrays.copyOf(character, character.length + 1);
  891. character[character.length - 1] = "";
  892. oldVersion = "1.1.06";
  893. }
  894. if (character.length <= 35) {
  895. // Introduction of Fishing
  896. // Version 1.2.00
  897. // commit a814b57311bc7734661109f0e77fc8bab3a0bd29
  898. character = Arrays.copyOf(character, character.length + 2);
  899. character[character.length - 1] = "0";
  900. character[character.length - 2] = "0";
  901. if (oldVersion == null) {
  902. oldVersion = "1.2.00";
  903. }
  904. }
  905. if (character.length <= 36) {
  906. // Introduction of Blast Mining cooldowns
  907. // Version 1.3.00-dev
  908. // commit fadbaf429d6b4764b8f1ad0efaa524a090e82ef5
  909. character = Arrays.copyOf(character, character.length + 1);
  910. character[character.length - 1] = "0";
  911. if (oldVersion == null) {
  912. oldVersion = "1.3.00";
  913. }
  914. }
  915. if (character.length <= 37) {
  916. // Making old-purge work with flatfile
  917. // Version 1.4.00-dev
  918. // commmit 3f6c07ba6aaf44e388cc3b882cac3d8f51d0ac28
  919. // XXX Cannot create an OfflinePlayer at startup, use 0 and fix in purge
  920. character = Arrays.copyOf(character, character.length + 1);
  921. character[character.length - 1] = "0";
  922. if (oldVersion == null) {
  923. oldVersion = "1.4.00";
  924. }
  925. }
  926. if (character.length <= 38) {
  927. // Addition of mob healthbars
  928. // Version 1.4.06
  929. // commit da29185b7dc7e0d992754bba555576d48fa08aa6
  930. character = Arrays.copyOf(character, character.length + 1);
  931. character[character.length - 1] = Config.getInstance().getMobHealthbarDefault().toString();
  932. if (oldVersion == null) {
  933. oldVersion = "1.4.06";
  934. }
  935. }
  936. if (character.length <= 39) {
  937. // Addition of Alchemy
  938. // Version 1.4.08
  939. character = Arrays.copyOf(character, character.length + 2);
  940. character[character.length - 1] = "0";
  941. character[character.length - 2] = "0";
  942. if (oldVersion == null) {
  943. oldVersion = "1.4.08";
  944. }
  945. }
  946. if (character.length <= 41) {
  947. // Addition of UUIDs
  948. // Version 1.5.01
  949. // Add a value because otherwise it gets removed
  950. character = Arrays.copyOf(character, character.length + 1);
  951. character[character.length - 1] = "NULL";
  952. if (oldVersion == null) {
  953. oldVersion = "1.5.01";
  954. }
  955. }
  956. if (character.length <= 42) {
  957. // Addition of scoreboard tips auto disable
  958. // Version 1.5.02
  959. character = Arrays.copyOf(character, character.length + 1);
  960. character[character.length - 1] = "0";
  961. if (oldVersion == null) {
  962. oldVersion = "1.5.02";
  963. }
  964. }
  965. if(character.length <= 43) {
  966. // Addition of Chimaera wing DATS
  967. character = Arrays.copyOf(character, character.length + 1);
  968. character[character.length - 1] = "0";
  969. if (oldVersion == null) {
  970. oldVersion = "2.1.133";
  971. }
  972. }
  973. if(character.length <= 65) {
  974. if (oldVersion == null) {
  975. oldVersion = "2.1.133";
  976. }
  977. character = Arrays.copyOf(character, 64); // new array size
  978. /*
  979. public static int SKILLS_TRIDENTS = 44;
  980. public static int EXP_TRIDENTS = 45;
  981. public static int SKILLS_CROSSBOWS = 46;
  982. public static int EXP_CROSSBOWS = 47;
  983. public static int BARSTATE_ACROBATICS = 48;
  984. public static int BARSTATE_ALCHEMY = 49;
  985. public static int BARSTATE_ARCHERY = 50;
  986. public static int BARSTATE_AXES = 51;
  987. public static int BARSTATE_EXCAVATION = 52;
  988. public static int BARSTATE_FISHING = 53;
  989. public static int BARSTATE_HERBALISM = 54;
  990. public static int BARSTATE_MINING = 55;
  991. public static int BARSTATE_REPAIR = 56;
  992. public static int BARSTATE_SALVAGE = 57;
  993. public static int BARSTATE_SMELTING = 58;
  994. public static int BARSTATE_SWORDS = 59;
  995. public static int BARSTATE_TAMING = 60;
  996. public static int BARSTATE_UNARMED = 61;
  997. public static int BARSTATE_WOODCUTTING = 62;
  998. public static int BARSTATE_TRIDENTS = 63;
  999. public static int BARSTATE_CROSSBOWS = 64;
  1000. */
  1001. character[44-1] = "0"; //trident skill lvl
  1002. character[45-1] = "0"; //trident xp value
  1003. character[46-1] = "0"; //xbow skill lvl
  1004. character[47-1] = "0"; //xbow xp lvl
  1005. //Barstates 48-64
  1006. character[48-1] = "NORMAL";
  1007. character[49-1] = "NORMAL";
  1008. character[50-1] = "NORMAL";
  1009. character[51-1] = "NORMAL";
  1010. character[52-1] = "NORMAL";
  1011. character[53-1] = "NORMAL";
  1012. character[54-1] = "NORMAL";
  1013. character[55-1] = "NORMAL";
  1014. character[56-1] = "NORMAL";
  1015. character[57-1] = "DISABLED"; //Child skills
  1016. character[58-1] = "DISABLED"; //Child skills
  1017. character[59-1] = "NORMAL";
  1018. character[60-1] = "NORMAL";
  1019. character[61-1] = "NORMAL";
  1020. character[62-1] = "NORMAL";
  1021. character[63-1] = "NORMAL";
  1022. character[64-1] = "NORMAL";
  1023. }
  1024. boolean corrupted = false;
  1025. for (int i = 0; i < character.length; i++) {
  1026. //Sigh... this code
  1027. if (character[i].isEmpty() && !(i == 2 || i == 3 || i == 23 || i == 33 || i == 41)) {
  1028. mcMMO.p.getLogger().info("Player data at index "+i+" appears to be empty, possible corruption of data has occurred.");
  1029. corrupted = true;
  1030. if (i == 37) {
  1031. character[i] = String.valueOf(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR);
  1032. }
  1033. else if (i == 38) {
  1034. character[i] = Config.getInstance().getMobHealthbarDefault().toString();
  1035. }
  1036. else {
  1037. character[i] = "0";
  1038. }
  1039. }
  1040. if (StringUtils.isInt(character[i]) && i == 38) {
  1041. corrupted = true;
  1042. character[i] = Config.getInstance().getMobHealthbarDefault().toString();
  1043. }
  1044. if (!StringUtils.isInt(character[i]) && !(i == 0 || i == 2 || i == 3 || i == 23 || i == 33 || i == 38 || i == 41)) {
  1045. corrupted = true;
  1046. character[i] = "0";
  1047. }
  1048. }
  1049. if (corrupted) {
  1050. mcMMO.p.getLogger().info("Updating corrupted database line for player " + character[USERNAME]);
  1051. }
  1052. if (oldVersion != null) {
  1053. mcMMO.p.getLogger().info("Updating database line from before version " + oldVersion + " for player " + character[USERNAME]);
  1054. }
  1055. updated |= corrupted;
  1056. updated |= oldVersion != null;
  1057. if (Config.getInstance().getTruncateSkills()) {
  1058. Map<PrimarySkillType, Integer> skills = getSkillMapFromLine(character);
  1059. for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) {
  1060. int cap = Config.getInstance().getLevelCap(skill);
  1061. if (skills.get(skill) > cap) {
  1062. updated = true;
  1063. }
  1064. }
  1065. }
  1066. if (updated) {
  1067. line = org.apache.commons.lang.StringUtils.join(character, ":") + ":";
  1068. }
  1069. writer.append(line).append("\r\n");
  1070. }
  1071. // Write the new file
  1072. out = new FileWriter(usersFilePath);
  1073. out.write(writer.toString());
  1074. }
  1075. catch (IOException e) {
  1076. mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString());
  1077. }
  1078. finally {
  1079. if (in != null) {
  1080. try {
  1081. in.close();
  1082. }
  1083. catch (IOException e) {
  1084. // Ignore
  1085. }
  1086. }
  1087. if (out != null) {
  1088. try {
  1089. out.close();
  1090. }
  1091. catch (IOException e) {
  1092. // Ignore
  1093. }
  1094. }
  1095. }
  1096. }
  1097. mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_FISHING);
  1098. mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_BLAST_MINING_COOLDOWN);
  1099. mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_SQL_INDEXES);
  1100. mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_MOB_HEALTHBARS);
  1101. mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_SQL_PARTY_NAMES);
  1102. mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_SPOUT);
  1103. mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_ALCHEMY);
  1104. return;
  1105. }
  1106. usersFile.getParentFile().mkdir();
  1107. try {
  1108. mcMMO.p.getLogger().info("Creating mcmmo.users file...");
  1109. new File(mcMMO.getUsersFilePath()).createNewFile();
  1110. }
  1111. catch (IOException e) {
  1112. e.printStackTrace();
  1113. }
  1114. }
  1115. private Integer getPlayerRank(String playerName, List<PlayerStat> statsList) {
  1116. if (statsList == null) {
  1117. return null;
  1118. }
  1119. int currentPos = 1;
  1120. for (PlayerStat stat : statsList) {
  1121. if (stat.name.equalsIgnoreCase(playerName)) {
  1122. return currentPos;
  1123. }
  1124. currentPos++;
  1125. }
  1126. return null;
  1127. }
  1128. private int putStat(List<PlayerStat> statList, String playerName, int statValue) {
  1129. statList.add(new PlayerStat(playerName, statValue));
  1130. return statValue;
  1131. }
  1132. private static class SkillComparator implements Comparator<PlayerStat> {
  1133. @Override
  1134. public int compare(PlayerStat o1, PlayerStat o2) {
  1135. return (o2.statVal - o1.statVal);
  1136. }
  1137. }
  1138. private PlayerProfile loadFromLine(String[] character) {
  1139. Map<PrimarySkillType, Integer> skills = getSkillMapFromLine(character); // Skill levels
  1140. Map<PrimarySkillType, Float> skillsXp = new EnumMap<PrimarySkillType, Float>(PrimarySkillType.class); // Skill & XP
  1141. Map<SuperAbilityType, Integer> skillsDATS = new EnumMap<SuperAbilityType, Integer>(SuperAbilityType.class); // Ability & Cooldown
  1142. Map<UniqueDataType, Integer> uniquePlayerDataMap = new EnumMap<UniqueDataType, Integer>(UniqueDataType.class);
  1143. Map<PrimarySkillType, ExperienceBarManager.BarState> xpBarStateMap = new EnumMap<PrimarySkillType, ExperienceBarManager.BarState>(PrimarySkillType.class);
  1144. MobHealthbarType mobHealthbarType;
  1145. int scoreboardTipsShown;
  1146. // TODO on updates, put new values in a try{} ?
  1147. skillsXp.put(PrimarySkillType.TAMING, (float) Integer.valueOf(character[EXP_TAMING]));
  1148. skillsXp.put(PrimarySkillType.MINING, (float) Integer.valueOf(character[EXP_MINING]));
  1149. skillsXp.put(PrimarySkillType.REPAIR, (float) Integer.valueOf(character[EXP_REPAIR]));
  1150. skillsXp.put(PrimarySkillType.WOODCUTTING, (float) Integer.valueOf(character[EXP_WOODCUTTING]));
  1151. skillsXp.put(PrimarySkillType.UNARMED, (float) Integer.valueOf(character[EXP_UNARMED]));
  1152. skillsXp.put(PrimarySkillType.HERBALISM, (float) Integer.valueOf(character[EXP_HERBALISM]));
  1153. skillsXp.put(PrimarySkillType.EXCAVATION, (float) Integer.valueOf(character[EXP_EXCAVATION]));
  1154. skillsXp.put(PrimarySkillType.ARCHERY, (float) Integer.valueOf(character[EXP_ARCHERY]));
  1155. skillsXp.put(PrimarySkillType.SWORDS, (float) Integer.valueOf(character[EXP_SWORDS]));
  1156. skillsXp.put(PrimarySkillType.AXES, (float) Integer.valueOf(character[EXP_AXES]));
  1157. skillsXp.put(PrimarySkillType.ACROBATICS, (float) Integer.valueOf(character[EXP_ACROBATICS]));
  1158. skillsXp.put(PrimarySkillType.FISHING, (float) Integer.valueOf(character[EXP_FISHING]));
  1159. skillsXp.put(PrimarySkillType.ALCHEMY, (float) Integer.valueOf(character[EXP_ALCHEMY]));
  1160. skillsXp.put(PrimarySkillType.TRIDENTS, (float) Integer.valueOf(character[EXP_TRIDENTS]));
  1161. skillsXp.put(PrimarySkillType.CROSSBOWS, (float) Integer.valueOf(character[EXP_CROSSBOWS]));
  1162. // Taming - Unused
  1163. skillsDATS.put(SuperAbilityType.SUPER_BREAKER, Integer.valueOf(character[COOLDOWN_SUPER_BREAKER]));
  1164. // Repair - Unused
  1165. skillsDATS.put(SuperAbilityType.TREE_FELLER, Integer.valueOf(character[COOLDOWN_TREE_FELLER]));
  1166. skillsDATS.put(SuperAbilityType.BERSERK, Integer.valueOf(character[COOLDOWN_BERSERK]));
  1167. skillsDATS.put(SuperAbilityType.GREEN_TERRA, Integer.valueOf(character[COOLDOWN_GREEN_TERRA]));
  1168. skillsDATS.put(SuperAbilityType.GIGA_DRILL_BREAKER, Integer.valueOf(character[COOLDOWN_GIGA_DRILL_BREAKER]));
  1169. // Archery - Unused
  1170. skillsDATS.put(SuperAbilityType.SERRATED_STRIKES, Integer.valueOf(character[COOLDOWN_SERRATED_STRIKES]));
  1171. skillsDATS.put(SuperAbilityType.SKULL_SPLITTER, Integer.valueOf(character[COOLDOWN_SKULL_SPLITTER]));
  1172. // Acrobatics - Unused
  1173. skillsDATS.put(SuperAbilityType.BLAST_MINING, Integer.valueOf(character[COOLDOWN_BLAST_MINING]));
  1174. try {
  1175. mobHealthbarType = MobHealthbarType.valueOf(character[HEALTHBAR]);
  1176. }
  1177. catch (Exception e) {
  1178. mobHealthbarType = Config.getInstance().getMobHealthbarDefault();
  1179. }
  1180. UUID uuid;
  1181. try {
  1182. uuid = UUID.fromString(character[UUID_INDEX]);
  1183. }
  1184. catch (Exception e) {
  1185. uuid = null;
  1186. }
  1187. try {
  1188. scoreboardTipsShown = Integer.parseInt(character[SCOREBOARD_TIPS]);
  1189. }
  1190. catch (Exception e) {
  1191. scoreboardTipsShown = 0;
  1192. }
  1193. try {
  1194. uniquePlayerDataMap.put(UniqueDataType.CHIMAERA_WING_DATS, Integer.valueOf(character[COOLDOWN_CHIMAERA_WING]));
  1195. }
  1196. catch (Exception e) {
  1197. uniquePlayerDataMap.put(UniqueDataType.CHIMAERA_WING_DATS, 0);
  1198. }
  1199. try {
  1200. xpBarStateMap.put(PrimarySkillType.ACROBATICS, SkillUtils.asBarState(character[BARSTATE_ACROBATICS]));
  1201. xpBarStateMap.put(PrimarySkillType.ALCHEMY, SkillUtils.asBarState(character[BARSTATE_ALCHEMY]));
  1202. xpBarStateMap.put(PrimarySkillType.ARCHERY, SkillUtils.asBarState(character[BARSTATE_ARCHERY]));
  1203. xpBarStateMap.put(PrimarySkillType.AXES, SkillUtils.asBarState(character[BARSTATE_AXES]));
  1204. xpBarStateMap.put(PrimarySkillType.EXCAVATION, SkillUtils.asBarState(character[BARSTATE_EXCAVATION]));
  1205. xpBarStateMap.put(PrimarySkillType.FISHING, SkillUtils.asBarState(character[BARSTATE_FISHING]));
  1206. xpBarStateMap.put(PrimarySkillType.HERBALISM, SkillUtils.asBarState(character[BARSTATE_HERBALISM]));
  1207. xpBarStateMap.put(PrimarySkillType.MINING, SkillUtils.asBarState(character[BARSTATE_MINING]));
  1208. xpBarStateMap.put(PrimarySkillType.REPAIR, SkillUtils.asBarState(character[BARSTATE_REPAIR]));
  1209. xpBarStateMap.put(PrimarySkillType.SALVAGE, SkillUtils.asBarState(character[BARSTATE_SALVAGE]));
  1210. xpBarStateMap.put(PrimarySkillType.SMELTING, SkillUtils.asBarState(character[BARSTATE_SMELTING]));
  1211. xpBarStateMap.put(PrimarySkillType.SWORDS, SkillUtils.asBarState(character[BARSTATE_SWORDS]));
  1212. xpBarStateMap.put(PrimarySkillType.TAMING, SkillUtils.asBarState(character[BARSTATE_TAMING]));
  1213. xpBarStateMap.put(PrimarySkillType.UNARMED, SkillUtils.asBarState(character[BARSTATE_UNARMED]));
  1214. xpBarStateMap.put(PrimarySkillType.WOODCUTTING, SkillUtils.asBarState(character[BARSTATE_WOODCUTTING]));
  1215. xpBarStateMap.put(PrimarySkillType.TRIDENTS, SkillUtils.asBarState(character[BARSTATE_TRIDENTS]));
  1216. xpBarStateMap.put(PrimarySkillType.CROSSBOWS, SkillUtils.asBarState(character[BARSTATE_CROSSBOWS]));
  1217. } catch (Exception e) {
  1218. xpBarStateMap = SkillUtils.generateDefaultBarStateMap();
  1219. }
  1220. return new PlayerProfile(character[USERNAME], uuid, skills, skillsXp, skillsDATS, mobHealthbarType, scoreboardTipsShown, uniquePlayerDataMap, xpBarStateMap);
  1221. }
  1222. private Map<PrimarySkillType, Integer> getSkillMapFromLine(String[] character) {
  1223. Map<PrimarySkillType, Integer> skills = new EnumMap<>(PrimarySkillType.class); // Skill & Level
  1224. skills.put(PrimarySkillType.TAMING, Integer.valueOf(character[SKILLS_TAMING]));
  1225. skills.put(PrimarySkillType.MINING, Integer.valueOf(character[SKILLS_MINING]));
  1226. skills.put(PrimarySkillType.REPAIR, Integer.valueOf(character[SKILLS_REPAIR]));
  1227. skills.put(PrimarySkillType.WOODCUTTING, Integer.valueOf(character[SKILLS_WOODCUTTING]));
  1228. skills.put(PrimarySkillType.UNARMED, Integer.valueOf(character[SKILLS_UNARMED]));
  1229. skills.put(PrimarySkillType.HERBALISM, Integer.valueOf(character[SKILLS_HERBALISM]));
  1230. skills.put(PrimarySkillType.EXCAVATION, Integer.valueOf(character[SKILLS_EXCAVATION]));
  1231. skills.put(PrimarySkillType.ARCHERY, Integer.valueOf(character[SKILLS_ARCHERY]));
  1232. skills.put(PrimarySkillType.SWORDS, Integer.valueOf(character[SKILLS_SWORDS]));
  1233. skills.put(PrimarySkillType.AXES, Integer.valueOf(character[SKILLS_AXES]));
  1234. skills.put(PrimarySkillType.ACROBATICS, Integer.valueOf(character[SKILLS_ACROBATICS]));
  1235. skills.put(PrimarySkillType.FISHING, Integer.valueOf(character[SKILLS_FISHING]));
  1236. skills.put(PrimarySkillType.ALCHEMY, Integer.valueOf(character[SKILLS_ALCHEMY]));
  1237. skills.put(PrimarySkillType.TRIDENTS, Integer.valueOf(character[SKILLS_TRIDENTS]));
  1238. skills.put(PrimarySkillType.CROSSBOWS, Integer.valueOf(character[SKILLS_CROSSBOWS]));
  1239. return skills;
  1240. }
  1241. public DatabaseType getDatabaseType() {
  1242. return DatabaseType.FLATFILE;
  1243. }
  1244. @Override
  1245. public void onDisable() { }
  1246. private int getSkillIndex(PrimarySkillType skill) {
  1247. switch (skill) {
  1248. case ACROBATICS:
  1249. return SKILLS_ACROBATICS;
  1250. case ALCHEMY:
  1251. return SKILLS_ALCHEMY;
  1252. case ARCHERY:
  1253. return SKILLS_ARCHERY;
  1254. case AXES:
  1255. return SKILLS_AXES;
  1256. case EXCAVATION:
  1257. return SKILLS_EXCAVATION;
  1258. case FISHING:
  1259. return SKILLS_FISHING;
  1260. case HERBALISM:
  1261. return SKILLS_HERBALISM;
  1262. case MINING:
  1263. return SKILLS_MINING;
  1264. case REPAIR:
  1265. return SKILLS_REPAIR;
  1266. case SWORDS:
  1267. return SKILLS_SWORDS;
  1268. case TAMING:
  1269. return SKILLS_TAMING;
  1270. case UNARMED:
  1271. return SKILLS_UNARMED;
  1272. case WOODCUTTING:
  1273. return SKILLS_WOODCUTTING;
  1274. case TRIDENTS:
  1275. return SKILLS_TRIDENTS;
  1276. case CROSSBOWS:
  1277. return SKILLS_CROSSBOWS;
  1278. default:
  1279. throw new RuntimeException("Primary Skills only");
  1280. }
  1281. }
  1282. public static int USERNAME = 0;
  1283. public static int SKILLS_MINING = 1;
  1284. public static int EXP_MINING = 4;
  1285. public static int SKILLS_WOODCUTTING = 5;
  1286. public static int EXP_WOODCUTTING = 6;
  1287. public static int SKILLS_REPAIR = 7;
  1288. public static int SKILLS_UNARMED = 8;
  1289. public static int SKILLS_HERBALISM = 9;
  1290. public static int SKILLS_EXCAVATION = 10;
  1291. public static int SKILLS_ARCHERY = 11;
  1292. public static int SKILLS_SWORDS = 12;
  1293. public static int SKILLS_AXES = 13;
  1294. public static int SKILLS_ACROBATICS = 14;
  1295. public static int EXP_REPAIR = 15;
  1296. public static int EXP_UNARMED = 16;
  1297. public static int EXP_HERBALISM = 17;
  1298. public static int EXP_EXCAVATION = 18;
  1299. public static int EXP_ARCHERY = 19;
  1300. public static int EXP_SWORDS = 20;
  1301. public static int EXP_AXES = 21;
  1302. public static int EXP_ACROBATICS = 22;
  1303. public static int SKILLS_TAMING = 24;
  1304. public static int EXP_TAMING = 25;
  1305. public static int COOLDOWN_BERSERK = 26;
  1306. public static int COOLDOWN_GIGA_DRILL_BREAKER = 27;
  1307. public static int COOLDOWN_TREE_FELLER = 28;
  1308. public static int COOLDOWN_GREEN_TERRA = 29;
  1309. public static int COOLDOWN_SERRATED_STRIKES = 30;
  1310. public static int COOLDOWN_SKULL_SPLITTER = 31;
  1311. public static int COOLDOWN_SUPER_BREAKER = 32;
  1312. public static int SKILLS_FISHING = 34;
  1313. public static int EXP_FISHING = 35;
  1314. public static int COOLDOWN_BLAST_MINING = 36;
  1315. public static int LAST_LOGIN = 37;
  1316. public static int HEALTHBAR = 38;
  1317. public static int SKILLS_ALCHEMY = 39;
  1318. public static int EXP_ALCHEMY = 40;
  1319. public static int UUID_INDEX = 41;
  1320. public static int SCOREBOARD_TIPS = 42;
  1321. public static int COOLDOWN_CHIMAERA_WING = 43;
  1322. public static int SKILLS_TRIDENTS = 44;
  1323. public static int EXP_TRIDENTS = 45;
  1324. public static int SKILLS_CROSSBOWS = 46;
  1325. public static int EXP_CROSSBOWS = 47;
  1326. public static int BARSTATE_ACROBATICS = 48;
  1327. public static int BARSTATE_ALCHEMY = 49;
  1328. public static int BARSTATE_ARCHERY = 50;
  1329. public static int BARSTATE_AXES = 51;
  1330. public static int BARSTATE_EXCAVATION = 52;
  1331. public static int BARSTATE_FISHING = 53;
  1332. public static int BARSTATE_HERBALISM = 54;
  1333. public static int BARSTATE_MINING = 55;
  1334. public static int BARSTATE_REPAIR = 56;
  1335. public static int BARSTATE_SALVAGE = 57;
  1336. public static int BARSTATE_SMELTING = 58;
  1337. public static int BARSTATE_SWORDS = 59;
  1338. public static int BARSTATE_TAMING = 60;
  1339. public static int BARSTATE_UNARMED = 61;
  1340. public static int BARSTATE_WOODCUTTING = 62;
  1341. public static int BARSTATE_TRIDENTS = 63;
  1342. public static int BARSTATE_CROSSBOWS = 64;
  1343. public void resetMobHealthSettings() {
  1344. BufferedReader in = null;
  1345. FileWriter out = null;
  1346. String usersFilePath = mcMMO.getUsersFilePath();
  1347. synchronized (fileWritingLock) {
  1348. try {
  1349. in = new BufferedReader(new FileReader(usersFilePath));
  1350. StringBuilder writer = new StringBuilder();
  1351. String line;
  1352. while ((line = in.readLine()) != null) {
  1353. // Remove empty lines from the file
  1354. if (line.isEmpty()) {
  1355. continue;
  1356. }
  1357. String[] character = line.split(":");
  1358. character[HEALTHBAR] = Config.getInstance().getMobHealthbarDefault().toString();
  1359. line = org.apache.commons.lang.StringUtils.join(character, ":") + ":";
  1360. writer.append(line).append("\r\n");
  1361. }
  1362. // Write the new file
  1363. out = new FileWriter(usersFilePath);
  1364. out.write(writer.toString());
  1365. }
  1366. catch (IOException e) {
  1367. mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString());
  1368. }
  1369. finally {
  1370. if (in != null) {
  1371. try {
  1372. in.close();
  1373. }
  1374. catch (IOException e) {
  1375. // Ignore
  1376. }
  1377. }
  1378. if (out != null) {
  1379. try {
  1380. out.close();
  1381. }
  1382. catch (IOException e) {
  1383. // Ignore
  1384. }
  1385. }
  1386. }
  1387. }
  1388. }
  1389. }