forked from MrBesen/lolautoaccept
only screenshot launcher window; organized
This commit is contained in:
parent
afb7c2adde
commit
84795aa725
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include "scaleableinputs.h"
|
||||
#include "screen.h"
|
||||
#include "matcher.h"
|
||||
|
||||
#include <xinputsimulator.h>
|
||||
|
||||
class LolAutoAccept {
|
||||
private:
|
||||
ScreenShot* screen;
|
||||
Matcher acceptmatcher;
|
||||
Matcher arrowmatcher;
|
||||
Matcher::Match lastacceptmatch;
|
||||
XInputSimulator& sim;
|
||||
|
||||
ScaleableInputs inputs;
|
||||
|
||||
std::string prepick;
|
||||
std::string ban;
|
||||
std::string pick;
|
||||
|
||||
enum class State {
|
||||
LOBBY,
|
||||
PREPICK,
|
||||
BAN,
|
||||
PICK,
|
||||
GAME
|
||||
};
|
||||
|
||||
State state = State::LOBBY;
|
||||
|
||||
void checkForGame();
|
||||
void performClick(uint32_t nr);
|
||||
void enterSearch(const std::string& text);
|
||||
void pickFirst(const std::string& search);
|
||||
public:
|
||||
LolAutoAccept();
|
||||
|
||||
void run();
|
||||
};
|
|
@ -19,6 +19,16 @@ public:
|
|||
|
||||
bool operator==(const Match&) const;
|
||||
bool operator!=(const Match&) const;
|
||||
|
||||
|
||||
// get the center of the button
|
||||
constexpr int getButtonX() const {
|
||||
return x + (width/2);
|
||||
}
|
||||
|
||||
constexpr int getButtonY() const {
|
||||
return y + (height/2);
|
||||
}
|
||||
};
|
||||
|
||||
Match match(const cv::Mat& img);
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
class ScaleableInputs {
|
||||
public:
|
||||
struct Point {
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
};
|
||||
|
||||
private:
|
||||
double xScale = 1;
|
||||
double yScale = 1;
|
||||
double xOffset = 0;
|
||||
double yOffset = 0;
|
||||
|
||||
std::vector<Point> points;
|
||||
|
||||
public:
|
||||
|
||||
void addPoint(Point p);
|
||||
void setScale(double x, double y);
|
||||
void setOffset(double x, double y);
|
||||
|
||||
Point get(uint32_t nr) const;
|
||||
|
||||
};
|
|
@ -12,20 +12,49 @@
|
|||
class ScreenShot {
|
||||
private:
|
||||
Display* display = nullptr;
|
||||
Window root;
|
||||
XWindowAttributes window_attributes;
|
||||
Window window;
|
||||
XWindowAttributes wattrib;
|
||||
XImage* ximg = nullptr;
|
||||
XShmSegmentInfo shminfo;
|
||||
|
||||
int x, y, width, height;
|
||||
|
||||
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);
|
||||
~ScreenShot();
|
||||
|
||||
void take(cv::Mat& cvimg);
|
||||
void operator() (cv::Mat& cvimg);
|
||||
|
||||
};
|
||||
constexpr operator bool () const {
|
||||
return valid;
|
||||
}
|
||||
|
||||
constexpr int getXOffset() const {
|
||||
return wattrib.x;
|
||||
}
|
||||
|
||||
constexpr int getYOffset() const {
|
||||
return wattrib.y;
|
||||
}
|
||||
|
||||
constexpr double getXScale() const {
|
||||
return wattrib.width / DEFAULTWIDTH;
|
||||
}
|
||||
|
||||
constexpr double getYScale() const {
|
||||
return wattrib.height / DEFAULTHEIGHT;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
void debugImage(cv::Mat img, const std::string& name = "");
|
|
@ -0,0 +1,131 @@
|
|||
#include "lolautoaccept.h"
|
||||
|
||||
#include <thread>
|
||||
#include <Log.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void LolAutoAccept::checkForGame() {
|
||||
cv::Mat img;
|
||||
screen->take(img);
|
||||
|
||||
cv::resize(img, img, cv::Size(ScreenShot::DEFAULTWIDTH, ScreenShot::DEFAULTHEIGHT));
|
||||
|
||||
Matcher::Match mat = acceptmatcher.match(img);
|
||||
|
||||
if(mat.doesMatch) {
|
||||
Log::info << "matched";
|
||||
cv::rectangle(img, cv::Point(mat.x, mat.y), cv::Point( mat.x + mat.width , mat.y + mat.height ), cv::Scalar(0, 0, 255, 0), 2);
|
||||
debugImage(img);
|
||||
|
||||
if(lastacceptmatch.doesMatch) {
|
||||
Log::info << "second match";
|
||||
|
||||
if(lastacceptmatch != mat) {
|
||||
Log::warn << "not same match!";
|
||||
lastacceptmatch.doesMatch = false;
|
||||
return;
|
||||
}
|
||||
|
||||
performClick(0); // accept Game
|
||||
|
||||
// security sleep
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
} else {
|
||||
Log::info << "first match";
|
||||
}
|
||||
} else {
|
||||
// check if next stage is here
|
||||
Matcher::Match mat = arrowmatcher.match(img);
|
||||
if(mat.doesMatch) {
|
||||
Log::info << "Pre pick state";
|
||||
|
||||
if(!prepick.empty())
|
||||
pickFirst(prepick);
|
||||
|
||||
state = State::PREPICK;
|
||||
}
|
||||
}
|
||||
lastacceptmatch = mat;
|
||||
}
|
||||
|
||||
void LolAutoAccept::performClick(uint32_t nr) {
|
||||
inputs.setOffset(screen->getXOffset(), screen->getYOffset());
|
||||
inputs.setScale(1 / screen->getXScale(), 1 / 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(120));
|
||||
sim.mouseClick(XIS::LEFT_MOUSE_BUTTON);
|
||||
|
||||
// move mouse away
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(120));
|
||||
sim.mouseMoveTo(0, 0);
|
||||
}
|
||||
|
||||
void LolAutoAccept::enterSearch(const std::string& text) {
|
||||
performClick(1); // click searchbox
|
||||
|
||||
Log::debug << "enter text: " << text;
|
||||
|
||||
sim.keySequence(text);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(180));
|
||||
}
|
||||
|
||||
void LolAutoAccept::pickFirst(const std::string& search) {
|
||||
enterSearch(search);
|
||||
|
||||
performClick(2); // first champion
|
||||
}
|
||||
|
||||
LolAutoAccept::LolAutoAccept() : acceptmatcher("imgs/Accept.png"), arrowmatcher("imgs/arrowdown.png"), sim(XInputSimulator::getInstance()) {
|
||||
inputs.addPoint({645, 560}); // accept game
|
||||
inputs.addPoint({775, 105}); // search box
|
||||
inputs.addPoint({180, 160}); // first champ
|
||||
}
|
||||
|
||||
void LolAutoAccept::run() {
|
||||
// get window
|
||||
auto wins = ScreenShot::getWindows("League of Legends");
|
||||
if(wins.size() != 1) {
|
||||
Log::fatal << "invalid count of windows found: " << wins.size();
|
||||
return;
|
||||
}
|
||||
|
||||
screen = (wins.at(0)); // just take the first
|
||||
|
||||
//delete other screens
|
||||
for(uint32_t i = 1; i < wins.size(); ++i) {
|
||||
ScreenShot* ss = wins.at(i);
|
||||
delete ss;
|
||||
}
|
||||
|
||||
lastacceptmatch = {false};
|
||||
while(true) {
|
||||
switch(state) {
|
||||
case State::LOBBY:
|
||||
checkForGame();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(800));
|
||||
}
|
||||
|
||||
delete wins.at(0);
|
||||
}
|
76
src/main.cpp
76
src/main.cpp
|
@ -1,24 +1,6 @@
|
|||
#include "lolautoaccept.h"
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
#include "screen.h"
|
||||
#include "matcher.h"
|
||||
|
||||
#include <xinputsimulator.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
static void debugImage(cv::Mat img) {
|
||||
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/" + std::to_string(t) + ".png", img);
|
||||
}
|
||||
#include <Log.h>
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
Log::init();
|
||||
|
@ -30,53 +12,21 @@ int main(int argc, const char** argv) {
|
|||
|
||||
Log::info << "Hello, World!";
|
||||
|
||||
// load template
|
||||
Matcher matcher("imgs/Accept.png");
|
||||
Matcher test1("imgs/arrowdown.png");
|
||||
Matcher test2("imgs/blitzcranktest.png");
|
||||
auto testimg = cv::imread("imgs/Bildschirmfoto vom 2022-02-28 19-27-59.png");
|
||||
auto testimg2 = cv::imread("imgs/Bildschirmfoto vom 2022-02-28 19-27-44.png");
|
||||
test1.match(testimg);
|
||||
test2.match(testimg);
|
||||
|
||||
ScreenShot screen;
|
||||
test1.match(testimg2);
|
||||
test2.match(testimg2);
|
||||
|
||||
XInputSimulator& sim = XInputSimulator::getInstance();
|
||||
return 0;
|
||||
|
||||
Matcher::Match lastmatch = {false};
|
||||
|
||||
while(true) {
|
||||
cv::Mat img;
|
||||
screen(img);
|
||||
|
||||
Matcher::Match mat = matcher.match(img);
|
||||
|
||||
if(mat.doesMatch) {
|
||||
Log::info << "matched";
|
||||
cv::rectangle(img, cv::Point(mat.x, mat.y), cv::Point( mat.x + mat.width , mat.y + mat.height ), cv::Scalar(0, 0, 255, 0), 2);
|
||||
debugImage(img);
|
||||
|
||||
if(lastmatch.doesMatch) {
|
||||
Log::info << "second match";
|
||||
|
||||
if(lastmatch != mat) {
|
||||
Log::warn << "not same match!";
|
||||
lastmatch.doesMatch = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
int x = mat.x + (mat.width/2);
|
||||
int y = mat.y + (mat.height/2);
|
||||
Log::info << "click";
|
||||
sim.mouseMoveTo(x, y);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
sim.mouseClick(XIS::LEFT_MOUSE_BUTTON);
|
||||
|
||||
// security sleep
|
||||
std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||
} else {
|
||||
Log::info << "first match";
|
||||
}
|
||||
}
|
||||
lastmatch = mat;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
}
|
||||
LolAutoAccept lolaa;
|
||||
lolaa.run();
|
||||
|
||||
Log::stop();
|
||||
return 0;
|
||||
|
|
|
@ -40,7 +40,7 @@ Matcher::Match Matcher::match(const cv::Mat& img) {
|
|||
cv::Point minLoc; cv::Point maxLoc;
|
||||
cv::minMaxLoc( out, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat() );
|
||||
|
||||
Log::debug << "minValbn: " << minValbn << " maxValbn: " << maxValbn << " minVal: " << minVal << " maxVal: " << maxVal << " minLoc: " << minLoc.x << " " << minLoc.y << " maxLoc: " << maxLoc.x << " " << maxLoc.y;
|
||||
Log::debug << "pixelcount: " << (templ.cols * templ.rows) << " minValbn: " << minValbn << " maxValbn: " << maxValbn << " minVal: " << minVal << " maxVal: " << maxVal << " minLoc: " << minLoc.x << " " << minLoc.y << " maxLoc: " << maxLoc.x << " " << maxLoc.y;
|
||||
|
||||
bool matched = minValbn < 2e7;
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#include "scaleableinputs.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);
|
||||
return {(uint32_t) ((p.x * xScale) + xOffset), (uint32_t) ((p.y * yScale) + yOffset)};
|
||||
}
|
136
src/screen.cpp
136
src/screen.cpp
|
@ -4,15 +4,103 @@
|
|||
|
||||
#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);
|
||||
root = DefaultRootWindow(display);
|
||||
window = DefaultRootWindow(display);
|
||||
|
||||
int count_screens = ScreenCount(display);
|
||||
if(count_screens == 0) {
|
||||
if (count_screens == 0) {
|
||||
puts("no screen info!");
|
||||
}
|
||||
for (int i = 0; i < count_screens; ++i) {
|
||||
|
@ -20,40 +108,32 @@ ScreenShot::ScreenShot() {
|
|||
printf("\tScreen %d: %dX%d\n", i + 1, screen->width, screen->height);
|
||||
}
|
||||
|
||||
XGetWindowAttributes(display, root, &window_attributes);
|
||||
Screen* screen = window_attributes.screen;
|
||||
width = screen->width;
|
||||
height = screen->height;
|
||||
x = 0;
|
||||
y = 0;
|
||||
|
||||
ximg = XShmCreateImage(display, DefaultVisualOfScreen(screen), DefaultDepthOfScreen(screen), ZPixmap, NULL, &shminfo, width, 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)
|
||||
puts("Fatal shminfo error!");
|
||||
Status s1 = XShmAttach(display, &shminfo);
|
||||
printf("XShmAttach() %s\n", s1 ? "success!" : "failure!");
|
||||
|
||||
init = true;
|
||||
valid = initImg();
|
||||
}
|
||||
|
||||
void ScreenShot::operator() (cv::Mat& cv_img){
|
||||
if(init)
|
||||
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;
|
||||
|
||||
XShmGetImage(display, root, ximg, 0, 0, 0x00ffffff);
|
||||
cv_img = cv::Mat(height, width, CV_8UC4, ximg->data);
|
||||
XShmGetImage(display, window, ximg, 0, 0, 0x00ffffff);
|
||||
cv_img = cv::Mat(wattrib.height, wattrib.width, CV_8UC4, ximg->data);
|
||||
}
|
||||
|
||||
ScreenShot::~ScreenShot(){
|
||||
if(!init)
|
||||
void ScreenShot::operator() (cv::Mat& cv_img) {
|
||||
take(cv_img);
|
||||
}
|
||||
|
||||
ScreenShot::~ScreenShot() {
|
||||
if (!init)
|
||||
XDestroyImage(ximg);
|
||||
|
||||
XShmDetach(display, &shminfo);
|
||||
shmdt(shminfo.shmaddr);
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
|
||||
if (closeDisp)
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue