diff --git a/Changelog.txt b/Changelog.txt index 310194a2f..45b3b08fa 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,15 +1,16 @@ Version 2.2.000 + TODO: More SQL unit tests + TODO: Test mysql/mariadb changes TODO: Trickshot: locale, multiple bounces, does not hurt yourself or allies, reduced damage per bounce? TODO: Add metadata cleanup unit tests TODO: Cleanup new arrow metadatas - TODO: SQL DB update - TODO: SQL unit tests TODO: com/gmail/nossr50/database/FlatFileDatabaseManager.java:109 reporting data entries that need correction on each launch TODO: Add Xbows/Tridents to salvage/repair TODO: Add unit test for combat XP values TODO: Add unit test to determine crossbow or bow skill TODO: Add unit test for trident xp processing TODO: Add missing entries to changelog + child.yml is gone now, its better this way Replaced 'Experience_Formula.Modifier' in experience.yml with 'Experience_Formula.Skill_Multiplier' which is easier to understand and less prone to divide by zero bugs (API) Many skills with RNG elements now send out a SubSkillEvent (which can be used to modify probability or cancel the results), some skills without RNG still send out this event when activated, this event is cancellable so it can be used to make a skill fail Treasure drop rate from Shake, Fishing, Hylian, and Excavation now benefit from the Luck perk diff --git a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java index f18cd18ca..37b895db9 100644 --- a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java +++ b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java @@ -9,7 +9,6 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.SkillTools; @@ -706,7 +705,7 @@ public final class ExperienceAPI { PrimarySkillType skill = getSkillType(skillType); if (SkillTools.isChildSkill(skill)) { - Set parentSkills = FamilyTree.getParents(skill); + var parentSkills = mcMMO.p.getSkillTools().getChildSkillParents(skill); for (PrimarySkillType parentSkill : parentSkills) { profile.addLevels(parentSkill, (levels / parentSkills.size())); @@ -737,7 +736,7 @@ public final class ExperienceAPI { PrimarySkillType skill = getSkillType(skillType); if (SkillTools.isChildSkill(skill)) { - Set parentSkills = FamilyTree.getParents(skill); + var parentSkills = mcMMO.p.getSkillTools().getChildSkillParents(skill); for (PrimarySkillType parentSkill : parentSkills) { profile.addLevels(parentSkill, (levels / parentSkills.size())); diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index 2f5a9c3ca..fac6a99ea 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -5,7 +5,6 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.NotificationManager; @@ -171,7 +170,7 @@ public abstract class SkillCommand implements TabExecutor { */ - Set parents = FamilyTree.getParents(skill); + var parents = mcMMO.p.getSkillTools().getChildSkillParents(skill); //TODO: Add JSON here /*player.sendMessage(parent.getName() + " - " + LocaleLoader.getString("Effects.Level.Overhaul", mcMMOPlayer.getSkillLevel(parent), mcMMOPlayer.getSkillXpLevel(parent), mcMMOPlayer.getXpToLevel(parent)))*/ diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index a2e85bf26..69dffb644 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -33,6 +33,7 @@ public final class SQLDatabaseManager implements DatabaseManager { public static final String USER_VARCHAR = "VARCHAR(40)"; public static final int CHILD_SKILLS_SIZE = 2; public static final String LEGACY_DRIVER_PATH = "com.mysql.jdbc.Driver"; + public static final int MAGIC_NUMBER = 44; private final String tablePrefix = mcMMO.p.getGeneralConfig().getMySQLTablePrefix(); private final Map cachedUserIDs = new HashMap<>(); @@ -128,6 +129,7 @@ public final class SQLDatabaseManager implements DatabaseManager { loadPool = new DataSource(poolProperties); checkStructure(); + } @NotNull @@ -151,6 +153,7 @@ public final class SQLDatabaseManager implements DatabaseManager { return connectionString; } + // TODO: unit tests public int purgePowerlessUsers() { massUpdateLock.lock(); logger.info("Purging powerless users..."); @@ -167,7 +170,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + "taming = 0 AND mining = 0 AND woodcutting = 0 AND repair = 0 " + "AND unarmed = 0 AND herbalism = 0 AND excavation = 0 AND " + "archery = 0 AND swords = 0 AND axes = 0 AND acrobatics = 0 " - + "AND fishing = 0 AND alchemy = 0;"); + + "AND fishing = 0 AND alchemy = 0 AND crossbows = 0 AND tridents = 0;"); statement.executeUpdate("DELETE FROM `" + tablePrefix + "experience` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "skills` `s` WHERE `" + tablePrefix + "experience`.`user_id` = `s`.`user_id`)"); statement.executeUpdate("DELETE FROM `" + tablePrefix + "huds` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "skills` `s` WHERE `" + tablePrefix + "huds`.`user_id` = `s`.`user_id`)"); @@ -564,15 +567,20 @@ public final class SQLDatabaseManager implements DatabaseManager { try { statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` " - + "SET user = ? " - + "WHERE user = ?"); + + "SET \"USER\" = ? " + + "WHERE \"USER\" = ?"); statement.setString(1, "_INVALID_OLD_USERNAME_"); statement.setString(2, playerName); statement.executeUpdate(); statement.close(); - statement = connection.prepareStatement("INSERT INTO " + tablePrefix + "users (user, uuid, lastlogin) VALUES (?, ?, UNIX_TIMESTAMP())", Statement.RETURN_GENERATED_KEYS); + + long currentTimeMillis = System.currentTimeMillis(); + + String sql = "INSERT INTO " + tablePrefix + "users (`user`, uuid, lastlogin) VALUES (?, ?, ?)"; + statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); statement.setString(1, playerName); statement.setString(2, uuid != null ? uuid.toString() : null); + statement.setLong(3, currentTimeMillis); statement.executeUpdate(); resultSet = statement.getGeneratedKeys(); @@ -640,17 +648,18 @@ public final class SQLDatabaseManager implements DatabaseManager { writeMissingRows(connection, id); statement = connection.prepareStatement( - "SELECT " - + "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, " - + "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, " - + "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, c.chimaera_wing, " - + "h.mobhealthbar, h.scoreboardtips, u.uuid, u.user " - + "FROM " + tablePrefix + "users u " - + "JOIN " + tablePrefix + "skills s ON (u.id = s.user_id) " - + "JOIN " + tablePrefix + "experience e ON (u.id = e.user_id) " - + "JOIN " + tablePrefix + "cooldowns c ON (u.id = c.user_id) " - + "JOIN " + tablePrefix + "huds h ON (u.id = h.user_id) " - + "WHERE u.id = ?"); + "SELECT " + + "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, S.CROSSBOWS, S.TRIDENTS, " + + "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, S.CROSSBOWS, S.TRIDENTS, " + + "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, C.CHIMAERA_WING, C.CROSSBOWS, C.TRIDENTS, " + + "H.MOBHEALTHBAR, H.SCOREBOARDTIPS, U.UUID, U.\"USER\" " + + "FROM " + tablePrefix + "USERS U " + + "JOIN " + tablePrefix + "SKILLS S ON U.ID = S.USER_ID " + + "JOIN " + tablePrefix + "EXPERIENCE E ON U.ID = E.USER_ID " + + "JOIN " + tablePrefix + "COOLDOWNS C ON U.ID = C.USER_ID " + + "JOIN " + tablePrefix + "HUDS H ON U.ID = H.USER_ID " + + "WHERE U.ID = ?" + ); statement.setInt(1, id); resultSet = statement.executeQuery(); @@ -658,7 +667,7 @@ public final class SQLDatabaseManager implements DatabaseManager { if (resultSet.next()) { try { PlayerProfile profile = loadFromResult(playerName, resultSet); - String name = resultSet.getString(42); // TODO: Magic Number, make sure it stays updated + String name = resultSet.getString(MAGIC_NUMBER); // TODO: Magic Number, make sure it stays updated resultSet.close(); statement.close(); @@ -668,15 +677,15 @@ public final class SQLDatabaseManager implements DatabaseManager { && uuid != null) { statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` " - + "SET user = ? " - + "WHERE user = ?"); + + "SET \"USER\" = ? " + + "WHERE \"USER\" = ?"); statement.setString(1, "_INVALID_OLD_USERNAME_"); statement.setString(2, name); statement.executeUpdate(); statement.close(); statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` " - + "SET user = ?, uuid = ? " + + "SET \"USER\" = ?, uuid = ? " + "WHERE id = ?"); statement.setString(1, playerName); statement.setString(2, uuid.toString()); @@ -913,6 +922,8 @@ public final class SQLDatabaseManager implements DatabaseManager { + "`acrobatics` int(32) unsigned NOT NULL DEFAULT '0'," + "`blast_mining` int(32) unsigned NOT NULL DEFAULT '0'," + "`chimaera_wing` int(32) unsigned NOT NULL DEFAULT '0'," + + "`crossbows` int(32) unsigned NOT NULL DEFAULT '0'," + + "`tridents` int(32) unsigned NOT NULL DEFAULT '0'," + "PRIMARY KEY (`user_id`)) " + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); tryClose(createStatement); @@ -939,6 +950,8 @@ public final class SQLDatabaseManager implements DatabaseManager { + "`acrobatics` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + "`fishing` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + "`alchemy` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + + "`crossbows` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + + "`tridents` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + "`total` int(10) unsigned NOT NULL DEFAULT "+totalLevel+"," + "PRIMARY KEY (`user_id`)) " + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); @@ -964,6 +977,8 @@ public final class SQLDatabaseManager implements DatabaseManager { + "`acrobatics` int(10) unsigned NOT NULL DEFAULT '0'," + "`fishing` int(10) unsigned NOT NULL DEFAULT '0'," + "`alchemy` int(10) unsigned NOT NULL DEFAULT '0'," + + "`crossbows` int(10) unsigned NOT NULL DEFAULT '0'," + + "`tridents` int(10) unsigned NOT NULL DEFAULT '0'," + "PRIMARY KEY (`user_id`)) " + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); tryClose(createStatement); @@ -986,7 +1001,8 @@ public final class SQLDatabaseManager implements DatabaseManager { } } - logger.info("Killing orphans"); + // TODO: refactor + LogUtils.debug(logger, "Killing orphans"); createStatement = connection.createStatement(); createStatement.executeUpdate("DELETE FROM `" + tablePrefix + "experience` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "users` `u` WHERE `" + tablePrefix + "experience`.`user_id` = `u`.`id`)"); createStatement.executeUpdate("DELETE FROM `" + tablePrefix + "huds` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "users` `u` WHERE `" + tablePrefix + "huds`.`user_id` = `u`.`id`)"); @@ -1016,7 +1032,7 @@ public final class SQLDatabaseManager implements DatabaseManager { } } - Connection getConnection(PoolIdentifier identifier) throws SQLException { + protected Connection getConnection(PoolIdentifier identifier) throws SQLException { Connection connection = null; switch (identifier) { case LOAD: @@ -1161,9 +1177,9 @@ public final class SQLDatabaseManager implements DatabaseManager { final int OFFSET_SKILLS = 0; // TODO update these numbers when the query // changes (a new skill is added) - final int OFFSET_XP = 13; - final int OFFSET_DATS = 26; - final int OFFSET_OTHER = 39; + final int OFFSET_XP = 15; + final int OFFSET_DATS = 28; + final int OFFSET_OTHER = 41; skills.put(PrimarySkillType.TAMING, result.getInt(OFFSET_SKILLS + 1)); skills.put(PrimarySkillType.MINING, result.getInt(OFFSET_SKILLS + 2)); @@ -1178,6 +1194,8 @@ public final class SQLDatabaseManager implements DatabaseManager { skills.put(PrimarySkillType.ACROBATICS, result.getInt(OFFSET_SKILLS + 11)); skills.put(PrimarySkillType.FISHING, result.getInt(OFFSET_SKILLS + 12)); skills.put(PrimarySkillType.ALCHEMY, result.getInt(OFFSET_SKILLS + 13)); + skills.put(PrimarySkillType.CROSSBOWS, result.getInt(OFFSET_SKILLS + 14)); + skills.put(PrimarySkillType.TRIDENTS, result.getInt(OFFSET_SKILLS + 15)); skillsXp.put(PrimarySkillType.TAMING, result.getFloat(OFFSET_XP + 1)); skillsXp.put(PrimarySkillType.MINING, result.getFloat(OFFSET_XP + 2)); @@ -1192,6 +1210,8 @@ public final class SQLDatabaseManager implements DatabaseManager { skillsXp.put(PrimarySkillType.ACROBATICS, result.getFloat(OFFSET_XP + 11)); skillsXp.put(PrimarySkillType.FISHING, result.getFloat(OFFSET_XP + 12)); skillsXp.put(PrimarySkillType.ALCHEMY, result.getFloat(OFFSET_XP + 13)); + skillsXp.put(PrimarySkillType.ALCHEMY, result.getFloat(OFFSET_XP + 14)); + skillsXp.put(PrimarySkillType.ALCHEMY, result.getFloat(OFFSET_XP + 15)); // Taming - Unused - result.getInt(OFFSET_DATS + 1) skillsDATS.put(SuperAbilityType.SUPER_BREAKER, result.getInt(OFFSET_DATS + 2)); @@ -1206,6 +1226,8 @@ public final class SQLDatabaseManager implements DatabaseManager { // Acrobatics - Unused - result.getInt(OFFSET_DATS + 11) skillsDATS.put(SuperAbilityType.BLAST_MINING, result.getInt(OFFSET_DATS + 12)); uniqueData.put(UniqueDataType.CHIMAERA_WING_DATS, result.getInt(OFFSET_DATS + 13)); + skillsDATS.put(SuperAbilityType.SUPER_SHOTGUN, result.getInt(OFFSET_DATS + 14)); + skillsDATS.put(SuperAbilityType.TRIDENTS_SUPER_ABILITY, result.getInt(OFFSET_DATS + 15)); try { scoreboardTipsShown = result.getInt(OFFSET_OTHER + 2); @@ -1709,4 +1731,28 @@ public final class SQLDatabaseManager implements DatabaseManager { " CHARACTER SET utf8mb4\n" + " COLLATE utf8mb4_unicode_ci;"; } + + public void printAllTablesWithColumns(Connection connection) { + try { + DatabaseMetaData metaData = connection.getMetaData(); + String[] types = {"TABLE"}; + ResultSet tables = metaData.getTables(null, null, "%", types); + + while (tables.next()) { + String tableName = tables.getString("TABLE_NAME"); + System.out.println("Table: " + tableName); + + ResultSet columns = metaData.getColumns(null, null, tableName, "%"); + while (columns.next()) { + String columnName = columns.getString("COLUMN_NAME"); + String columnType = columns.getString("TYPE_NAME"); + System.out.println(" Column: " + columnName + " Type: " + columnType); + } + columns.close(); + } + tables.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index 59c918a1e..a89e9bab0 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -30,7 +30,6 @@ import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager; import com.gmail.nossr50.skills.alchemy.AlchemyManager; import com.gmail.nossr50.skills.archery.ArcheryManager; import com.gmail.nossr50.skills.axes.AxesManager; -import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.skills.crossbows.CrossbowsManager; import com.gmail.nossr50.skills.excavation.ExcavationManager; import com.gmail.nossr50.skills.fishing.FishingManager; @@ -618,7 +617,7 @@ public class McMMOPlayer implements Identified { } if (SkillTools.isChildSkill(skill)) { - Set parentSkills = FamilyTree.getParents(skill); + var parentSkills = mcMMO.p.getSkillTools().getChildSkillParents(skill); float splitXp = xp / parentSkills.size(); for (PrimarySkillType parentSkill : parentSkills) { @@ -675,7 +674,7 @@ public class McMMOPlayer implements Identified { xp = mcMMOPlayerPreXpGainEvent.getXpGained(); if (SkillTools.isChildSkill(primarySkillType)) { - Set parentSkills = FamilyTree.getParents(primarySkillType); + var parentSkills = mcMMO.p.getSkillTools().getChildSkillParents(primarySkillType); for (PrimarySkillType parentSkill : parentSkills) { applyXpGain(parentSkill, xp / parentSkills.size(), xpGainReason, xpGainSource); diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java index 65ebf4c85..74c15a27d 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java @@ -7,9 +7,9 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.player.PlayerProfileSaveTask; -import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.SkillTools; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -363,7 +363,7 @@ public class PlayerProfile { markProfileDirty(); if (SkillTools.isChildSkill(skill)) { - Set parentSkills = FamilyTree.getParents(skill); + var parentSkills = mcMMO.p.getSkillTools().getChildSkillParents(skill); float dividedXP = (xp / parentSkills.size()); for (PrimarySkillType parentSkill : parentSkills) { @@ -431,8 +431,12 @@ public class PlayerProfile { return mcMMO.getFormulaManager().getXPtoNextLevel(level, formulaType); } - private int getChildSkillLevel(PrimarySkillType primarySkillType) { - Set parents = FamilyTree.getParents(primarySkillType); + private int getChildSkillLevel(@NotNull PrimarySkillType primarySkillType) throws IllegalArgumentException { + if (!SkillTools.isChildSkill(primarySkillType)) { + throw new IllegalArgumentException(primarySkillType + " is not a child skill!"); + } + + ImmutableList parents = mcMMO.p.getSkillTools().getChildSkillParents(primarySkillType); int sum = 0; for (PrimarySkillType parent : parents) { diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index 0b06663bc..2cacfa3c7 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -30,7 +30,6 @@ import com.gmail.nossr50.runnables.player.ClearRegisteredXPGainTask; import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask; import com.gmail.nossr50.runnables.player.PowerLevelUpdatingTask; import com.gmail.nossr50.skills.alchemy.Alchemy; -import com.gmail.nossr50.skills.child.ChildConfig; import com.gmail.nossr50.skills.repair.repairables.Repairable; import com.gmail.nossr50.skills.repair.repairables.RepairableManager; import com.gmail.nossr50.skills.repair.repairables.SimpleRepairableManager; @@ -563,8 +562,6 @@ public class mcMMO extends JavaPlugin { SoundConfig.getInstance(); RankConfig.getInstance(); - new ChildConfig(); - List repairables = new ArrayList<>(); if (generalConfig.getToolModsEnabled()) { diff --git a/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java b/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java deleted file mode 100644 index 0e200bafa..000000000 --- a/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.gmail.nossr50.skills.child; - -import com.gmail.nossr50.config.BukkitConfig; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.LogUtils; -import com.gmail.nossr50.util.text.StringUtils; -import org.bukkit.configuration.file.YamlConfiguration; - -import java.util.EnumSet; -import java.util.Locale; - -public class ChildConfig extends BukkitConfig { - public ChildConfig() { - super("child.yml"); - loadKeys(); - } - - @Override - protected void loadKeys() { - config.setDefaults(YamlConfiguration.loadConfiguration(mcMMO.p.getResourceAsReader("child.yml"))); - - FamilyTree.clearRegistrations(); // when reloading, need to clear statics - - for (PrimarySkillType skill : mcMMO.p.getSkillTools().CHILD_SKILLS) { - LogUtils.debug(mcMMO.p.getLogger(), "Finding parents of " + skill.name()); - - EnumSet parentSkills = EnumSet.noneOf(PrimarySkillType.class); - boolean useDefaults = false; // If we had an error we back out and use defaults - - for (String name : config.getStringList(StringUtils.getCapitalized(skill.name()))) { - try { - PrimarySkillType parentSkill = PrimarySkillType.valueOf(name.toUpperCase(Locale.ENGLISH)); - FamilyTree.enforceNotChildSkill(parentSkill); - parentSkills.add(parentSkill); - } - catch (IllegalArgumentException ex) { - mcMMO.p.getLogger().warning(name + " is not a valid skill type, or is a child skill!"); - useDefaults = true; - break; - } - } - - if (useDefaults) { - parentSkills.clear(); - for (String name : config.getDefaults().getStringList(StringUtils.getCapitalized(skill.name()))) { - /* We do less checks in here because it's from inside our jar. - * If they're dedicated enough to have modified it, they can have the errors it may produce. - * Alternatively, this can be used to allow child skills to be parent skills, provided there are no circular dependencies this is an advanced sort of configuration. - */ - parentSkills.add(PrimarySkillType.valueOf(name.toUpperCase(Locale.ENGLISH))); - } - } - - // Register them - for (PrimarySkillType parentSkill : parentSkills) { - LogUtils.debug(mcMMO.p.getLogger(), "Registering " + parentSkill.name() + " as parent of " + skill.name()); - FamilyTree.registerParent(skill, parentSkill); - } - } - - FamilyTree.closeRegistration(); - } -} diff --git a/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java b/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java deleted file mode 100644 index 0be533600..000000000 --- a/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.gmail.nossr50.skills.child; - -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import com.gmail.nossr50.util.skills.SkillTools; - -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Set; - -public class FamilyTree { - private static final HashMap> tree = new HashMap<>(); - - public static Set getParents(PrimarySkillType childSkill) { - enforceChildSkill(childSkill); - - // We do not check if we have the child skill in question, as not having it would mean we did something wrong, and an NPE is desired. - return tree.get(childSkill); - } - - protected static void registerParent(PrimarySkillType childSkill, PrimarySkillType parentSkill) { - enforceChildSkill(childSkill); - enforceNotChildSkill(parentSkill); - - if (!tree.containsKey(childSkill)) { - tree.put(childSkill, EnumSet.noneOf(PrimarySkillType.class)); - } - - tree.get(childSkill).add(parentSkill); - } - - protected static void closeRegistration() { - for (PrimarySkillType childSkill : tree.keySet()) { - Set immutableSet = Collections.unmodifiableSet(tree.get(childSkill)); - tree.put(childSkill, immutableSet); - } - } - - protected static void clearRegistrations() { - tree.clear(); - } - - protected static void enforceChildSkill(PrimarySkillType skill) { - if (!SkillTools.isChildSkill(skill)) { - throw new IllegalArgumentException(skill.name() + " is not a child skill!"); - } - } - - protected static void enforceNotChildSkill(PrimarySkillType skill) { - if (SkillTools.isChildSkill(skill)) { - throw new IllegalArgumentException(skill.name() + " is a child skill!"); - } - } -} diff --git a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java index 1237ce086..4d2d51560 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java @@ -11,7 +11,6 @@ import com.gmail.nossr50.events.scoreboard.ScoreboardEventReason; import com.gmail.nossr50.events.scoreboard.ScoreboardObjectiveEventReason; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.util.LogUtils; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.player.NotificationManager; @@ -495,7 +494,7 @@ public class ScoreboardWrapper { sidebarObjective.getScore(ScoreboardManager.LABEL_REMAINING_XP).setScore(mcMMOPlayer.getXpToLevel(targetSkill) - currentXP); } else { - for (PrimarySkillType parentSkill : FamilyTree.getParents(targetSkill)) { + for (PrimarySkillType parentSkill : mcMMO.p.getSkillTools().getChildSkillParents(targetSkill)) { sidebarObjective.getScore(ScoreboardManager.skillLabels.get(parentSkill)).setScore(mcMMOPlayer.getSkillLevel(parentSkill)); } } diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java index 6329b3934..985f93bce 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java @@ -30,6 +30,8 @@ public class SkillTools { public final @NotNull ImmutableSet EXACT_SUBSKILL_NAMES; public final @NotNull ImmutableList CHILD_SKILLS; public final static @NotNull ImmutableList NON_CHILD_SKILLS; + public final static @NotNull ImmutableList SALVAGE_PARENTS; + public final static @NotNull ImmutableList SMELTING_PARENTS; public final @NotNull ImmutableList COMBAT_SKILLS; public final @NotNull ImmutableList GATHERING_SKILLS; public final @NotNull ImmutableList MISC_SKILLS; @@ -50,6 +52,8 @@ public class SkillTools { } NON_CHILD_SKILLS = ImmutableList.copyOf(tempNonChildSkills); + SALVAGE_PARENTS = ImmutableList.of(PrimarySkillType.REPAIR, PrimarySkillType.FISHING); + SMELTING_PARENTS = ImmutableList.of(PrimarySkillType.MINING, PrimarySkillType.REPAIR); } public SkillTools(@NotNull mcMMO pluginRef) throws InvalidSkillException { @@ -140,18 +144,13 @@ public class SkillTools { */ List childSkills = new ArrayList<>(); -// List nonChildSkills = new ArrayList<>(); for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { if (isChildSkill(primarySkillType)) childSkills.add(primarySkillType); -// } { -// nonChildSkills.add(primarySkillType); -// } } CHILD_SKILLS = ImmutableList.copyOf(childSkills); -// NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills); /* * Build categorized skill lists @@ -329,7 +328,6 @@ public class SkillTools { } public Set getSubSkills(PrimarySkillType primarySkillType) { - //TODO: Cache this! return primarySkillChildrenMap.get(primarySkillType); } @@ -429,4 +427,17 @@ public class SkillTools { public @NotNull ImmutableList getMiscSkills() { return MISC_SKILLS; } + + public @NotNull ImmutableList getChildSkillParents(PrimarySkillType childSkill) + throws IllegalArgumentException { + switch (childSkill) { + case SALVAGE -> { + return SALVAGE_PARENTS; + } + case SMELTING -> { + return SMELTING_PARENTS; + } + default -> throw new IllegalArgumentException("Skill " + childSkill + " is not a child skill"); + } + } } diff --git a/src/main/resources/child.yml b/src/main/resources/child.yml deleted file mode 100644 index 685a6ce71..000000000 --- a/src/main/resources/child.yml +++ /dev/null @@ -1,16 +0,0 @@ -# -# mcMMO child skill configuration -# Last updated on ${project.version}-b${BUILD_NUMBER} -# -# You do not need to modify this file except to change parents of child skills -# -# If you wish a child skill to be the parent of another child skill, you must also make your changes to the child.yml within the jar -# WARNING: THIS IS NOT SUPPORTED, IF YOU DO SO YOU ARE RESPONSIBLE FOR THE ISSUES THAT MAY ARISE. That said, watch out for circular dependencies, those are bad. -# -##### -Salvage: - - Fishing - - Repair -Smelting: - - Mining - - Repair \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java index 8240ba3e2..d70332321 100644 --- a/src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java @@ -2,22 +2,27 @@ package com.gmail.nossr50.database; import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.config.GeneralConfig; +import com.gmail.nossr50.datatypes.MobHealthbarType; +import com.gmail.nossr50.datatypes.database.UpgradeType; +import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.LogUtils; import com.gmail.nossr50.util.compat.CompatibilityManager; import com.gmail.nossr50.util.platform.MinecraftGameVersion; import com.gmail.nossr50.util.platform.version.SimpleNumericVersion; +import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.util.upgrade.UpgradeManager; import org.bukkit.Material; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; import org.mockito.MockedStatic; import org.mockito.Mockito; +import java.sql.*; +import java.util.Locale; +import java.util.Set; import java.util.logging.Logger; import static org.junit.jupiter.api.Assertions.*; @@ -32,6 +37,7 @@ class SQLDatabaseManagerTest { static AdvancedConfig advancedConfig; static UpgradeManager upgradeManager; static CompatibilityManager compatibilityManager; + static SkillTools skillTools; @BeforeAll static void setUpAll() { @@ -50,6 +56,10 @@ class SQLDatabaseManagerTest { // starting level when(mcMMO.p.getAdvancedConfig().getStartingLevel()).thenReturn(0); + // wire skill tools + skillTools = new SkillTools(mcMMO.p); + when(mcMMO.p.getSkillTools()).thenReturn(skillTools); + // compatibility manager mock compatibilityManager = Mockito.mock(CompatibilityManager.class); when(mcMMO.getCompatibilityManager()).thenReturn(compatibilityManager); @@ -107,6 +117,9 @@ class SQLDatabaseManagerTest { // host when(mcMMO.p.getGeneralConfig().getMySQLServerName()).thenReturn("localhost"); + + // unused mob health bar thingy + when(mcMMO.p.getGeneralConfig().getMobHealthbarDefault()).thenReturn(MobHealthbarType.HEARTS); } @BeforeEach @@ -120,6 +133,11 @@ class SQLDatabaseManagerTest { sqlDatabaseManager = null; } + @AfterAll + static void tearDownAll() { + mockedMcMMO.close(); + } + @Test void testGetConnectionMisc() throws Exception { assertNotNull(sqlDatabaseManager.getConnection(SQLDatabaseManager.PoolIdentifier.MISC)); @@ -142,4 +160,16 @@ class SQLDatabaseManagerTest { when(player.getName()).thenReturn("nossr50"); sqlDatabaseManager.newUser(player); } -} \ No newline at end of file + + @Test + void testNewUserGetSkillLevel() { + Player player = Mockito.mock(Player.class); + when(player.getUniqueId()).thenReturn(java.util.UUID.randomUUID()); + when(player.getName()).thenReturn("nossr50"); + PlayerProfile playerProfile = sqlDatabaseManager.newUser(player); + + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { + assertEquals(0, playerProfile.getSkillLevel(primarySkillType)); + } + } +}