Bug fixes and cleanup

Fix co-pilot induced column bugs
Fix insert/update statements
Added saving functionality
Added update clause for column
This commit is contained in:
David Markowitz 2023-05-07 04:09:10 -07:00
parent 820b375c50
commit bc518be654
3 changed files with 134 additions and 108 deletions

View File

@ -273,23 +273,34 @@ void LeaderboardManager::SaveScore(const LWOOBJID& playerID, GameID gameID, Lead
va_end(args); va_end(args);
} }
std::string FormatInsert(const std::string& columns, const std::string& format, va_list args, bool update) { std::string FormatInsert(const std::string& columns, const std::string& format, va_list args, bool useUpdate) {
const char* insert = "INSERT"; const char* insert = "INSERT";
const char* update = "UPDATE"; const char* update = "UPDATE";
auto queryBase = "%s leaderboard SET %s WHERE id = ?;"; const char* queryType = useUpdate ? update : insert;
const char* scoreFilter = "character_id = ? AND game_id = ?";
const char* usedFilter = useUpdate ? scoreFilter : "";
constexpr uint16_t STRING_LENGTH = 400; constexpr uint16_t STRING_LENGTH = 400;
char formattedInsert[STRING_LENGTH]; char formattedInsert[STRING_LENGTH];
auto queryBase = "%s leaderboard SET %s, character_id = ?, game_id = ? %s;";
snprintf(formattedInsert, STRING_LENGTH, queryBase, queryType, format.c_str(), usedFilter);
char finishedQuery[STRING_LENGTH]; char finishedQuery[STRING_LENGTH];
snprintf(formattedInsert, STRING_LENGTH, queryBase, columns.c_str(), format.c_str());
vsnprintf(finishedQuery, STRING_LENGTH, formattedInsert, args); vsnprintf(finishedQuery, STRING_LENGTH, formattedInsert, args);
return finishedQuery; return finishedQuery;
} }
void LeaderboardManager::SaveScore(const LWOOBJID& playerID, GameID gameID, Leaderboard::Type leaderboardType, va_list args) { void LeaderboardManager::SaveScore(const LWOOBJID& playerID, GameID gameID, Leaderboard::Type leaderboardType, va_list args) {
// Increment the numTimes this player has played this game.
std::unique_ptr<sql::PreparedStatement> incrementStatement(Database::CreatePreppedStmt("UPDATE leaderboard SET timesPlayed = timesPlayed + 1 WHERE character_id = ? AND game_id = ?;"));
incrementStatement->setInt(1, playerID);
incrementStatement->setInt(2, gameID);
incrementStatement->executeUpdate();
std::string insertStatement; std::string insertStatement;
std::string selectedColumns; std::string selectedColumns;
std::string insertFormat; std::string insertFormat;
// If ResultSet is empty, just insert our score.
std::va_list argsCopy; std::va_list argsCopy;
va_copy(argsCopy, args); va_copy(argsCopy, args);
@ -300,8 +311,8 @@ void LeaderboardManager::SaveScore(const LWOOBJID& playerID, GameID gameID, Lead
break; break;
} }
case Leaderboard::Type::Racing: { case Leaderboard::Type::Racing: {
selectedColumns = "bestLapTime, bestTime"; selectedColumns = "bestLapTime, bestTime, numWins";
insertFormat = "bestLapTime=%f, bestTime=%f"; insertFormat = "bestLapTime=%f, bestTime=%f, numWins=%i";
break; break;
} }
case Leaderboard::Type::UnusedLeaderboard4: { case Leaderboard::Type::UnusedLeaderboard4: {
@ -311,18 +322,18 @@ void LeaderboardManager::SaveScore(const LWOOBJID& playerID, GameID gameID, Lead
} }
case Leaderboard::Type::MonumentRace: case Leaderboard::Type::MonumentRace:
case Leaderboard::Type::FootRace: { case Leaderboard::Type::FootRace: {
selectedColumns = "time"; selectedColumns = "bestTime";
insertFormat = "time=%i"; insertFormat = "bestTime=%i";
break; break;
} }
case Leaderboard::Type::Survival: { case Leaderboard::Type::Survival: {
selectedColumns = "points, time"; selectedColumns = "score, bestTime";
insertFormat = "points=%i, time=%i"; insertFormat = "score=%i, bestTime=%i";
break; break;
} }
case Leaderboard::Type::SurvivalNS: { case Leaderboard::Type::SurvivalNS: {
selectedColumns = "time, wave"; selectedColumns = "bestTime, score";
insertFormat = "time=%i, wave=%i"; insertFormat = "bestTime=%i, score=%i";
break; break;
} }
case Leaderboard::Type::Donations: { case Leaderboard::Type::Donations: {
@ -340,112 +351,126 @@ void LeaderboardManager::SaveScore(const LWOOBJID& playerID, GameID gameID, Lead
} }
} }
const char* lookup = "SELECT %s FROM leaderboard WHERE character_id = ? AND game_id = ?;"; const char* lookup = "SELECT %s FROM leaderboard WHERE character_id = ? AND game_id = ?;";
constexpr uint16_t STRING_LENGTH = 400; constexpr uint16_t STRING_LENGTH = 400;
char lookupBuffer[STRING_LENGTH]; char lookupBuffer[STRING_LENGTH];
snprintf(lookupBuffer, STRING_LENGTH, lookup, selectedColumns.c_str()); snprintf(lookupBuffer, STRING_LENGTH, lookup, selectedColumns.c_str());
std::unique_ptr<sql::PreparedStatement> query(Database::CreatePreppedStmt(lookupBuffer)); std::unique_ptr<sql::PreparedStatement> query(Database::CreatePreppedStmt(lookupBuffer));
query->setInt(1, playerID); query->setInt(1, playerID);
query->setInt(2, gameID); query->setInt(2, gameID);
std::unique_ptr<sql::ResultSet> myScoreResult(query->executeQuery()); std::unique_ptr<sql::ResultSet> myScoreResult(query->executeQuery());
switch (leaderboardType) { std::string saveQuery;
case Leaderboard::Type::ShootingGallery: { if (myScoreResult->next()) {
int32_t oldScore = myScoreResult->getInt("score"); switch (leaderboardType) {
int32_t score; case Leaderboard::Type::ShootingGallery: {
score = va_arg(argsCopy, int32_t); int32_t oldScore = myScoreResult->getInt("score");
int32_t score;
score = va_arg(argsCopy, int32_t);
float oldHitPercentage = myScoreResult->getFloat("hitPercentage"); float oldHitPercentage = myScoreResult->getFloat("hitPercentage");
float hitPercentage; float hitPercentage;
hitPercentage = va_arg(argsCopy, double); hitPercentage = va_arg(argsCopy, double);
int32_t oldStreak = myScoreResult->getInt("streak"); int32_t oldStreak = myScoreResult->getInt("streak");
int32_t streak; int32_t streak;
streak = va_arg(argsCopy, int32_t); streak = va_arg(argsCopy, int32_t);
if ( if (
score > oldScore || // If score is better score > oldScore || // If score is better
(score == oldScore && hitPercentage > oldHitPercentage) || // or if the score is tied and the hitPercentage is better (score == oldScore && hitPercentage > oldHitPercentage) || // or if the score is tied and the hitPercentage is better
(score == oldScore && hitPercentage == oldHitPercentage && streak > oldStreak)) { // or if the score and hitPercentage are tied and the streak is better (score == oldScore && hitPercentage == oldHitPercentage && streak > oldStreak)) { // or if the score and hitPercentage are tied and the streak is better
// Save saveQuery = FormatInsert(selectedColumns, insertFormat, args, true);
}
break;
} }
break; case Leaderboard::Type::Racing: {
} float oldLapTime = myScoreResult->getFloat("bestLapTime");
case Leaderboard::Type::Racing: { float lapTime;
float oldLapTime = myScoreResult->getFloat("bestLapTime"); lapTime = va_arg(argsCopy, double);
float lapTime;
lapTime = va_arg(argsCopy, double);
float oldTime = myScoreResult->getFloat("bestTime"); float oldTime = myScoreResult->getFloat("bestTime");
float oldTime; float newTime;
oldTime = va_arg(argsCopy, double); newTime = va_arg(argsCopy, double);
int32_t oldNumWins = myScoreResult->getInt("numWins"); int32_t oldNumWins = myScoreResult->getInt("numWins");
bool won; bool won;
won = va_arg(argsCopy, int32_t); won = va_arg(argsCopy, int32_t);
// Compare bestTime, if LOWER save // Compare bestTime, if LOWER save
// Compare bestLapTime, if LOWER save // Compare bestLapTime, if LOWER save
// Increment numWins if player won // Increment numWins if player won
break; break;
} }
case Leaderboard::Type::UnusedLeaderboard4: { case Leaderboard::Type::UnusedLeaderboard4: {
int32_t oldScore = myScoreResult->getInt("score"); int32_t oldScore = myScoreResult->getInt("score");
int32_t points; int32_t points;
points = va_arg(argsCopy, int32_t); points = va_arg(argsCopy, int32_t);
// Compare score, if HIGHER save // Compare score, if HIGHER save
break; break;
} }
case Leaderboard::Type::MonumentRace: { case Leaderboard::Type::MonumentRace: {
int32_t oldTime = myScoreResult->getInt("time"); int32_t oldTime = myScoreResult->getInt("bestTime");
int32_t time; int32_t time;
time = va_arg(argsCopy, int32_t); time = va_arg(argsCopy, int32_t);
// Compare time, if LOWER save // Compare time, if LOWER save
break; break;
} }
case Leaderboard::Type::FootRace: { case Leaderboard::Type::FootRace: {
int32_t oldTime = myScoreResult->getInt("time"); int32_t oldTime = myScoreResult->getInt("bestTime");
int32_t time; int32_t time;
time = va_arg(argsCopy, int32_t); time = va_arg(argsCopy, int32_t);
// Compare time, if HIGHER save // Compare time, if HIGHER save
break; break;
} }
case Leaderboard::Type::Survival: { case Leaderboard::Type::Survival: {
int32_t oldPoints = myScoreResult->getInt("points"); int32_t oldPoints = myScoreResult->getInt("score");
int32_t points; int32_t points;
points = va_arg(argsCopy, int32_t); points = va_arg(argsCopy, int32_t);
int32_t oldTime = myScoreResult->getInt("time"); int32_t oldTime = myScoreResult->getInt("bestTime");
int32_t time; int32_t time;
time = va_arg(argsCopy, int32_t); time = va_arg(argsCopy, int32_t);
// Compare points, if HIGHER save, if TIED compare time, if LOWER save // Compare points, if HIGHER save, if TIED compare time, if LOWER save
// If classic_survival_scoring is 1, reverse the order of the points and time columns // If classic_survival_scoring is 1, reverse the order of the points and time columns
break; break;
} }
case Leaderboard::Type::SurvivalNS: { case Leaderboard::Type::SurvivalNS: {
int32_t oldTime = myScoreResult->getInt("time"); int32_t oldTime = myScoreResult->getInt("bestTime");
int32_t time; int32_t time;
time = va_arg(argsCopy, int32_t); time = va_arg(argsCopy, int32_t);
int32_t oldWave = myScoreResult->getInt("wave"); int32_t oldWave = myScoreResult->getInt("score");
int32_t wave; int32_t wave;
wave = va_arg(argsCopy, int32_t); wave = va_arg(argsCopy, int32_t);
// Compare wave, if HIGHER save, if TIED compare time, if LOWER save // Compare wave, if HIGHER save, if TIED compare time, if LOWER save
break; break;
}
case Leaderboard::Type::Donations: {
int32_t oldScore = myScoreResult->getInt("score");
int32_t score;
score = va_arg(argsCopy, int32_t);
// Compare score, if HIGHER save
break;
}
case Leaderboard::Type::None: {
// This type is included here simply to resolve a compiler warning on mac about unused enum types
Game::logger->Log("LeaderboardManager", "Warning: Saving score for leaderboard of type None. Are you sure this is intended?");
break;
}
default:
Game::logger->Log("LeaderboardManager", "Unknown leaderboard type %i. Cannot save score!", leaderboardType);
break;
}
} else {
saveQuery = FormatInsert(selectedColumns, insertFormat, argsCopy, false);
} }
case Leaderboard::Type::Donations: { Game::logger->Log("LeaderboardManager", "%s", saveQuery.c_str());
int32_t oldScore = myScoreResult->getInt("score"); if (!saveQuery.empty()) {
int32_t score; std::unique_ptr<sql::PreparedStatement> insertQuery(Database::CreatePreppedStmt(saveQuery));
score = va_arg(argsCopy, int32_t); insertQuery->setInt(1, playerID);
// Compare score, if HIGHER save insertQuery->setInt(2, gameID);
break; insertQuery->execute();
}
case Leaderboard::Type::None: {
// This type is included here simply to resolve a compiler warning on mac about unused enum types
Game::logger->Log("LeaderboardManager", "Warning: Saving score for leaderboard of type None. Are you sure this is intended?");
break;
}
default:
Game::logger->Log("LeaderboardManager", "Unknown leaderboard type %i. Cannot save score!", leaderboardType);
break;
} }
va_end(argsCopy); va_end(argsCopy);
} }

