detecting closed client

This commit is contained in:
mrbesen 2022-07-29 00:05:22 +02:00
parent 97a822746e
commit 65b91f8d5a
Signed by untrusted user: MrBesen
GPG Key ID: 596B2350DCD67504
8 changed files with 131 additions and 77 deletions

View File

@ -15,6 +15,7 @@ class LolAutoAccept {
public:
using onposchange_func = std::function<void(Position)>;
using onruneschange_func = std::function<void(const RunePage&)>;
using onfailed_func = std::function<void()>;
protected:
struct Stage {
Stage();
@ -29,11 +30,13 @@ protected:
std::vector<Stage> stages;
Position currentPosition = Position::INVALID;
bool currentPositionSet = false;
uint32_t lastPickedChamp = 0;
Config::RootConfig& config;
DataDragon& dd;
onposchange_func onPoschange;
onruneschange_func onRuneschange;
onfailed_func onFailed;
bool shouldrun = false;
std::thread lolaathread;
@ -53,7 +56,7 @@ public:
PICK = 2,
};
LolAutoAccept(Config::RootConfig& config, DataDragon& dd, onposchange_func = {}, onruneschange_func = {});
LolAutoAccept(Config::RootConfig& config, DataDragon& dd, onfailed_func = {}, onposchange_func = {}, onruneschange_func = {});
~LolAutoAccept();
void setChamps(const std::vector<uint32_t>& champs, State s);

View File

@ -38,6 +38,7 @@ signals:
private:
// returns empty string on no match
void onPosChange(Position newpos); // to trigger the signal from a QObject
void onFail(); // get triggerd, when the autoacceptor fails (lost connection)
Ui::MainWindow *ui;
std::thread lolaathread;

View File

@ -18,6 +18,12 @@ public:
DELETE
};
struct WebException {
CURLcode curlresponse = CURLE_OK;
WebException(CURLcode c = CURLE_OK);
};
protected:
QByteArray requestRaw(const std::string& url, Method m = Method::GET, const std::string& data = {});
QJsonDocument request(const std::string& url, Method m = Method::GET, const std::string& data = {});

View File

