#include "clientapi.h" #include #include #include #include "json.h" // calculate the size of a constant sized array #define ARRSIZE(ARRNAME) (sizeof(ARRNAME) / sizeof(ARRNAME[0])) #define ARR(NAME, ...) static const QString NAME ## Names[] = {__VA_ARGS__}; \ static const uint32_t NAME ## NamesCount = ARRSIZE(NAME ## Names); ARR(ReadyCheckState, "Invalid", "None", "InProgress", "Accepted", "Declined"); ARR(GameflowPhase, "None", "Lobby", "Matchmaking", "CheckedIntoTournament", "ReadyCheck", "ChampSelect", "GameStart", "FailedToLaunch", "InProgress", "Reconnect", "WaitingForStats", "PreEndOfGame", "EndOfGame", "TerminatedInError"); ARR(ChampSelectPhase, "Invalid", "GAME_STARTING", "PLANNING", "BAN_PICK", "FINALIZATION"); ARR(Position, "Invalid", "top", "jungle", "middle", "bottom", "utility"); ARR(ShortPosition, "", "Top", "Jgl", "Mid", "Bot", "Sup"); ARR(ChampSelectActionType, "Invalid", "ban", "pick", "ten_bans_reveal"); template static T mapEnum(const QString& input, const QString* names, uint32_t count, T defaul) { if(input.isEmpty()) return defaul; for (uint32_t i = 0; i < count; ++i) { if (names[i] == input) { return (T) i; } } qWarning() << "no mapping of enum-string: " << input << " using default: " << defaul << " type: " << typeid(T).name(); return defaul; } #define MAPENUM(VAR, ENUM, DEFAULT) \ mapEnum(VAR, ENUM ## Names, ENUM ## NamesCount, ClientAPI:: ENUM :: DEFAULT) template static std::vector readVector(QJsonArray arr) { std::vector out; out.reserve(arr.size()); for(auto it : arr) { out.push_back(convert((QJsonValue) it)); } return out; } ClientAPI::ReadyCheckState ClientAPI::toReadyCheckState(const QJsonObject& obj) { QString searchState = getValue(obj, "state", "Invalid"); QString playerresponse = getValue(obj, "playerResponse", "None"); ClientAPI::ReadyCheckState response = MAPENUM(playerresponse, ReadyCheckState, NONE); if(response == ClientAPI::ReadyCheckState::NONE) { auto sstate = MAPENUM(searchState, ReadyCheckState, INVALID); if(sstate == ClientAPI::ReadyCheckState::INPROGRESS) { return sstate; } } return response; } ClientAPI::GameflowPhase ClientAPI::toGameflowPhase(const QString& str) { return MAPENUM(str, GameflowPhase, NONE); } ClientAPI::ChampSelectPhase ClientAPI::toChampSelectPhase(const QString& str) { return MAPENUM(str, ChampSelectPhase, INVALID); } Position toPosition(const QString& str) { return mapEnum(str, PositionNames, PositionNamesCount, Position::INVALID); } QString toString(Position p) { return PositionNames[(int) p]; } QString toShortString(Position p) { return ShortPositionNames[(int) p]; } ClientAPI::ChampSelectActionType ClientAPI::toChampSelectActionType(const QString& str) { return MAPENUM(str, ChampSelectActionType, INVALID); } ClientAPI::TimerInfo::TimerInfo() {} ClientAPI::TimerInfo::TimerInfo(const QJsonObject& obj) { adjustedTimeLeftInPhase = getValue(obj, "adjustedTimeLeftInPhase", 0); internalNowInEpochMs = getValue(obj, "internalNowInEpochMs", 0); isefinite = getValue(obj, "isefinite", 0); phase = MAPENUM(getValue(obj, "phase", "Invalid"), ChampSelectPhase, INVALID); totalTimeInPhase = getValue(obj, "totalTimeInPhase", 0); } ClientAPI::ChampSelectAction::ChampSelectAction() {} ClientAPI::ChampSelectAction::ChampSelectAction(const QJsonObject& json) { actorCellID = getValue(json, "actorCellId"); championID = getValue(json, "championId"); completed = getValue(json, "completed"); id = getValue(json, "id"); isAllyAction = getValue(json, "isAllyAction"); isInProgress = getValue(json, "isInProgress"); const QString typestr = getValue(json, "type", "Invalid"); type = toChampSelectActionType(typestr); } ClientAPI::ChampSelectCell::ChampSelectCell() {} ClientAPI::ChampSelectCell::ChampSelectCell(const QJsonObject& json) { position = toPosition(getValue(json, "assignedPosition")); cellID = getValue(json, "cellId"); championID = getValue(json, "championId"); championPickIntentID = getValue(json, "championPickIntent"); summonerID = getValue(json, "summonerId"); spell1Id = getValue(json, "spell1Id", 0); spell2Id = getValue(json, "spell2Id", 0); } std::vector ClientAPI::loadAllInfos(const QJsonArray& arr) { std::vector out; out.reserve(arr.size()); // should usualy be 5 for(auto it = arr.constBegin(); it != arr.constEnd(); ++it) { if(it->isObject()) { out.push_back((ChampSelectCell) it->toObject()); } } return out; } ClientAPI::ChampSelectSession::ChampSelectSession() {} ClientAPI::ChampSelectSession::ChampSelectSession(const QJsonObject& json) { // loading actions auto actionsref = json["actions"]; // its an array of array id ChampSelectAction if(actionsref.isArray()) { QJsonArray jactions = actionsref.toArray(); for(auto jact = jactions.constBegin(); jact != jactions.constEnd(); ++jact) { if(!jact->isArray()) continue; QJsonArray jactarr = jact->toArray(); for(auto it = jactarr.constBegin(); it != jactarr.constEnd(); ++it) { if(it->isObject()) { actions.push_back((ChampSelectAction) it->toObject()); } } } } counter = getValue(json, "counter"); gameid = getValue(json, "gameId"); allowDuplicatePick = getValue(json, "allowDuplicatePicks", false); allowRerolling = getValue(json, "allowRerolling", false); allowSkinSelection = getValue(json, "allowSkinSelection", true); hasSimultaneousBans = getValue(json, "hasSimultaneousBans", false); hasSimultaneousPicks = getValue(json, "hasSimultaneousPicks", true); isCustomGame = getValue(json, "isCustomGame", false); isSpectating = getValue(json, "isSpectating", false); skipChampionSelect = getValue(json, "skipChampionSelect", false); rerollsRemaining = getValue(json, "rerollsRemaining", 0); localPlayerCellId = getValue(json, "localPlayerCellId", -1); auto timerref = json["timer"]; if(timerref.isObject()) { timer = (TimerInfo) timerref.toObject(); } // load cellinfo auto myteamref = json["myTeam"]; if(myteamref.isArray()) { myTeam = loadAllInfos(myteamref.toArray()); } auto theirteamref = json["theirTeam"]; if(theirteamref.isArray()) { theirTeam = loadAllInfos(theirteamref.toArray()); } } ClientAPI::ChampSelectSession::operator bool() { return gameid != 0; } ClientAPI::RunePage::RunePage() {} ClientAPI::RunePage::RunePage(const QJsonObject& json) { id = getValue(json, "id", 0); lastmodified = getValue(json, "lastModified", 0); runepage.primaryStyle = getValue(json, "primaryStyleId", 0); runepage.secondaryStyle = getValue(json, "subStyleId", 0); name = getValue(json, "name"); isDeleteable = getValue(json, "isDeletable", false); isEditable = getValue(json, "isEditable", false); isActive = getValue(json, "isActive", false); isCurrent = getValue(json, "current", false); isValid = getValue(json, "isValid", false); order = getValue(json, "order", 0); auto selectedref = json["selectedPerkIds"]; if(selectedref.isArray()) { runepage.selectedAspects = readVector(selectedref.toArray()); } } RuneStyleSlot::RuneStyleSlot() {} RuneStyleSlot::RuneStyleSlot(const QJsonObject& json) { type = getValue(json, "type"); auto perksj = json["perks"]; if(perksj.isArray()) { perks = readVector(perksj.toArray()); } } RuneStyle::RuneStyle() {} RuneStyle::RuneStyle(const QJsonObject& json) { id = getValue(json, "id", 0); name = getValue(json, "name"); iconPath = getValue(json, "iconPath"); tooltip = getValue(json, "tooltip"); idName = getValue(json, "idName"); auto subStylesRef = json["allowedSubStyles"]; if(subStylesRef.isArray()) { allowedSubStyles = readVector(subStylesRef.toArray()); } auto runeSlotsRef = json["slots"]; if(runeSlotsRef.isArray()) { runeSlots = readVector(runeSlotsRef.toArray()); } } RuneAspekt::RuneAspekt() {} RuneAspekt::RuneAspekt(const QJsonObject& json) { id = getValue(json, "id", 0); name = getValue(json, "name"); shortDesc = getValue(json, "shortDesc"); longDesc = getValue(json, "longDesc"); tooltip = getValue(json, "tooltip"); iconPath = getValue(json, "iconPath"); } ClientAPI::Message::Message() {} ClientAPI::Message::Message(const QJsonObject& json) { body = getValue(json, "body"); fromId = getValue(json, "fromId"); fromPid = getValue(json, "fromPid"); fromSummonerId = getValue(json, "fromSummonerId"); id = getValue(json, "id"); isHistorical = getValue(json, "isHistorical", true); timestamp = getValue(json, "timestamp"); type = getValue(json, "type"); } ClientAPI::Conversation::Conversation() {} ClientAPI::Conversation::Conversation(const QJsonObject& json) : lastMessage(nullptr) { gameName = getValue(json, "gameName"); gameTag = getValue(json, "gameTag"); id = getValue(json, "id"); isMuted = getValue(json, "isMuted"); name = getValue(json, "name"); password = getValue(json, "password"); pid = getValue(json, "pid"); targetRegion = getValue(json, "targetRegion"); type = getValue(json, "type"); unreadMessageCount = getValue(json, "unreadMessageCount"); auto msgref = json["lastMessage"]; if(msgref.isObject()) { lastMessage = std::make_shared(msgref.toObject()); } } #define PRINTENUM(ENUMNAME) \ std::ostream& operator<<(std::ostream& str, const ClientAPI:: ENUMNAME & state) { \ assert(((uint32_t) state) < ENUMNAME ## NamesCount); \ return str << ENUMNAME ## Names[(uint32_t) state].toStdString() << " (" << (uint32_t) state << ')'; \ } \ \ QDebug operator<<(QDebug str, const ClientAPI:: ENUMNAME & state) { \ assert(((uint32_t) state) < ENUMNAME ## NamesCount); \ return str << ENUMNAME ## Names[(uint32_t) state] << " (" << (uint32_t) state << ')'; \ } PRINTENUM(ReadyCheckState) PRINTENUM(GameflowPhase) PRINTENUM(ChampSelectPhase) PRINTENUM(ChampSelectActionType) // not using macro because its not in ClientAPI std::ostream& operator<<(std::ostream& str, const Position & state) { assert(((uint32_t) state) < PositionNamesCount); return str << PositionNames[(uint32_t) state].toStdString() << " (" << (uint32_t) state << ')'; } QDebug operator<<(QDebug str, const Position & state) { assert(((uint32_t) state) < PositionNamesCount); return str << PositionNames[(uint32_t) state] << " (" << (uint32_t) state << ')'; }