RunePage class added and refactored; find matching runepages

This commit is contained in:
mrbesen 2022-07-10 14:32:44 +02:00
parent c03b123af0
commit 4716e48cbf
Signed by untrusted user: MrBesen
GPG Key ID: 596B2350DCD67504
15 changed files with 129 additions and 66 deletions

View File

@ -4,6 +4,7 @@
#include <QJsonObject>
#include "restclient.h"
#include "runepage.h"
#include "position.h"
class BlitzAPI : public RestClient {
@ -12,9 +13,8 @@ public:
struct ChampionInfo {
std::vector<uint32_t> skillorder;
std::vector<uint32_t> runes;
uint32_t primaryRuneStyle = 0;
uint32_t secondaryRuneStyle = 0;
RunePage runepage;
// items?

View File

@ -4,6 +4,7 @@
#include "restclient.h"
#include "position.h"
#include "runeaspekt.h"
#include "runepage.h"
class ClientAPI : public RestClient {
public:
@ -132,8 +133,6 @@ public:
struct RunePage {
uint64_t id = 0;
uint64_t lastmodified = 0;
uint32_t primaryStyleID = 0;
uint32_t subStyleID = 0;
std::string name;
bool isDeleteable = true;
bool isEditable = true;
@ -141,7 +140,7 @@ public:
bool isCurrent = false;
bool isValid = true;
uint32_t order = 0; // position in the ui
std::vector<uint32_t> selectedPerkIDs;
::RunePage runepage;
RunePage();
explicit RunePage(const QJsonObject& json);

View File

@ -8,11 +8,12 @@
#include "clientapi.h"
#include "config.h"
#include "datadragon.h"
#include "runepage.h"
class LolAutoAccept {
public:
using onposchange_func = std::function<void(Position)>;
using onruneschange_func = std::function<void(const std::vector<uint32_t>, uint32_t, uint32_t)>;
using onruneschange_func = std::function<void(const RunePage&)>;
protected:
struct Stage {
Stage();
@ -63,6 +64,7 @@ public:
const std::vector<RuneAspekt>& getRuneAspekts();
void applyRunes();
void setOnRuneChangeFunc(onruneschange_func on);
private:
void stopJoinThread();
@ -84,5 +86,7 @@ private:
void pickPhase(const ownactions_t& ownactions);
void phase(const ownactions_t& ownactions, ClientAPI::ChampSelectActionType type, State s, bool complete, std::function<bool(uint32_t)> filter = {});
static int32_t getBestRunePage(const std::vector<ClientAPI::RunePage>& allpages);
static int32_t getMatchingRunePage(const RunePage& rp, const std::vector<ClientAPI::RunePage>& allpages);
void champSelect();
void applyRunes_internal(uint32_t champid, Position pos);
};

View File

@ -38,7 +38,6 @@ signals:
private:
// returns empty string on no match
void onPosChange(Position newpos); // to trigger the signal from a QObject
void onRuneChanged(const std::vector<uint32_t>& runes, uint32_t prim, uint32_t sec);
Ui::MainWindow *ui;
std::thread lolaathread;

View File

@ -1,7 +1,9 @@
#pragma once
#include <QWidget>
#include "runeaspekt.h"
#include "runepage.h"
namespace Ui {
class RuneDisplay;
@ -15,16 +17,14 @@ public:
~RuneDisplay();
void setRuneMeta(const std::vector<RuneAspekt>& runeinfo);
void setRunes(const std::vector<uint32_t>& ids, uint32_t primary, uint32_t secondary);
void setRunes(const RunePage& rp);
private:
void updateText();
std::string getRuneText(uint32_t id);
Ui::RuneDisplay *ui;
std::vector<uint32_t> runes;
uint32_t primary;
uint32_t secondary;
RunePage runepage;
std::vector<RuneAspekt> runeinfo;
};

17
include/runepage.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include <cstdint>
#include <ostream>
#include <vector>
// represents a runepage
struct RunePage {
public:
uint32_t primaryStyle = 0;
uint32_t secondaryStyle = 0;
std::vector<uint32_t> selectedAspects; // all selected aspekts (should be exactly 9)
bool operator==(const RunePage& rp) const;
};
std::ostream& operator<<(std::ostream&, const RunePage&);

View File

@ -46,6 +46,7 @@ SOURCES += \
src/memoryimagecache.cpp \
src/restclient.cpp \
src/runedisplay.cpp \
src/runepage.cpp \
src/settingstab.cpp \
src/stagesettings.cpp \
thirdparty/Log/Log.cpp
@ -71,6 +72,7 @@ HEADERS += \
include/memoryimagecache.h \
include/restclient.h \
include/runedisplay.h \
include/runepage.h \
include/settingstab.h \
include/stagesettings.h \
thirdparty/Log/Log.h

View File

@ -43,8 +43,10 @@ BlitzAPI::ChampionInfo::ChampionInfo(const QJsonObject& json) {
// runes
// TODO: create a diffrent algorithm to choose wich runes should be picked, insted of just the first one
QJsonValue runesarrref = json["runes"];
std::vector<uint32_t>& runes = runepage.selectedAspects;
if(runesarrref.isArray()) {
QJsonArray runesarr = runesarrref.toArray();
runes.clear();
runes.resize(9, 0);// a list of runes, that are taken (the first one is a speare for the primary one)
for(auto it : runesarr) {
if(!it.isObject()) continue;
@ -59,9 +61,9 @@ BlitzAPI::ChampionInfo::ChampionInfo(const QJsonObject& json) {
Log::debug << "found rune: index: " << index << " +1 set to: " << runes.at(index+1);
if(index == 0) {
primaryRuneStyle = rune["treeId"].toInt();
runepage.primaryStyle = rune["treeId"].toInt();
} else if(index == 3) {
secondaryRuneStyle = rune["treeId"].toInt();
runepage.secondaryStyle = rune["treeId"].toInt();
}
}
}

View File

@ -206,11 +206,11 @@ bool ClientAPI::editRunePage(const RunePage& page) {
QJsonObject pagereq;
pagereq["name"] = QString::fromStdString(page.name);
pagereq["primaryStyleId"] = (int) page.primaryStyleID;
pagereq["subStyleId"] = (int) page.subStyleID;
pagereq["primaryStyleId"] = (int) page.runepage.primaryStyle;
pagereq["subStyleId"] = (int) page.runepage.secondaryStyle;
QJsonArray selected;
for(uint32_t sel : page.selectedPerkIDs) {
for(uint32_t sel : page.runepage.selectedAspects) {
selected.push_back((int) sel);
}

View File

@ -186,8 +186,8 @@ ClientAPI::RunePage::RunePage() {}
ClientAPI::RunePage::RunePage(const QJsonObject& json) {
id = getValue<int32_t>(json, "id", 0);
lastmodified = getValue<int64_t>(json, "lastModified", 0);
primaryStyleID = getValue<int32_t>(json, "primaryStyleId", 0);
subStyleID = getValue<int32_t>(json, "subStyleId", 0);
runepage.primaryStyle = getValue<int32_t>(json, "primaryStyleId", 0);
runepage.secondaryStyle = getValue<int32_t>(json, "subStyleId", 0);
name = getValue<std::string>(json, "name");
isDeleteable = getValue<bool>(json, "isDeletable", false);
isEditable = getValue<bool>(json, "isEditable", false);
@ -198,7 +198,7 @@ ClientAPI::RunePage::RunePage(const QJsonObject& json) {
auto selectedref = json["selectedPerkIds"];
if(selectedref.isArray()) {
selectedPerkIDs = readVector<uint32_t>(selectedref.toArray());
runepage.selectedAspects = readVector<uint32_t>(selectedref.toArray());
}
}

View File

@ -87,6 +87,10 @@ void LolAutoAccept::applyRunes() {
nextApplyRunes = true;
}
void LolAutoAccept::setOnRuneChangeFunc(onruneschange_func on) {
onRuneschange = on;
}
void LolAutoAccept::stopJoinThread() {
stop();
@ -290,7 +294,7 @@ int32_t LolAutoAccept::getBestRunePage(const std::vector<ClientAPI::RunePage>& p
// search for a rune page with a name that starts with "AA: "
for(uint32_t i = 0; i < pages.size(); ++i) {
const ClientAPI::RunePage& rp = pages.at(i);
if(rp.name.size() >= 4 && rp.name.substr(4) == "AA: ") {
if(rp.name.size() >= 4 && rp.name.substr(0, 4) == "AA: ") {
return i;
}
}
@ -305,6 +309,12 @@ int32_t LolAutoAccept::getBestRunePage(const std::vector<ClientAPI::RunePage>& p
return -1;
}
int32_t LolAutoAccept::getMatchingRunePage(const RunePage& rp, const std::vector<ClientAPI::RunePage>& allpages) {
auto it = std::find_if(allpages.begin(), allpages.end(), [rp](const ClientAPI::RunePage& r){ return r.runepage == rp; });
return (it == allpages.end()) ? -1 : it - allpages.begin();
}
void LolAutoAccept::champSelect() {
auto session = clientapi->getChampSelectSession();
int32_t cellid = session.localPlayerCellId;
@ -335,8 +345,9 @@ void LolAutoAccept::champSelect() {
// update runes
if(onRuneschange) {
auto champinfo = blitzapi.getChampionInfo(pickedChamp, pos); // TODO: add detection for enemy champ
Log::info << "champinfo aquired: " << champinfo.runes.size() << " runes primary style: " << champinfo.primaryRuneStyle;
onRuneschange(champinfo.runes, champinfo.primaryRuneStyle, champinfo.secondaryRuneStyle); //
Log::info << "champinfo aquired: " << champinfo.runepage;
onRuneschange(champinfo.runepage);
}
}
@ -368,38 +379,53 @@ void LolAutoAccept::champSelect() {
}
if(nextApplyRunes) {
nextApplyRunes = false;
Log::note << "apply runes";
// choose page
auto pages = clientapi->getAllRunePages();
int32_t pageoffset = getBestRunePage(pages);
if(pageoffset < 0) {
Log::warn << "no rune page found!";
return;
}
ClientAPI::RunePage& rp = pages.at(pageoffset);
Log::info << "replace runepage id: " << rp.id << " old-name: " << rp.name;
auto champinfo = blitzapi.getChampionInfo(pickedChamp, pos);
Log::info << "fetched champion info runes: " << champinfo.runes.size();
ClientAPI::RunePage newpage;
newpage.id = rp.id;
newpage.name = "AA: " + std::to_string(pickedChamp) + " " + toString(pos); // TODO: resolve champname? add role?
newpage.selectedPerkIDs = champinfo.runes;
newpage.primaryStyleID = champinfo.primaryRuneStyle;
newpage.subStyleID = champinfo.secondaryRuneStyle;
clientapi->editRunePage(newpage);
//select runepage
if(!rp.isCurrent) {
Log::info << "page is not selected, selecting now (id: " << newpage.id << ')';
clientapi->selectRunePage(newpage.id);
}
Log::info << "runepage done";
applyRunes_internal(pickedChamp, pos);
}
}
void LolAutoAccept::applyRunes_internal(uint32_t champid, Position pos) {
nextApplyRunes = false;
Log::note << "apply runes";
// get recommended runes and stuff
auto champinfo = blitzapi.getChampionInfo(champid, pos);
Log::info << "fetched champion info runes: " << champinfo.runepage;
// choose page
auto pages = clientapi->getAllRunePages();
// check for page that allready contains the settings
int32_t choosepage = getMatchingRunePage(champinfo.runepage, pages);
if(choosepage != -1) {
ClientAPI::RunePage& page = pages.at(choosepage);
Log::info << "matching runepage found, selecting: " << page.id << " " << page.name;
if(clientapi->selectRunePage(page.id)) {
return;
}
Log::warn << "selecting runepage failed";
}
// find page to replace
int32_t pageoffset = getBestRunePage(pages);
if(pageoffset < 0) {
Log::warn << "no rune page found!";
return;
}
ClientAPI::RunePage& rp = pages.at(pageoffset);
Log::info << "replace runepage id: " << rp.id << " old-name: " << rp.name;
ClientAPI::RunePage newpage;
newpage.id = rp.id;
newpage.name = "AA: " + std::to_string(champid) + " " + toString(pos); // TODO: resolve champname? add role?
newpage.runepage = champinfo.runepage;
clientapi->editRunePage(newpage);
//select runepage
if(!rp.isCurrent) {
Log::info << "page is not selected, selecting now (id: " << newpage.id << ')';
clientapi->selectRunePage(newpage.id);
}
Log::info << "runepage done";
}

View File

@ -4,9 +4,11 @@
#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), std::bind(&MainWindow::onRuneChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)) {
lolaa(conf.getConfig(), dd, std::bind(&MainWindow::onPosChange, this, std::placeholders::_1)) {
ui->setupUi(this);
lolaa.setOnRuneChangeFunc(std::bind(&RuneDisplay::setRunes, ui->runedisplay, std::placeholders::_1));
conf.load();
// for all tabs - set their config and datadragon
@ -100,6 +102,3 @@ void MainWindow::onPosChange(Position newpos) {
}
}
void MainWindow::onRuneChanged(const std::vector<uint32_t>& runes, uint32_t prim, uint32_t sec) {
ui->runedisplay->setRunes(runes, prim, sec);
}

View File

@ -15,10 +15,8 @@ void RuneDisplay::setRuneMeta(const std::vector<RuneAspekt>& ri) {
runeinfo = ri;
}
void RuneDisplay::setRunes(const std::vector<uint32_t>& ids, uint32_t primary, uint32_t secondary) {
runes = ids;
this->primary = primary;
this->secondary = secondary;
void RuneDisplay::setRunes(const RunePage& rp) {
runepage = rp;
updateText();
}
@ -26,9 +24,9 @@ void RuneDisplay::setRunes(const std::vector<uint32_t>& ids, uint32_t primary, u
void RuneDisplay::updateText() {
std::ostringstream out;
out << "primary: " << getRuneText(primary) << " secondary: " << getRuneText(secondary) << '\n';
out << "primary: " << getRuneText(runepage.primaryStyle) << " secondary: " << getRuneText(runepage.secondaryStyle) << '\n';
for(uint32_t rune : runes) {
for(uint32_t rune : runepage.selectedAspects) {
out << getRuneText(rune) << '\n';
}
ui->runetext->setText(QString::fromStdString(out.str()));

14
src/runepage.cpp Normal file
View File

@ -0,0 +1,14 @@
#include "runepage.h"
#include <algorithm>
bool RunePage::operator==(const RunePage& rp) const {
if(primaryStyle == rp.primaryStyle && secondaryStyle == rp.secondaryStyle && selectedAspects.size() == rp.selectedAspects.size()) {
return std::is_permutation(selectedAspects.begin(), selectedAspects.end(), rp.selectedAspects.begin());
}
return false;
}
std::ostream& operator<<(std::ostream& str, const RunePage& rp) {
return str << "Primary: " << rp.primaryStyle << " Secondary: " << rp.secondaryStyle << " aspects: " << rp.selectedAspects.size();
}

View File

@ -117,6 +117,9 @@
</item>
<item>
<widget class="QPushButton" name="applyRunesBtn">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Select a Runepage and modify it to this runes.&lt;br/&gt;The page used is the first that:&lt;/p&gt;&lt;ol style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;matches this Runes&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;has a name starting with &amp;quot;AA:&amp;quot;&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;is currently selected&lt;/li&gt;&lt;/ol&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Apply Runes</string>
</property>