@ -79,7 +79,9 @@ BlitzAPI::ChampionInfo BlitzAPI::getChampionInfo(uint32_t championID, Position p
QJsonObject vars;
vars["championId"] = (int) championID;
vars["role"] = QString::fromStdString(POSITIONNAMES[(int) p]);
if(p != Position::INVALID) {
vars["role"] = QString::fromStdString(POSITIONNAMES[(int) p]);
}
vars["queue"] = "RANKED_SOLO_5X5";
if(enemyChampionID == 0)
@ -89,12 +91,17 @@ BlitzAPI::ChampionInfo BlitzAPI::getChampionInfo(uint32_t championID, Position p
vars["key"] = "PUBLIC"; // ? what does this do?
QJsonDocument jvars(vars);
const std::string variables = jvars.toJson().toStdString();
const std::string variables = jvars.toJson(QJsonDocument::Compact).toStdString();
const std::string query = "query ChampionBuilds($championId:Int!,$queue:Queue!,$role:Role,$opponentChampionId:Int,$key:ChampionBuildKey){championBuildStats(championId:$championId,queue:$queue,role:$role,opponentChampionId:$opponentChampionId,key:$key){championId opponentChampionId queue role builds{completedItems{games index averageIndex itemId wins}games mythicId mythicAverageIndex primaryRune runes{games index runeId wins treeId}skillOrders{games skillOrder wins}startingItems{games startingItemIds wins}summonerSpells{games summonerSpellIds wins}wins}}}";
const std::string requeststr = "query=" + escape(query) + "&variables=" + escape(variables);
Log::debug << "GetChampionInfo requestVariables: " << variables;
Log::debug << "GetChampionInfo requestVariables: " << variables << " requeststr: " << requeststr;
QJsonDocument doc = request(requeststr);
QJsonDocument doc;
try {
doc = request(requeststr);
} catch(RestClient::WebException& e) {
return {};
}
if(!doc.isObject()) {
// error
@ -102,6 +109,8 @@ BlitzAPI::ChampionInfo BlitzAPI::getChampionInfo(uint32_t championID, Position p
return {};
}
Log::debug << "championinfo Response: " << doc.toJson().trimmed().toStdString();
QJsonObject obj = doc.object();
QJsonValueRef dataref = obj["data"];

View File

@ -68,7 +68,11 @@ QPixmap DataDragon::getImage(const std::string& champid, ImageType imgtype, bool
const std::string url = getImageUrl(champid, imgtype);
if(url.empty()) return {};
QByteArray arr = requestRaw(url);
QByteArray arr;
try {
arr = requestRaw(url);
} catch(RestClient::WebException& e) {}
if(arr.isEmpty()) {
Log::error << "image could not be loaded";
return {};
@ -259,19 +263,21 @@ void DataDragon::getVersionInternal() {
version = champCache.getVersion();
if(!version.empty()) return;
QJsonDocument jversions = request("api/versions.json");
if(jversions.isArray()) {
QJsonArray jverarr = jversions.array();
if(!jverarr.empty()) {
version = jverarr.at(0).toString().toStdString();
Log::info << "got League version: " << version;
try {
QJsonDocument jversions = request("api/versions.json");
if(jversions.isArray()) {
QJsonArray jverarr = jversions.array();
if(!jverarr.empty()) {
version = jverarr.at(0).toString().toStdString();
Log::info << "got League version: " << version;
lock.unlock();
cachedatacv.notify_all();
return;
lock.unlock();
cachedatacv.notify_all();
return;
}
}
}
Log::error << "error parsing version object";
Log::error << "error parsing version object";
} catch(RestClient::WebException& e) {}
}
void DataDragon::getChampsInternal() {
@ -283,12 +289,14 @@ void DataDragon::getChampsInternal() {
QJsonDocument jchamps = champCache.getChamps();
bool cacheSuccessfull = !jchamps.isEmpty();
if(!cacheSuccessfull) {
jchamps = request(getCDNString() + "data/" + locale + "/champion.json");
if(jchamps.isEmpty()) {
// try again with default locale
locale = "en_US";
try {
jchamps = request(getCDNString() + "data/" + locale + "/champion.json");
}
if(jchamps.isEmpty()) {
// try again with default locale
locale = "en_US";
jchamps = request(getCDNString() + "data/" + locale + "/champion.json");
}
} catch(RestClient::WebException& e) {}
}
if(jchamps.isObject()) {
// save to cache

View File

@ -7,7 +7,7 @@
LolAutoAccept::Stage::Stage() {}
LolAutoAccept::Stage::~Stage() {}
LolAutoAccept::LolAutoAccept(Config::RootConfig& config, DataDragon& dd, onposchange_func onposch, onruneschange_func onrunch) : config(config), dd(dd), onPoschange(onposch), onRuneschange(onrunch) {
LolAutoAccept::LolAutoAccept(Config::RootConfig& config, DataDragon& dd, onfailed_func fail, onposchange_func onposch, onruneschange_func onrunch) : config(config), dd(dd), onFailed(fail), onPoschange(onposch), onRuneschange(onrunch) {
std::lock_guard lock(stagesMutex);
stages.resize(3); // accept, ban, pick
}
@ -115,64 +115,80 @@ void LolAutoAccept::stopJoinThread() {
void LolAutoAccept::innerRun() {
shouldrun = true;
while(shouldrun) {
uint32_t extrasleep = 800;
auto start = std::chrono::high_resolution_clock::now();
try {
while(shouldrun) {
uint32_t extrasleep = 800;
auto start = std::chrono::high_resolution_clock::now();
auto phase = clientapi->getGameflowPhase();
Log::info << "current Gameflowphase: " << phase;
auto phase = clientapi->getGameflowPhase();
Log::info << "current Gameflowphase: " << phase;
// do processing
if(phase == ClientAPI::GameflowPhase::LOBBY) {
resetAllOffsets();
resetRunes();
} else if(phase == ClientAPI::GameflowPhase::MATCHMAKING) {
extrasleep = 200;
resetAllOffsets();
resetRunes();
} else if(phase == ClientAPI::GameflowPhase::READYCHECK) {
if(stages.at(0).enabled) { // auto accept enabled
auto state = clientapi->getReadyCheckState();
// do processing
if(phase == ClientAPI::GameflowPhase::LOBBY) {
resetAllOffsets();
resetRunes();
} else if(phase == ClientAPI::GameflowPhase::MATCHMAKING) {
extrasleep = 200;
resetAllOffsets();
resetRunes();
} else if(phase == ClientAPI::GameflowPhase::READYCHECK) {
if(stages.at(0).enabled) { // auto accept enabled
auto state = clientapi->getReadyCheckState();
Log::info << "readychack state: " << state;
if(state == ClientAPI::ReadyCheckState::INPROGRESS) {
Log::info << "auto accepting";
clientapi->acceptMatch();
Log::info << "readychack state: " << state;
if(state == ClientAPI::ReadyCheckState::INPROGRESS) {
Log::info << "auto accepting";
clientapi->acceptMatch();
}
}
resetAllOffsets();
extrasleep = 0; // no extra sleep
} else if(phase == ClientAPI::GameflowPhase::CHAMPSELECT) {
champSelect();
extrasleep = 0; // no extra sleep
} else if(phase == ClientAPI::GameflowPhase::INPROGRESS) {
extrasleep = 30000; // 30s bonus sleep
resetAllOffsets();
resetRunes();
} else if(phase == ClientAPI::GameflowPhase::ENDOFGAME) {
extrasleep = 2000; // 2 s bonus sleep
resetAllOffsets();
resetRunes();
} else if(phase == ClientAPI::GameflowPhase::PREENDOFGAME) {
extrasleep = 4000; // 4 s bonus sleep
resetAllOffsets();
resetRunes();
} else if(phase == ClientAPI::GameflowPhase::WAITINGFORSTATS) {
extrasleep = 4000; // 4 s bonus sleep
resetAllOffsets();
resetRunes();
} else if(phase == ClientAPI::GameflowPhase::NONE) {
extrasleep = 10000; // 10 s bonus sleep - no lobby
resetAllOffsets();
resetRunes();
}
resetAllOffsets();
extrasleep = 0; // no extra sleep
} else if(phase == ClientAPI::GameflowPhase::CHAMPSELECT) {
champSelect();
extrasleep = 0; // no extra sleep
} else if(phase == ClientAPI::GameflowPhase::INPROGRESS) {
extrasleep = 30000; // 30s bonus sleep
resetAllOffsets();
resetRunes();
} else if(phase == ClientAPI::GameflowPhase::ENDOFGAME) {
extrasleep = 2000; // 2 s bonus sleep
resetAllOffsets();
resetRunes();
} else if(phase == ClientAPI::GameflowPhase::PREENDOFGAME) {
extrasleep = 4000; // 4 s bonus sleep
resetAllOffsets();
resetRunes();
} else if(phase == ClientAPI::GameflowPhase::WAITINGFORSTATS) {
extrasleep = 4000; // 4 s bonus sleep
resetAllOffsets();
resetRunes();
} else if(phase == ClientAPI::GameflowPhase::NONE) {
extrasleep = 10000; // 10 s bonus sleep - no lobby
resetAllOffsets();
resetRunes();
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> dur = (end-start);
//if(dur.count() > 1e-5)
Log::note << "iteration took: " << (dur.count() * 1000) << " ms extrasleep: " << extrasleep;
std::this_thread::sleep_for(std::chrono::milliseconds(400 + extrasleep));
}
} catch(RestClient::WebException& e) {
Log::error << "WebException catched: " << e.curlresponse;
if(e.curlresponse == CURLE_COULDNT_CONNECT) {
// free clientapi
clientapi.reset();
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> dur = (end-start);
//if(dur.count() > 1e-5)
Log::note << "iteration took: " << (dur.count() * 1000) << " ms extrasleep: " << extrasleep;
// disable this thread
shouldrun = false;
std::this_thread::sleep_for(std::chrono::milliseconds(400 + extrasleep));
// notify the ui
if(onFailed) {
onFailed();
}
}
}
}
@ -182,6 +198,7 @@ void LolAutoAccept::resetAllOffsets() {
}
currentPosition = Position::INVALID;
currentPositionSet = false;
lastPickedChamp = 0;
}
void LolAutoAccept::resetRunes() {
@ -358,7 +375,6 @@ void LolAutoAccept::champSelect() {
// find own cellid info
const ClientAPI::ChampSelectCell* me = nullptr;
uint32_t pickedChamp = 0;
static uint32_t lastPickedChamp = 0;
for(const auto& it : session.myTeam) {
if(it.cellID == cellid) {
me = &it;

View File

@ -4,7 +4,7 @@
#include <Log.h>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), dd(QLocale().name().toStdString()),
lolaa(conf.getConfig(), dd, std::bind(&MainWindow::onPosChange, this, std::placeholders::_1)) {
lolaa(conf.getConfig(), dd, std::bind(&MainWindow::onFail, this), std::bind(&MainWindow::onPosChange, this, std::placeholders::_1)) {
ui->setupUi(this);
lolaa.setOnRuneChangeFunc(std::bind(&RuneDisplay::setRunes, ui->runedisplay, std::placeholders::_1));
@ -103,3 +103,8 @@ void MainWindow::onPosChange(Position newpos) {
emit requestTabChange((int) newpos);
}
void MainWindow::onFail() {
ui->mainswitch->setChecked(false);
ui->statusbar->showMessage(tr("Auto-Acceptor failed!"));
}

View File

@ -33,6 +33,7 @@ static void dump(const char* text, FILE* stream, unsigned char* ptr, size_t size
static int my_trace(CURL* handle, curl_infotype type, char* data, size_t size, void* userp) {
const char* text;
(void) handle; /* prevent compiler warning */
(void) userp;
switch (type) {
case CURLINFO_TEXT:
@ -73,6 +74,9 @@ RestClient::~RestClient() {
curl = nullptr;
}
RestClient::WebException::WebException(CURLcode c) : curlresponse(c) {
}
QByteArray RestClient::requestRaw(const std::string& url, Method m, const std::string& data) {
if (!curl) return {};
@ -135,9 +139,11 @@ QByteArray RestClient::requestRaw(const std::string& url, Method m, const std::s
long responsecode = -1;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responsecode);
Log::warn << "API request failed: " << baseurl << " " << url << " -> " << responsecode;
}
else {
} else {
Log::warn << "API request failed: " << baseurl << " " << url << " " << curl_easy_strerror(res);
if(res == CURLE_COULDNT_CONNECT) {
throw WebException(res);
}
}
return {};
}