step to REST api
This commit is contained in:
parent
07ee1df44e
commit
500b12f756
|
@ -5,26 +5,54 @@
|
|||
|
||||
class ClientAPI : public RestClient {
|
||||
public:
|
||||
enum class SearchState : uint32_t {
|
||||
enum class ReadyCheckState : uint32_t {
|
||||
INVALID = 0,
|
||||
SEARCHING,
|
||||
FOUND,
|
||||
|
||||
ABANDONEDLOWPRIORITYQUEUE,
|
||||
CANCELED,
|
||||
ERROR,
|
||||
SERVICEERROR,
|
||||
SERVICESHUTDOWN,
|
||||
NONE,
|
||||
INPROGRESS,
|
||||
Accepted,
|
||||
DECLINED
|
||||
};
|
||||
|
||||
enum class GameflowPhase : uint32_t {
|
||||
NONE = 0,
|
||||
LOBBY,
|
||||
MATCHMAKING,
|
||||
CHECKEDINTOTOURNAMENT,
|
||||
READYCHECK,
|
||||
CHAMPSELECT,
|
||||
GAMESTART,
|
||||
FAILEDTOLAUNCH,
|
||||
INPROGRESS,
|
||||
RECONNECT,
|
||||
WAITINGFORSTATS,
|
||||
PREENDOFGAME,
|
||||
ENDOFGAME,
|
||||
TERMINATEDINERROR,
|
||||
};
|
||||
|
||||
struct TimerInfo {
|
||||
int64_t adjustedTimeLeftInPhase;
|
||||
int64_t internalNowInEpochMs;
|
||||
bool isefinite;
|
||||
std::string phase;
|
||||
int64_t totalTimeInPhase;
|
||||
|
||||
bool valid = false;
|
||||
};
|
||||
|
||||
ClientAPI(const ClientAccess& access);
|
||||
~ClientAPI();
|
||||
|
||||
SearchState getSearchState();
|
||||
ReadyCheckState getReadyCheckState();
|
||||
GameflowPhase getGameflowPhase();
|
||||
void acceptMatch();
|
||||
void declineMatch();
|
||||
|
||||
std::vector<int32_t> getBannableChampIDs();
|
||||
std::vector<int32_t> getPickableChampIDs();
|
||||
|
||||
TimerInfo getTimerInfo();
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
|
@ -32,3 +60,6 @@ protected:
|
|||
private:
|
||||
ClientAccess access;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream&, const ClientAPI::ReadyCheckState&);
|
||||
std::ostream& operator<<(std::ostream&, const ClientAPI::GameflowPhase&);
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
#include "screen.h"
|
||||
|
||||
class FakeScreen : public ScreenShot {
|
||||
private:
|
||||
int xoffset = 0;
|
||||
int yoffset = 0;
|
||||
int xsize = 0;
|
||||
int ysize = 0;
|
||||
public:
|
||||
|
||||
FakeScreen(int xoffset = 0, int yoffset = 0, int xsize = 0, int ysize = 0);
|
||||
~FakeScreen();
|
||||
|
||||
virtual void take(cv::Mat& cvimg) override;
|
||||
virtual void operator() (cv::Mat& cvimg) override;
|
||||
|
||||
virtual int getXOffset() const override;
|
||||
virtual int getYOffset() const override;
|
||||
virtual double getXScale() const override;
|
||||
virtual double getYScale() const override;
|
||||
};
|
|
@ -1,67 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "scaleableinputs.h"
|
||||
#include "screen.h"
|
||||
#include "matcher.h"
|
||||
|
||||
#include <xinputsimulator.h>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
|
||||
#include "clientapi.h"
|
||||
|
||||
class LolAutoAccept {
|
||||
protected:
|
||||
struct Stage {
|
||||
Stage(const std::string& matchertmpl);
|
||||
Stage();
|
||||
virtual ~Stage();
|
||||
|
||||
Matcher matcher;
|
||||
std::string champ; // not every stage has a champ
|
||||
bool enabled = false;
|
||||
virtual void action(LolAutoAccept& lolaa) = 0;
|
||||
virtual bool process(LolAutoAccept& lolaa, cv::Mat& img);
|
||||
virtual void action(LolAutoAccept& lolaa);
|
||||
};
|
||||
|
||||
struct CooldownStage : public Stage {
|
||||
CooldownStage(const std::string& matchertmpl);
|
||||
|
||||
time_t lastused = 0;
|
||||
uint32_t cooldown = 30; // how long until this stage can be used again (seconds)
|
||||
|
||||
virtual bool process(LolAutoAccept& lolaa, cv::Mat& img) override;
|
||||
};
|
||||
|
||||
struct AcceptStage : public Stage {
|
||||
AcceptStage();
|
||||
virtual void action(LolAutoAccept& lolaa) override;
|
||||
};
|
||||
|
||||
struct PrePickStage : public CooldownStage {
|
||||
PrePickStage();
|
||||
virtual void action(LolAutoAccept& lolaa) override;
|
||||
};
|
||||
|
||||
struct BanStage : public CooldownStage {
|
||||
BanStage();
|
||||
virtual void action(LolAutoAccept& lolaa) override;
|
||||
};
|
||||
|
||||
struct PickStage : public CooldownStage {
|
||||
PickStage();
|
||||
virtual void action(LolAutoAccept& lolaa) override;
|
||||
};
|
||||
|
||||
ScreenShot* screen = nullptr;
|
||||
|
||||
std::vector<Stage*> stages;
|
||||
XInputSimulator& sim;
|
||||
|
||||
ScaleableInputs inputs;
|
||||
|
||||
bool shouldrun = false;
|
||||
std::thread lolaathread;
|
||||
|
||||
void performClick(uint32_t nr, bool movemouseaway = true);
|
||||
void enterSearch(const std::string& text);
|
||||
void pickFirst(const std::string& search);
|
||||
std::shared_ptr<ClientAPI> clientapi;
|
||||
|
||||
public:
|
||||
enum class State {
|
||||
LOBBY = 0,
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
class Matcher {
|
||||
private:
|
||||
cv::Mat templ;
|
||||
cv::Mat mask;
|
||||
int32_t posx = -1;
|
||||
int32_t posy = -1;
|
||||
|
||||
static std::string pathbase;
|
||||
public:
|
||||
static void setPathBase(const std::string& pa);
|
||||
|
||||
Matcher(const std::string& filename);
|
||||
Matcher(const cv::Mat& templ);
|
||||
~Matcher();
|
||||
|
||||
// instead of searching for a match, just look at this position
|
||||
void setOffset(int32_t x, int32_t y);
|
||||
|
||||
struct Match {
|
||||
bool doesMatch = false;
|
||||
int x = 0, y = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
bool operator==(const Match&) const;
|
||||
bool operator!=(const Match&) const;
|
||||
};
|
||||
|
||||
Match match(const cv::Mat& img);
|
||||
|
||||
private:
|
||||
Match matchAll(const cv::Mat& img);
|
||||
Match matchPos(const cv::Mat& img);
|
||||
|
||||
// when the template has a alpha channel try to create a mask from that
|
||||
void maskFromTemplate();
|
||||
};
|
|
@ -1,89 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#include <X11/extensions/XShm.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
|
||||
#undef Bool
|
||||
#undef CursorShape
|
||||
#undef None
|
||||
#undef KeyPress
|
||||
#undef KeyRelease
|
||||
#undef ButtonPress
|
||||
#undef ButtonRelease
|
||||
#undef MotionNotify
|
||||
#undef EnterNotify
|
||||
#undef LeaveNotify
|
||||
#undef FocusIn
|
||||
#undef FocusOut
|
||||
#undef KeymapNotify
|
||||
#undef Expose
|
||||
#undef GraphicsExpose
|
||||
#undef NoExpose
|
||||
#undef VisibilityNotify
|
||||
#undef CreateNotify
|
||||
#undef DestroyNotify
|
||||
#undef UnmapNotify
|
||||
#undef MapNotify
|
||||
#undef MapRequest
|
||||
#undef ReparentNotify
|
||||
#undef ConfigureNotify
|
||||
#undef ConfigureRequest
|
||||
#undef GravityNotify
|
||||
#undef ResizeRequest
|
||||
#undef CirculateNotify
|
||||
#undef CirculateRequest
|
||||
#undef PropertyNotify
|
||||
#undef SelectionClear
|
||||
#undef SelectionRequest
|
||||
#undef SelectionNotify
|
||||
#undef ColormapNotify
|
||||
#undef ClientMessage
|
||||
#undef MappingNotify
|
||||
#undef GenericEvent
|
||||
#undef LASTEvent
|
||||
#undef FontChange
|
||||
|
||||
class ScreenShot {
|
||||
private:
|
||||
Display* display = nullptr;
|
||||
Window window;
|
||||
XWindowAttributes wattrib;
|
||||
XImage* ximg = nullptr;
|
||||
XShmSegmentInfo shminfo;
|
||||
|
||||
bool init;
|
||||
bool closeDisp = true;
|
||||
bool valid = false;
|
||||
std::string windowname;
|
||||
|
||||
bool updateAttrib();
|
||||
bool initImg();
|
||||
public:
|
||||
|
||||
static std::vector<ScreenShot*> getWindows(const std::string& name);
|
||||
|
||||
static const uint32_t DEFAULTWIDTH;
|
||||
static const uint32_t DEFAULTHEIGHT;
|
||||
|
||||
ScreenShot();
|
||||
ScreenShot(Display* d, Window w);
|
||||
virtual ~ScreenShot();
|
||||
|
||||
virtual void take(cv::Mat& cvimg);
|
||||
virtual void operator() (cv::Mat& cvimg);
|
||||
|
||||
constexpr operator bool () const {
|
||||
return valid;
|
||||
}
|
||||
|
||||
virtual int getXOffset() const;
|
||||
virtual int getYOffset() const;
|
||||
virtual double getXScale() const;
|
||||
virtual double getYScale() const;
|
||||
};
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
void debugImage(cv::Mat img, const std::string& name = "");
|
|
@ -29,21 +29,13 @@ SOURCES += \
|
|||
src/config.cpp \
|
||||
src/datadragon.cpp \
|
||||
src/datadragonimagecache.cpp \
|
||||
src/fakescreen.cpp \
|
||||
src/files.cpp \
|
||||
src/json.cpp \
|
||||
src/lolautoaccept_accept.cpp \
|
||||
src/lolautoaccept_ban.cpp \
|
||||
src/lolautoaccept_pick.cpp \
|
||||
src/lolautoaccept_prepick.cpp \
|
||||
src/lolautoaccept.cpp \
|
||||
src/main.cpp \
|
||||
src/mainwindow.cpp \
|
||||
src/matcher.cpp \
|
||||
src/memoryimagecache.cpp \
|
||||
src/restclient.cpp \
|
||||
src/scaleableinputs.cpp \
|
||||
src/screen.cpp \
|
||||
src/stagesettings.cpp \
|
||||
thirdparty/Log/Log.cpp
|
||||
|
||||
|
@ -56,16 +48,12 @@ HEADERS += \
|
|||
include/config.h \
|
||||
include/datadragon.h \
|
||||
include/datadragonimagecache.h \
|
||||
include/fakescreen.h \
|
||||
include/files.h \
|
||||
include/json.h \
|
||||
include/lolautoaccept.h \
|
||||
include/mainwindow.h \
|
||||
include/matcher.h \
|
||||
include/memoryimagecache.h \
|
||||
include/restclient.h \
|
||||
include/scaleableinputs.h \
|
||||
include/screen.h \
|
||||
include/stagesettings.h \
|
||||
thirdparty/Log/Log.h
|
||||
|
||||
|
|
|
@ -1,19 +1,26 @@
|
|||
#include "clientapi.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include <Log.h>
|
||||
|
||||
#include "json.h"
|
||||
|
||||
static const std::string SearchStateNames[] = {"Invalid", "Searching", "Found", "AbandonedLowPriorityQueue", "Canceled", "Error", "ServiceError", "ServiceShutdown"};
|
||||
static const uint32_t SearchStateNamesCount = sizeof(SearchStateNames) / sizeof(SearchStateNames[0]);
|
||||
// calculate the size of a constant sized array
|
||||
#define ARRSIZE(ARRNAME) (sizeof(ARRNAME) / sizeof(ARRNAME[0]))
|
||||
|
||||
static const std::string ReadyCheckStateNames[] = { "Invalid", "None", "InProgress", "Accepted", "Declined" };
|
||||
static const uint32_t ReadyCheckStateNamesCount = ARRSIZE(ReadyCheckStateNames);
|
||||
|
||||
static const std::string GameflowPhaseNames[] = {"None", "Lobby", "Matchmaking", "CheckedIntoTournament", "ReadyCheck", "ChampSelect", "GameStart", "FailedToLaunch", "InProgress", "Reconnect", "WaitingForStats", "PreEndOfGame", "EndOfGame", "TerminatedInError"};
|
||||
static const uint32_t GameflowPhaseNamesCount = ARRSIZE(GameflowPhaseNames);
|
||||
|
||||
template<typename T>
|
||||
static T mapEnum(const std::string& input, const std::string* names, uint32_t count, T defaul) {
|
||||
for(uint32_t i = 0; i < count; ++i) {
|
||||
if(names[i] == input) {
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (names[i] == input) {
|
||||
return (T) i;
|
||||
}
|
||||
}
|
||||
|
@ -28,24 +35,105 @@ ClientAPI::ClientAPI(const ClientAccess& ca) : RestClient(ca.getURL()), access(c
|
|||
}
|
||||
ClientAPI::~ClientAPI() {}
|
||||
|
||||
ClientAPI::SearchState ClientAPI::getSearchState() {
|
||||
QJsonDocument doc = request("lol-lobby/v2/lobby/matchmaking/search-state");
|
||||
ClientAPI::ReadyCheckState ClientAPI::getReadyCheckState() {
|
||||
QJsonDocument doc = request("lol-matchmaking/v1/ready-check");
|
||||
|
||||
if(doc.isObject()) {
|
||||
if (doc.isObject()) {
|
||||
QJsonObject obj = doc.object();
|
||||
std::string searchState = getValue<std::string>(obj, "searchState", "Invalid");
|
||||
Log::info << "ready check obj: " << doc.toJson().toStdString();
|
||||
|
||||
return mapEnum(searchState, SearchStateNames, SearchStateNamesCount, ClientAPI::SearchState::INVALID);
|
||||
std::string searchState = getValue<std::string>(obj, "state", "Invalid");
|
||||
std::string playerresponse = getValue<std::string>(obj, "playerResponse", "None");
|
||||
|
||||
ClientAPI::ReadyCheckState response = mapEnum(playerresponse, ReadyCheckStateNames, ReadyCheckStateNamesCount, ClientAPI::ReadyCheckState::NONE);
|
||||
|
||||
if(response == ClientAPI::ReadyCheckState::NONE) {
|
||||
auto sstate = mapEnum(searchState, ReadyCheckStateNames, ReadyCheckStateNamesCount, ClientAPI::ReadyCheckState::INVALID);
|
||||
if(sstate == ClientAPI::ReadyCheckState::INPROGRESS) {
|
||||
return sstate;
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
return ClientAPI::SearchState::INVALID;
|
||||
return ClientAPI::ReadyCheckState::NONE;
|
||||
}
|
||||
|
||||
ClientAPI::GameflowPhase ClientAPI::getGameflowPhase() {
|
||||
// it is just a json-string no object
|
||||
QByteArray data = requestRaw("lol-gameflow/v1/gameflow-phase");
|
||||
|
||||
std::string datastr = data.toStdString();
|
||||
if (data.size() > 2) {
|
||||
datastr = datastr.substr(1, datastr.size() -2);
|
||||
|
||||
return mapEnum(datastr, GameflowPhaseNames, GameflowPhaseNamesCount, ClientAPI::GameflowPhase::NONE);
|
||||
}
|
||||
|
||||
return ClientAPI::GameflowPhase::NONE;
|
||||
}
|
||||
|
||||
void ClientAPI::acceptMatch() {
|
||||
|
||||
request("lol-matchmaking/v1/ready-check/accept", Method::POST);
|
||||
}
|
||||
|
||||
void ClientAPI::declineMatch() {
|
||||
|
||||
request("lol-matchmaking/v1/ready-check/decline", Method::POST);
|
||||
}
|
||||
|
||||
static std::vector<int32_t> fromArrayToVector(const QJsonArray& arr) {
|
||||
std::vector<int32_t> out;
|
||||
out.reserve(arr.size());
|
||||
for (auto it = arr.begin(); it != arr.end(); ++it) {
|
||||
if (it->isDouble())
|
||||
out.push_back(it->toInt());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<int32_t> ClientAPI::getBannableChampIDs() {
|
||||
QJsonDocument doc = request("lol-champ-select/v1/bannable-champion-ids");
|
||||
|
||||
if (doc.isArray()) {
|
||||
return fromArrayToVector(doc.array());
|
||||
}
|
||||
|
||||
return {}; // empty vector
|
||||
}
|
||||
|
||||
std::vector<int32_t> ClientAPI::getPickableChampIDs() {
|
||||
QJsonDocument doc = request("lol-champ-select/v1/pickable-champion-ids");
|
||||
|
||||
if (doc.isArray()) {
|
||||
return fromArrayToVector(doc.array());
|
||||
}
|
||||
|
||||
return {}; // empty vector
|
||||
}
|
||||
|
||||
ClientAPI::TimerInfo ClientAPI::getTimerInfo() {
|
||||
QJsonDocument doc = request("lol-champ-select/v1/session/timer");
|
||||
|
||||
if (!doc.isObject()) return {};
|
||||
|
||||
TimerInfo ti;
|
||||
|
||||
QJsonObject obj = doc.object();
|
||||
ti.adjustedTimeLeftInPhase = getValue<int64_t>(obj, "adjustedTimeLeftInPhase", 0);
|
||||
ti.internalNowInEpochMs = getValue<int64_t>(obj, "internalNowInEpochMs", 0);
|
||||
ti.isefinite = getValue<bool>(obj, "isefinite", 0);
|
||||
ti.phase = getValue<std::string>(obj, "phase", "");
|
||||
ti.totalTimeInPhase = getValue<int64_t>(obj, "totalTimeInPhase", 0);
|
||||
|
||||
return ti;
|
||||
}
|
||||
|
||||
#define PRINTENUM(ENUMNAME) \
|
||||
std::ostream& operator<<(std::ostream& str, const ClientAPI:: ENUMNAME & state) { \
|
||||
return str << ENUMNAME ## Names[(int) state] << " (" << (int) state << ')'; \
|
||||
}
|
||||
|
||||
|
||||
PRINTENUM(ReadyCheckState)
|
||||
PRINTENUM(GameflowPhase)
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
#include "fakescreen.h"
|
||||
|
||||
FakeScreen::FakeScreen(int xoffset, int yoffset, int xsize, int ysize) : ScreenShot(),
|
||||
xoffset(xoffset), yoffset(yoffset), xsize(xsize), ysize(ysize) {
|
||||
}
|
||||
|
||||
FakeScreen::~FakeScreen() {}
|
||||
|
||||
|
||||
void FakeScreen::take(cv::Mat& cvimg) {
|
||||
// take screenshot from entire screen using base class
|
||||
cv::Mat entireScreen;
|
||||
ScreenShot::take(entireScreen);
|
||||
|
||||
// only return part of the screenshot
|
||||
entireScreen({yoffset, yoffset + ysize}, {xoffset, xoffset + xsize}).copyTo(cvimg);
|
||||
}
|
||||
|
||||
void FakeScreen::operator() (cv::Mat& cvimg) {
|
||||
take(cvimg);
|
||||
}
|
||||
|
||||
|
||||
int FakeScreen::getXOffset() const {
|
||||
return xoffset;
|
||||
}
|
||||
|
||||
int FakeScreen::getYOffset() const {
|
||||
return yoffset;
|
||||
}
|
||||
|
||||
double FakeScreen::getXScale() const {
|
||||
return xsize / (double) DEFAULTWIDTH;
|
||||
}
|
||||
|
||||
double FakeScreen::getYScale() const {
|
||||
return ysize / (double) DEFAULTHEIGHT;
|
||||
}
|
|
@ -3,99 +3,18 @@
|
|||
#include <thread>
|
||||
#include <Log.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "fakescreen.h"
|
||||
|
||||
// set to 1 to use the test screenshot feature
|
||||
#define TESTSCREEN 0
|
||||
|
||||
void debugImage(cv::Mat img, const std::string& name) {
|
||||
if(img.channels() > 3) {
|
||||
std::vector<cv::Mat> channels(4);
|
||||
cv::split(img, channels);
|
||||
channels.resize(3); // drop alpha channel
|
||||
cv::merge(channels, img);
|
||||
}
|
||||
|
||||
time_t t = time(0);
|
||||
cv::imwrite("debugimages/" + name + std::to_string(t) + ".png", img);
|
||||
}
|
||||
|
||||
LolAutoAccept::Stage::Stage(const std::string& matchertmpl) : matcher(matchertmpl) {}
|
||||
LolAutoAccept::Stage::Stage() {}
|
||||
LolAutoAccept::Stage::~Stage() {}
|
||||
|
||||
bool LolAutoAccept::Stage::process(LolAutoAccept& lolaa, cv::Mat& img) {
|
||||
if(enabled) {
|
||||
auto match = matcher.match(img);
|
||||
if(match.doesMatch) {
|
||||
action(lolaa);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
LolAutoAccept::CooldownStage::CooldownStage(const std::string& matchertmpl) : Stage(matchertmpl) {}
|
||||
|
||||
bool LolAutoAccept::CooldownStage::process(LolAutoAccept& lolaa, cv::Mat& img) {
|
||||
if((time(0) - lastused) > cooldown) {
|
||||
if(Stage::process(lolaa, img)) {
|
||||
lastused = time(0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void LolAutoAccept::performClick(uint32_t nr, bool movemouseaway) {
|
||||
inputs.setOffset(screen->getXOffset(), screen->getYOffset());
|
||||
inputs.setScale(screen->getXScale(), screen->getYScale());
|
||||
|
||||
auto p = inputs.get(nr);
|
||||
Log::info << "click " << nr << " @ " << p.x << " " << p.y;
|
||||
|
||||
sim.mouseMoveTo(p.x, p.y);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(170));
|
||||
sim.mouseClick(XIS::LEFT_MOUSE_BUTTON);
|
||||
|
||||
// move mouse away
|
||||
if(movemouseaway) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(170));
|
||||
p = inputs.get(0);
|
||||
sim.mouseMoveTo(p.x, p.y);
|
||||
}
|
||||
}
|
||||
|
||||
void LolAutoAccept::enterSearch(const std::string& text) {
|
||||
performClick(2, false); // click searchbox
|
||||
|
||||
Log::debug << "enter text: " << text;
|
||||
|
||||
sim.keySequence(text);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(750));
|
||||
}
|
||||
|
||||
void LolAutoAccept::pickFirst(const std::string& search) {
|
||||
enterSearch(search);
|
||||
|
||||
performClick(3, false); // first champion
|
||||
}
|
||||
|
||||
LolAutoAccept::LolAutoAccept() : sim(XInputSimulator::getInstance()) {
|
||||
// click positions in 1280x720 scale
|
||||
inputs.addPoint({0, 0}); // zero zero
|
||||
inputs.addPoint({645, 560}); // accept game
|
||||
inputs.addPoint({775, 105}); // search box
|
||||
inputs.addPoint({380, 160}); // first champ
|
||||
inputs.addPoint({638, 608}); // pick/ban champ
|
||||
void LolAutoAccept::Stage::action(LolAutoAccept& lolaa) {}
|
||||
|
||||
LolAutoAccept::LolAutoAccept() {
|
||||
stages.reserve(4);
|
||||
stages.push_back(new AcceptStage());
|
||||
stages.push_back(new PrePickStage());
|
||||
stages.push_back(new BanStage());
|
||||
stages.push_back(new PickStage());
|
||||
stages.push_back(new Stage()); // accept
|
||||
stages.push_back(new Stage()); // prepick
|
||||
stages.push_back(new Stage()); // ban
|
||||
stages.push_back(new Stage()); // pick
|
||||
}
|
||||
|
||||
LolAutoAccept::~LolAutoAccept() {
|
||||
|
@ -104,9 +23,6 @@ LolAutoAccept::~LolAutoAccept() {
|
|||
for(auto s : stages) {
|
||||
delete s;
|
||||
}
|
||||
|
||||
delete screen;
|
||||
screen = nullptr;
|
||||
}
|
||||
|
||||
void LolAutoAccept::setChamp(const std::string& champ, State s) {
|
||||
|
@ -128,37 +44,21 @@ void LolAutoAccept::setEnabled(bool b, State s) {
|
|||
}
|
||||
|
||||
bool LolAutoAccept::init() {
|
||||
if(screen)
|
||||
return true;
|
||||
if(clientapi) return true;
|
||||
|
||||
// get window
|
||||
#if TESTSCREEN == 0
|
||||
auto wins = ScreenShot::getWindows("League of Legends");
|
||||
if(wins.size() != 1) {
|
||||
Log::fatal << "invalid count of windows found: " << wins.size();
|
||||
for(auto w : wins) {
|
||||
delete w;
|
||||
}
|
||||
return false;
|
||||
auto ca = ClientAccess::find();
|
||||
if(ca) {
|
||||
clientapi = std::make_shared<ClientAPI>(*ca.get());
|
||||
}
|
||||
|
||||
screen = (wins.at(0)); // just take the first
|
||||
#else
|
||||
|
||||
// testing whole screen, but take a part of it, so it behaves like a focused screenshot
|
||||
screen = new FakeScreen(1, 683, 1280, 720);
|
||||
#endif
|
||||
|
||||
// testing: whole screen:
|
||||
// screen = new ScreenShot();
|
||||
return true;
|
||||
return (bool) clientapi;
|
||||
}
|
||||
|
||||
void LolAutoAccept::run() {
|
||||
// make sure its not running
|
||||
stopJoinThread();
|
||||
|
||||
if(!screen) return;
|
||||
if(!clientapi) return; // no client api
|
||||
|
||||
lolaathread = std::thread(&LolAutoAccept::innerRun, this);
|
||||
}
|
||||
|
@ -181,24 +81,29 @@ void LolAutoAccept::innerRun() {
|
|||
while(shouldrun) {
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
cv::Mat img;
|
||||
screen->take(img);
|
||||
cv::resize(img, img, cv::Size(ScreenShot::DEFAULTWIDTH, ScreenShot::DEFAULTHEIGHT));
|
||||
auto phase = clientapi->getGameflowPhase();
|
||||
Log::debug << "current Gameflowphase: " << phase;
|
||||
|
||||
// TODO: do processing
|
||||
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();
|
||||
}
|
||||
} else if(phase == ClientAPI::GameflowPhase::CHAMPSELECT) {
|
||||
|
||||
for(size_t i = 0; i < stages.size(); ++i) {
|
||||
Log::trace << "processing stage " << i;
|
||||
Stage* stage = stages.at(i);
|
||||
if(stage->process(*this, img)) {
|
||||
Log::debug << "stage successful: " << i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> dur = (end-start);
|
||||
if(dur.count() > 1e-5)
|
||||
Log::info << "iteration took: " << (dur.count() * 1000) << " ms";
|
||||
//if(dur.count() > 1e-5)
|
||||
Log::info << "iteration took: " << (dur.count() * 1000) << " ms";
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(800));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1200));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
#include "lolautoaccept.h"
|
||||
|
||||
LolAutoAccept::AcceptStage::AcceptStage() : Stage("imgs/accept.png") {
|
||||
matcher.setOffset(539, 529);
|
||||
}
|
||||
|
||||
void LolAutoAccept::AcceptStage::action(LolAutoAccept& lolaa) {
|
||||
lolaa.performClick(1); // accept Game
|
||||
|
||||
// security sleep
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
#include "lolautoaccept.h"
|
||||
|
||||
LolAutoAccept::BanStage::BanStage() : CooldownStage("imgs/ban.png") {
|
||||
matcher.setOffset(1232, 90);
|
||||
cooldown = 30;
|
||||
}
|
||||
|
||||
void LolAutoAccept::BanStage::action(LolAutoAccept& lolaa) {
|
||||
if(!champ.empty()) {
|
||||
lolaa.pickFirst(champ);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1800));
|
||||
|
||||
// click "ban"
|
||||
lolaa.performClick(4);
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
#include "lolautoaccept.h"
|
||||
|
||||
LolAutoAccept::PickStage::PickStage() : CooldownStage("imgs/pick.png") {
|
||||
matcher.setOffset(538, 587);
|
||||
cooldown = 30;
|
||||
}
|
||||
|
||||
void LolAutoAccept::PickStage::action(LolAutoAccept& lolaa) {
|
||||
if(!champ.empty()) {
|
||||
lolaa.pickFirst(champ);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1800));
|
||||
|
||||
// click "accept"
|
||||
lolaa.performClick(4);
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#include "lolautoaccept.h"
|
||||
|
||||
LolAutoAccept::PrePickStage::PrePickStage() : CooldownStage("imgs/arrowdown.png") {
|
||||
matcher.setOffset(615, 617);
|
||||
cooldown = 15;
|
||||
}
|
||||
|
||||
void LolAutoAccept::PrePickStage::action(LolAutoAccept& lolaa) {
|
||||
if(!champ.empty())
|
||||
lolaa.pickFirst(champ);
|
||||
}
|
18
src/main.cpp
18
src/main.cpp
|
@ -12,6 +12,8 @@
|
|||
#include "arg.h"
|
||||
#include "mainwindow.h"
|
||||
#include "lolautoaccept.h"
|
||||
#include "clientaccess.h"
|
||||
#include "clientapi.h"
|
||||
|
||||
static std::string getBaseString(char** argv) {
|
||||
std::string base;
|
||||
|
@ -51,7 +53,6 @@ int main(int argc, char** argv) {
|
|||
|
||||
std::string base = getBaseString(argv);
|
||||
Log::info << "appbase: " << base;
|
||||
Matcher::setPathBase(base);
|
||||
|
||||
LolAutoAccept lolaa;
|
||||
QApplication app(argc, argv);
|
||||
|
@ -65,21 +66,6 @@ int main(int argc, char** argv) {
|
|||
QIcon icon(QString::fromStdString(base + "lolautoaccept.png"));
|
||||
win.setWindowIcon(icon);
|
||||
|
||||
while(!lolaa.init()) {
|
||||
QMessageBox warn;
|
||||
warn.setWindowIcon(icon);
|
||||
warn.setWindowTitle(MainWindow::tr("LoL-Auto-Accept"));
|
||||
warn.setText(QMessageBox::tr("League of Legends Client not found!"));
|
||||
warn.setInformativeText(QMessageBox::tr("Open the client and retry or close."));
|
||||
warn.setStandardButtons(QMessageBox::Retry | QMessageBox::Close);
|
||||
warn.setDefaultButton(QMessageBox::Retry);
|
||||
warn.setIcon(QMessageBox::Warning);
|
||||
if(warn.exec() == QMessageBox::Close) {
|
||||
Log::stop();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
win.show();
|
||||
int ret = app.exec();
|
||||
|
||||
|
|
102
src/matcher.cpp
102
src/matcher.cpp
|
@ -1,102 +0,0 @@
|
|||
#include "matcher.h"
|
||||
|
||||
#include <Log.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
std::string Matcher::pathbase;
|
||||
|
||||
void Matcher::setPathBase(const std::string& pa) {
|
||||
pathbase = pa;
|
||||
}
|
||||
|
||||
Matcher::Matcher(const std::string& filename) {
|
||||
templ = cv::imread(pathbase + filename, cv::IMREAD_UNCHANGED); // unchanged so alpha channel does not get dropped
|
||||
maskFromTemplate();
|
||||
}
|
||||
Matcher::Matcher(const cv::Mat& templ) {
|
||||
templ.copyTo(this->templ);
|
||||
maskFromTemplate();
|
||||
}
|
||||
Matcher::~Matcher() {}
|
||||
|
||||
void Matcher::setOffset(int32_t x, int32_t y) {
|
||||
posx = x;
|
||||
posy = y;
|
||||
}
|
||||
|
||||
|
||||
bool Matcher::Match::operator==(const Match& other) const {
|
||||
return doesMatch == other.doesMatch && x == other.x && y == other.y && width == other.width && height == other.height;
|
||||
}
|
||||
|
||||
bool Matcher::Match::operator!=(const Match& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
|
||||
Matcher::Match Matcher::match(const cv::Mat& img) {
|
||||
// remove Alpha channel from input
|
||||
cv::Mat converted;
|
||||
cv::cvtColor(img, converted, cv::COLOR_RGBA2RGB);
|
||||
|
||||
if(posx < 0 || posy < 0) {
|
||||
return matchAll(converted);
|
||||
}
|
||||
return matchPos(converted);
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/43133263/4399859
|
||||
Matcher::Match Matcher::matchAll(const cv::Mat& img) {
|
||||
// create out mat
|
||||
int result_cols = img.cols - templ.cols + 1;
|
||||
int result_rows = img.rows - templ.rows + 1;
|
||||
cv::Mat out(result_rows, result_cols, CV_32FC1);
|
||||
Log::info << "match size: " << result_cols << " " << result_cols;
|
||||
|
||||
// match
|
||||
cv::matchTemplate(img, templ, out, cv::TM_CCORR_NORMED, mask);
|
||||
|
||||
double minVal; double maxVal;
|
||||
cv::Point minLoc; cv::Point maxLoc;
|
||||
cv::minMaxLoc( out, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat());
|
||||
|
||||
Log::debug << "pixelcount: " << (templ.cols * templ.rows) << " minVal: " << minVal << " maxVal: " << maxVal << " minLoc: " << minLoc.x << " " << minLoc.y << " maxLoc: " << maxLoc.x << " " << maxLoc.y;
|
||||
|
||||
bool matched = maxVal > 0.95;
|
||||
|
||||
return {matched, maxLoc.x, maxLoc.y, templ.cols, templ.rows};
|
||||
}
|
||||
|
||||
Matcher::Match Matcher::matchPos(const cv::Mat& img) {
|
||||
cv::Mat matchpart = img(cv::Range(posy, posy + templ.rows), cv::Range(posx, posx + templ.cols));
|
||||
|
||||
// create out mat (only one pxl)
|
||||
cv::Mat out(1, 1, CV_32FC1);
|
||||
|
||||
// match
|
||||
cv::matchTemplate(matchpart, templ, out, cv::TM_CCORR_NORMED, mask);
|
||||
|
||||
float val = out.at<float>({0, 0});
|
||||
bool matched = val > 0.95;
|
||||
|
||||
Log::debug << "val: " << val;
|
||||
|
||||
return {matched, posx, posy, templ.cols, templ.rows};
|
||||
}
|
||||
|
||||
void Matcher::maskFromTemplate() {
|
||||
if(templ.channels() == 4) {
|
||||
// split channels
|
||||
std::vector<cv::Mat> split;
|
||||
cv::split(templ, split);
|
||||
|
||||
// template without alpha channel
|
||||
cv::merge(std::vector(split.begin(), split.end()-1), templ);
|
||||
|
||||
// 3*alpha channel
|
||||
cv::Mat alphaChannel = split.at(3);
|
||||
alphaChannel.convertTo(alphaChannel, CV_8U);
|
||||
cv::merge(std::vector(3, alphaChannel), mask);
|
||||
}
|
||||
}
|
|
@ -45,7 +45,9 @@ QByteArray RestClient::requestRaw(const std::string& url, Method m) {
|
|||
case Method::GET:
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); break;
|
||||
case Method::POST:
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1L); break;
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
|
||||
break;
|
||||
case Method::PUT:
|
||||
curl_easy_setopt(curl, CURLOPT_PUT, 1L); break;
|
||||
case Method::DELETE:
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
#include "scaleableinputs.h"
|
||||
|
||||
#include <Log.h>
|
||||
|
||||
void ScaleableInputs::addPoint(Point p) {
|
||||
points.push_back(p);
|
||||
}
|
||||
|
||||
void ScaleableInputs::setScale(double x, double y) {
|
||||
xScale = x;
|
||||
yScale = y;
|
||||
}
|
||||
|
||||
void ScaleableInputs::setOffset(double x, double y) {
|
||||
xOffset = x;
|
||||
yOffset = y;
|
||||
}
|
||||
|
||||
ScaleableInputs::Point ScaleableInputs::get(uint32_t nr) const {
|
||||
Point p = points.at(nr);
|
||||
|
||||
Log::debug << "scaling: " << p.x << " " << p.y << " with: " << xOffset << " " << yOffset << " scale: " << xScale << " " << yScale;
|
||||
|
||||
return {(uint32_t) ((p.x * xScale) + xOffset), (uint32_t) ((p.y * yScale) + yOffset)};
|
||||
}
|
161
src/screen.cpp
161
src/screen.cpp
|
@ -1,161 +0,0 @@
|
|||
// g++ screena.cpp -o screena -lX11 -lXext -Ofast -mfpmath=both -march=native -m64 -funroll-loops -mavx2 `pkg-config opencv --cflags --libs` && ./screena
|
||||
|
||||
// This includes most headers!
|
||||
|
||||
#include "screen.h"
|
||||
|
||||
#include <X11/cursorfont.h>
|
||||
#include <Log.h>
|
||||
|
||||
const uint32_t ScreenShot::DEFAULTWIDTH = 1280;
|
||||
const uint32_t ScreenShot::DEFAULTHEIGHT = 720;
|
||||
|
||||
// https://stackoverflow.com/a/39781697/4399859
|
||||
|
||||
static void searchWindows(Display* disp, Window top, const std::string& search, std::vector<Window>& result) {
|
||||
|
||||
char* window_name;
|
||||
if (XFetchName(disp, top, &window_name)) {
|
||||
if (search == window_name) {
|
||||
result.push_back(top);
|
||||
return; // dont look for kids
|
||||
}
|
||||
}
|
||||
|
||||
Window* children = nullptr, dummy;
|
||||
unsigned int nchildren;
|
||||
if (!XQueryTree(disp, top, &dummy, &dummy, &children, &nchildren))
|
||||
return;
|
||||
|
||||
for (unsigned int i = 0; i < nchildren; i++) {
|
||||
searchWindows(disp, children[i], search, result);
|
||||
}
|
||||
if (children)
|
||||
XFree((char*) children);
|
||||
}
|
||||
|
||||
std::vector<ScreenShot*> ScreenShot::getWindows(const std::string& name) {
|
||||
Display* display = XOpenDisplay(nullptr);
|
||||
|
||||
Log::info << "searching for: " << name;
|
||||
|
||||
std::vector<Window> list;
|
||||
searchWindows(display, DefaultRootWindow(display), name, list);
|
||||
std::vector<ScreenShot*> out;
|
||||
|
||||
out.reserve(list.size());
|
||||
for (Window w : list) {
|
||||
ScreenShot* ss = new ScreenShot(display, w);
|
||||
if(ss->valid)
|
||||
out.push_back(ss);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
bool ScreenShot::updateAttrib() {
|
||||
Status attrb = XGetWindowAttributes(display, window, &wattrib);
|
||||
|
||||
if (attrb == BadWindow || attrb == BadDrawable) {
|
||||
Log::error << "XGetWindowAttributes() falied";
|
||||
return false;
|
||||
}
|
||||
|
||||
if((wattrib.c_class != InputOutput) || (wattrib.map_state != IsViewable)) {
|
||||
Log::warn << "Window is not viewable - window class: " << wattrib.c_class << " map state: " << wattrib.map_state << " - ignoring window";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScreenShot::initImg() {
|
||||
bool upd = updateAttrib();
|
||||
if(!upd) return false;
|
||||
|
||||
char* wname = nullptr;
|
||||
XFetchName(display, window, &wname);
|
||||
if (wname)
|
||||
windowname = std::string(wname);
|
||||
|
||||
Log::info << "Window " << std::quoted(windowname) << " x: " << wattrib.x << " y: " << wattrib.y << " w: " << wattrib.width << " h: " << wattrib.height;
|
||||
|
||||
ximg = XShmCreateImage(display, wattrib.visual, wattrib.depth, ZPixmap, NULL, &shminfo, wattrib.width, wattrib.height);
|
||||
|
||||
shminfo.shmid = shmget(IPC_PRIVATE, ximg->bytes_per_line * ximg->height, IPC_CREAT | 0777);
|
||||
shminfo.shmaddr = ximg->data = (char*) shmat(shminfo.shmid, 0, 0);
|
||||
shminfo.readOnly = false;
|
||||
if (shminfo.shmid < 0)
|
||||
Log::fatal << "Fatal shminfo error!";
|
||||
Status s1 = XShmAttach(display, &shminfo);
|
||||
Log::info << "XShmAttach() " << (s1 ? "success!" : "failure!");
|
||||
|
||||
init = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
ScreenShot::ScreenShot() {
|
||||
|
||||
display = XOpenDisplay(nullptr);
|
||||
window = DefaultRootWindow(display);
|
||||
|
||||
int count_screens = ScreenCount(display);
|
||||
if (count_screens == 0) {
|
||||
puts("no screen info!");
|
||||
}
|
||||
for (int i = 0; i < count_screens; ++i) {
|
||||
Screen* screen = ScreenOfDisplay(display, i);
|
||||
printf("\tScreen %d: %dX%d\n", i + 1, screen->width, screen->height);
|
||||
}
|
||||
|
||||
valid = initImg();
|
||||
}
|
||||
|
||||
ScreenShot::ScreenShot(Display* d, Window w) : display(d), window(w), closeDisp(false) {
|
||||
valid = initImg();
|
||||
}
|
||||
|
||||
void ScreenShot::take(cv::Mat& cv_img) {
|
||||
if (init)
|
||||
init = false;
|
||||
|
||||
// window not viewable
|
||||
if(!updateAttrib()) {
|
||||
cv_img.create(0, 0, 0);
|
||||
}
|
||||
|
||||
XShmGetImage(display, window, ximg, 0, 0, 0x00ffffff);
|
||||
cv_img = cv::Mat(wattrib.height, wattrib.width, CV_8UC4, ximg->data);
|
||||
}
|
||||
|
||||
void ScreenShot::operator() (cv::Mat& cv_img) {
|
||||
take(cv_img);
|
||||
}
|
||||
|
||||
ScreenShot::~ScreenShot() {
|
||||
if (!init)
|
||||
XDestroyImage(ximg);
|
||||
|
||||
XShmDetach(display, &shminfo);
|
||||
shmdt(shminfo.shmaddr);
|
||||
|
||||
if (closeDisp)
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
|
||||
|
||||
int ScreenShot::getXOffset() const {
|
||||
return wattrib.x;
|
||||
}
|
||||
|
||||
int ScreenShot::getYOffset() const {
|
||||
return wattrib.y;
|
||||
}
|
||||
|
||||
double ScreenShot::getXScale() const {
|
||||
return wattrib.width / (double) DEFAULTWIDTH;
|
||||
}
|
||||
|
||||
double ScreenShot::getYScale() const {
|
||||
return wattrib.height / (double) DEFAULTHEIGHT;
|
||||
}
|
Loading…
Reference in New Issue