2023-05-30 11:11:37 +00:00
|
|
|
#ifndef __LEADERBOARDMANAGER__H__
|
|
|
|
#define __LEADERBOARDMANAGER__H__
|
|
|
|
|
2023-04-13 07:45:03 +00:00
|
|
|
#include <map>
|
2023-05-31 01:21:10 +00:00
|
|
|
#include <memory>
|
2023-05-30 11:11:37 +00:00
|
|
|
#include <string_view>
|
2023-04-13 07:45:03 +00:00
|
|
|
#include <vector>
|
2021-12-05 17:54:36 +00:00
|
|
|
|
2023-04-13 04:57:58 +00:00
|
|
|
#include "Singleton.h"
|
|
|
|
#include "dCommonVars.h"
|
2023-04-14 08:32:52 +00:00
|
|
|
#include "LDFFormat.h"
|
2021-12-05 17:54:36 +00:00
|
|
|
|
2023-05-09 01:36:28 +00:00
|
|
|
namespace sql {
|
|
|
|
class ResultSet;
|
|
|
|
};
|
|
|
|
|
|
|
|
namespace RakNet {
|
2023-04-13 04:57:58 +00:00
|
|
|
class BitStream;
|
2021-12-05 17:54:36 +00:00
|
|
|
};
|
|
|
|
|
2023-05-30 11:38:19 +00:00
|
|
|
class Score {
|
|
|
|
public:
|
|
|
|
Score() {
|
|
|
|
primaryScore = 0;
|
|
|
|
secondaryScore = 0;
|
|
|
|
tertiaryScore = 0;
|
|
|
|
}
|
|
|
|
Score(const uint32_t primaryScore, const uint32_t secondaryScore = 0, const 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 GameID = uint32_t;
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
class Leaderboard {
|
|
|
|
public:
|
2023-04-13 04:57:58 +00:00
|
|
|
|
|
|
|
// Enums for leaderboards
|
|
|
|
enum InfoType : uint32_t {
|
|
|
|
Top, // Top 11 all time players
|
|
|
|
MyStanding, // Ranking of the current player
|
|
|
|
Friends // Ranking between friends
|
|
|
|
};
|
|
|
|
|
|
|
|
enum Type : uint32_t {
|
|
|
|
ShootingGallery,
|
|
|
|
Racing,
|
|
|
|
MonumentRace,
|
|
|
|
FootRace,
|
2023-04-17 22:19:13 +00:00
|
|
|
UnusedLeaderboard4, // There is no 4 defined anywhere in the cdclient, but it takes a Score.
|
|
|
|
Survival,
|
2023-04-14 04:55:09 +00:00
|
|
|
SurvivalNS,
|
|
|
|
Donations,
|
2023-05-09 07:06:43 +00:00
|
|
|
None
|
2023-04-13 04:57:58 +00:00
|
|
|
};
|
|
|
|
|
2023-05-03 07:38:38 +00:00
|
|
|
Leaderboard(const GameID gameID, const Leaderboard::InfoType infoType, const bool weekly, LWOOBJID relatedPlayer, const Leaderboard::Type = None);
|
|
|
|
|
|
|
|
~Leaderboard();
|
2023-04-13 04:57:58 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Serialize the Leaderboard to a BitStream
|
2023-05-09 01:36:28 +00:00
|
|
|
*
|
2023-04-13 04:57:58 +00:00
|
|
|
* Expensive! Leaderboards are very string intensive so be wary of performatnce calling this method.
|
|
|
|
*/
|
2023-05-30 11:38:19 +00:00
|
|
|
void Serialize(RakNet::BitStream* bitStream) const;
|
2023-04-13 04:57:58 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Based on the associated gameID, return true if the score provided
|
|
|
|
* is better than the current entries' score
|
2023-05-09 01:36:28 +00:00
|
|
|
* @param score
|
|
|
|
* @return true
|
|
|
|
* @return false
|
2023-04-13 04:57:58 +00:00
|
|
|
*/
|
2023-04-13 07:45:03 +00:00
|
|
|
bool IsScoreBetter(const uint32_t score) const { return false; };
|
2023-04-13 04:57:58 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Builds the leaderboard from the database based on the associated gameID
|
2023-05-30 11:11:37 +00:00
|
|
|
*
|
2023-05-09 02:59:10 +00:00
|
|
|
* @param resultStart The index to start the leaderboard at. Zero indexed.
|
|
|
|
* @param resultEnd The index to end the leaderboard at. Zero indexed.
|
2023-04-13 04:57:58 +00:00
|
|
|
*/
|
2023-05-09 02:35:19 +00:00
|
|
|
void SetupLeaderboard(uint32_t resultStart = 0, uint32_t resultEnd = 10);
|
2023-04-13 04:57:58 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Sends the leaderboard to the client specified by targetID.
|
|
|
|
*/
|
2023-05-30 11:23:48 +00:00
|
|
|
void Send(const LWOOBJID targetID) const;
|
2023-05-09 01:36:28 +00:00
|
|
|
|
|
|
|
// Helper functions to get the columns, ordering and insert format for a leaderboard
|
2023-05-30 11:11:37 +00:00
|
|
|
static const std::string_view GetColumns(Type leaderboardType);
|
|
|
|
static const std::string_view GetInsertFormat(Type leaderboardType);
|
|
|
|
static const std::string_view GetOrdering(Type leaderboardType);
|
2021-12-05 17:54:36 +00:00
|
|
|
private:
|
2023-05-04 23:53:36 +00:00
|
|
|
// Returns true if the string needs formatting
|
|
|
|
bool GetRankingQuery(std::string& lookupReturn) const;
|
2023-05-09 01:36:28 +00:00
|
|
|
|
|
|
|
// Takes the resulting query from a leaderboard lookup and converts it to the LDF we need
|
|
|
|
// to send it to a client.
|
|
|
|
void QueryToLdf(std::unique_ptr<sql::ResultSet>& rows);
|
|
|
|
|
2023-05-28 11:30:20 +00:00
|
|
|
using LeaderboardEntry = std::vector<LDFBaseData*>;
|
|
|
|
using LeaderboardEntries = std::vector<LeaderboardEntry>;
|
|
|
|
|
2023-04-13 04:57:58 +00:00
|
|
|
LeaderboardEntries entries;
|
2021-12-05 17:54:36 +00:00
|
|
|
LWOOBJID relatedPlayer;
|
2023-04-13 04:57:58 +00:00
|
|
|
GameID gameID;
|
|
|
|
InfoType infoType;
|
|
|
|
Leaderboard::Type leaderboardType;
|
2021-12-05 17:54:36 +00:00
|
|
|
bool weekly;
|
|
|
|
};
|
|
|
|
|
2023-05-30 11:11:37 +00:00
|
|
|
namespace LeaderboardManager {
|
|
|
|
|
2023-05-28 11:30:20 +00:00
|
|
|
using LeaderboardCache = std::map<GameID, Leaderboard::Type>;
|
2023-05-10 05:21:41 +00:00
|
|
|
void SendLeaderboard(GameID gameID, Leaderboard::InfoType infoType, bool weekly, LWOOBJID playerID, LWOOBJID targetID, uint32_t resultStart = 0, uint32_t resultEnd = 10);
|
2023-05-09 01:36:28 +00:00
|
|
|
|
2023-05-30 11:38:19 +00:00
|
|
|
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);
|
2023-05-09 01:36:28 +00:00
|
|
|
|
2023-05-30 11:38:19 +00:00
|
|
|
void GetLeaderboard(const uint32_t gameID, const Leaderboard::InfoType infoType, const bool weekly, const LWOOBJID playerID = LWOOBJID_EMPTY);
|
2023-05-30 11:11:37 +00:00
|
|
|
|
|
|
|
Leaderboard::Type GetLeaderboardType(const GameID gameID);
|
|
|
|
extern LeaderboardCache leaderboardCache;
|
2021-12-05 17:54:36 +00:00
|
|
|
};
|
|
|
|
|
2023-05-30 11:11:37 +00:00
|
|
|
#endif //!__LEADERBOARDMANAGER__H__
|