kill child.yml and more work on sql unit tests

This commit is contained in:
nossr50 2023-12-27 22:52:51 -08:00
parent b0efd46584
commit a941a1cc7f
13 changed files with 139 additions and 188 deletions

View File

@ -1,15 +1,16 @@
Version 2.2.000 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: Trickshot: locale, multiple bounces, does not hurt yourself or allies, reduced damage per bounce?
TODO: Add metadata cleanup unit tests TODO: Add metadata cleanup unit tests
TODO: Cleanup new arrow metadatas 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: 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 Xbows/Tridents to salvage/repair
TODO: Add unit test for combat XP values TODO: Add unit test for combat XP values
TODO: Add unit test to determine crossbow or bow skill TODO: Add unit test to determine crossbow or bow skill
TODO: Add unit test for trident xp processing TODO: Add unit test for trident xp processing
TODO: Add missing entries to changelog 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 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 (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 Treasure drop rate from Shake, Fishing, Hylian, and Excavation now benefit from the Luck perk

View File

@ -9,7 +9,6 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.player.PlayerProfile;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.child.FamilyTree;
import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.CombatUtils;
import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.util.skills.SkillTools;
@ -706,7 +705,7 @@ public final class ExperienceAPI {
PrimarySkillType skill = getSkillType(skillType); PrimarySkillType skill = getSkillType(skillType);
if (SkillTools.isChildSkill(skill)) { if (SkillTools.isChildSkill(skill)) {
Set<PrimarySkillType> parentSkills = FamilyTree.getParents(skill); var parentSkills = mcMMO.p.getSkillTools().getChildSkillParents(skill);
for (PrimarySkillType parentSkill : parentSkills) { for (PrimarySkillType parentSkill : parentSkills) {
profile.addLevels(parentSkill, (levels / parentSkills.size())); profile.addLevels(parentSkill, (levels / parentSkills.size()));
@ -737,7 +736,7 @@ public final class ExperienceAPI {
PrimarySkillType skill = getSkillType(skillType); PrimarySkillType skill = getSkillType(skillType);
if (SkillTools.isChildSkill(skill)) { if (SkillTools.isChildSkill(skill)) {
Set<PrimarySkillType> parentSkills = FamilyTree.getParents(skill); var parentSkills = mcMMO.p.getSkillTools().getChildSkillParents(skill);
for (PrimarySkillType parentSkill : parentSkills) { for (PrimarySkillType parentSkill : parentSkills) {
profile.addLevels(parentSkill, (levels / parentSkills.size())); profile.addLevels(parentSkill, (levels / parentSkills.size()));

View File

@ -5,7 +5,6 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.child.FamilyTree;
import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.commands.CommandUtils;
import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.NotificationManager;
@ -171,7 +170,7 @@ public abstract class SkillCommand implements TabExecutor {
*/ */
Set<PrimarySkillType> parents = FamilyTree.getParents(skill); var parents = mcMMO.p.getSkillTools().getChildSkillParents(skill);
//TODO: Add JSON here //TODO: Add JSON here
/*player.sendMessage(parent.getName() + " - " + LocaleLoader.getString("Effects.Level.Overhaul", mcMMOPlayer.getSkillLevel(parent), mcMMOPlayer.getSkillXpLevel(parent), mcMMOPlayer.getXpToLevel(parent)))*/ /*player.sendMessage(parent.getName() + " - " + LocaleLoader.getString("Effects.Level.Overhaul", mcMMOPlayer.getSkillLevel(parent), mcMMOPlayer.getSkillXpLevel(parent), mcMMOPlayer.getXpToLevel(parent)))*/

View File

@ -33,6 +33,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
public static final String USER_VARCHAR = "VARCHAR(40)"; public static final String USER_VARCHAR = "VARCHAR(40)";
public static final int CHILD_SKILLS_SIZE = 2; public static final int CHILD_SKILLS_SIZE = 2;
public static final String LEGACY_DRIVER_PATH = "com.mysql.jdbc.Driver"; 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 String tablePrefix = mcMMO.p.getGeneralConfig().getMySQLTablePrefix();
private final Map<UUID, Integer> cachedUserIDs = new HashMap<>(); private final Map<UUID, Integer> cachedUserIDs = new HashMap<>();
@ -128,6 +129,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
loadPool = new DataSource(poolProperties); loadPool = new DataSource(poolProperties);
checkStructure(); checkStructure();
} }
@NotNull @NotNull
@ -151,6 +153,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
return connectionString; return connectionString;
} }
// TODO: unit tests
public int purgePowerlessUsers() { public int purgePowerlessUsers() {
massUpdateLock.lock(); massUpdateLock.lock();
logger.info("Purging powerless users..."); 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 " + "taming = 0 AND mining = 0 AND woodcutting = 0 AND repair = 0 "
+ "AND unarmed = 0 AND herbalism = 0 AND excavation = 0 AND " + "AND unarmed = 0 AND herbalism = 0 AND excavation = 0 AND "
+ "archery = 0 AND swords = 0 AND axes = 0 AND acrobatics = 0 " + "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 + "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`)"); 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 { try {
statement = connection.prepareStatement( statement = connection.prepareStatement(
"UPDATE `" + tablePrefix + "users` " "UPDATE `" + tablePrefix + "users` "
+ "SET user = ? " + "SET \"USER\" = ? "
+ "WHERE user = ?"); + "WHERE \"USER\" = ?");
statement.setString(1, "_INVALID_OLD_USERNAME_"); statement.setString(1, "_INVALID_OLD_USERNAME_");
statement.setString(2, playerName); statement.setString(2, playerName);
statement.executeUpdate(); statement.executeUpdate();
statement.close(); 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(1, playerName);
statement.setString(2, uuid != null ? uuid.toString() : null); statement.setString(2, uuid != null ? uuid.toString() : null);
statement.setLong(3, currentTimeMillis);
statement.executeUpdate(); statement.executeUpdate();
resultSet = statement.getGeneratedKeys(); resultSet = statement.getGeneratedKeys();
@ -640,17 +648,18 @@ public final class SQLDatabaseManager implements DatabaseManager {
writeMissingRows(connection, id); writeMissingRows(connection, id);
statement = connection.prepareStatement( statement = connection.prepareStatement(
"SELECT " "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.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, " "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.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 " "H.MOBHEALTHBAR, H.SCOREBOARDTIPS, U.UUID, U.\"USER\" " +
+ "FROM " + tablePrefix + "users u " "FROM " + tablePrefix + "USERS U " +
+ "JOIN " + tablePrefix + "skills s ON (u.id = s.user_id) " "JOIN " + tablePrefix + "SKILLS S ON U.ID = S.USER_ID " +
+ "JOIN " + tablePrefix + "experience e ON (u.id = e.user_id) " "JOIN " + tablePrefix + "EXPERIENCE E ON U.ID = E.USER_ID " +
+ "JOIN " + tablePrefix + "cooldowns c ON (u.id = c.user_id) " "JOIN " + tablePrefix + "COOLDOWNS C ON U.ID = C.USER_ID " +
+ "JOIN " + tablePrefix + "huds h ON (u.id = h.user_id) " "JOIN " + tablePrefix + "HUDS H ON U.ID = H.USER_ID " +
+ "WHERE u.id = ?"); "WHERE U.ID = ?"
);
statement.setInt(1, id); statement.setInt(1, id);
resultSet = statement.executeQuery(); resultSet = statement.executeQuery();
@ -658,7 +667,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
if (resultSet.next()) { if (resultSet.next()) {
try { try {
PlayerProfile profile = loadFromResult(playerName, resultSet); 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(); resultSet.close();
statement.close(); statement.close();
@ -668,15 +677,15 @@ public final class SQLDatabaseManager implements DatabaseManager {
&& uuid != null) { && uuid != null) {
statement = connection.prepareStatement( statement = connection.prepareStatement(
"UPDATE `" + tablePrefix + "users` " "UPDATE `" + tablePrefix + "users` "
+ "SET user = ? " + "SET \"USER\" = ? "
+ "WHERE user = ?"); + "WHERE \"USER\" = ?");
statement.setString(1, "_INVALID_OLD_USERNAME_"); statement.setString(1, "_INVALID_OLD_USERNAME_");
statement.setString(2, name); statement.setString(2, name);
statement.executeUpdate(); statement.executeUpdate();
statement.close(); statement.close();
statement = connection.prepareStatement( statement = connection.prepareStatement(
"UPDATE `" + tablePrefix + "users` " "UPDATE `" + tablePrefix + "users` "
+ "SET user = ?, uuid = ? " + "SET \"USER\" = ?, uuid = ? "
+ "WHERE id = ?"); + "WHERE id = ?");
statement.setString(1, playerName); statement.setString(1, playerName);
statement.setString(2, uuid.toString()); statement.setString(2, uuid.toString());
@ -913,6 +922,8 @@ public final class SQLDatabaseManager implements DatabaseManager {
+ "`acrobatics` int(32) unsigned NOT NULL DEFAULT '0'," + "`acrobatics` int(32) unsigned NOT NULL DEFAULT '0',"
+ "`blast_mining` 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'," + "`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`)) " + "PRIMARY KEY (`user_id`)) "
+ "DEFAULT CHARSET=" + CHARSET_SQL + ";"); + "DEFAULT CHARSET=" + CHARSET_SQL + ";");
tryClose(createStatement); tryClose(createStatement);
@ -939,6 +950,8 @@ public final class SQLDatabaseManager implements DatabaseManager {
+ "`acrobatics` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + "`acrobatics` int(10) unsigned NOT NULL DEFAULT "+startingLevel+","
+ "`fishing` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + "`fishing` int(10) unsigned NOT NULL DEFAULT "+startingLevel+","
+ "`alchemy` 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+"," + "`total` int(10) unsigned NOT NULL DEFAULT "+totalLevel+","
+ "PRIMARY KEY (`user_id`)) " + "PRIMARY KEY (`user_id`)) "
+ "DEFAULT CHARSET=" + CHARSET_SQL + ";"); + "DEFAULT CHARSET=" + CHARSET_SQL + ";");
@ -964,6 +977,8 @@ public final class SQLDatabaseManager implements DatabaseManager {
+ "`acrobatics` int(10) unsigned NOT NULL DEFAULT '0'," + "`acrobatics` int(10) unsigned NOT NULL DEFAULT '0',"
+ "`fishing` int(10) unsigned NOT NULL DEFAULT '0'," + "`fishing` int(10) unsigned NOT NULL DEFAULT '0',"
+ "`alchemy` 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`)) " + "PRIMARY KEY (`user_id`)) "
+ "DEFAULT CHARSET=" + CHARSET_SQL + ";"); + "DEFAULT CHARSET=" + CHARSET_SQL + ";");
tryClose(createStatement); 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 = 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 + "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`)"); 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; Connection connection = null;
switch (identifier) { switch (identifier) {
case LOAD: case LOAD:
@ -1161,9 +1177,9 @@ public final class SQLDatabaseManager implements DatabaseManager {
final int OFFSET_SKILLS = 0; // TODO update these numbers when the query final int OFFSET_SKILLS = 0; // TODO update these numbers when the query
// changes (a new skill is added) // changes (a new skill is added)
final int OFFSET_XP = 13; final int OFFSET_XP = 15;
final int OFFSET_DATS = 26; final int OFFSET_DATS = 28;
final int OFFSET_OTHER = 39; final int OFFSET_OTHER = 41;
skills.put(PrimarySkillType.TAMING, result.getInt(OFFSET_SKILLS + 1)); skills.put(PrimarySkillType.TAMING, result.getInt(OFFSET_SKILLS + 1));
skills.put(PrimarySkillType.MINING, result.getInt(OFFSET_SKILLS + 2)); 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.ACROBATICS, result.getInt(OFFSET_SKILLS + 11));
skills.put(PrimarySkillType.FISHING, result.getInt(OFFSET_SKILLS + 12)); skills.put(PrimarySkillType.FISHING, result.getInt(OFFSET_SKILLS + 12));
skills.put(PrimarySkillType.ALCHEMY, result.getInt(OFFSET_SKILLS + 13)); 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.TAMING, result.getFloat(OFFSET_XP + 1));
skillsXp.put(PrimarySkillType.MINING, result.getFloat(OFFSET_XP + 2)); 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.ACROBATICS, result.getFloat(OFFSET_XP + 11));
skillsXp.put(PrimarySkillType.FISHING, result.getFloat(OFFSET_XP + 12)); 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 + 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) // Taming - Unused - result.getInt(OFFSET_DATS + 1)
skillsDATS.put(SuperAbilityType.SUPER_BREAKER, result.getInt(OFFSET_DATS + 2)); 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) // Acrobatics - Unused - result.getInt(OFFSET_DATS + 11)
skillsDATS.put(SuperAbilityType.BLAST_MINING, result.getInt(OFFSET_DATS + 12)); skillsDATS.put(SuperAbilityType.BLAST_MINING, result.getInt(OFFSET_DATS + 12));
uniqueData.put(UniqueDataType.CHIMAERA_WING_DATS, result.getInt(OFFSET_DATS + 13)); 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 { try {
scoreboardTipsShown = result.getInt(OFFSET_OTHER + 2); scoreboardTipsShown = result.getInt(OFFSET_OTHER + 2);
@ -1709,4 +1731,28 @@ public final class SQLDatabaseManager implements DatabaseManager {
" CHARACTER SET utf8mb4\n" + " CHARACTER SET utf8mb4\n" +
" COLLATE utf8mb4_unicode_ci;"; " 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();
}
}
} }

View File

@ -30,7 +30,6 @@ import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager;
import com.gmail.nossr50.skills.alchemy.AlchemyManager; import com.gmail.nossr50.skills.alchemy.AlchemyManager;
import com.gmail.nossr50.skills.archery.ArcheryManager; import com.gmail.nossr50.skills.archery.ArcheryManager;
import com.gmail.nossr50.skills.axes.AxesManager; 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.crossbows.CrossbowsManager;
import com.gmail.nossr50.skills.excavation.ExcavationManager; import com.gmail.nossr50.skills.excavation.ExcavationManager;
import com.gmail.nossr50.skills.fishing.FishingManager; import com.gmail.nossr50.skills.fishing.FishingManager;
@ -618,7 +617,7 @@ public class McMMOPlayer implements Identified {
} }
if (SkillTools.isChildSkill(skill)) { if (SkillTools.isChildSkill(skill)) {
Set<PrimarySkillType> parentSkills = FamilyTree.getParents(skill); var parentSkills = mcMMO.p.getSkillTools().getChildSkillParents(skill);
float splitXp = xp / parentSkills.size(); float splitXp = xp / parentSkills.size();
for (PrimarySkillType parentSkill : parentSkills) { for (PrimarySkillType parentSkill : parentSkills) {
@ -675,7 +674,7 @@ public class McMMOPlayer implements Identified {
xp = mcMMOPlayerPreXpGainEvent.getXpGained(); xp = mcMMOPlayerPreXpGainEvent.getXpGained();
if (SkillTools.isChildSkill(primarySkillType)) { if (SkillTools.isChildSkill(primarySkillType)) {
Set<PrimarySkillType> parentSkills = FamilyTree.getParents(primarySkillType); var parentSkills = mcMMO.p.getSkillTools().getChildSkillParents(primarySkillType);
for (PrimarySkillType parentSkill : parentSkills) { for (PrimarySkillType parentSkill : parentSkills) {
applyXpGain(parentSkill, xp / parentSkills.size(), xpGainReason, xpGainSource); applyXpGain(parentSkill, xp / parentSkills.size(), xpGainReason, xpGainSource);

View File

@ -7,9 +7,9 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType;
import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.runnables.player.PlayerProfileSaveTask; 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.player.UserManager;
import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.util.skills.SkillTools;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -363,7 +363,7 @@ public class PlayerProfile {
markProfileDirty(); markProfileDirty();
if (SkillTools.isChildSkill(skill)) { if (SkillTools.isChildSkill(skill)) {
Set<PrimarySkillType> parentSkills = FamilyTree.getParents(skill); var parentSkills = mcMMO.p.getSkillTools().getChildSkillParents(skill);
float dividedXP = (xp / parentSkills.size()); float dividedXP = (xp / parentSkills.size());
for (PrimarySkillType parentSkill : parentSkills) { for (PrimarySkillType parentSkill : parentSkills) {
@ -431,8 +431,12 @@ public class PlayerProfile {
return mcMMO.getFormulaManager().getXPtoNextLevel(level, formulaType); return mcMMO.getFormulaManager().getXPtoNextLevel(level, formulaType);
} }
private int getChildSkillLevel(PrimarySkillType primarySkillType) { private int getChildSkillLevel(@NotNull PrimarySkillType primarySkillType) throws IllegalArgumentException {
Set<PrimarySkillType> parents = FamilyTree.getParents(primarySkillType); if (!SkillTools.isChildSkill(primarySkillType)) {
throw new IllegalArgumentException(primarySkillType + " is not a child skill!");
}
ImmutableList<PrimarySkillType> parents = mcMMO.p.getSkillTools().getChildSkillParents(primarySkillType);
int sum = 0; int sum = 0;
for (PrimarySkillType parent : parents) { for (PrimarySkillType parent : parents) {

View File

@ -30,7 +30,6 @@ import com.gmail.nossr50.runnables.player.ClearRegisteredXPGainTask;
import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask; import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask;
import com.gmail.nossr50.runnables.player.PowerLevelUpdatingTask; import com.gmail.nossr50.runnables.player.PowerLevelUpdatingTask;
import com.gmail.nossr50.skills.alchemy.Alchemy; 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.Repairable;
import com.gmail.nossr50.skills.repair.repairables.RepairableManager; import com.gmail.nossr50.skills.repair.repairables.RepairableManager;
import com.gmail.nossr50.skills.repair.repairables.SimpleRepairableManager; import com.gmail.nossr50.skills.repair.repairables.SimpleRepairableManager;
@ -563,8 +562,6 @@ public class mcMMO extends JavaPlugin {
SoundConfig.getInstance(); SoundConfig.getInstance();
RankConfig.getInstance(); RankConfig.getInstance();
new ChildConfig();
List<Repairable> repairables = new ArrayList<>(); List<Repairable> repairables = new ArrayList<>();
if (generalConfig.getToolModsEnabled()) { if (generalConfig.getToolModsEnabled()) {

View File

@ -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<PrimarySkillType> 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();
}
}

View File

@ -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<PrimarySkillType, Set<PrimarySkillType>> tree = new HashMap<>();
public static Set<PrimarySkillType> 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<PrimarySkillType> 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!");
}
}
}

View File

@ -11,7 +11,6 @@ import com.gmail.nossr50.events.scoreboard.ScoreboardEventReason;
import com.gmail.nossr50.events.scoreboard.ScoreboardObjectiveEventReason; import com.gmail.nossr50.events.scoreboard.ScoreboardObjectiveEventReason;
import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.child.FamilyTree;
import com.gmail.nossr50.util.LogUtils; import com.gmail.nossr50.util.LogUtils;
import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Misc;
import com.gmail.nossr50.util.player.NotificationManager; 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); sidebarObjective.getScore(ScoreboardManager.LABEL_REMAINING_XP).setScore(mcMMOPlayer.getXpToLevel(targetSkill) - currentXP);
} }
else { 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)); sidebarObjective.getScore(ScoreboardManager.skillLabels.get(parentSkill)).setScore(mcMMOPlayer.getSkillLevel(parentSkill));
} }
} }

View File

@ -30,6 +30,8 @@ public class SkillTools {
public final @NotNull ImmutableSet<String> EXACT_SUBSKILL_NAMES; public final @NotNull ImmutableSet<String> EXACT_SUBSKILL_NAMES;
public final @NotNull ImmutableList<PrimarySkillType> CHILD_SKILLS; public final @NotNull ImmutableList<PrimarySkillType> CHILD_SKILLS;
public final static @NotNull ImmutableList<PrimarySkillType> NON_CHILD_SKILLS; public final static @NotNull ImmutableList<PrimarySkillType> NON_CHILD_SKILLS;
public final static @NotNull ImmutableList<PrimarySkillType> SALVAGE_PARENTS;
public final static @NotNull ImmutableList<PrimarySkillType> SMELTING_PARENTS;
public final @NotNull ImmutableList<PrimarySkillType> COMBAT_SKILLS; public final @NotNull ImmutableList<PrimarySkillType> COMBAT_SKILLS;
public final @NotNull ImmutableList<PrimarySkillType> GATHERING_SKILLS; public final @NotNull ImmutableList<PrimarySkillType> GATHERING_SKILLS;
public final @NotNull ImmutableList<PrimarySkillType> MISC_SKILLS; public final @NotNull ImmutableList<PrimarySkillType> MISC_SKILLS;
@ -50,6 +52,8 @@ public class SkillTools {
} }
NON_CHILD_SKILLS = ImmutableList.copyOf(tempNonChildSkills); 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 { public SkillTools(@NotNull mcMMO pluginRef) throws InvalidSkillException {
@ -140,18 +144,13 @@ public class SkillTools {
*/ */
List<PrimarySkillType> childSkills = new ArrayList<>(); List<PrimarySkillType> childSkills = new ArrayList<>();
// List<PrimarySkillType> nonChildSkills = new ArrayList<>();
for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { for (PrimarySkillType primarySkillType : PrimarySkillType.values()) {
if (isChildSkill(primarySkillType)) if (isChildSkill(primarySkillType))
childSkills.add(primarySkillType); childSkills.add(primarySkillType);
// } {
// nonChildSkills.add(primarySkillType);
// }
} }
CHILD_SKILLS = ImmutableList.copyOf(childSkills); CHILD_SKILLS = ImmutableList.copyOf(childSkills);
// NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills);
/* /*
* Build categorized skill lists * Build categorized skill lists
@ -329,7 +328,6 @@ public class SkillTools {
} }
public Set<SubSkillType> getSubSkills(PrimarySkillType primarySkillType) { public Set<SubSkillType> getSubSkills(PrimarySkillType primarySkillType) {
//TODO: Cache this!
return primarySkillChildrenMap.get(primarySkillType); return primarySkillChildrenMap.get(primarySkillType);
} }
@ -429,4 +427,17 @@ public class SkillTools {
public @NotNull ImmutableList<PrimarySkillType> getMiscSkills() { public @NotNull ImmutableList<PrimarySkillType> getMiscSkills() {
return MISC_SKILLS; return MISC_SKILLS;
} }
public @NotNull ImmutableList<PrimarySkillType> 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");
}
}
} }

View File

@ -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

View File

@ -2,22 +2,27 @@ package com.gmail.nossr50.database;
import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.config.AdvancedConfig;
import com.gmail.nossr50.config.GeneralConfig; 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.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.LogUtils;
import com.gmail.nossr50.util.compat.CompatibilityManager; import com.gmail.nossr50.util.compat.CompatibilityManager;
import com.gmail.nossr50.util.platform.MinecraftGameVersion; import com.gmail.nossr50.util.platform.MinecraftGameVersion;
import com.gmail.nossr50.util.platform.version.SimpleNumericVersion; import com.gmail.nossr50.util.platform.version.SimpleNumericVersion;
import com.gmail.nossr50.util.skills.SkillTools;
import com.gmail.nossr50.util.upgrade.UpgradeManager; import com.gmail.nossr50.util.upgrade.UpgradeManager;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic; import org.mockito.MockedStatic;
import org.mockito.Mockito; import org.mockito.Mockito;
import java.sql.*;
import java.util.Locale;
import java.util.Set;
import java.util.logging.Logger; import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
@ -32,6 +37,7 @@ class SQLDatabaseManagerTest {
static AdvancedConfig advancedConfig; static AdvancedConfig advancedConfig;
static UpgradeManager upgradeManager; static UpgradeManager upgradeManager;
static CompatibilityManager compatibilityManager; static CompatibilityManager compatibilityManager;
static SkillTools skillTools;
@BeforeAll @BeforeAll
static void setUpAll() { static void setUpAll() {
@ -50,6 +56,10 @@ class SQLDatabaseManagerTest {
// starting level // starting level
when(mcMMO.p.getAdvancedConfig().getStartingLevel()).thenReturn(0); when(mcMMO.p.getAdvancedConfig().getStartingLevel()).thenReturn(0);
// wire skill tools
skillTools = new SkillTools(mcMMO.p);
when(mcMMO.p.getSkillTools()).thenReturn(skillTools);
// compatibility manager mock // compatibility manager mock
compatibilityManager = Mockito.mock(CompatibilityManager.class); compatibilityManager = Mockito.mock(CompatibilityManager.class);
when(mcMMO.getCompatibilityManager()).thenReturn(compatibilityManager); when(mcMMO.getCompatibilityManager()).thenReturn(compatibilityManager);
@ -107,6 +117,9 @@ class SQLDatabaseManagerTest {
// host // host
when(mcMMO.p.getGeneralConfig().getMySQLServerName()).thenReturn("localhost"); when(mcMMO.p.getGeneralConfig().getMySQLServerName()).thenReturn("localhost");
// unused mob health bar thingy
when(mcMMO.p.getGeneralConfig().getMobHealthbarDefault()).thenReturn(MobHealthbarType.HEARTS);
} }
@BeforeEach @BeforeEach
@ -120,6 +133,11 @@ class SQLDatabaseManagerTest {
sqlDatabaseManager = null; sqlDatabaseManager = null;
} }
@AfterAll
static void tearDownAll() {
mockedMcMMO.close();
}
@Test @Test
void testGetConnectionMisc() throws Exception { void testGetConnectionMisc() throws Exception {
assertNotNull(sqlDatabaseManager.getConnection(SQLDatabaseManager.PoolIdentifier.MISC)); assertNotNull(sqlDatabaseManager.getConnection(SQLDatabaseManager.PoolIdentifier.MISC));
@ -142,4 +160,16 @@ class SQLDatabaseManagerTest {
when(player.getName()).thenReturn("nossr50"); when(player.getName()).thenReturn("nossr50");
sqlDatabaseManager.newUser(player); sqlDatabaseManager.newUser(player);
} }
@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));
}
}
} }