More safety against corrupt data when loading data for FlatFile

This commit is contained in:
nossr50 2021-03-11 13:11:11 -08:00
parent d77c8c88a3
commit 2203d61c10
3 changed files with 87 additions and 45 deletions

View File

@ -385,6 +385,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
} }
private void writeUserToLine(PlayerProfile profile, String playerName, UUID uuid, StringBuilder writer) { private void writeUserToLine(PlayerProfile profile, String playerName, UUID uuid, StringBuilder writer) {
// FlyingMonkey_:0:::0:0:0:0:0:0:0:0:0:0:5:0:156:460:
writer.append(playerName).append(":"); writer.append(playerName).append(":");
writer.append(profile.getSkillLevel(PrimarySkillType.MINING)).append(":"); writer.append(profile.getSkillLevel(PrimarySkillType.MINING)).append(":");
writer.append(":"); writer.append(":");
@ -936,6 +937,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
HashSet<String> players = new HashSet<>(); HashSet<String> players = new HashSet<>();
while ((line = in.readLine()) != null) { while ((line = in.readLine()) != null) {
String oldVersion = null;
// Remove empty lines from the file // Remove empty lines from the file
if (line.isEmpty()) { if (line.isEmpty()) {
continue; continue;
@ -968,8 +971,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
continue; continue;
} }
String oldVersion = null;
if (character.length > 33 && !character[33].isEmpty()) { if (character.length > 33 && !character[33].isEmpty()) {
// Removal of Spout Support // Removal of Spout Support
// Version 1.4.07-dev2 // Version 1.4.07-dev2
@ -984,11 +985,21 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
if (Config.getInstance().getTruncateSkills()) { if (Config.getInstance().getTruncateSkills()) {
for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) { for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) {
int index = getSkillIndex(skill); int index = getSkillIndex(skill);
if (index >= character.length) { if (index >= character.length) {
continue; continue;
} }
int cap = Config.getInstance().getLevelCap(skill); int cap = Config.getInstance().getLevelCap(skill);
if (Integer.parseInt(character[index]) > cap) { int skillLevel = 0;
try {
skillLevel = Integer.parseInt(character[index]);
} catch (NumberFormatException e) {
mcMMO.p.getLogger().severe("Repairing some corrupt or unexpected data in mcmmo.users it is possible some data may be lost.");
}
if (skillLevel > cap) {
mcMMO.p.getLogger().warning("Truncating " + skill.getName() + " to configured max level for player " + character[USERNAME_INDEX]); mcMMO.p.getLogger().warning("Truncating " + skill.getName() + " to configured max level for player " + character[USERNAME_INDEX]);
character[index] = cap + ""; character[index] = cap + "";
updated = true; updated = true;
@ -1224,34 +1235,34 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
MobHealthbarType mobHealthbarType; MobHealthbarType mobHealthbarType;
int scoreboardTipsShown; int scoreboardTipsShown;
// TODO on updates, put new values in a try{} ? String username = character[USERNAME_INDEX];
skillsXp.put(PrimarySkillType.TAMING, (float) Integer.parseInt(character[EXP_TAMING])); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.TAMING, EXP_TAMING, username);
skillsXp.put(PrimarySkillType.MINING, (float) Integer.parseInt(character[EXP_MINING])); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.MINING, EXP_MINING, username);
skillsXp.put(PrimarySkillType.REPAIR, (float) Integer.parseInt(character[EXP_REPAIR])); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.REPAIR, EXP_REPAIR, username);
skillsXp.put(PrimarySkillType.WOODCUTTING, (float) Integer.parseInt(character[EXP_WOODCUTTING])); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.WOODCUTTING, EXP_WOODCUTTING, username);
skillsXp.put(PrimarySkillType.UNARMED, (float) Integer.parseInt(character[EXP_UNARMED])); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.UNARMED, EXP_UNARMED, username);
skillsXp.put(PrimarySkillType.HERBALISM, (float) Integer.parseInt(character[EXP_HERBALISM])); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.HERBALISM, EXP_HERBALISM, username);
skillsXp.put(PrimarySkillType.EXCAVATION, (float) Integer.parseInt(character[EXP_EXCAVATION])); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.EXCAVATION, EXP_EXCAVATION, username);
skillsXp.put(PrimarySkillType.ARCHERY, (float) Integer.parseInt(character[EXP_ARCHERY])); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.ARCHERY, EXP_ARCHERY, username);
skillsXp.put(PrimarySkillType.SWORDS, (float) Integer.parseInt(character[EXP_SWORDS])); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.SWORDS, EXP_SWORDS, username);
skillsXp.put(PrimarySkillType.AXES, (float) Integer.parseInt(character[EXP_AXES])); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.AXES, EXP_AXES, username);
skillsXp.put(PrimarySkillType.ACROBATICS, (float) Integer.parseInt(character[EXP_ACROBATICS])); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.ACROBATICS, EXP_ACROBATICS, username);
skillsXp.put(PrimarySkillType.FISHING, (float) Integer.parseInt(character[EXP_FISHING])); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.FISHING, EXP_FISHING, username);
skillsXp.put(PrimarySkillType.ALCHEMY, (float) Integer.parseInt(character[EXP_ALCHEMY])); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.ALCHEMY, EXP_ALCHEMY, username);
// Taming - Unused // Taming - Unused
skillsDATS.put(SuperAbilityType.SUPER_BREAKER, Integer.valueOf(character[COOLDOWN_SUPER_BREAKER])); tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SUPER_BREAKER, COOLDOWN_SUPER_BREAKER, username);
// Repair - Unused // Repair - Unused
skillsDATS.put(SuperAbilityType.TREE_FELLER, Integer.valueOf(character[COOLDOWN_TREE_FELLER])); tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.TREE_FELLER, COOLDOWN_TREE_FELLER, username);
skillsDATS.put(SuperAbilityType.BERSERK, Integer.valueOf(character[COOLDOWN_BERSERK])); tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.BERSERK, COOLDOWN_BERSERK, username);
skillsDATS.put(SuperAbilityType.GREEN_TERRA, Integer.valueOf(character[COOLDOWN_GREEN_TERRA])); tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.GREEN_TERRA, COOLDOWN_GREEN_TERRA, username);
skillsDATS.put(SuperAbilityType.GIGA_DRILL_BREAKER, Integer.valueOf(character[COOLDOWN_GIGA_DRILL_BREAKER])); tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.GIGA_DRILL_BREAKER, COOLDOWN_GIGA_DRILL_BREAKER, username);
// Archery - Unused // Archery - Unused
skillsDATS.put(SuperAbilityType.SERRATED_STRIKES, Integer.valueOf(character[COOLDOWN_SERRATED_STRIKES])); tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SERRATED_STRIKES, COOLDOWN_SERRATED_STRIKES, username);
skillsDATS.put(SuperAbilityType.SKULL_SPLITTER, Integer.valueOf(character[COOLDOWN_SKULL_SPLITTER])); tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SKULL_SPLITTER, COOLDOWN_SKULL_SPLITTER, username);
// Acrobatics - Unused // Acrobatics - Unused
skillsDATS.put(SuperAbilityType.BLAST_MINING, Integer.valueOf(character[COOLDOWN_BLAST_MINING])); tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.BLAST_MINING, COOLDOWN_BLAST_MINING, username);
try { try {
mobHealthbarType = MobHealthbarType.valueOf(character[HEALTHBAR]); mobHealthbarType = MobHealthbarType.valueOf(character[HEALTHBAR]);
@ -1285,26 +1296,60 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
return new PlayerProfile(character[USERNAME_INDEX], uuid, skills, skillsXp, skillsDATS, mobHealthbarType, scoreboardTipsShown, uniquePlayerDataMap); return new PlayerProfile(character[USERNAME_INDEX], uuid, skills, skillsXp, skillsDATS, mobHealthbarType, scoreboardTipsShown, uniquePlayerDataMap);
} }
private Map<PrimarySkillType, Integer> getSkillMapFromLine(String[] character) { private void tryLoadSkillCooldownFromRawData(@NotNull Map<SuperAbilityType, Integer> cooldownMap, @NotNull String[] character, @NotNull SuperAbilityType superAbilityType, int cooldownSuperBreaker, @NotNull String userName) {
Map<PrimarySkillType, Integer> skills = new EnumMap<>(PrimarySkillType.class); // Skill & Level try {
cooldownMap.put(superAbilityType, Integer.valueOf(character[cooldownSuperBreaker]));
} catch (NumberFormatException e) {
mcMMO.p.getLogger().severe("Data corruption when trying to load the value for skill "+superAbilityType.toString()+" for player named " + userName+ " setting value to zero");
e.printStackTrace();
}
}
skills.put(PrimarySkillType.TAMING, Integer.valueOf(character[SKILLS_TAMING])); private void tryLoadSkillFloatValuesFromRawData(@NotNull Map<PrimarySkillType, Float> skillMap, @NotNull String[] character, @NotNull PrimarySkillType primarySkillType, int expTaming, @NotNull String userName) {
skills.put(PrimarySkillType.MINING, Integer.valueOf(character[SKILLS_MINING])); try {
skills.put(PrimarySkillType.REPAIR, Integer.valueOf(character[SKILLS_REPAIR])); float valueFromString = Integer.parseInt(character[expTaming]);
skills.put(PrimarySkillType.WOODCUTTING, Integer.valueOf(character[SKILLS_WOODCUTTING])); skillMap.put(primarySkillType, valueFromString);
skills.put(PrimarySkillType.UNARMED, Integer.valueOf(character[SKILLS_UNARMED])); } catch (NumberFormatException e) {
skills.put(PrimarySkillType.HERBALISM, Integer.valueOf(character[SKILLS_HERBALISM])); skillMap.put(primarySkillType, 0F);
skills.put(PrimarySkillType.EXCAVATION, Integer.valueOf(character[SKILLS_EXCAVATION])); mcMMO.p.getLogger().severe("Data corruption when trying to load the value for skill "+primarySkillType.toString()+" for player named " + userName+ " setting value to zero");
skills.put(PrimarySkillType.ARCHERY, Integer.valueOf(character[SKILLS_ARCHERY])); e.printStackTrace();
skills.put(PrimarySkillType.SWORDS, Integer.valueOf(character[SKILLS_SWORDS])); }
skills.put(PrimarySkillType.AXES, Integer.valueOf(character[SKILLS_AXES])); }
skills.put(PrimarySkillType.ACROBATICS, Integer.valueOf(character[SKILLS_ACROBATICS]));
skills.put(PrimarySkillType.FISHING, Integer.valueOf(character[SKILLS_FISHING])); private void tryLoadSkillIntValuesFromRawData(@NotNull Map<PrimarySkillType, Integer> skillMap, @NotNull String[] character, @NotNull PrimarySkillType primarySkillType, int expTaming, @NotNull String userName) {
skills.put(PrimarySkillType.ALCHEMY, Integer.valueOf(character[SKILLS_ALCHEMY])); try {
int valueFromString = Integer.parseInt(character[expTaming]);
skillMap.put(primarySkillType, valueFromString);
} catch (NumberFormatException e) {
skillMap.put(primarySkillType, 0);
mcMMO.p.getLogger().severe("Data corruption when trying to load the value for skill "+primarySkillType.toString()+" for player named " + userName+ " setting value to zero");
e.printStackTrace();
}
}
private @NotNull Map<PrimarySkillType, Integer> getSkillMapFromLine(@NotNull String[] character) {
Map<PrimarySkillType, Integer> skills = new EnumMap<>(PrimarySkillType.class); // Skill & Level
String username = character[USERNAME_INDEX];
tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.TAMING, SKILLS_TAMING, username);
tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.MINING, SKILLS_MINING, username);
tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.REPAIR, SKILLS_REPAIR, username);
tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.WOODCUTTING, SKILLS_WOODCUTTING, username);
tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.UNARMED, SKILLS_UNARMED, username);
tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.HERBALISM, SKILLS_HERBALISM, username);
tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.EXCAVATION, SKILLS_EXCAVATION, username);
tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ARCHERY, SKILLS_ARCHERY, username);
tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.SWORDS, SKILLS_SWORDS, username);
tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.AXES, SKILLS_AXES, username);
tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ACROBATICS, SKILLS_ACROBATICS, username);
tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.FISHING, SKILLS_FISHING, username);
tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ALCHEMY, SKILLS_ALCHEMY, username);
return skills; return skills;
} }
public DatabaseType getDatabaseType() { public DatabaseType getDatabaseType() {
return DatabaseType.FLATFILE; return DatabaseType.FLATFILE;
} }

