diff --git a/include/clientapi.h b/include/clientapi.h index e74850e..82cab44 100644 --- a/include/clientapi.h +++ b/include/clientapi.h @@ -97,6 +97,8 @@ public: int32_t championID = 0; int32_t championPickIntentID = 0; int64_t summonerID = 0; + int64_t spell1Id = 0; // 4 = flash, 6 = ghost, 7 = heal, 11 = smite, 12 = teleport, 14 = ignite + int64_t spell2Id = 0; ChampSelectCell(); explicit ChampSelectCell(const QJsonObject& json); @@ -148,6 +150,37 @@ public: explicit RunePage(const QJsonObject& json); }; + struct Message { + std::string body; + std::string fromId; + std::string fromPid; + int64_t fromSummonerId; + std::string id; + bool isHistorical; + std::string timestamp; + std::string type; // known types: chat (1:1), customGame, championSelect, groupchat + + Message(); + explicit Message(const QJsonObject& json); + }; + + struct Conversation { + std::string gameName; + std::string gameTag; + std::string id; + bool isMuted; + std::shared_ptr lastMessage; + std::string name; + std::string password; + std::string pid; + std::string targetRegion; + std::string type; + int64_t unreadMessageCount; + + Conversation(); + explicit Conversation(const QJsonObject& json); + }; + ClientAPI(const ClientAccess& access); ~ClientAPI(); @@ -164,6 +197,10 @@ public: TimerInfo getTimerInfo(); + // chats + std::vector getAllConversations(); + Message sendMessage(const std::string& chatid, const std::string& messagebody); + // rune stuff RunePage getCurrentRunePage(); std::vector getAllRunePages(); diff --git a/include/lolautoaccept.h b/include/lolautoaccept.h index 7a726e2..0bc3bb1 100644 --- a/include/lolautoaccept.h +++ b/include/lolautoaccept.h @@ -49,6 +49,9 @@ protected: bool nextApplyRunes = false; + std::string chatid; // the chatid of the chat from the champselect + std::chrono::time_point lastMessageSent; + public: enum class State { LOBBY = 0, @@ -96,5 +99,7 @@ private: static int32_t getBestRunePage(const std::vector& allpages); static int32_t getMatchingRunePage(const RunePage& rp, const std::vector& allpages); void champSelect(); + void smiteWarning(const std::vector& cells); + const std::string& getChatid(); void applyRunes_internal(uint32_t champid, Position pos); -}; \ No newline at end of file +}; diff --git a/src/clientapi.cpp b/src/clientapi.cpp index 5e1a590..4082da1 100644 --- a/src/clientapi.cpp +++ b/src/clientapi.cpp @@ -148,6 +148,53 @@ ClientAPI::TimerInfo ClientAPI::getTimerInfo() { return (TimerInfo) obj; } +std::vector ClientAPI::getAllConversations() { + std::vector out; + QJsonDocument doc = request("lol-chat/v1/conversations"); + if(doc.isArray()) { + QJsonArray arr = doc.array(); + out.reserve(arr.size()); + + for(auto elem : arr) { + if(elem.isObject()) { + out.push_back((Conversation) elem.toObject()); + } + } + } + + return out; +} + +ClientAPI::Message ClientAPI::sendMessage(const std::string& chatid, const std::string& messagebody) { + QJsonObject requestj; + requestj["body"] = QString::fromStdString(messagebody); + QJsonDocument requestdoc(requestj); + const std::string requeststr = requestdoc.toJson(QJsonDocument::JsonFormat::Compact).toStdString(); + Log::debug << "requeststr: " << requeststr; + QJsonDocument doc = request("lol-chat/v1/conversations/" + chatid + "/messages", Method::POST, requeststr); + + std::string error; + if(doc.isObject()) { + QJsonObject obj = doc.object(); + auto errref = obj["errorCode"]; + auto msgref = obj["message"]; + if(errref.isString()) { + error = errref.toString().toStdString() + " "; + } + if(msgref.isString()) { + error += msgref.toString().toStdString(); + } + + if(error.empty()) { + return (Message) obj; + } + } + + Log::note << "send message error: " << error; + return {}; +} + + ClientAPI::RunePage ClientAPI::getCurrentRunePage() { QJsonDocument doc = request("lol-perks/v1/currentpage"); diff --git a/src/clientapi_json.cpp b/src/clientapi_json.cpp index d28d0a8..f5819cb 100644 --- a/src/clientapi_json.cpp +++ b/src/clientapi_json.cpp @@ -119,6 +119,8 @@ ClientAPI::ChampSelectCell::ChampSelectCell(const QJsonObject& json) { 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) { @@ -226,10 +228,42 @@ RuneAspekt::RuneAspekt(const QJsonObject& json) { 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(((int) state) < ENUMNAME ## NamesCount); \ - return str << ENUMNAME ## Names[(int) state] << " (" << (int) state << ')'; \ + assert(((uint32_t) state) < ENUMNAME ## NamesCount); \ + return str << ENUMNAME ## Names[(uint32_t) state] << " (" << (uint32_t) state << ')'; \ } @@ -238,7 +272,8 @@ PRINTENUM(GameflowPhase) PRINTENUM(ChampSelectPhase) PRINTENUM(ChampSelectActionType) -std::ostream& operator<<(std::ostream& str, const Position & state) { \ - assert(((int) state) < PositionNamesCount); \ - return str << PositionNames[(int) state] << " (" << (int) state << ')'; \ +// 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] << " (" << (uint32_t) state << ')'; } diff --git a/src/lolautoaccept.cpp b/src/lolautoaccept.cpp index 9c1a20e..4e47f72 100644 --- a/src/lolautoaccept.cpp +++ b/src/lolautoaccept.cpp @@ -115,6 +115,9 @@ void LolAutoAccept::stopJoinThread() { void LolAutoAccept::innerRun() { shouldrun = true; + auto convs = clientapi->getAllConversations(); + Log::info << "got " << convs.size() << " conversations"; + try { while(shouldrun) { uint32_t extrasleep = 800; @@ -199,6 +202,7 @@ void LolAutoAccept::resetAllOffsets() { currentPosition = Position::INVALID; currentPositionSet = false; lastPickedChamp = 0; + chatid.clear(); } void LolAutoAccept::resetRunes() { @@ -424,6 +428,9 @@ void LolAutoAccept::champSelect() { pickPhase(ownactions); } else if(session.timer.phase == ClientAPI::ChampSelectPhase::FINALIZATION) { // trade? + + // check for smite + smiteWarning(session.myTeam); } if(nextApplyRunes) { @@ -431,6 +438,46 @@ void LolAutoAccept::champSelect() { } } +void LolAutoAccept::smiteWarning(const std::vector& cells) { + uint32_t smiteCount = 0; + for(const ClientAPI::ChampSelectCell& member : cells) { + Log::info << "position: " << member.position << " spells: " << member.spell1Id << " " << member.spell2Id; + smiteCount += (member.spell1Id == 11 || member.spell2Id == 11); + } + + if(smiteCount != 1) { + // check timeout + std::chrono::time_point currenttime = std::chrono::system_clock::now(); + if((currenttime - lastMessageSent) < std::chrono::seconds(2)) { + return; + } + + Log::info << "smite warning: " << smiteCount; + const std::string& chatid = getChatid(); + if(!chatid.empty()) { + clientapi->sendMessage(chatid, "smite"); + lastMessageSent = currenttime; + } + } +} + +const std::string& LolAutoAccept::getChatid() { + if(chatid.empty()) { + std::vector convs = clientapi->getAllConversations(); + Log::info << "got " << convs.size() << " conversations"; + + for(const ClientAPI::Conversation& conv : convs) { + Log::info << " id: " << conv.id << " type: " << conv.type << " name: " << conv.name << " gameName: " << conv.gameName; + if(conv.type == "championSelect" && conv.name.empty()) { + Log::info << "groupchat found"; + chatid = conv.id; + return chatid; + } + } + } + return chatid; //might be empty string +} + void LolAutoAccept::applyRunes_internal(uint32_t champid, Position pos) { nextApplyRunes = false; Log::note << "apply runes"; diff --git a/thirdparty/Log b/thirdparty/Log index 96d10d6..5bf9e68 160000 --- a/thirdparty/Log +++ b/thirdparty/Log @@ -1 +1 @@ -Subproject commit 96d10d6e72ddaffd8b688db5ef2705e38aff3a75 +Subproject commit 5bf9e688b125ac042292d8f554711d7337fe88c0