/////////////////////////////////////////////////////////////////// //*-------------------------------------------------------------*// //| Part of the Game Jolt API C++ Library (http://gamejolt.com) |// //*-------------------------------------------------------------*// //| Released under the zlib License |// //| More information available in the readme file |// //*-------------------------------------------------------------*// /////////////////////////////////////////////////////////////////// #include "gjAPI.h" #include gjScoreTable* gjScoreTable::s_pPrimary = NULL; // **************************************************************** /* constructor */ gjScoreTable::gjScoreTable(const gjData& aScoreTableData, gjAPI* pAPI)noexcept : m_iID (atoi(SAFE_MAP_GET(aScoreTableData, "id").c_str())) , m_sTitle (SAFE_MAP_GET(aScoreTableData, "name")) , m_sDescription (SAFE_MAP_GET(aScoreTableData, "description")) , m_iSortDir (0) , m_pAPI (pAPI) { // set the primary status m_bPrimary = (SAFE_MAP_GET(aScoreTableData, "primary") == "1") ? true : false; // set pointer to the primary score table if(m_bPrimary && !s_pPrimary) s_pPrimary = this; // reserve some memory m_apScore.reserve(GJ_API_RESERVE_SCORE); m_apVerify.reserve(4); } // **************************************************************** /* destructor */ gjScoreTable::~gjScoreTable() { // reset pointer to the primary score table if(s_pPrimary == this) s_pPrimary = NULL; // delete score entries FOR_EACH(it, m_apScore) SAFE_DELETE(*it) FOR_EACH(it, m_apVerify) SAFE_DELETE(*it) // clear container m_apScore.clear(); m_apVerify.clear(); } // **************************************************************** /* check for cached score entries */ int gjScoreTable::__CheckCache(const bool bOnlyUser, const int& iLimit, gjScoreList* papOutput) { if(!bOnlyUser) return GJ_INVALID_INPUT; if(!m_iSortDir) return GJ_INVALID_CALL; // fetch cached main user gjUserPtr pMainUser; if(m_pAPI->InterUser()->CheckCache(m_pAPI->GetUserName(), &pMainUser) != GJ_OK) return GJ_REQUEST_CANCELED; if(papOutput) { // retrieve cached main user score entries int iCount = 0; FOR_EACH(it, m_apScore) { gjScore* pScore = (*it); if(pScore->GetUserID() == pMainUser->GetID()) { (*papOutput).push_back(pScore); if(++iCount >= iLimit) break; } } return iCount ? GJ_OK : GJ_NO_DATA_FOUND; } return GJ_NO_DATA_FOUND; } // **************************************************************** /* process score data and cache score entries */ int gjScoreTable::__Process(const std::string& sData, void* pAdd, gjScoreList* papOutput) { // parse output gjDataList aaReturn; if(m_pAPI->ParseRequestKeypair(sData, &aaReturn) != GJ_OK) { gjAPI::ErrorLogAdd("API Error: could not parse scores"); return GJ_REQUEST_FAILED; } // create score entries FOR_EACH(it, aaReturn) { gjScore* pNewScore = new gjScore(*it, this, m_pAPI); bool bNew = true; // remove invalid score if(pNewScore->GetUserName() == "") { SAFE_DELETE(pNewScore) continue; } // check if specific score entry is already available FOR_EACH(it, m_apScore) { gjScore* pOldScore = (*it); if(pOldScore->GetUserName() == pNewScore->GetUserName() && pOldScore->GetSort() == pNewScore->GetSort()) { // specific score entry already available SAFE_DELETE(pNewScore) pNewScore = pOldScore; bNew = false; break; } } if(bNew) m_apScore.push_back(pNewScore); if(papOutput) (*papOutput).push_back(pNewScore); } // try to determine the sort direction if(!m_iSortDir) { if(aaReturn.size() >= 2) { if(std::atoi(SAFE_MAP_GET(aaReturn[0], "sort").c_str()) > std::atoi(SAFE_MAP_GET(aaReturn[1], "sort").c_str())) m_iSortDir = GJ_SORT_DESC; if(std::atoi(SAFE_MAP_GET(aaReturn[0], "sort").c_str()) < std::atoi(SAFE_MAP_GET(aaReturn[1], "sort").c_str())) m_iSortDir = GJ_SORT_ASC; } } // sort score entries if(m_iSortDir) std::sort(m_apScore.begin(), m_apScore.end(), (m_iSortDir == GJ_SORT_DESC) ? SortDescending : SortAscending); return papOutput->size() ? GJ_OK : GJ_NO_DATA_FOUND; } // **************************************************************** /* callback for successfully adding a score entry */ int gjScoreTable::__AddScoreCallback(const std::string& sData, void* pAdd, gjScorePtr* pOutput) { gjScore* pNewScore = static_cast(pAdd); // remove score entry from verification list FOR_EACH(it, m_apVerify) { if((*it) == pNewScore) { m_apVerify.erase(it); break; } } // cache score entry m_apScore.push_back(pNewScore); // sort score entries if(m_iSortDir) std::sort(m_apScore.begin(), m_apScore.end(), (m_iSortDir == GJ_SORT_DESC) ? SortDescending : SortAscending); if(pOutput) (*pOutput) = pNewScore; return GJ_OK; } // **************************************************************** /* constructor */ gjScore::gjScore(const gjData& sScoreData, gjScoreTable* pScoreTable, gjAPI* pAPI)noexcept : m_sScore (SAFE_MAP_GET(sScoreData, "score")) , m_iSort (atoi(SAFE_MAP_GET(sScoreData, "sort").c_str())) , m_sExtraData (SAFE_MAP_GET(sScoreData, "extra_data")) , m_sDate (SAFE_MAP_GET(sScoreData, "stored")) , m_pScoreTable (pScoreTable) , m_pAPI (pAPI) { // check for guest const std::string sGuest = SAFE_MAP_GET(sScoreData, "guest"); const bool bGuest = (sGuest == "") ? false : true; // set user ID and name m_iUserID = bGuest ? -1 : atoi(SAFE_MAP_GET(sScoreData, "user_id").c_str()); m_sUserName = bGuest ? sGuest : SAFE_MAP_GET(sScoreData, "user"); } // **************************************************************** /* callbacks for sorting the score table */ bool SortAscending(const gjScore* i, const gjScore* j) {return (i->GetSort() < j->GetSort());} bool SortDescending(const gjScore* i, const gjScore* j) {return (i->GetSort() > j->GetSort());}