mirror of
https://github.com/DarkflameUniverse/DarkflameServer
synced 2024-08-30 18:43:58 +00:00
Convert to using only floats
This will cover all of our bases for any type of score. No need to do any conversions.
This commit is contained in:
parent
47deca6f4f
commit
b8878da61b
@ -1,7 +1,8 @@
|
||||
#define _DEBUG
|
||||
|
||||
#include "LeaderboardManager.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include "Database.h"
|
||||
#include "EntityManager.h"
|
||||
#include "Character.h"
|
||||
@ -14,7 +15,6 @@
|
||||
#include "Entity.h"
|
||||
#include "LDFFormat.h"
|
||||
#include "DluAssert.h"
|
||||
#include <sstream>
|
||||
|
||||
#include "CDActivitiesTable.h"
|
||||
#include "Metrics.hpp"
|
||||
@ -32,7 +32,12 @@ Leaderboard::Leaderboard(const GameID gameID, const Leaderboard::InfoType infoTy
|
||||
}
|
||||
|
||||
Leaderboard::~Leaderboard() {
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Leaderboard::Clear() {
|
||||
for (auto& entry : entries) for (auto data : entry) delete data;
|
||||
|
||||
}
|
||||
|
||||
inline void WriteLeaderboardRow(std::ostringstream& leaderboard, const uint32_t& index, LDFBaseData* data) {
|
||||
@ -44,7 +49,7 @@ void Leaderboard::Serialize(RakNet::BitStream* bitStream) const {
|
||||
bitStream->Write(infoType);
|
||||
|
||||
std::ostringstream leaderboard;
|
||||
Game::logger->Log("LeaderboardManager", "game is %i info type %i ", gameID, infoType);
|
||||
|
||||
leaderboard << "ADO.Result=7:1"; // Unused in 1.10.64, but is in captures
|
||||
leaderboard << "\nResult.Count=1:1"; // number of results, always 1
|
||||
if (!this->entries.empty()) leaderboard << "\nResult[0].Index=0:RowNumber"; // "Primary key". Live doesn't include this if there are no entries.
|
||||
@ -63,12 +68,12 @@ void Leaderboard::Serialize(RakNet::BitStream* bitStream) const {
|
||||
bitStream->Write<uint32_t>(leaderboardSize);
|
||||
// Doing this all in 1 call so there is no possbility of a dangling pointer.
|
||||
bitStream->WriteAlignedBytes(reinterpret_cast<const unsigned char*>(GeneralUtils::ASCIIToUTF16(leaderboard.str()).c_str()), leaderboardSize * sizeof(char16_t));
|
||||
if (leaderboardSize > 0) bitStream->Write<uint16_t>(0);
|
||||
bitStream->Write0();
|
||||
bitStream->Write0();
|
||||
}
|
||||
|
||||
void Leaderboard::QueryToLdf(std::unique_ptr<sql::ResultSet>& rows) {
|
||||
Clear();
|
||||
if (rows->rowsCount() == 0) return;
|
||||
|
||||
this->entries.reserve(rows->rowsCount());
|
||||
@ -84,49 +89,49 @@ void Leaderboard::QueryToLdf(std::unique_ptr<sql::ResultSet>& rows) {
|
||||
entry.push_back(new LDFData<uint64_t>(u"RowNumber", rows->getInt("ranking")));
|
||||
switch (leaderboardType) {
|
||||
case Type::ShootingGallery:
|
||||
entry.push_back(new LDFData<float>(u"HitPercentage", (rows->getInt("hitPercentage") / 100.0f)));
|
||||
entry.push_back(new LDFData<float>(u"HitPercentage", (rows->getInt("primaryScore") / 100.0f)));
|
||||
// HitPercentage:3 between 0 and 1
|
||||
entry.push_back(new LDFData<int32_t>(u"Score", rows->getInt("score")));
|
||||
entry.push_back(new LDFData<int32_t>(u"Score", rows->getInt("secondaryScore")));
|
||||
// Score:1
|
||||
entry.push_back(new LDFData<int32_t>(u"Streak", rows->getInt("streak")));
|
||||
entry.push_back(new LDFData<int32_t>(u"Streak", rows->getInt("tertiaryScore")));
|
||||
// Streak:1
|
||||
break;
|
||||
case Type::Racing:
|
||||
entry.push_back(new LDFData<float>(u"BestLapTime", rows->getDouble("bestLapTime")));
|
||||
entry.push_back(new LDFData<float>(u"BestTime", rows->getDouble("primaryScore")));
|
||||
// BestLapTime:3
|
||||
entry.push_back(new LDFData<float>(u"BestTime", rows->getDouble("bestTime")));
|
||||
entry.push_back(new LDFData<float>(u"BestLapTime", rows->getDouble("secondaryScore")));
|
||||
// BestTime:3
|
||||
entry.push_back(new LDFData<int32_t>(u"License", 1));
|
||||
// License:1 - 1 if player has completed mission 637 and 0 otherwise
|
||||
entry.push_back(new LDFData<int32_t>(u"NumWins", rows->getInt("numWins")));
|
||||
entry.push_back(new LDFData<int32_t>(u"NumWins", rows->getInt("tertiaryScore")));
|
||||
// NumWins:1
|
||||
break;
|
||||
case Type::UnusedLeaderboard4:
|
||||
entry.push_back(new LDFData<int32_t>(u"Points", rows->getInt("score")));
|
||||
entry.push_back(new LDFData<int32_t>(u"Points", rows->getInt("primaryScore")));
|
||||
// Points:1
|
||||
break;
|
||||
case Type::MonumentRace:
|
||||
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("bestTime")));
|
||||
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("primaryScore")));
|
||||
// Time:1(?)
|
||||
break;
|
||||
case Type::FootRace:
|
||||
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("bestTime")));
|
||||
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("primaryScore")));
|
||||
// Time:1
|
||||
break;
|
||||
case Type::Survival:
|
||||
entry.push_back(new LDFData<int32_t>(u"Points", rows->getInt("score")));
|
||||
entry.push_back(new LDFData<int32_t>(u"Points", rows->getInt("primaryScore")));
|
||||
// Points:1
|
||||
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("bestTime")));
|
||||
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("secondaryScore")));
|
||||
// Time:1
|
||||
break;
|
||||
case Type::SurvivalNS:
|
||||
entry.push_back(new LDFData<int32_t>(u"Wave", rows->getInt("score")));
|
||||
entry.push_back(new LDFData<int32_t>(u"Wave", rows->getInt("primaryScore")));
|
||||
// Wave:1
|
||||
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("bestTime")));
|
||||
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("secondaryScore")));
|
||||
// Time:1
|
||||
break;
|
||||
case Type::Donations:
|
||||
entry.push_back(new LDFData<int32_t>(u"Points", rows->getInt("score")));
|
||||
entry.push_back(new LDFData<int32_t>(u"Points", rows->getInt("primaryScore")));
|
||||
// Score:1
|
||||
break;
|
||||
case Type::None:
|
||||
@ -139,98 +144,33 @@ void Leaderboard::QueryToLdf(std::unique_ptr<sql::ResultSet>& rows) {
|
||||
}
|
||||
|
||||
const std::string_view Leaderboard::GetColumns(Leaderboard::Type leaderboardType) {
|
||||
const char* columns;
|
||||
switch (leaderboardType) {
|
||||
case Type::ShootingGallery:
|
||||
columns = "hitPercentage, score, streak";
|
||||
break;
|
||||
case Type::Racing:
|
||||
columns = "bestLapTime, bestTime, numWins";
|
||||
break;
|
||||
case Type::Donations:
|
||||
case Type::UnusedLeaderboard4:
|
||||
columns = "score";
|
||||
break;
|
||||
case Type::MonumentRace:
|
||||
case Type::FootRace:
|
||||
columns = "bestTime";
|
||||
break;
|
||||
case Type::Survival:
|
||||
columns = "bestTime, score";
|
||||
break;
|
||||
case Type::SurvivalNS:
|
||||
columns = "bestTime, score";
|
||||
break;
|
||||
case Type::None:
|
||||
columns = "";
|
||||
// This type is included here simply to resolve a compiler warning on mac about unused enum types
|
||||
break;
|
||||
}
|
||||
return columns;
|
||||
return "primaryScore, secondaryScore, tertiaryScore";
|
||||
}
|
||||
|
||||
const std::string_view Leaderboard::GetInsertFormat(Leaderboard::Type leaderboardType) {
|
||||
const char* columns;
|
||||
switch (leaderboardType) {
|
||||
case Type::ShootingGallery:
|
||||
columns = "score=%i, hitPercentage=%i, streak=%i";
|
||||
break;
|
||||
case Type::Racing:
|
||||
columns = "bestLapTime=%i, bestTime=%i, numWins=numWins + %i";
|
||||
break;
|
||||
case Type::Donations:
|
||||
case Type::UnusedLeaderboard4:
|
||||
columns = "score=%i";
|
||||
break;
|
||||
case Type::MonumentRace:
|
||||
case Type::FootRace:
|
||||
columns = "bestTime=%i";
|
||||
break;
|
||||
case Type::Survival:
|
||||
columns = "bestTime=%i, score=%i";
|
||||
break;
|
||||
case Type::SurvivalNS:
|
||||
columns = "bestTime=%i, score=%i";
|
||||
break;
|
||||
case Type::None:
|
||||
columns = "";
|
||||
// This type is included here simply to resolve a compiler warning on mac about unused enum types
|
||||
break;
|
||||
}
|
||||
return columns;
|
||||
return "primaryScore %f, secondaryScore %f, tertiaryScore %f";
|
||||
}
|
||||
|
||||
const std::string_view Leaderboard::GetOrdering(Leaderboard::Type leaderboardType) {
|
||||
const char* orderBase;
|
||||
// Use a switch case and return desc for all 3 columns if higher is better and asc if lower is better
|
||||
switch (leaderboardType) {
|
||||
case Type::ShootingGallery:
|
||||
orderBase = "score DESC, streak DESC, hitPercentage DESC";
|
||||
break;
|
||||
case Type::Racing:
|
||||
orderBase = "bestTime ASC, bestLapTime ASC, numWins DESC";
|
||||
break;
|
||||
case Type::Donations:
|
||||
case Type::UnusedLeaderboard4:
|
||||
orderBase = "score DESC";
|
||||
break;
|
||||
case Type::MonumentRace:
|
||||
orderBase = "bestTime ASC";
|
||||
break;
|
||||
case Type::FootRace:
|
||||
orderBase = "bestTime DESC";
|
||||
break;
|
||||
case Type::Survival:
|
||||
orderBase = "score DESC, bestTime DESC";
|
||||
break;
|
||||
case Type::UnusedLeaderboard4:
|
||||
case Type::SurvivalNS:
|
||||
orderBase = "bestTime DESC, score DESC";
|
||||
break;
|
||||
case Type::Donations:
|
||||
return "primaryScore DESC, secondaryScore DESC, tertiaryScore DESC";
|
||||
case Type::Racing:
|
||||
case Type::MonumentRace:
|
||||
return "primaryScore ASC, secondaryScore ASC, tertiaryScore ASC";
|
||||
case Type::None:
|
||||
orderBase = "";
|
||||
// This type is included here simply to resolve a compiler warning on mac about unused enum types
|
||||
break;
|
||||
case Type::Survival:
|
||||
return Game::config->GetValue("classic_survival_scoring") == "1" ?
|
||||
"primaryScore DESC, secondaryScore DESC, tertiaryScore DESC" :
|
||||
"secondaryScore DESC, primaryScore DESC, tertiaryScore DESC";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
return orderBase;
|
||||
}
|
||||
|
||||
void Leaderboard::SetupLeaderboard(uint32_t resultStart, uint32_t resultEnd) {
|
||||
@ -285,34 +225,22 @@ void Leaderboard::SetupLeaderboard(uint32_t resultStart, uint32_t resultEnd) {
|
||||
)
|
||||
)QUERY";
|
||||
|
||||
[[likely]] if (this->infoType != InfoType::Friends) friendsQuery.clear();
|
||||
if (this->infoType != InfoType::Friends) friendsQuery.clear();
|
||||
const auto orderBase = GetOrdering(this->leaderboardType);
|
||||
const auto selectBase = GetColumns(this->leaderboardType);
|
||||
|
||||
constexpr uint16_t STRING_LENGTH = 2048;
|
||||
char lookupBuffer[STRING_LENGTH];
|
||||
int32_t res = snprintf(lookupBuffer, STRING_LENGTH, queryBase.data(), orderBase.data(), friendsQuery.data(), selectBase.data(), resultStart, resultEnd);
|
||||
DluAssert(res != -1);
|
||||
|
||||
std::string baseLookupStr;
|
||||
char baseRankingBuffer[STRING_LENGTH];
|
||||
bool neededFormatting;
|
||||
[[unlikely]] if (this->infoType == InfoType::Top) {
|
||||
baseLookupStr = "SELECT id FROM leaderboard WHERE game_id = ? ORDER BY %s LIMIT 1";
|
||||
neededFormatting = true;
|
||||
std::string baseLookup;
|
||||
if (this->infoType == InfoType::Top) {
|
||||
baseLookup = "SELECT id FROM leaderboard WHERE game_id = ? ORDER BY ";
|
||||
baseLookup += orderBase.data();
|
||||
} else {
|
||||
baseLookupStr = "SELECT id FROM leaderboard WHERE game_id = ? AND character_id = ? LIMIT 1";
|
||||
neededFormatting = false;
|
||||
baseLookup = "SELECT id FROM leaderboard WHERE game_id = ? AND character_id = ";
|
||||
baseLookup += std::to_string(this->relatedPlayer);
|
||||
}
|
||||
baseLookup += " LIMIT 1";
|
||||
|
||||
// If we need to format the base ranking query, do so, otherwise just copy the query since it's already formatted.
|
||||
if (neededFormatting) snprintf(baseRankingBuffer, STRING_LENGTH, baseLookupStr.c_str(), orderBase.data());
|
||||
else std::copy(baseLookupStr.begin(), baseLookupStr.end() + 1, baseRankingBuffer);
|
||||
|
||||
std::unique_ptr<sql::PreparedStatement> baseQuery(Database::CreatePreppedStmt(baseRankingBuffer));
|
||||
std::unique_ptr<sql::PreparedStatement> baseQuery(Database::CreatePreppedStmt(baseLookup));
|
||||
baseQuery->setInt(1, this->gameID);
|
||||
if (!neededFormatting) baseQuery->setInt(2, this->relatedPlayer);
|
||||
|
||||
std::unique_ptr<sql::ResultSet> baseResult(baseQuery->executeQuery());
|
||||
|
||||
if (!baseResult->next()) return; // In this case, there are no entries in the leaderboard for this game.
|
||||
@ -320,6 +248,10 @@ void Leaderboard::SetupLeaderboard(uint32_t resultStart, uint32_t resultEnd) {
|
||||
uint32_t relatedPlayerLeaderboardId = baseResult->getInt("id");
|
||||
|
||||
// Create and execute the actual save here
|
||||
constexpr uint16_t STRING_LENGTH = 2048;
|
||||
char lookupBuffer[STRING_LENGTH];
|
||||
[[maybe_unused]] int32_t res = snprintf(lookupBuffer, STRING_LENGTH, queryBase.data(), orderBase.data(), friendsQuery.data(), selectBase.data(), resultStart, resultEnd);
|
||||
DluAssert(res != -1);
|
||||
std::unique_ptr<sql::PreparedStatement> query(Database::CreatePreppedStmt(lookupBuffer));
|
||||
|
||||
query->setInt(1, this->gameID);
|
||||
@ -365,7 +297,7 @@ std::string FormatInsert(const Leaderboard::Type& type, const Score& score, cons
|
||||
return finishedQuery;
|
||||
}
|
||||
|
||||
void LeaderboardManager::SaveScore(const LWOOBJID& playerID, const GameID gameID, const Leaderboard::Type leaderboardType, const uint32_t primaryScore, const uint32_t secondaryScore, const uint32_t tertiaryScore) {
|
||||
void LeaderboardManager::SaveScore(const LWOOBJID& playerID, const GameID gameID, const Leaderboard::Type leaderboardType, const float primaryScore, const float secondaryScore, const float tertiaryScore) {
|
||||
auto* lookup = "SELECT * FROM leaderboard WHERE character_id = ? AND game_id = ?;";
|
||||
|
||||
std::unique_ptr<sql::PreparedStatement> query(Database::CreatePreppedStmt(lookup));
|
||||
@ -381,46 +313,46 @@ void LeaderboardManager::SaveScore(const LWOOBJID& playerID, const GameID gameID
|
||||
switch (leaderboardType) {
|
||||
// Higher score better
|
||||
case Leaderboard::Type::ShootingGallery: {
|
||||
oldScore.SetPrimaryScore(myScoreResult->getInt("score"));
|
||||
oldScore.SetSecondaryScore(myScoreResult->getInt("hitPercentage"));
|
||||
oldScore.SetTertiaryScore(myScoreResult->getInt("streak"));
|
||||
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
|
||||
oldScore.SetSecondaryScore(myScoreResult->getInt("secondaryScore"));
|
||||
oldScore.SetTertiaryScore(myScoreResult->getInt("tertiaryScore"));
|
||||
break;
|
||||
}
|
||||
case Leaderboard::Type::FootRace: {
|
||||
oldScore.SetPrimaryScore(myScoreResult->getInt("bestTime"));
|
||||
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
|
||||
break;
|
||||
}
|
||||
case Leaderboard::Type::Survival: {
|
||||
// Config option may reverse these
|
||||
oldScore.SetPrimaryScore(myScoreResult->getInt("bestTime"));
|
||||
oldScore.SetSecondaryScore(myScoreResult->getInt("score"));
|
||||
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
|
||||
oldScore.SetSecondaryScore(myScoreResult->getInt("secondaryScore"));
|
||||
break;
|
||||
}
|
||||
case Leaderboard::Type::SurvivalNS: {
|
||||
oldScore.SetPrimaryScore(myScoreResult->getInt("bestTime"));
|
||||
oldScore.SetSecondaryScore(myScoreResult->getInt("score"));
|
||||
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
|
||||
oldScore.SetSecondaryScore(myScoreResult->getInt("secondaryScore"));
|
||||
break;
|
||||
}
|
||||
case Leaderboard::Type::UnusedLeaderboard4:
|
||||
case Leaderboard::Type::Donations: {
|
||||
oldScore.SetPrimaryScore(myScoreResult->getInt("score"));
|
||||
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
|
||||
break;
|
||||
}
|
||||
case Leaderboard::Type::Racing: {
|
||||
oldScore.SetPrimaryScore(myScoreResult->getInt("bestTime"));
|
||||
oldScore.SetSecondaryScore(myScoreResult->getInt("bestLapTime"));
|
||||
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
|
||||
oldScore.SetSecondaryScore(myScoreResult->getInt("secondaryScore"));
|
||||
lowerScoreBetter = true;
|
||||
break;
|
||||
}
|
||||
case Leaderboard::Type::MonumentRace: {
|
||||
oldScore.SetPrimaryScore(myScoreResult->getInt("bestTime"));
|
||||
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
|
||||
lowerScoreBetter = true;
|
||||
// Do score checking here
|
||||
break;
|
||||
}
|
||||
case Leaderboard::Type::None:
|
||||
default:
|
||||
Game::logger->Log("LeaderboardManager", "Unknown leaderboard type %i. Cannot save score!", leaderboardType);
|
||||
Game::logger->Log("LeaderboardManager", "Unknown leaderboard type %i for game %i. Cannot save score!", leaderboardType, gameID);
|
||||
return;
|
||||
}
|
||||
bool newHighScore = lowerScoreBetter ? newScore < oldScore : newScore > oldScore;
|
||||
|
@ -25,7 +25,7 @@ public:
|
||||
secondaryScore = 0;
|
||||
tertiaryScore = 0;
|
||||
}
|
||||
Score(const uint32_t primaryScore, const uint32_t secondaryScore = 0, const uint32_t tertiaryScore = 0) {
|
||||
Score(const float primaryScore, const float secondaryScore = 0, const float tertiaryScore = 0) {
|
||||
this->primaryScore = primaryScore;
|
||||
this->secondaryScore = secondaryScore;
|
||||
this->tertiaryScore = tertiaryScore;
|
||||
@ -36,18 +36,18 @@ public:
|
||||
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 SetPrimaryScore(const float score) { primaryScore = score; }
|
||||
float GetPrimaryScore() const { return primaryScore; }
|
||||
|
||||
void SetSecondaryScore(const uint32_t score) { secondaryScore = score; }
|
||||
uint32_t GetSecondaryScore() const { return secondaryScore; }
|
||||
void SetSecondaryScore(const float score) { secondaryScore = score; }
|
||||
float GetSecondaryScore() const { return secondaryScore; }
|
||||
|
||||
void SetTertiaryScore(const uint32_t score) { tertiaryScore = score; }
|
||||
uint32_t GetTertiaryScore() const { return tertiaryScore; }
|
||||
void SetTertiaryScore(const float score) { tertiaryScore = score; }
|
||||
float GetTertiaryScore() const { return tertiaryScore; }
|
||||
private:
|
||||
uint32_t primaryScore;
|
||||
uint32_t secondaryScore;
|
||||
uint32_t tertiaryScore;
|
||||
float primaryScore;
|
||||
float secondaryScore;
|
||||
float tertiaryScore;
|
||||
};
|
||||
|
||||
using GameID = uint32_t;
|
||||
@ -73,10 +73,11 @@ public:
|
||||
Donations,
|
||||
None
|
||||
};
|
||||
|
||||
Leaderboard() = delete;
|
||||
Leaderboard(const GameID gameID, const Leaderboard::InfoType infoType, const bool weekly, LWOOBJID relatedPlayer, const Leaderboard::Type = None);
|
||||
|
||||
~Leaderboard();
|
||||
void Clear();
|
||||
|
||||
/**
|
||||
* Serialize the Leaderboard to a BitStream
|
||||
@ -85,15 +86,6 @@ public:
|
||||
*/
|
||||
void Serialize(RakNet::BitStream* bitStream) const;
|
||||
|
||||
/**
|
||||
* Based on the associated gameID, return true if the score provided
|
||||
* is better than the current entries' score
|
||||
* @param score
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool IsScoreBetter(const uint32_t score) const { return false; };
|
||||
|
||||
/**
|
||||
* Builds the leaderboard from the database based on the associated gameID
|
||||
*
|
||||
@ -135,7 +127,7 @@ namespace LeaderboardManager {
|
||||
using LeaderboardCache = std::map<GameID, Leaderboard::Type>;
|
||||
void SendLeaderboard(GameID gameID, Leaderboard::InfoType infoType, bool weekly, LWOOBJID playerID, LWOOBJID targetID, uint32_t resultStart = 0, uint32_t resultEnd = 10);
|
||||
|
||||
void SaveScore(const LWOOBJID& playerID, const GameID gameID, const Leaderboard::Type leaderboardType, const uint32_t primaryScore, const uint32_t secondaryScore = 0, const uint32_t tertiaryScore = 0);
|
||||
void SaveScore(const LWOOBJID& playerID, const GameID gameID, const Leaderboard::Type leaderboardType, const float primaryScore, const float secondaryScore = 0, const float tertiaryScore = 0);
|
||||
|
||||
void GetLeaderboard(const uint32_t gameID, const Leaderboard::InfoType infoType, const bool weekly, const LWOOBJID playerID = LWOOBJID_EMPTY);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user