View File

@ -2,14 +2,12 @@ package com.gmail.nossr50.party;
import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.Config;
import com.gmail.nossr50.datatypes.chat.ChatChannel; import com.gmail.nossr50.datatypes.chat.ChatChannel;
import com.gmail.nossr50.datatypes.database.UpgradeType;
import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.interactions.NotificationType;
import com.gmail.nossr50.datatypes.party.ItemShareType; import com.gmail.nossr50.datatypes.party.ItemShareType;
import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.party.Party;
import com.gmail.nossr50.datatypes.party.PartyLeader; import com.gmail.nossr50.datatypes.party.PartyLeader;
import com.gmail.nossr50.datatypes.party.ShareMode; import com.gmail.nossr50.datatypes.party.ShareMode;
import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.player.PlayerProfile;
import com.gmail.nossr50.events.party.McMMOPartyAllianceChangeEvent; import com.gmail.nossr50.events.party.McMMOPartyAllianceChangeEvent;
import com.gmail.nossr50.events.party.McMMOPartyChangeEvent; import com.gmail.nossr50.events.party.McMMOPartyChangeEvent;
import com.gmail.nossr50.events.party.McMMOPartyChangeEvent.EventReason; import com.gmail.nossr50.events.party.McMMOPartyChangeEvent.EventReason;

View File

@ -1,10 +1,9 @@
package com.gmail.nossr50.util.text; package com.gmail.nossr50.util.text;
import org.junit.Assert;
import org.junit.Test;
import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import org.junit.Assert;
import org.junit.Test;
/** /**
* This Unit Test checks if Adventure was set up correctly and works as expected. * This Unit Test checks if Adventure was set up correctly and works as expected.