View File

@ -7,5 +7,6 @@ ALTER TABLE leaderboard
MODIFY time FLOAT NOT NULL DEFAULT 0; MODIFY time FLOAT NOT NULL DEFAULT 0;
ALTER TABLE leaderboard CHANGE time bestTime float; ALTER TABLE leaderboard CHANGE time bestTime float;
ALTER TABLE leaderboard CHANGE last_played TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP();
UPDATE leaderboard SET streak = bestTime where game_id = 1864; UPDATE leaderboard SET streak = bestTime where game_id = 1864;

View File

@ -30,10 +30,10 @@ protected:
Leaderboard leaderboard(gameID, infoType, false, 14231, type); Leaderboard leaderboard(gameID, infoType, false, 14231, type);
leaderboard.SetupLeaderboard(); leaderboard.SetupLeaderboard();
leaderboard.Serialize(&bitStream); leaderboard.Serialize(&bitStream);
TestLeaderboard(leaderboard, 1); // TestLeaderboard(leaderboard, 1);
TestLeaderboard(leaderboard, 10); // TestLeaderboard(leaderboard, 10);
TestLeaderboard(leaderboard, 100); // TestLeaderboard(leaderboard, 100);
TestLeaderboard(leaderboard, 1000); // TestLeaderboard(leaderboard, 1000);
} }
CBITSTREAM; CBITSTREAM;
@ -73,9 +73,9 @@ protected:
TEST_F(LeaderboardTests, LeaderboardSpeedTest) { TEST_F(LeaderboardTests, LeaderboardSpeedTest) {
RunTests(1864, Leaderboard::Type::ShootingGallery , Leaderboard::InfoType::Top); RunTests(1864, Leaderboard::Type::ShootingGallery , Leaderboard::InfoType::Top);
RunTests(1864, Leaderboard::Type::ShootingGallery, Leaderboard::InfoType::MyStanding); // RunTests(1864, Leaderboard::Type::ShootingGallery, Leaderboard::InfoType::MyStanding);
RunTests(1864, Leaderboard::Type::ShootingGallery, Leaderboard::InfoType::Friends); // RunTests(1864, Leaderboard::Type::ShootingGallery, Leaderboard::InfoType::Friends);
LeaderboardManager::Instance().SaveScore(14231, 0, Leaderboard::Type::ShootingGallery, 3, 3000, 15.0f, 100); LeaderboardManager::Instance().SaveScore(14231, 1864, Leaderboard::Type::ShootingGallery, 3, 53001, 15.0f, 100);
// RunTests(0, Leaderboard::Type::Racing); // RunTests(0, Leaderboard::Type::Racing);
LeaderboardManager::Instance().SaveScore(14231, 0, Leaderboard::Type::Racing, 3, 260.0f, 250.0f, true); LeaderboardManager::Instance().SaveScore(14231, 0, Leaderboard::Type::Racing, 3, 260.0f, 250.0f, true);
// RunTests(0, Leaderboard::Type::MonumentRace); // RunTests(0, Leaderboard::Type::MonumentRace);