diff --git a/dDatabase/MigrationRunner.cpp b/dDatabase/MigrationRunner.cpp index 5e70c401..d9c5aa38 100644 --- a/dDatabase/MigrationRunner.cpp +++ b/dDatabase/MigrationRunner.cpp @@ -7,6 +7,8 @@ #include "GeneralUtils.h" #include "dLogger.h" #include "BinaryPathFinder.h" +#include "CDActivitiesTable.h" +#include "CDClientManager.h" #include @@ -56,6 +58,8 @@ void MigrationRunner::RunMigrations() { Game::logger->Log("MigrationRunner", "Running migration: %s", migration.name.c_str()); if (migration.name == "dlu/5_brick_model_sd0.sql") { runSd0Migrations = true; + } else if (migration.name == "dlu/10_Update_Leaderboard_Columns.sql") { + continue; } else { finalSQL.append(migration.data.c_str()); } @@ -109,7 +113,7 @@ void MigrationRunner::RunSQLiteMigrations() { // Check if there is an entry in the migration history table on the cdclient database. cdstmt = CDClientDatabase::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;"); - cdstmt.bind((int32_t) 1, migration.name.c_str()); + cdstmt.bind((int32_t)1, migration.name.c_str()); auto cdres = cdstmt.execQuery(); bool doExit = !cdres.eof(); cdres.finalize(); @@ -127,7 +131,7 @@ void MigrationRunner::RunSQLiteMigrations() { if (doExit) { // Insert into cdclient database if there is an entry in the main database but not the cdclient database. cdstmt = CDClientDatabase::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);"); - cdstmt.bind((int32_t) 1, migration.name.c_str()); + cdstmt.bind((int32_t)1, migration.name.c_str()); cdstmt.execQuery().finalize(); cdstmt.finalize(); continue; @@ -148,7 +152,7 @@ void MigrationRunner::RunSQLiteMigrations() { // Insert into cdclient database. cdstmt = CDClientDatabase::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);"); - cdstmt.bind((int32_t) 1, migration.name.c_str()); + cdstmt.bind((int32_t)1, migration.name.c_str()); cdstmt.execQuery().finalize(); cdstmt.finalize(); CDClientDatabase::ExecuteQuery("COMMIT;"); @@ -156,3 +160,23 @@ void MigrationRunner::RunSQLiteMigrations() { Game::logger->Log("MigrationRunner", "CDServer database is up to date."); } + +void MigrationRunner::MigrateLeaderboard() { + Game::logger->Log("MigrationRunner", "Checking if leaderboard migration needs to be run..."); + { + std::unique_ptr stmt(Database::CreatePreppedStmt("SELECT * FROM migration_history WHERE name = ?;")); + stmt->setString(1, "dlu/10_Update_Leaderboard_Columns.sql"); + std::unique_ptr res(stmt->executeQuery()); + if (res->next()) { + Game::logger->Log("MigrationRunner", "Leaderboard migration has already been run."); + return; + } + } + auto activitiesTable = CDClientManager::Instance().GetTable(); + auto leaderboards = activitiesTable->Query([=](const CDActivities& entry) { + return entry.leaderboardType != -1; + }); + for (auto entry : leaderboards) { + Game::logger->Log("MigrationRunner", "Got leaderboard type %i for activity %i", entry.leaderboardType, entry.ActivityID); + } +} diff --git a/dDatabase/MigrationRunner.h b/dDatabase/MigrationRunner.h index 0cb36d53..00a1d720 100644 --- a/dDatabase/MigrationRunner.h +++ b/dDatabase/MigrationRunner.h @@ -10,4 +10,5 @@ struct Migration { namespace MigrationRunner { void RunMigrations(); void RunSQLiteMigrations(); + void MigrateLeaderboard(); }; diff --git a/dGame/LeaderboardManager.cpp b/dGame/LeaderboardManager.cpp index d3037fae..cc47c109 100644 --- a/dGame/LeaderboardManager.cpp +++ b/dGame/LeaderboardManager.cpp @@ -41,53 +41,59 @@ void Leaderboard::Serialize(RakNet::BitStream* bitStream) const { WriteLeaderboardRow(leaderboard, index, "LastPlayed", eLDFType::LDF_TYPE_U64, entry.lastPlayed); WriteLeaderboardRow(leaderboard, index, "NumPlayed", eLDFType::LDF_TYPE_S32, 1); WriteLeaderboardRow(leaderboard, index, "name", eLDFType::LDF_TYPE_UTF_16, entry.playerName); + WriteLeaderboardRow(leaderboard, index, "RowNumber", eLDFType::LDF_TYPE_S32, entry.placement); // Each minigame has its own "points" system switch (leaderboardType) { case Type::ShootingGallery: - WriteLeaderboardRow(leaderboard, index, "HitPercentage", eLDFType::LDF_TYPE_FLOAT, 0.0f); - // HitPercentage:3 between 0 and 1 - WriteLeaderboardRow(leaderboard, index, "RowNumber", eLDFType::LDF_TYPE_S32, entry.placement); - // RowNumber:1 - WriteLeaderboardRow(leaderboard, index, "Score", eLDFType::LDF_TYPE_S32, entry.score); - // Score:1 + WriteLeaderboardRow(leaderboard, index, "HitPercentage", eLDFType::LDF_TYPE_FLOAT, 0.0f); + // HitPercentage:3 between 0 and 1 + WriteLeaderboardRow(leaderboard, index, "Score", eLDFType::LDF_TYPE_S32, entry.score); + // Score:1 + WriteLeaderboardRow(leaderboard, index, "Streak", eLDFType::LDF_TYPE_S32, 0); + // Streak:1 + break; case Type::Racing: - WriteLeaderboardRow(leaderboard, index, "BestLapTime", eLDFType::LDF_TYPE_FLOAT, 0.0f); - // BestLapTime:3 - WriteLeaderboardRow(leaderboard, index, "BestTime", eLDFType::LDF_TYPE_FLOAT, 0.0f); - // BestTime:3 - WriteLeaderboardRow(leaderboard, index, "License", eLDFType::LDF_TYPE_S32, 0); - // License:1 - WriteLeaderboardRow(leaderboard, index, "NumWins", eLDFType::LDF_TYPE_S32, 0); - // NumWins:1 - WriteLeaderboardRow(leaderboard, index, "RowNumber", eLDFType::LDF_TYPE_U64, entry.placement); - // RowNumber:8 + WriteLeaderboardRow(leaderboard, index, "BestLapTime", eLDFType::LDF_TYPE_FLOAT, 0.0f); + // BestLapTime:3 + WriteLeaderboardRow(leaderboard, index, "BestTime", eLDFType::LDF_TYPE_FLOAT, 0.0f); + // BestTime:3 + WriteLeaderboardRow(leaderboard, index, "License", eLDFType::LDF_TYPE_S32, 0); + // License:1 + WriteLeaderboardRow(leaderboard, index, "NumWins", eLDFType::LDF_TYPE_S32, 0); + // NumWins:1 + break; + case Type::UnusedLeaderboard4: + WriteLeaderboardRow(leaderboard, index, "Points", eLDFType::LDF_TYPE_S32, entry.score); + // Points:1 + break; case Type::MonumentRace: - WriteLeaderboardRow(leaderboard, index, "RowNumber", eLDFType::LDF_TYPE_S32, entry.placement); - // RowNumber:1 - // Time:1(?) + WriteLeaderboardRow(leaderboard, index, "Time", eLDFType::LDF_TYPE_S32, entry.time); + // Time:1(?) + break; case Type::FootRace: - WriteLeaderboardRow(leaderboard, index, "RowNumber", eLDFType::LDF_TYPE_S32, entry.placement); - // RowNumber:1 - WriteLeaderboardRow(leaderboard, index, "Time", eLDFType::LDF_TYPE_S32, 0); - // Time:1 + WriteLeaderboardRow(leaderboard, index, "Time", eLDFType::LDF_TYPE_S32, entry.time); + // Time:1 + break; case Type::Survival: - WriteLeaderboardRow(leaderboard, index, "Points", eLDFType::LDF_TYPE_S32, entry.score); - // Points:1 - WriteLeaderboardRow(leaderboard, index, "RowNumber", eLDFType::LDF_TYPE_S32, entry.placement); - // RowNumber:1 - WriteLeaderboardRow(leaderboard, index, "Time", eLDFType::LDF_TYPE_S32, 0); - // Time:1 + WriteLeaderboardRow(leaderboard, index, "Points", eLDFType::LDF_TYPE_S32, entry.score); + // Points:1 + WriteLeaderboardRow(leaderboard, index, "Time", eLDFType::LDF_TYPE_S32, entry.time); + // Time:1 + break; case Type::SurvivalNS: - WriteLeaderboardRow(leaderboard, index, "RowNumber", eLDFType::LDF_TYPE_U64, entry.placement); - // RowNumber:8 - WriteLeaderboardRow(leaderboard, index, "Time", eLDFType::LDF_TYPE_S32, entry.time); - // Time:1 - WriteLeaderboardRow(leaderboard, index, "Wave", eLDFType::LDF_TYPE_S32, entry.score); - // Wave:1 + WriteLeaderboardRow(leaderboard, index, "Time", eLDFType::LDF_TYPE_S32, entry.time); + // Time:1 + WriteLeaderboardRow(leaderboard, index, "Wave", eLDFType::LDF_TYPE_S32, entry.score); + // Wave:1 + break; case Type::Donations: - // Something? idk yet. + WriteLeaderboardRow(leaderboard, index, "Score", eLDFType::LDF_TYPE_S32, entry.score); + // Score:1 + // Something? idk yet. + break; case Type::None: + // This type is included here simply to resolve a compiler warning on mac about unused enum types break; default: break; diff --git a/dGame/LeaderboardManager.h b/dGame/LeaderboardManager.h index 6432aa8d..4a42a268 100644 --- a/dGame/LeaderboardManager.h +++ b/dGame/LeaderboardManager.h @@ -37,7 +37,7 @@ public: Racing, MonumentRace, FootRace, - // There is no 4 defined anywhere in the client or cdclient + UnusedLeaderboard4,// There is no 4 defined anywhere in the client or cdclient Survival = 5, SurvivalNS, Donations, diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index f10b33bf..61dbb121 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -150,12 +150,6 @@ int main(int argc, char** argv) { const bool oldCDServerExists = std::filesystem::exists(Game::assetManager->GetResPath() / "CDServer.sqlite"); const bool fdbExists = std::filesystem::exists(Game::assetManager->GetResPath() / "cdclient.fdb"); - auto query = Database::CreatePreppedStmt("select name, score, time, UNIX_TIMESTAMP(last_played) as lastPlayed from leaderboard as l join charinfo as ci on ci.id = l.character_id where game_id = 1864 order by score desc, time desc limit 11;"); - auto myResult = query->executeQuery(); - while (myResult->next()) { - Game::logger->Log("MasterServer", "%s %i %i %i", myResult->getString("name").c_str(), myResult->getInt("score"), myResult->getInt("time"), myResult->getInt("lastPlayed")); - } - if (!cdServerExists) { if (oldCDServerExists) { // If the file doesn't exist in the new CDServer location, copy it there. We copy because we may not have write permissions from the previous directory. @@ -208,6 +202,9 @@ int main(int argc, char** argv) { return EXIT_FAILURE; } + // This migration relies on cdclient data so run it last + MigrationRunner::MigrateLeaderboard(); + //If the first command line argument is -a or --account then make the user //input a username and password, with the password being hidden. if (argc > 1 && diff --git a/migrations/dlu/10_Update_Leaderboard_Columns.sql b/migrations/dlu/10_Update_Leaderboard_Columns.sql new file mode 100644 index 00000000..c9afb81e --- /dev/null +++ b/migrations/dlu/10_Update_Leaderboard_Columns.sql @@ -0,0 +1 @@ +# This migration is a mock. See the real migration in MigrationRunner::MigrateLeaderboard. diff --git a/migrations/dlu/9_Update_Leaderboard_Storage.sql b/migrations/dlu/9_Update_Leaderboard_Storage.sql new file mode 100644 index 00000000..1b3b1f13 --- /dev/null +++ b/migrations/dlu/9_Update_Leaderboard_Storage.sql @@ -0,0 +1,8 @@ +ALTER TABLE leaderboard +ADD COLUMN hitPercentage FLOAT NOT NULL DEFAULT 0, +ADD COLUMN streak INT NOT NULL DEFAULT 0, +ADD COLUMN bestLapTime FLOAT NOT NULL DEFAULT 0, +ADD COLUMN numWins INT NOT NULL DEFAULT 0, +MODIFY time FLOAT NOT NULL DEFAULT 0; + +ALTER TABLE leaderboard CHANGE time bestTime float; diff --git a/tests/dGameTests/LeaderboardTests.cpp b/tests/dGameTests/LeaderboardTests.cpp index 6a45298b..86fb6333 100644 --- a/tests/dGameTests/LeaderboardTests.cpp +++ b/tests/dGameTests/LeaderboardTests.cpp @@ -32,6 +32,15 @@ protected: bitStream.Reset(); } + void RunTests(Leaderboard::Type type) { + Game::logger->Log("LeaderboardTests", "Testing leaderboard %i for Serialize speed", type); + Leaderboard leaderboard(0, Leaderboard::InfoType::Top, false, type); + TestLeaderboard(leaderboard, 1); + TestLeaderboard(leaderboard, 10); + TestLeaderboard(leaderboard, 100); + TestLeaderboard(leaderboard, 1000); + } + CBITSTREAM; }; @@ -68,9 +77,5 @@ protected: */ TEST_F(LeaderboardTests, LeaderboardSpeedTest) { - Leaderboard leaderboard(10, Leaderboard::InfoType::MyStanding, false, Leaderboard::Type::Survival); - TestLeaderboard(leaderboard, 1); - TestLeaderboard(leaderboard, 10); - TestLeaderboard(leaderboard, 100); - TestLeaderboard(leaderboard, 1000); + RunTests(Leaderboard::Type::Racing); }