From 0107d05d55364fd01a9e5241275585577abbbcf3 Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Tue, 30 May 2023 04:11:37 -0700 Subject: [PATCH] draft --- dGame/LeaderboardManager.cpp | 215 ++++++------------ dGame/LeaderboardManager.h | 61 +++-- dGame/dComponents/RacingControlComponent.cpp | 4 +- dGame/dGameMessages/GameMessages.cpp | 2 +- .../02_server/Map/AG/NpcAgCourseStarter.cpp | 2 +- dScripts/ActivityManager.cpp | 4 +- .../dlu/9_Update_Leaderboard_Storage.sql | 10 +- 7 files changed, 123 insertions(+), 175 deletions(-) diff --git a/dGame/LeaderboardManager.cpp b/dGame/LeaderboardManager.cpp index 81cdbb8b..d153a1fd 100644 --- a/dGame/LeaderboardManager.cpp +++ b/dGame/LeaderboardManager.cpp @@ -11,12 +11,15 @@ #include "GeneralUtils.h" #include "Entity.h" #include "LDFFormat.h" +#include "DluAssert.h" #include #include "CDActivitiesTable.h" #include "Metrics.hpp" -LeaderboardManager::LeaderboardCache LeaderboardManager::leaderboardCache = {}; +namespace LeaderboardManager { + LeaderboardCache leaderboardCache; +} Leaderboard::Leaderboard(const GameID gameID, const Leaderboard::InfoType infoType, const bool weekly, LWOOBJID relatedPlayer, const Leaderboard::Type leaderboardType) { this->gameID = gameID; @@ -143,7 +146,7 @@ void Leaderboard::QueryToLdf(std::unique_ptr& rows) { } } -const std::string Leaderboard::GetColumns(Leaderboard::Type leaderboardType) { +const std::string_view Leaderboard::GetColumns(Leaderboard::Type leaderboardType) { std::string columns; switch (leaderboardType) { case Type::ShootingGallery: @@ -177,7 +180,7 @@ const std::string Leaderboard::GetColumns(Leaderboard::Type leaderboardType) { return columns; } -const std::string Leaderboard::GetInsertFormat(Leaderboard::Type leaderboardType) { +const std::string_view Leaderboard::GetInsertFormat(Leaderboard::Type leaderboardType) { std::string columns; switch (leaderboardType) { case Type::ShootingGallery: @@ -211,7 +214,7 @@ const std::string Leaderboard::GetInsertFormat(Leaderboard::Type leaderboardType return columns; } -const std::string Leaderboard::GetOrdering(Leaderboard::Type leaderboardType) { +const std::string_view Leaderboard::GetOrdering(Leaderboard::Type leaderboardType) { std::string orderBase; switch (leaderboardType) { case Type::ShootingGallery: @@ -296,19 +299,18 @@ void Leaderboard::SetupLeaderboard(uint32_t resultStart, uint32_t resultEnd) { ) )QUERY"; - const std::string orderBase = GetOrdering(this->leaderboardType); - const std::string selectBase = GetColumns(this->leaderboardType); + const auto orderBase = GetOrdering(this->leaderboardType); + const auto selectBase = GetColumns(this->leaderboardType); constexpr uint16_t STRING_LENGTH = 1526; char lookupBuffer[STRING_LENGTH]; // If we are getting the friends leaderboard, add the friends query, otherwise fill it in with nothing. if (this->infoType == InfoType::Friends) { - snprintf(lookupBuffer, STRING_LENGTH, queryBase.c_str(), - orderBase.c_str(), friendsQuery, selectBase.c_str(), resultStart, resultEnd); - } - else { - snprintf(lookupBuffer, STRING_LENGTH, queryBase.c_str(), - orderBase.c_str(), "", selectBase.c_str(), resultStart, resultEnd); + snprintf(lookupBuffer, STRING_LENGTH, queryBase.data(), + orderBase.data(), friendsQuery, selectBase.data(), resultStart, resultEnd); + } else { + snprintf(lookupBuffer, STRING_LENGTH, queryBase.data(), + orderBase.data(), "", selectBase.data(), resultStart, resultEnd); } std::string baseLookupStr; @@ -355,186 +357,99 @@ void Leaderboard::Send(LWOOBJID targetID) { } } -void LeaderboardManager::SaveScore(const LWOOBJID& playerID, GameID gameID, Leaderboard::Type leaderboardType, uint32_t argumentCount, ...) { - va_list args; - va_start(args, argumentCount); - SaveScore(playerID, gameID, leaderboardType, args); - va_end(args); -} +std::string LeaderboardManager::FormatInsert(const Leaderboard::Type& type, const Score& score, const bool useUpdate) { + auto insertFormat = Leaderboard::GetInsertFormat(type); -std::string FormatInsert(const std::string& columns, const std::string& format, va_list args, bool useUpdate) { - const char* insertClause = "INSERT"; - const char* updateClause = "UPDATE"; - const char* queryType = useUpdate ? updateClause : insertClause; + auto* queryType = useUpdate ? "UPDATE" : "INSERT"; - const char* insertFilter = ", character_id = ?, game_id = ?, timesPlayed = 1"; - const char* updateFilter = ", timesPlayed = timesPlayed + 1 WHERE character_id = ? AND game_id = ?"; - const char* usedFilter = useUpdate ? updateFilter : insertFilter; + auto* usedFilter = useUpdate ? + ", timesPlayed = timesPlayed + 1 WHERE character_id = ? AND game_id = ?" : + ", character_id = ?, game_id = ?"; + // First fill in the format constexpr uint16_t STRING_LENGTH = 400; char formattedInsert[STRING_LENGTH]; - auto queryBase = "%s leaderboard SET %s %s;"; - snprintf(formattedInsert, STRING_LENGTH, queryBase, queryType, format.c_str(), usedFilter); + snprintf(formattedInsert, STRING_LENGTH, "%s leaderboard SET %s %s;", queryType, insertFormat.data(), usedFilter); + // Then fill in our score char finishedQuery[STRING_LENGTH]; - vsnprintf(finishedQuery, STRING_LENGTH, formattedInsert, args); + snprintf(finishedQuery, STRING_LENGTH, formattedInsert, score.GetPrimaryScore(), score.GetSecondaryScore(), score.GetTertiaryScore()); + DluAssert() return finishedQuery; } -void LeaderboardManager::SaveScore(const LWOOBJID& playerID, GameID gameID, Leaderboard::Type leaderboardType, va_list activityScore) { - std::string selectedColumns = Leaderboard::GetColumns(leaderboardType); - std::string insertFormat = Leaderboard::GetInsertFormat(leaderboardType); - const char* lookup = "SELECT %s FROM leaderboard WHERE character_id = ? AND game_id = ?;"; +void LeaderboardManager::SaveScore(const LWOOBJID& playerID, GameID gameID, Leaderboard::Type leaderboardType, uint32_t primaryScore, uint32_t secondaryScore, uint32_t tertiaryScore) { + auto* lookup = "SELECT * FROM leaderboard WHERE character_id = ? AND game_id = ?;"; - constexpr uint16_t STRING_LENGTH = 400; - char lookupBuffer[STRING_LENGTH]; - snprintf(lookupBuffer, STRING_LENGTH, lookup, selectedColumns.c_str()); - - std::unique_ptr query(Database::CreatePreppedStmt(lookupBuffer)); + std::unique_ptr query(Database::CreatePreppedStmt(lookup)); query->setInt(1, playerID); query->setInt(2, gameID); std::unique_ptr myScoreResult(query->executeQuery()); - std::va_list argsCopy; - va_copy(argsCopy, activityScore); std::string saveQuery; + Score newScore(primaryScore, secondaryScore, tertiaryScore); if (myScoreResult->next()) { + Score oldScore; + bool lowerScoreBetter = false; switch (leaderboardType) { + // Higher score better case Leaderboard::Type::ShootingGallery: { - int32_t oldScore = myScoreResult->getInt("score"); - int32_t score; - score = va_arg(argsCopy, int32_t); - - int32_t oldHitPercentage = myScoreResult->getFloat("hitPercentage"); - int32_t hitPercentage; - hitPercentage = va_arg(argsCopy, int32_t); - - int32_t oldStreak = myScoreResult->getInt("streak"); - int32_t streak; - streak = va_arg(argsCopy, int32_t); - - if (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 && streak > oldStreak)) { // or if the score and hitPercentage are tied and the streak is better - saveQuery = FormatInsert(selectedColumns, insertFormat, activityScore, true); - } - break; - } - case Leaderboard::Type::Racing: { - uint32_t oldLapTime = myScoreResult->getFloat("bestLapTime"); - uint32_t lapTime; - lapTime = va_arg(argsCopy, uint32_t); - - uint32_t oldTime = myScoreResult->getFloat("bestTime"); - uint32_t newTime; - newTime = va_arg(argsCopy, uint32_t); - - bool won; - won = va_arg(argsCopy, int32_t); - - if (newTime < oldTime || - (newTime == oldTime && lapTime < oldLapTime)) { - saveQuery = FormatInsert(selectedColumns, insertFormat, activityScore, true); - } else if (won) { - std::unique_ptr incrementStatement(Database::CreatePreppedStmt("UPDATE leaderboard SET numWins = numWins + 1 WHERE character_id = ? AND game_id = ?;")); - incrementStatement->setInt(1, playerID); - incrementStatement->setInt(2, gameID); - incrementStatement->executeUpdate(); - } - break; - } - case Leaderboard::Type::UnusedLeaderboard4: { - int32_t oldScore = myScoreResult->getInt("score"); - int32_t points; - points = va_arg(argsCopy, int32_t); - - if (points > oldScore) { - saveQuery = FormatInsert(selectedColumns, insertFormat, activityScore, true); - } - break; - } - case Leaderboard::Type::MonumentRace: { - int32_t oldTime = myScoreResult->getInt("bestTime"); - int32_t time; - time = va_arg(argsCopy, int32_t); - - if (time < oldTime) { - saveQuery = FormatInsert(selectedColumns, insertFormat, activityScore, true); - } + oldScore.SetPrimaryScore(myScoreResult->getInt("score")); + oldScore.SetSecondaryScore(myScoreResult->getInt("hitPercentage")); + oldScore.SetTertiaryScore(myScoreResult->getInt("streak")); break; } case Leaderboard::Type::FootRace: { - int32_t oldTime = myScoreResult->getInt("bestTime"); - int32_t time; - time = va_arg(argsCopy, int32_t); - - if (time > oldTime) { - saveQuery = FormatInsert(selectedColumns, insertFormat, activityScore, true); - } + oldScore.SetPrimaryScore(myScoreResult->getInt("bestTime")); break; } case Leaderboard::Type::Survival: { - int32_t oldTime = myScoreResult->getInt("bestTime"); - int32_t time; - time = va_arg(argsCopy, int32_t); - - int32_t oldPoints = myScoreResult->getInt("score"); - int32_t points; - points = va_arg(argsCopy, int32_t); - - if (points > oldPoints || (points == oldPoints && time < oldTime)) { - saveQuery = FormatInsert(selectedColumns, insertFormat, activityScore, true); - } + // Config option may reverse these + oldScore.SetPrimaryScore(myScoreResult->getInt("bestTime")); + oldScore.SetSecondaryScore(myScoreResult->getInt("score")); break; } case Leaderboard::Type::SurvivalNS: { - int32_t oldTime = myScoreResult->getInt("bestTime"); - int32_t time; - time = va_arg(argsCopy, int32_t); - - int32_t oldWave = myScoreResult->getInt("score"); - int32_t wave; - wave = va_arg(argsCopy, int32_t); - - if (time < oldTime || (time == oldTime && wave > oldWave)) { - saveQuery = FormatInsert(selectedColumns, insertFormat, activityScore, true); - } + oldScore.SetPrimaryScore(myScoreResult->getInt("bestTime")); + oldScore.SetSecondaryScore(myScoreResult->getInt("score")); break; } + case Leaderboard::Type::UnusedLeaderboard4: case Leaderboard::Type::Donations: { - int32_t oldScore = myScoreResult->getInt("score"); - int32_t score; - score = va_arg(argsCopy, int32_t); - - if (score > oldScore) { - saveQuery = FormatInsert(selectedColumns, insertFormat, activityScore, true); - } + oldScore.SetPrimaryScore(myScoreResult->getInt("score")); break; } + case Leaderboard::Type::Racing: + oldScore.SetPrimaryScore(myScoreResult->getInt("bestTime")); + oldScore.SetSecondaryScore(myScoreResult->getInt("bestLapTime")); + lowerScoreBetter = true; + break; + case Leaderboard::Type::MonumentRace: + oldScore.SetPrimaryScore(myScoreResult->getInt("bestTime")); + lowerScoreBetter = true; + // Do score checking here + break; case Leaderboard::Type::None: default: - Game::logger->Log("LeaderboardManager", "Unknown leaderboard type %i. Cannot save score!", leaderboardType); - va_end(argsCopy); + Game::logger->Log("LeaderboardManager", "Unknown leaderboard type %i. Cannot save score!", leaderboardType); return; } + bool newHighScore = lowerScoreBetter ? newScore < oldScore : newScore > oldScore; + if (newHighScore) { + saveQuery = FormatInsert(leaderboardType, newScore, true); + } else if (leaderboardType == Leaderboard::Type::Racing && tertiaryScore) { + saveQuery = "UPDATE leaderboard SET numWins = numWins + 1, timesPlayed = timesPlayed + 1 WHERE character_id = ? AND game_id = ?;"; + } else { + saveQuery = "UPDATE leaderboard SET timesPlayed = timesPlayed + 1 WHERE character_id = ? AND game_id = ?;"; + } } else { - saveQuery = FormatInsert(selectedColumns, insertFormat, activityScore, false); - } - std::unique_ptr saveStatement; - if (!saveQuery.empty()) { - Game::logger->Log("LeaderboardManager", "Executing update with query %s", saveQuery.c_str()); - std::unique_ptr updateStatement(Database::CreatePreppedStmt(saveQuery)); - saveStatement = std::move(updateStatement); - } else { - Game::logger->Log("LeaderboardManager", "No new score to save, incrementing numTimesPlayed"); - // Increment the numTimes this player has played this game. - std::unique_ptr updateStatement(Database::CreatePreppedStmt("UPDATE leaderboard SET timesPlayed = timesPlayed + 1 WHERE character_id = ? AND game_id = ?;")); - saveStatement = std::move(updateStatement); + saveQuery = FormatInsert(leaderboardType, newScore, false); } + + std::unique_ptr saveStatement(Database::CreatePreppedStmt(saveQuery)); saveStatement->setInt(1, playerID); saveStatement->setInt(2, gameID); saveStatement->execute(); - va_end(argsCopy); } void LeaderboardManager::SendLeaderboard(uint32_t gameID, Leaderboard::InfoType infoType, bool weekly, LWOOBJID playerID, LWOOBJID targetID, uint32_t resultStart, uint32_t resultEnd) { diff --git a/dGame/LeaderboardManager.h b/dGame/LeaderboardManager.h index 6a7ba665..0d810a67 100644 --- a/dGame/LeaderboardManager.h +++ b/dGame/LeaderboardManager.h @@ -1,7 +1,8 @@ -#pragma once -#include +#ifndef __LEADERBOARDMANAGER__H__ +#define __LEADERBOARDMANAGER__H__ + #include -#include +#include #include #include "Singleton.h" @@ -62,7 +63,7 @@ public: /** * Builds the leaderboard from the database based on the associated gameID - * + * * @param resultStart The index to start the leaderboard at. Zero indexed. * @param resultEnd The index to end the leaderboard at. Zero indexed. */ @@ -74,9 +75,9 @@ public: void Send(LWOOBJID targetID); // Helper functions to get the columns, ordering and insert format for a leaderboard - static const std::string GetColumns(Type leaderboardType); - static const std::string GetInsertFormat(Type leaderboardType); - static const std::string GetOrdering(Type leaderboardType); + static const std::string_view GetColumns(Type leaderboardType); + static const std::string_view GetInsertFormat(Type leaderboardType); + static const std::string_view GetOrdering(Type leaderboardType); private: inline void WriteLeaderboardRow(std::ostringstream& leaderboard, const uint32_t& index, LDFBaseData* data); @@ -98,9 +99,40 @@ private: bool weekly; }; -class LeaderboardManager : public Singleton { +namespace LeaderboardManager { + class Score { + public: + Score() { + primaryScore = 0; + secondaryScore = 0; + tertiaryScore = 0; + } + Score(uint32_t primaryScore, uint32_t secondaryScore = 0, uint32_t tertiaryScore = 0) { + this->primaryScore = primaryScore; + this->secondaryScore = secondaryScore; + this->tertiaryScore = tertiaryScore; + } + bool operator<(const Score& rhs) const { + return primaryScore < rhs.primaryScore || (primaryScore == rhs.primaryScore && secondaryScore < rhs.secondaryScore) || (primaryScore == rhs.primaryScore && secondaryScore == rhs.secondaryScore && tertiaryScore < rhs.tertiaryScore); + } + bool operator>(const Score& rhs) const { + return primaryScore > rhs.primaryScore || (primaryScore == rhs.primaryScore && secondaryScore > rhs.secondaryScore) || (primaryScore == rhs.primaryScore && secondaryScore == rhs.secondaryScore && tertiaryScore > rhs.tertiaryScore); + } + void SetPrimaryScore(const uint32_t score) { primaryScore = score; } + uint32_t GetPrimaryScore() const { return primaryScore; } + + void SetSecondaryScore(const uint32_t score) { secondaryScore = score; } + uint32_t GetSecondaryScore() const { return secondaryScore; } + + void SetTertiaryScore(const uint32_t score) { tertiaryScore = score; } + uint32_t GetTertiaryScore() const { return tertiaryScore; } + private: + uint32_t primaryScore; + uint32_t secondaryScore; + uint32_t tertiaryScore; + }; + using LeaderboardCache = std::map; -public: void SendLeaderboard(GameID gameID, Leaderboard::InfoType infoType, bool weekly, LWOOBJID playerID, LWOOBJID targetID, uint32_t resultStart = 0, uint32_t resultEnd = 10); /** @@ -111,12 +143,13 @@ public: * @param argumentCount The number of arguments in the va_list * @param ... The score to save */ - void SaveScore(const LWOOBJID& playerID, GameID gameID, Leaderboard::Type leaderboardType, uint32_t argumentCount, ...); + void SaveScore(const LWOOBJID& playerID, GameID gameID, Leaderboard::Type leaderboardType, uint32_t primaryScore, uint32_t secondaryScore = 0, uint32_t tertiaryScore = 0); - static Leaderboard::Type GetLeaderboardType(const GameID gameID); - static LeaderboardCache leaderboardCache; -private: - void SaveScore(const LWOOBJID& playerID, GameID gameID, Leaderboard::Type leaderboardType, va_list args); void GetLeaderboard(uint32_t gameID, Leaderboard::InfoType infoType, bool weekly, LWOOBJID playerID = LWOOBJID_EMPTY); + std::string FormatInsert(const Leaderboard::Type& type, const Score& score, const bool useUpdate); + + Leaderboard::Type GetLeaderboardType(const GameID gameID); + extern LeaderboardCache leaderboardCache; }; +#endif //!__LEADERBOARDMANAGER__H__ diff --git a/dGame/dComponents/RacingControlComponent.cpp b/dGame/dComponents/RacingControlComponent.cpp index f74c92fa..efd6b44e 100644 --- a/dGame/dComponents/RacingControlComponent.cpp +++ b/dGame/dComponents/RacingControlComponent.cpp @@ -400,8 +400,8 @@ void RacingControlComponent::HandleMessageBoxResponse(Entity* player, const auto score = m_LoadedPlayers * 10 + data->finished; LootGenerator::Instance().GiveActivityLoot(player, m_Parent, m_ActivityID, score); - auto leaderboardType = LeaderboardManager::Instance().GetLeaderboardType(m_ActivityID); - LeaderboardManager::Instance().SaveScore(player->GetObjectID(), m_ActivityID, leaderboardType, 3, data->bestLapTime, data->raceTime, data->finished == 1); + // auto leaderboardType = LeaderboardManager::Instance().GetLeaderboardType(m_ActivityID); + // LeaderboardManager::Instance().SaveScore(player->GetObjectID(), m_ActivityID, leaderboardType, 3, data->bestLapTime, data->raceTime, data->finished == 1); // Giving rewards GameMessages::SendNotifyRacingClient( diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index dae0636a..5bdec2ac 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -1661,7 +1661,7 @@ void GameMessages::HandleRequestActivitySummaryLeaderboardData(RakNet::BitStream bool weekly = inStream->ReadBit(); - LeaderboardManager::Instance().SendLeaderboard(gameID, queryType, weekly, entity->GetObjectID(), entity->GetObjectID(), resultsStart, resultsEnd); + // LeaderboardManager::Instance().SendLeaderboard(gameID, queryType, weekly, entity->GetObjectID(), entity->GetObjectID(), resultsStart, resultsEnd); } void GameMessages::HandleActivityStateChangeRequest(RakNet::BitStream* inStream, Entity* entity) { diff --git a/dScripts/02_server/Map/AG/NpcAgCourseStarter.cpp b/dScripts/02_server/Map/AG/NpcAgCourseStarter.cpp index 670fd7ee..20e749ee 100644 --- a/dScripts/02_server/Map/AG/NpcAgCourseStarter.cpp +++ b/dScripts/02_server/Map/AG/NpcAgCourseStarter.cpp @@ -94,7 +94,7 @@ void NpcAgCourseStarter::OnFireEventServerSide(Entity* self, Entity* sender, std EntityManager::Instance()->SerializeEntity(self); auto leaderboardType = LeaderboardManager::GetLeaderboardType(scriptedActivityComponent->GetActivityID()); - LeaderboardManager::Instance().SaveScore(sender->GetObjectID(), scriptedActivityComponent->GetActivityID(), leaderboardType, 1, finish); + // LeaderboardManager::Instance().SaveScore(sender->GetObjectID(), scriptedActivityComponent->GetActivityID(), leaderboardType, 1, finish); GameMessages::SendNotifyClientObject(self->GetObjectID(), u"ToggleLeaderBoard", scriptedActivityComponent->GetActivityID(), 0, sender->GetObjectID(), diff --git a/dScripts/ActivityManager.cpp b/dScripts/ActivityManager.cpp index 85365e01..96186688 100644 --- a/dScripts/ActivityManager.cpp +++ b/dScripts/ActivityManager.cpp @@ -88,7 +88,7 @@ void ActivityManager::SaveScore(Entity* self, LWOOBJID playerID, uint32_t val1, // Save the new score to the leaderboard and show the leaderboard to the player auto leaderboardType = LeaderboardManager::GetLeaderboardType(gameID); Game::logger->Log("ActivityManager", "leaderboard type %i %i args %i %i %i", leaderboardType, gameID, val1, val2, val3); - LeaderboardManager::Instance().SaveScore(playerID, gameID, leaderboardType, 3, val1, val2, val3); + // LeaderboardManager::Instance().SaveScore(playerID, gameID, leaderboardType, 3, val1, val2, val3); // Makes the leaderboard show up for the player GameMessages::SendNotifyClientObject(self->GetObjectID(), u"ToggleLeaderBoard", gameID, 0, playerID, "", player->GetSystemAddress()); @@ -125,7 +125,7 @@ void ActivityManager::GetLeaderboardData(Entity* self, const LWOOBJID playerID, // Save the new score to the leaderboard and show the leaderboard to the player auto leaderboardType = LeaderboardManager::GetLeaderboardType(gameID); Game::logger->Log("ActivityManager", "gameID %i", gameID, activityID); - LeaderboardManager::Instance().SendLeaderboard(activityID, Leaderboard::InfoType::MyStanding, false, playerID, self->GetObjectID(), 0, numResults); + // LeaderboardManager::Instance().SendLeaderboard(activityID, Leaderboard::InfoType::MyStanding, false, playerID, self->GetObjectID(), 0, numResults); } void ActivityManager::ActivityTimerStart(Entity* self, const std::string& timerName, const float_t updateInterval, diff --git a/migrations/dlu/9_Update_Leaderboard_Storage.sql b/migrations/dlu/9_Update_Leaderboard_Storage.sql index c90ba4a2..6721e74e 100644 --- a/migrations/dlu/9_Update_Leaderboard_Storage.sql +++ b/migrations/dlu/9_Update_Leaderboard_Storage.sql @@ -1,12 +1,12 @@ ALTER TABLE leaderboard - ADD COLUMN hitPercentage FLOAT NOT NULL DEFAULT 0, + ADD COLUMN hitPercentage INT NOT NULL DEFAULT 0, ADD COLUMN streak INT NOT NULL DEFAULT 0, - ADD COLUMN bestLapTime FLOAT NOT NULL DEFAULT 0, + ADD COLUMN bestLapTime INT NOT NULL DEFAULT 0, ADD COLUMN numWins INT NOT NULL DEFAULT 0, - ADD COLUMN timesPlayed INT NOT NULL DEFAULT 0, - MODIFY time FLOAT NOT NULL DEFAULT 0; + ADD COLUMN timesPlayed INT NOT NULL DEFAULT 1, + MODIFY time INT NOT NULL DEFAULT 0; -ALTER TABLE leaderboard CHANGE time bestTime float; +ALTER TABLE leaderboard CHANGE time bestTime INT; ALTER TABLE leaderboard CHANGE last_played last_played TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP(); UPDATE leaderboard SET streak = bestTime where game_id = 1864;