Compare commits
106 Commits
Author | SHA1 | Date |
---|---|---|
mrbesen | 2b4d718481 | |
mrbesen | b009411f55 | |
mrbesen | 16e1813f95 | |
mrbesen | 90c328aa4b | |
mrbesen | d316c2d24a | |
mrbesen | a1dc7f1011 | |
mrbesen | 1a353a5a21 | |
mrbesen | 86b91774a7 | |
mrbesen | 2b92291fa4 | |
mrbesen | c2d198b1c7 | |
mrbesen | 5bdb21e268 | |
mrbesen | b1c4739138 | |
mrbesen | 2cacbfe27f | |
Oliver | 5d0795dbd0 | |
Oliver | 9f2b175502 | |
Oliver | 2fdb7544c8 | |
Oliver | 12a2d71762 | |
mrbesen | 01e9a42482 | |
mrbesen | e7a10f2921 | |
mrbesen | 7d5f61dba8 | |
mrbesen | df78570e51 | |
mrbesen | a9fa26346f | |
mrbesen | 201f3665b3 | |
mrbesen | 61c64def43 | |
mrbesen | adcf715694 | |
mrbesen | b919a64ae6 | |
mrbesen | 42ff827caf | |
mrbesen | 4535495b09 | |
mrbesen | e9f99b2323 | |
mrbesen | bc63e4be72 | |
mrbesen | 96d57e8b8a | |
mrbesen | 17b244ec81 | |
mrbesen | 5aff7f431a | |
mrbesen | 14ec8a711b | |
mrbesen | ee7a11b0ef | |
mrbesen | 67175bc446 | |
mrbesen | d375c590f8 | |
mrbesen | 41de5a8652 | |
mrbesen | 67d5614be3 | |
mrbesen | 4aa35ff4e1 | |
mrbesen | ef36280894 | |
mrbesen | 6ffdf23085 | |
mrbesen | 5f3ff9e292 | |
mrbesen | e67c18f2ce | |
mrbesen | 0aca8969f9 | |
mrbesen | aa982d3798 | |
mrbesen | dd125d3183 | |
mrbesen | 152873d860 | |
mrbesen | 5fc50a524c | |
mrbesen | 3f1c264818 | |
mrbesen | 49bdc60071 | |
mrbesen | bc6f80c187 | |
mrbesen | ec4566f76a | |
mrbesen | 7cd1795155 | |
mrbesen | 53d642f507 | |
mrbesen | dd01c70230 | |
mrbesen | af63c975c7 | |
mrbesen | 7c96b8b188 | |
mrbesen | 6365ef1d6f | |
Oliver | d0d4638ca9 | |
MrBesen | 24cd4f71a3 | |
Oliver | d27c4c9371 | |
mrbesen | 47504fdd41 | |
mrbesen | d178716463 | |
mrbesen | ea1d72514c | |
mrbesen | 9c60193f24 | |
mrbesen | 6ab09c8caf | |
mrbesen | 4618a20a33 | |
mrbesen | 7789e7cfbb | |
mrbesen | a6f391cc4b | |
mrbesen | 226c031ecf | |
mrbesen | 71853c65d6 | |
mrbesen | 738364aa13 | |
MrBesen | 94020e5a04 | |
MrBesen | 58795ad66e | |
MrBesen | 0d43798a1c | |
MrBesen | c8341ef491 | |
MrBesen | 5bb58008c7 | |
mrbesen | 4fae1740e9 | |
Oliver | 03e4017e7f | |
mrbesen | ffc83a175f | |
mrbesen | 65b91f8d5a | |
mrbesen | 97a822746e | |
mrbesen | bb4555585e | |
mrbesen | e316b2bfe0 | |
mrbesen | 6d931be725 | |
mrbesen | 716a2e4067 | |
mrbesen | ece3d162e8 | |
mrbesen | c2203b4b5d | |
mrbesen | 1cb3134c8e | |
mrbesen | 4716e48cbf | |
mrbesen | c03b123af0 | |
mrbesen | 4bcdf80fab | |
mrbesen | d8e8e1c459 | |
mrbesen | d3379ab794 | |
mrbesen | e893852bc1 | |
mrbesen | e2f04637f2 | |
mrbesen | 5dd822d332 | |
mrbesen | d9ad8cb464 | |
mrbesen | abbbaf00aa | |
mrbesen | a4312e1570 | |
mrbesen | bce9dfb793 | |
mrbesen | 94d2869c51 | |
mrbesen | 68c7ce92d9 | |
mrbesen | 0276f83f3f | |
mrbesen | 1cc36ae0ee |
|
@ -25,4 +25,11 @@ Makefile
|
|||
|
||||
AppDir/
|
||||
*.AppImage
|
||||
qrc_res.cpp
|
||||
|
||||
debian/*
|
||||
!debian/source
|
||||
!debian/changelog
|
||||
!debian/control
|
||||
!debian/lolautoaccept.install
|
||||
!debian/rules
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
[submodule "thirdparty/Log"]
|
||||
path = thirdparty/Log
|
||||
url = https://git.okaestne.de/okaestne/Log.git
|
||||
url = https://git.mrbesen.de/MrBesen/Log.git
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/lolautoaccept",
|
||||
"args": [],
|
||||
"args": ["--debug-log"],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
|
|
15
Readme.md
|
@ -2,8 +2,8 @@
|
|||
|
||||
This is a tool, that tries to automatically accept a league of legends game.
|
||||
It is developed on linux and there is no effort to port it to windows.
|
||||
It works by taking a screenshot every second, analysing it using opencv and clicking on `accept` using XInputSimulator.
|
||||
It has problems when the champion you want to play is banned or picked by someone else. I only tested this in normals and ranked. (No Aram, Custom, URF, ....)
|
||||
It works by accessing the launcher using the LCU-API more about that api can be found [here](http://www.mingweisamuel.com/lcu-schema/tool/).
|
||||
I only tested this in normals and ranked (No Aram, Custom, URF, ....) but you may want to give it a try.
|
||||
|
||||
## Prebuilt Binary
|
||||
There is a prebuild AppImage that should work on every linux x86_64 computer.
|
||||
|
@ -13,16 +13,9 @@ There is a prebuild AppImage that should work on every linux x86_64 computer.
|
|||
|
||||
## Dependencies
|
||||
- Qt5
|
||||
- opencv4
|
||||
- X11
|
||||
- [XInputSimulator](https://github.com/a3f/XInputSimulator.git) (is a submodule)
|
||||
- libcurl
|
||||
- [Log](https://git.okaestne.de/okaestne/Log) (is a submodule)
|
||||
|
||||
## Notes
|
||||
* The Program should be able to detect the buttons no matter the client-language. But it was heavily tested with _german_.
|
||||
* The program has troubles detecting the button, when the mouse is hovering it. (Dont hover the launcher with your mouse.)
|
||||
* The launcher should be in 1280x720 (It might work with other resolutions, but they are not tested and are known to have potential problems).
|
||||
* Needs X11 and probably does not work with wayland (ubuntu). But i did not try that.
|
||||
|
||||
## Compile
|
||||
Be sure to clone with submodules:
|
||||
|
@ -31,8 +24,6 @@ git clone --recurse-submodules https://git.mrbesen.de/MrBesen/lolautoaccept.git
|
|||
```
|
||||
Then in its root folder:
|
||||
```
|
||||
./makeXInputSimulator.sh
|
||||
|
||||
qmake
|
||||
|
||||
# build the appimage
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
lolautoaccept (0.0.8) focal; urgency=medium
|
||||
|
||||
* add Rune Tab to manage runes
|
||||
* add RuneEditor to edit runes
|
||||
* add Loading window
|
||||
* fix Bug that caused to many processes to be inspected for Lol-Client informations
|
||||
* add --access flag for debugging and testing
|
||||
* add Dodge Button
|
||||
|
||||
-- MrBesen <> Sat, 02 Sep 2023 16:28:31 +0200
|
||||
|
||||
lolautoaccept (0.0.7) unstable; urgency=medium
|
||||
|
||||
* add tab icons
|
||||
* embed translations with qt
|
||||
* adjust stagesettings ui
|
||||
* add autosave for configurations
|
||||
* change to log-version with qt-support
|
||||
|
||||
-- MrBesen <> Sun, 05 Feb 2023 13:48:39 +0100
|
||||
|
||||
lolautoaccept (0.0.6) unstable; urgency=medium
|
||||
|
||||
[ MrBesen Tue, 11 Oct 2022 20:17:00 +0200 ]
|
||||
* fix the default tab
|
||||
* fix the `enable pick` and `enable ban` buttons
|
||||
* add autowrite - automatically send a text message in the champselect lobby
|
||||
|
||||
-- MrBesen <> Tue, 11 Oct 2022 20:17:54 +0200
|
||||
|
||||
lolautoaccept (0.0.5) unstable; urgency=medium
|
||||
|
||||
* Initial release.
|
||||
|
||||
-- Oliver <git@oliver-kaestner.de> Mon, 05 Sep 2022 01:42:50 +0200
|
|
@ -0,0 +1,17 @@
|
|||
Source: lolautoaccept
|
||||
Section: games
|
||||
Priority: optional
|
||||
Maintainer: MrBesen <mrbesen@mrbesen.de>
|
||||
Build-Depends: debhelper-compat (= 12),
|
||||
libcurl4-openssl-dev,
|
||||
librsvg2-bin,
|
||||
qtbase5-dev,
|
||||
qttools5-dev-tools
|
||||
Standards-Version: 4.5.0
|
||||
|
||||
Package: lolautoaccept
|
||||
Architecture: any
|
||||
Depends: ${misc:Depends},
|
||||
${shlibs:Depends},
|
||||
Description: League of Legends Auto-Acceptor
|
||||
Can accept games, pick and ban champions and more.
|
|
@ -0,0 +1,3 @@
|
|||
lolautoaccept usr/bin/
|
||||
resources/lolautoaccept.desktop usr/share/applications/
|
||||
resources/lolautoaccept.svg usr/share/icons/hicolor/scalable/apps/
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/make -f
|
||||
|
||||
%:
|
||||
dh $@
|
|
@ -0,0 +1 @@
|
|||
3.0 (native)
|
BIN
imgs/accept.png
Before Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 380 B |
BIN
imgs/ban.png
Before Width: | Height: | Size: 1.7 KiB |
BIN
imgs/pick.png
Before Width: | Height: | Size: 7.3 KiB |
|
@ -2,6 +2,7 @@
|
|||
|
||||
struct Args {
|
||||
int debugLog = 0; // cast to bool later
|
||||
int access = 0;
|
||||
};
|
||||
|
||||
Args parseArgs(int argc, char** argv);
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "restclient.h"
|
||||
#include "runepage.h"
|
||||
#include "position.h"
|
||||
|
||||
class BlitzAPI : public RestClient {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BlitzAPI();
|
||||
|
||||
struct ChampionInfo {
|
||||
std::vector<uint32_t> skillorder;
|
||||
|
||||
RunePage runepage;
|
||||
|
||||
// items?
|
||||
|
||||
ChampionInfo();
|
||||
explicit ChampionInfo(const QJsonObject&);
|
||||
};
|
||||
|
||||
ChampionInfo getChampionInfo(uint32_t championID, Position p, uint32_t enemyChampionID = 0); // TODO: add more parameters: Queue (Ranked 5x5)
|
||||
private:
|
||||
};
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <QJsonDocument>
|
||||
|
||||
// This file caches the champion metadata
|
||||
class ChampCache {
|
||||
public:
|
||||
ChampCache();
|
||||
|
||||
QString getVersion();
|
||||
|
||||
QJsonDocument getChamps();
|
||||
void saveChamps(QJsonDocument doc, const QString& version);
|
||||
|
||||
private:
|
||||
QString basefolder;
|
||||
uint64_t maxage = 86400; // is in seconds
|
||||
};
|
|
@ -10,7 +10,7 @@ public:
|
|||
explicit ChampRow(QListWidget *parent = nullptr);
|
||||
~ChampRow();
|
||||
|
||||
void setChamp(const std::string& name, uint32_t id, QPixmap icon);
|
||||
void setChamp(const DataDragon::ChampData& cd, QPixmap icon);
|
||||
QString getChamp() const;
|
||||
uint32_t getChampID() const;
|
||||
QPixmap getIcon();
|
||||
|
|
|
@ -1,28 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <QString>
|
||||
|
||||
class ClientAccess {
|
||||
ClientAccess();
|
||||
ClientAccess(const std::string& token, uint16_t port);
|
||||
public:
|
||||
static std::shared_ptr<ClientAccess> find(bool uselockfile = true);
|
||||
private:
|
||||
// returns the name and value of a argument or empty string if it could not be parsed
|
||||
static std::string parseArg(const std::string& input, std::string& value);
|
||||
static std::shared_ptr<ClientAccess> findUsingArgs(const std::vector<std::string>& cmdline);
|
||||
static std::shared_ptr<ClientAccess> findUsingLockfile(const std::vector<std::string>& cmdline, pid_t pid);
|
||||
ClientAccess(const QString& token, uint16_t port);
|
||||
static std::shared_ptr<ClientAccess> find();
|
||||
|
||||
public:
|
||||
std::string getBasicAuth() const;
|
||||
QString getBasicAuth() const;
|
||||
uint16_t getPort() const;
|
||||
|
||||
std::string getURL() const;
|
||||
QString getURL() const;
|
||||
|
||||
private:
|
||||
|
||||
std::string authcode;
|
||||
QString authcode;
|
||||
uint16_t port = 0;
|
||||
};
|
||||
};
|
||||
|
||||
std::shared_ptr<ClientAccess> createFromLockfile(std::istream& lockfile);
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include "clientaccess.h"
|
||||
#include "datadragonimagecache.h"
|
||||
#include "memoryimagecache.h"
|
||||
#include "position.h"
|
||||
#include "restclient.h"
|
||||
#include "runeaspekt.h"
|
||||
#include "runepage.h"
|
||||
#include "runestyle.h"
|
||||
|
||||
class ClientAPI : public RestClient {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class ReadyCheckState : uint32_t {
|
||||
INVALID = 0,
|
||||
|
@ -31,25 +39,16 @@ public:
|
|||
ENDOFGAME,
|
||||
TERMINATEDINERROR,
|
||||
};
|
||||
static GameflowPhase toGameflowPhase(const std::string&);
|
||||
static GameflowPhase toGameflowPhase(const QString&);
|
||||
|
||||
enum class ChampSelectPhase : uint32_t {
|
||||
INVALID = 0,
|
||||
GAME_STARTING,
|
||||
PLANNING,
|
||||
BAN_PICK,
|
||||
FINALIZATION
|
||||
};
|
||||
static ChampSelectPhase toChampSelectPhase(const std::string& str);
|
||||
|
||||
enum class Position : uint32_t {
|
||||
INVALID = 0,
|
||||
TOP,
|
||||
MIDDLE,
|
||||
BOTTOM,
|
||||
JUNGLE,
|
||||
UTILITY
|
||||
};
|
||||
static Position toPosition(const std::string& str);
|
||||
static ChampSelectPhase toChampSelectPhase(const QString& str);
|
||||
|
||||
enum class ChampSelectActionType : uint32_t {
|
||||
INVALID = 0,
|
||||
|
@ -57,14 +56,14 @@ public:
|
|||
PICK,
|
||||
TEN_BANS_REVEAL,
|
||||
};
|
||||
static ChampSelectActionType toChampSelectActionType(const std::string& str);
|
||||
static ChampSelectActionType toChampSelectActionType(const QString& str);
|
||||
|
||||
struct TimerInfo {
|
||||
int64_t adjustedTimeLeftInPhase;
|
||||
int64_t internalNowInEpochMs;
|
||||
bool isefinite;
|
||||
ChampSelectPhase phase;
|
||||
int64_t totalTimeInPhase;
|
||||
int64_t adjustedTimeLeftInPhase = 0;
|
||||
int64_t internalNowInEpochMs = 0;
|
||||
bool isefinite = false;
|
||||
ChampSelectPhase phase = ChampSelectPhase::INVALID;
|
||||
int64_t totalTimeInPhase = 0;
|
||||
|
||||
bool valid = false;
|
||||
|
||||
|
@ -74,12 +73,12 @@ public:
|
|||
|
||||
struct PlayerInfo {
|
||||
int64_t summonerid = 0; // to test validity -> test if this is not null
|
||||
std::string gameName;
|
||||
std::string name;
|
||||
std::string statusMessage;
|
||||
QString gameName;
|
||||
QString name;
|
||||
QString statusMessage;
|
||||
|
||||
// lol specific
|
||||
std::string puuid;
|
||||
QString puuid;
|
||||
uint32_t level = 0;
|
||||
};
|
||||
|
||||
|
@ -97,11 +96,13 @@ public:
|
|||
};
|
||||
|
||||
struct ChampSelectCell {
|
||||
Position position;
|
||||
Position position = Position::INVALID;
|
||||
int32_t cellID = 0;
|
||||
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, 13 = klarheitz, 14 = ignite, 32 = snowball
|
||||
int64_t spell2Id = 0;
|
||||
|
||||
ChampSelectCell();
|
||||
explicit ChampSelectCell(const QJsonObject& json);
|
||||
|
@ -137,6 +138,53 @@ public:
|
|||
operator bool();
|
||||
};
|
||||
|
||||
struct RunePage {
|
||||
uint64_t id = 0;
|
||||
uint64_t lastmodified = 0;
|
||||
QString name;
|
||||
bool isDeleteable = true;
|
||||
bool isEditable = true;
|
||||
bool isActive = false; // what is the difference between active and current????
|
||||
bool isCurrent = false;
|
||||
bool isValid = true;
|
||||
uint32_t order = 0; // position in the ui
|
||||
::RunePage runepage;
|
||||
|
||||
RunePage();
|
||||
explicit RunePage(const QJsonObject& json);
|
||||
};
|
||||
|
||||
struct Message {
|
||||
QString body;
|
||||
QString fromId;
|
||||
QString fromPid;
|
||||
int64_t fromSummonerId;
|
||||
QString id;
|
||||
bool isHistorical;
|
||||
QString timestamp;
|
||||
QString type; // known types: chat (1:1), customGame, championSelect, groupchat
|
||||
|
||||
Message();
|
||||
explicit Message(const QJsonObject& json);
|
||||
};
|
||||
|
||||
struct Conversation {
|
||||
QString gameName;
|
||||
QString gameTag;
|
||||
QString id;
|
||||
bool isMuted;
|
||||
std::shared_ptr<Message> lastMessage;
|
||||
QString name;
|
||||
QString password;
|
||||
QString pid;
|
||||
QString targetRegion;
|
||||
QString type;
|
||||
int64_t unreadMessageCount;
|
||||
|
||||
Conversation();
|
||||
explicit Conversation(const QJsonObject& json);
|
||||
};
|
||||
|
||||
ClientAPI(const ClientAccess& access);
|
||||
~ClientAPI();
|
||||
|
||||
|
@ -147,23 +195,46 @@ public:
|
|||
ChampSelectSession getChampSelectSession();
|
||||
bool setChampSelectAction(int32_t actionid, int32_t champid, bool completed);
|
||||
PlayerInfo getSelf();
|
||||
std::vector<std::string> getLog();
|
||||
void dodge();
|
||||
|
||||
std::vector<int32_t> getBannableChampIDs();
|
||||
std::vector<int32_t> getPickableChampIDs();
|
||||
|
||||
TimerInfo getTimerInfo();
|
||||
|
||||
protected:
|
||||
// chats
|
||||
std::vector<Conversation> getAllConversations();
|
||||
Message sendMessage(const QString& chatid, const QString& messagebody);
|
||||
|
||||
// rune stuff
|
||||
RunePage getCurrentRunePage();
|
||||
std::vector<RunePage> getAllRunePages();
|
||||
bool selectRunePage(uint64_t id);
|
||||
bool editRunePage(const RunePage& page);
|
||||
bool createRunePage(const RunePage& page);
|
||||
bool deleteRunePage(uint64_t id);
|
||||
|
||||
std::vector<RuneAspekt> getAllRuneAspekts();
|
||||
std::vector<RuneStyle> getAllRuneStyles();
|
||||
|
||||
const QString& getRuneStyleByID(uint32_t id);
|
||||
|
||||
QPixmap getImageResource(QString path);
|
||||
|
||||
private:
|
||||
ClientAccess access;
|
||||
|
||||
MemoryImageCache memImageCache;
|
||||
DataDragonImageCache imageCache;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream&, const ClientAPI::ReadyCheckState&);
|
||||
std::ostream& operator<<(std::ostream&, const ClientAPI::GameflowPhase&);
|
||||
std::ostream& operator<<(std::ostream&, const ClientAPI::ChampSelectPhase&);
|
||||
std::ostream& operator<<(std::ostream&, const ClientAPI::Position&);
|
||||
std::ostream& operator<<(std::ostream&, const ClientAPI::ChampSelectActionType&);
|
||||
#define DEFINEOPERATOR(CLASS) \
|
||||
std::ostream& operator<<(std::ostream&, const ClientAPI::CLASS&); \
|
||||
QDebug operator<<(QDebug, const ClientAPI::CLASS&);
|
||||
|
||||
DEFINEOPERATOR(ReadyCheckState)
|
||||
DEFINEOPERATOR(GameflowPhase)
|
||||
DEFINEOPERATOR(ChampSelectPhase)
|
||||
DEFINEOPERATOR(ChampSelectActionType)
|
||||
|
||||
#undef DEFINEOPERATOR
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class ClipboardPopup;
|
||||
}
|
||||
|
||||
class ClipboardPopup : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class Direction {
|
||||
Paste,
|
||||
Copy
|
||||
};
|
||||
|
||||
explicit ClipboardPopup(Direction dir, QWidget* parent = nullptr);
|
||||
~ClipboardPopup();
|
||||
|
||||
void setText(QString text);
|
||||
QString getText() const;
|
||||
|
||||
private slots:
|
||||
void textPasted();
|
||||
void copyButton();
|
||||
|
||||
private:
|
||||
Ui::ClipboardPopup *ui;
|
||||
|
||||
Direction direction;
|
||||
int lastKnownTextSize = 0;
|
||||
};
|
|
@ -1,7 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "position.h"
|
||||
#include "runepage.h"
|
||||
|
||||
class Config {
|
||||
public:
|
||||
struct StageConfig {
|
||||
|
@ -9,8 +13,38 @@ public:
|
|||
StageConfig(const QJsonObject&);
|
||||
operator QJsonObject() const;
|
||||
|
||||
std::vector<std::string> champs;
|
||||
bool enabled;
|
||||
std::vector<QString> champs;
|
||||
bool enabled = false;
|
||||
};
|
||||
|
||||
struct PositionConfig {
|
||||
PositionConfig();
|
||||
PositionConfig(const QJsonObject&);
|
||||
operator QJsonObject() const;
|
||||
|
||||
Position position; // top, bot, sup,...
|
||||
|
||||
StageConfig ban;
|
||||
StageConfig pick;
|
||||
};
|
||||
|
||||
struct RunePageConfig {
|
||||
RunePageConfig();
|
||||
RunePageConfig(QString name, const RunePage& rp);
|
||||
RunePageConfig(const QJsonObject&);
|
||||
operator QJsonObject() const;
|
||||
|
||||
QString name;
|
||||
RunePage runepage;
|
||||
};
|
||||
|
||||
struct GeneralRunePageConfig {
|
||||
GeneralRunePageConfig();
|
||||
GeneralRunePageConfig(const QJsonObject&);
|
||||
operator QJsonObject() const;
|
||||
|
||||
bool autoSync;
|
||||
std::vector<std::shared_ptr<RunePageConfig>> runePages;
|
||||
};
|
||||
|
||||
struct RootConfig {
|
||||
|
@ -18,10 +52,15 @@ public:
|
|||
RootConfig(const QJsonObject&);
|
||||
operator QJsonObject() const;
|
||||
|
||||
StageConfig prepick;
|
||||
StageConfig ban;
|
||||
StageConfig pick;
|
||||
std::shared_ptr<Config::PositionConfig> getPositionConfig(Position position);
|
||||
|
||||
std::vector<std::shared_ptr<PositionConfig>> positionConfigs;
|
||||
GeneralRunePageConfig runepagesConfig;
|
||||
|
||||
bool enabledAutoAccept;
|
||||
bool enabledSmiteWarn;
|
||||
bool enabledAutoWrite;
|
||||
QString autoWriteText;
|
||||
};
|
||||
|
||||
Config();
|
||||
|
@ -32,7 +71,7 @@ public:
|
|||
|
||||
RootConfig& getConfig();
|
||||
private:
|
||||
std::string configFolderPath;
|
||||
std::string configFilePath;
|
||||
QString configFolderPath;
|
||||
QString configFilePath;
|
||||
RootConfig root;
|
||||
};
|
||||
|
|
|
@ -3,21 +3,26 @@
|
|||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <set>
|
||||
#include <QString>
|
||||
#include <vector>
|
||||
|
||||
#include <QPixmap>
|
||||
|
||||
#include "datadragonimagecache.h"
|
||||
#include "champcache.h"
|
||||
#include "memoryimagecache.h"
|
||||
#include "restclient.h"
|
||||
|
||||
class QThread;
|
||||
|
||||
class DataDragon : public RestClient {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using notifyImgfunc_t = std::function<void(QPixmap)>;
|
||||
|
||||
DataDragon(const std::string& locale);
|
||||
DataDragon(const QString& locale);
|
||||
~DataDragon();
|
||||
DataDragon(const DataDragon&) = delete;
|
||||
DataDragon& operator=(const DataDragon&) = delete;
|
||||
|
@ -27,11 +32,11 @@ public:
|
|||
ChampData();
|
||||
ChampData(const QJsonObject& source);
|
||||
|
||||
std::string name;
|
||||
std::string id;
|
||||
int key;
|
||||
std::string partype;
|
||||
std::string title;
|
||||
QString name;
|
||||
QString id;
|
||||
int key = 0;
|
||||
QString partype;
|
||||
QString title;
|
||||
};
|
||||
|
||||
enum class ImageType {
|
||||
|
@ -41,50 +46,68 @@ public:
|
|||
};
|
||||
|
||||
// might block until version is available
|
||||
const std::string& getVersion();
|
||||
const QString& getVersion();
|
||||
// might block until champ data is available
|
||||
const std::vector<ChampData>& getChamps();
|
||||
// might block until image is downloaded
|
||||
QPixmap getImage(const std::string& champid, ImageType imgtype = ImageType::SQUARE);
|
||||
void getImageAsnyc(const std::string& champid, notifyImgfunc_t func, ImageType imgtype = ImageType::SQUARE);
|
||||
QPixmap getImage(const QString& champid, ImageType imgtype = ImageType::SQUARE, bool writeMemcache = true);
|
||||
void getImageAsnyc(const QString& champid, notifyImgfunc_t func, ImageType imgtype = ImageType::SQUARE);
|
||||
// might block until champ data is available
|
||||
const ChampData& getBestMatchingChamp(const std::string& name, int* count = nullptr);
|
||||
std::vector<const ChampData*> getMatchingChamp(const std::string& name, uint32_t limit = 25);
|
||||
const ChampData& getBestMatchingChamp(const QString& name, int* count = nullptr);
|
||||
std::vector<const ChampData*> getMatchingChamp(const QString& name, uint32_t limit = 25);
|
||||
const ChampData* getChampByID(uint32_t id);
|
||||
|
||||
std::vector<uint32_t> resolveChampIDs(const std::vector<QString>& champnames);
|
||||
|
||||
void startThread();
|
||||
|
||||
static const ChampData EMPTYCHAMP;
|
||||
protected:
|
||||
std::string getImageUrl(const std::string& champid, ImageType type);
|
||||
std::string getCDNString() const;
|
||||
|
||||
public slots:
|
||||
void stop();
|
||||
|
||||
signals:
|
||||
// loading progress in 0.0 - 1.0
|
||||
void loading(float);
|
||||
|
||||
// which champion is currently prefretched
|
||||
void fetchingChamp(QString);
|
||||
|
||||
protected:
|
||||
QString getImageUrl(const QString& champid, ImageType type);
|
||||
QString getCDNString() const;
|
||||
|
||||
void prefetchChampImage(const QString& champid, ImageType imgtype = ImageType::SQUARE);
|
||||
void getVersionInternal();
|
||||
void getChampsInternal();
|
||||
void startThread();
|
||||
void stopThread();
|
||||
void stopAndJoinThread();
|
||||
void threadLoop();
|
||||
|
||||
std::string locale;
|
||||
std::string version;
|
||||
QString locale;
|
||||
QString version;
|
||||
std::vector<ChampData> champs;
|
||||
std::mutex cachedatamutex;
|
||||
std::condition_variable cachedatacv;
|
||||
std::set<QString> notDownloadedImages; // the champions of which the square image is not downloaded yet. Is used to download them on idle
|
||||
|
||||
private:
|
||||
struct Task {
|
||||
std::string champid;
|
||||
QString champid;
|
||||
notifyImgfunc_t func;
|
||||
ImageType type;
|
||||
};
|
||||
|
||||
|
||||
DataDragonImageCache cache[3];
|
||||
ChampCache champCache;
|
||||
MemoryImageCache memcache;
|
||||
std::list<Task> tasks;
|
||||
std::mutex tasksmutex;
|
||||
std::condition_variable tasksnotemptycv;
|
||||
std::thread bgthread;
|
||||
QThread* bgthread;
|
||||
bool shouldrun = true;
|
||||
};
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& str, const DataDragon::ChampData& cd);
|
||||
std::ostream& operator<<(std::ostream& str, const DataDragon::ChampData& cd);
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
#include <QPixmap>
|
||||
|
||||
class DataDragonImageCache {
|
||||
public:
|
||||
DataDragonImageCache(const std::string& folderextra, const std::string& imageext = ".jpg");
|
||||
DataDragonImageCache(const QString& folderextra, const QString& imageext = ".jpg");
|
||||
~DataDragonImageCache();
|
||||
|
||||
QPixmap getImage(const std::string& name);
|
||||
void addImageRaw(const QByteArray& arr, const std::string& name);
|
||||
bool hasImage(const QString& name);
|
||||
QPixmap getImage(const QString& name);
|
||||
void addImageRaw(const QByteArray& arr, const QString& name);
|
||||
private:
|
||||
std::string getFilepath(const std::string& name) const;
|
||||
QString getFilepath(const QString& name) const;
|
||||
|
||||
std::string cacheDir;
|
||||
std::string imageext; // file extention including dot
|
||||
QString cacheDir;
|
||||
QString imageext; // file extention including dot
|
||||
};
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
// from: https://www.gingerbill.org/article/2015/08/19/defer-in-cpp/
|
||||
|
||||
#include <functional>
|
||||
|
||||
struct privDefer {
|
||||
std::function<void()> f;
|
||||
privDefer(std::function<void()> f) : f(f) {}
|
||||
~privDefer() { f(); }
|
||||
};
|
||||
|
||||
#define DEFER_1(x, y) x##y
|
||||
#define DEFER_2(x, y) DEFER_1(x, y)
|
||||
#define DEFER_3(x) DEFER_2(x, __COUNTER__)
|
||||
#define defer(code) auto DEFER_3(_defer_) = privDefer([&](){code;})
|
|
@ -3,9 +3,13 @@
|
|||
// stuff required for file handling
|
||||
|
||||
#include <string>
|
||||
#include <QString>
|
||||
|
||||
// create a directory and its parents
|
||||
bool mkdirs(const std::string& path);
|
||||
bool mkdirs(const QString& path);
|
||||
|
||||
// get $HOME or a useful default value
|
||||
std::string getHome();
|
||||
QString getHome();
|
||||
|
||||
// folder for caching example: $HOME/.cache/lolautoaccept/
|
||||
QString getCache();
|
||||
|
|
|
@ -12,15 +12,24 @@ T convert(const QJsonValue& val) {
|
|||
template<>
|
||||
int convert(const QJsonValue& val);
|
||||
|
||||
template<>
|
||||
uint32_t convert(const QJsonValue& val);
|
||||
|
||||
template<>
|
||||
int64_t convert(const QJsonValue& val);
|
||||
|
||||
template<>
|
||||
std::string convert(const QJsonValue& val);
|
||||
uint64_t convert(const QJsonValue& val);
|
||||
|
||||
template<>
|
||||
QString convert(const QJsonValue& val);
|
||||
|
||||
template<>
|
||||
bool convert(const QJsonValue& val);
|
||||
|
||||
template<>
|
||||
QString convert(const QJsonValue& val);
|
||||
|
||||
template<typename T>
|
||||
T getValue(const QJsonObject& obj, const char* key, const T& def = {}) {
|
||||
auto it = obj.constFind(key);
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef LOADINGWINDOW_H
|
||||
#define LOADINGWINDOW_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QCloseEvent;
|
||||
|
||||
namespace Ui {
|
||||
class LoadingWindow;
|
||||
}
|
||||
|
||||
class LoadingWindow : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LoadingWindow( QWidget* parent = nullptr );
|
||||
~LoadingWindow();
|
||||
|
||||
public slots:
|
||||
void setChampion(QString championName);
|
||||
void setText(QString text);
|
||||
|
||||
// should be 0.0 to 1.0
|
||||
void setProgress(float val);
|
||||
|
||||
signals:
|
||||
void closed();
|
||||
|
||||
protected:
|
||||
virtual void closeEvent(QCloseEvent*) override;
|
||||
|
||||
private:
|
||||
Ui::LoadingWindow* ui;
|
||||
};
|
||||
|
||||
#endif // LOADINGWINDOW_H
|
|
@ -2,10 +2,20 @@
|
|||
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "blitzapi.h"
|
||||
#include "clientapi.h"
|
||||
#include "config.h"
|
||||
#include "datadragon.h"
|
||||
#include "runepage.h"
|
||||
#include "runestyle.h"
|
||||
|
||||
class LolAutoAccept : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
class LolAutoAccept {
|
||||
protected:
|
||||
struct Stage {
|
||||
Stage();
|
||||
|
@ -16,43 +26,89 @@ protected:
|
|||
uint32_t currentOffset = 0;
|
||||
};
|
||||
|
||||
std::vector<Stage*> stages;
|
||||
std::mutex stagesMutex; // protects stagesvector
|
||||
std::vector<Stage> stages;
|
||||
Position currentPosition = Position::INVALID;
|
||||
bool currentPositionSet = false;
|
||||
uint32_t lastPickedChamp = 0;
|
||||
int32_t lastCellId = -1; // last cellid -> if changed -> reset
|
||||
|
||||
Config::RootConfig& config;
|
||||
DataDragon& dd;
|
||||
|
||||
bool shouldrun = false;
|
||||
std::thread lolaathread;
|
||||
|
||||
std::shared_ptr<ClientAPI> clientapi;
|
||||
|
||||
int64_t summonerid = -1;
|
||||
BlitzAPI blitzapi;
|
||||
std::vector<RuneAspekt> runeaspekts;
|
||||
std::vector<RuneStyle> runestyles;
|
||||
|
||||
ClientAPI::GameflowPhase lastPhase;
|
||||
bool dodgeNow = false;
|
||||
bool nextApplyRunes = false;
|
||||
bool smiteWarnEnabled = true;
|
||||
bool autoWriteTextEnabled = false;
|
||||
bool autoWriteTextDone = false;
|
||||
QString autoWriteText;
|
||||
|
||||
QString chatid; // the chatid of the chat from the champselect
|
||||
std::chrono::time_point<std::chrono::system_clock> lastMessageSent;
|
||||
|
||||
public:
|
||||
enum class State {
|
||||
LOBBY = 0,
|
||||
PREPICK = 1,
|
||||
BAN = 2,
|
||||
PICK = 3,
|
||||
GAME = 4
|
||||
BAN = 1,
|
||||
PICK = 2,
|
||||
};
|
||||
|
||||
LolAutoAccept();
|
||||
~LolAutoAccept();
|
||||
enum class Status {
|
||||
Off,
|
||||
Running,
|
||||
Failed
|
||||
};
|
||||
Q_ENUM(Status)
|
||||
|
||||
LolAutoAccept(Config::RootConfig& config, DataDragon& dd, QObject* parent = nullptr);
|
||||
virtual ~LolAutoAccept();
|
||||
|
||||
void setChamps(const std::vector<uint32_t>& champs, State s);
|
||||
void setEnabled(bool b, State s);
|
||||
void setSmiteWarn(bool b);
|
||||
|
||||
bool init(); // returns true on success
|
||||
void run();
|
||||
void stop();
|
||||
Status getStatus();
|
||||
|
||||
void reload(); // reload the config, when something was changed
|
||||
|
||||
const std::vector<RuneAspekt>& getRuneAspekts();
|
||||
const std::vector<RuneStyle>& getRuneStyles();
|
||||
void setAutoWriteText(bool enabled, const QString& text = {});
|
||||
|
||||
public slots:
|
||||
void dodge();
|
||||
|
||||
signals:
|
||||
void statusChanged(LolAutoAccept::Status); // new status: 0 = off, 1 = on, 2 = failed
|
||||
void positionChanged(Position);
|
||||
void dodgePossible(bool); // true = the dodge button is available
|
||||
|
||||
private:
|
||||
void stopJoinThread();
|
||||
void innerRun();
|
||||
void resetPickOffsets();
|
||||
void resetAllOffsets();
|
||||
void applyConfigToStage(Stage& stage, const Config::StageConfig& stageconf);
|
||||
void loadPosition(Position pos);
|
||||
|
||||
uint32_t getChampOfState(State s);
|
||||
void nextChampOfState(State s);
|
||||
|
||||
static bool isChampIntentofTeammate(uint32_t champid, const ClientAPI::ChampSelectSession& session);
|
||||
static bool isChampBanned(uint32_t champid, const ClientAPI::ChampSelectSession& session);
|
||||
|
||||
using ownactions_t = std::vector<ClientAPI::ChampSelectAction>;
|
||||
ownactions_t getOwnActions(int32_t cellid, const std::vector<ClientAPI::ChampSelectAction> actions);
|
||||
|
@ -60,5 +116,11 @@ private:
|
|||
void banPhase(const ownactions_t& ownactions, const ClientAPI::ChampSelectSession& session);
|
||||
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 smiteWarning(const std::vector<ClientAPI::ChampSelectCell>& cells);
|
||||
const QString& getChatid();
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(LolAutoAccept::Status)
|
||||
|
|
|
@ -12,36 +12,61 @@ QT_BEGIN_NAMESPACE
|
|||
namespace Ui { class MainWindow; }
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class QMessageBox;
|
||||
class QTimer;
|
||||
|
||||
class LoadingWindow;
|
||||
class X11Helper;
|
||||
|
||||
|
||||
class MainWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow(LolAutoAccept& lolaa, QWidget *parent = nullptr);
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
protected:
|
||||
virtual void closeEvent(QCloseEvent* event) override;
|
||||
virtual void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
signals:
|
||||
void requestTabChange(int tabindex);
|
||||
|
||||
public slots:
|
||||
void resetSaveTimer();
|
||||
|
||||
private slots:
|
||||
void loadingStatus(float);
|
||||
|
||||
void toggleLeagueVisibility();
|
||||
|
||||
void toggleMainswitch(bool);
|
||||
void aatoggled(bool);
|
||||
void pptoggled(bool);
|
||||
void ppedited();
|
||||
void bantoggled(bool);
|
||||
void banedited();
|
||||
void picktoggled(bool);
|
||||
void pickedited();
|
||||
void smitewarntoggled(bool);
|
||||
|
||||
void tabtoggled(Position, LolAutoAccept::State, bool);
|
||||
void tabchanged(Position, LolAutoAccept::State);
|
||||
|
||||
void autoWriteChanged();
|
||||
|
||||
void saveConfig();
|
||||
void initDone();
|
||||
|
||||
// returns empty string on no match
|
||||
void onPosChange(Position newpos); // to trigger the signal from a QObject
|
||||
void lolaaStatusChanged(LolAutoAccept::Status); // get triggerd, when the autoacceptor fails (lost connection)
|
||||
|
||||
private:
|
||||
// returns empty string on no match
|
||||
const DataDragon::ChampData& getBestMatchingChamp(const std::string& name);
|
||||
|
||||
bool loading;
|
||||
Ui::MainWindow *ui;
|
||||
LolAutoAccept& lolaa;
|
||||
QTimer* saveTimer;
|
||||
std::thread lolaathread;
|
||||
DataDragon dd;
|
||||
Config conf;
|
||||
LolAutoAccept lolaa;
|
||||
LoadingWindow* lwin;
|
||||
QMessageBox* dodgeQuestion;
|
||||
X11Helper* x11Helper;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <QString>
|
||||
#include <QPixmap>
|
||||
|
||||
class MemoryImageCache {
|
||||
public:
|
||||
MemoryImageCache(size_t maxsize = 25);
|
||||
|
||||
void addImage(QPixmap, const std::string& title, int type);
|
||||
QPixmap getImage(const std::string& title, int type);
|
||||
void addImage(QPixmap, const QString& title, int type);
|
||||
QPixmap getImage(const QString& title, int type);
|
||||
private:
|
||||
void cleanUp();
|
||||
|
||||
struct CachedImage {
|
||||
time_t lastaccessed = 0;
|
||||
QPixmap imageref;
|
||||
std::string title;
|
||||
QString title;
|
||||
int type;
|
||||
|
||||
bool operator<(const CachedImage& other) const;
|
||||
};
|
||||
static std::function<bool(const CachedImage&)> getImageMatcher(const std::string& title, int type);
|
||||
static std::function<bool(const CachedImage&)> getImageMatcher(const QString& title, int type);
|
||||
|
||||
std::list<CachedImage> cache;
|
||||
size_t maxsize;
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include <QDebug>
|
||||
#include <QVariant>
|
||||
|
||||
enum class Position : uint32_t {
|
||||
INVALID = 0,
|
||||
TOP,
|
||||
JUNGLE,
|
||||
MIDDLE,
|
||||
BOTTOM,
|
||||
UTILITY
|
||||
};
|
||||
Position toPosition(const QString& str);
|
||||
QString toString(Position p);
|
||||
QString toShortString(Position p);
|
||||
|
||||
std::ostream& operator<<(std::ostream&, const Position&);
|
||||
QDebug operator<<(QDebug , const Position&);
|
||||
|
||||
Q_DECLARE_METATYPE(Position)
|
|
@ -1,12 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <QJsonDocument>
|
||||
#include <curl/curl.h>
|
||||
|
||||
class RestClient {
|
||||
#include <QObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QString>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#undef DELETE
|
||||
#endif
|
||||
|
||||
|
||||
class RestClient : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RestClient(const std::string& base);
|
||||
RestClient(const QString& base);
|
||||
RestClient(const RestClient&) = delete;
|
||||
virtual ~RestClient();
|
||||
|
||||
enum class Method {
|
||||
|
@ -17,15 +27,28 @@ public:
|
|||
DELETE
|
||||
};
|
||||
|
||||
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 = {});
|
||||
void enableDebugging(bool enabled = true);
|
||||
struct WebException {
|
||||
CURLcode curlresponse = CURLE_OK;
|
||||
|
||||
std::string baseurl;
|
||||
WebException(CURLcode c = CURLE_OK);
|
||||
};
|
||||
|
||||
protected:
|
||||
QByteArray requestRaw(const QString& url, Method m = Method::GET, const QString& data = {});
|
||||
QJsonDocument request(const QString& url, Method m = Method::GET, const QString& data = {});
|
||||
void enableDebugging(bool enabled = true);
|
||||
QString escape(const QString& in) const;
|
||||
|
||||
QString baseurl;
|
||||
|
||||
CURL* curl = nullptr; // the curl (does curling)
|
||||
|
||||
std::string basicauth; // basic auth code (user:pw) or empty string to disable
|
||||
bool disableCertCheck = false;
|
||||
QString basicauth; // basic auth code (user:pw) or empty string to disable
|
||||
#ifdef WIN32
|
||||
bool disableCertCheck = true;
|
||||
#else
|
||||
bool disableCertCheck = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
const char* toString(RestClient::Method);
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class QJsonObject;
|
||||
|
||||
struct RuneAspekt {
|
||||
uint32_t id = 0;
|
||||
QString name;
|
||||
QString shortDesc;
|
||||
QString longDesc;
|
||||
QString tooltip;
|
||||
QString iconPath;
|
||||
|
||||
RuneAspekt();
|
||||
explicit RuneAspekt(const QJsonObject& json);
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Ui {
|
||||
class RuneAspektButton;
|
||||
}
|
||||
|
||||
class RuneAspektButtonGroup;
|
||||
class RuneAspektButton : public QPushButton {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RuneAspektButton(QWidget* parent = nullptr);
|
||||
~RuneAspektButton();
|
||||
|
||||
void setAspektId(uint32_t id);
|
||||
void setButtonGroup(RuneAspektButtonGroup* group);
|
||||
|
||||
bool isSelected() const;
|
||||
|
||||
signals:
|
||||
void aspektToggled(int aspekt);
|
||||
|
||||
public slots:
|
||||
void buttonPressed();
|
||||
void dataChanged(); // triggers a refresh
|
||||
void checkSelection(uint32_t aspekt); // only used for rune styles
|
||||
|
||||
private slots:
|
||||
void setShowSelection(bool selected); // show/hide the red border
|
||||
|
||||
public:
|
||||
uint32_t aspektId = 0;
|
||||
|
||||
private:
|
||||
Ui::RuneAspektButton* ui;
|
||||
RuneAspektButtonGroup* group = nullptr;
|
||||
};
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
|
||||
class RuneAspektButton;
|
||||
class RuneAspektButtonGroup : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RuneAspektButtonGroup(QObject* parent, uint32_t size);
|
||||
virtual ~RuneAspektButtonGroup();
|
||||
|
||||
void addButton(RuneAspektButton* button);
|
||||
void setSelectedRunes(const QVector<int>& newRunes);
|
||||
|
||||
constexpr const QVector<int>& getSelectedRunes() const { return selectedRune; }
|
||||
constexpr uint32_t getSize() const { return size; }
|
||||
|
||||
void setSubgroups(const QVector<QVector<int>>& newSubgroups);
|
||||
|
||||
static const int INVALID_ASPEKT_ID;
|
||||
signals:
|
||||
void changed(); // signal that the group was changed -> all buttons should refresh
|
||||
|
||||
private slots:
|
||||
void buttonPressed(int aspektId);
|
||||
|
||||
private:
|
||||
// try to fetch a aspektId, that is in selectedRune and in the same subgroup as aspektId
|
||||
// return 0 when no suitable candidate is found
|
||||
int getOtherSubgroupMemeber(int aspketId);
|
||||
|
||||
QVector<int> selectedRune;
|
||||
QVector<QVector<int>> subgroups; // might be empty
|
||||
uint32_t size = 0;
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "runeaspekt.h"
|
||||
#include "runepage.h"
|
||||
#include "runestyle.h"
|
||||
|
||||
namespace Ui {
|
||||
class RuneDisplay;
|
||||
}
|
||||
|
||||
class RuneDisplay : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RuneDisplay(QWidget *parent = nullptr);
|
||||
~RuneDisplay();
|
||||
|
||||
void setRuneMeta(const std::vector<RuneAspekt>& runeinfo);
|
||||
void setStyles(const std::vector<RuneStyle>& styleinfos);
|
||||
void setRunes(const RunePage& rp);
|
||||
|
||||
private slots:
|
||||
void applyRunesClicked();
|
||||
|
||||
signals:
|
||||
void applyRunes();
|
||||
|
||||
private:
|
||||
void updateText();
|
||||
QString getRuneText(uint32_t id);
|
||||
QString getRuneStyleByID(uint32_t id);
|
||||
|
||||
Ui::RuneDisplay *ui;
|
||||
|
||||
RunePage runepage;
|
||||
|
||||
std::vector<RuneAspekt> runeinfo;
|
||||
std::vector<RuneStyle> runestyles;
|
||||
|
||||
};
|
|
@ -0,0 +1,65 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QVector>
|
||||
|
||||
#include "runeaspekt.h"
|
||||
#include "runepage.h"
|
||||
#include "runestyle.h"
|
||||
|
||||
namespace Ui {
|
||||
class RuneEditor;
|
||||
}
|
||||
|
||||
class ClientAPI;
|
||||
class RuneAspektButton;
|
||||
class RuneAspektButtonGroup;
|
||||
class QGridLayout;
|
||||
|
||||
class RuneEditor : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RuneEditor(QWidget* parent = nullptr);
|
||||
~RuneEditor();
|
||||
|
||||
void setClient(ClientAPI& client);
|
||||
void setRunepage(const ::RunePage& rp);
|
||||
|
||||
void selectStyle(uint32_t id);
|
||||
void selectSubStyle(uint32_t id);
|
||||
|
||||
void clearLayout(QLayout* layout);
|
||||
|
||||
void setName(QString text);
|
||||
QString getName() const;
|
||||
|
||||
const RunePage& getRunepage();
|
||||
|
||||
signals:
|
||||
void selectionChanged();
|
||||
|
||||
void selectPrimary(int aspektId);
|
||||
void selectSecondary(int aspektId);
|
||||
|
||||
private:
|
||||
const RuneStyle* getRuneStyle(uint32_t id) const;
|
||||
RuneAspektButton* createStyleButton(const RuneStyle& rs, bool selected);
|
||||
RuneAspektButton* createAspektButton(uint32_t perk);
|
||||
RuneAspektButton* createButtonFromResource(QString resource);
|
||||
void fillRuneStyle(QGridLayout* target, const RuneStyle& rs);
|
||||
QString fixString(QString text);
|
||||
|
||||
Ui::RuneEditor* ui;
|
||||
|
||||
ClientAPI* client = nullptr;
|
||||
::RunePage runepage;
|
||||
std::vector<RuneAspekt> aspekts;
|
||||
std::vector<RuneStyle> styles;
|
||||
|
||||
|
||||
// 0 = keystone, 1-3 = main runes, 4 = sub runes (2), 5-7 = stats
|
||||
QVector<RuneAspektButtonGroup*> groups;
|
||||
};
|
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "config.h"
|
||||
#include "runeaspekt.h"
|
||||
#include "runestyle.h"
|
||||
|
||||
namespace Ui {
|
||||
class RuneManager;
|
||||
}
|
||||
|
||||
class ClientAPI;
|
||||
class DataDragon;
|
||||
class QListWidgetItem;
|
||||
class QTimer;
|
||||
|
||||
class RuneManager : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RuneManager(QWidget* parent = nullptr);
|
||||
~RuneManager();
|
||||
|
||||
void setConfig(Config& config);
|
||||
void setDataDragon(DataDragon& dd);
|
||||
|
||||
private slots:
|
||||
void loadRunes();
|
||||
void reloadClientRunes();
|
||||
void setRunesEnabled(bool enabled);
|
||||
|
||||
void saveRunePageClient(int id, QString name, const RunePage& rp);
|
||||
void saveRunePageAA(int id, QString name, const RunePage& rp);
|
||||
|
||||
void deleteRunepageClient(int id);
|
||||
void deleteRunepageAA(int id);
|
||||
|
||||
void autoSyncToggled();
|
||||
|
||||
private:
|
||||
void syncRunes();
|
||||
void reloadAARunes();
|
||||
|
||||
Ui::RuneManager* ui;
|
||||
std::shared_ptr<ClientAPI> client;
|
||||
Config* config = nullptr;
|
||||
QTimer* initialLoadTimer = nullptr;
|
||||
|
||||
std::vector<RuneAspekt> runeInfo;
|
||||
std::vector<RuneStyle> runeStyles;
|
||||
};
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QJsonObject>
|
||||
// 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)
|
||||
|
||||
RunePage();
|
||||
bool operator==(const RunePage& rp) const;
|
||||
|
||||
operator bool() const; // check if this runepage is valid (this does not check semantic validity, only if the values are set as they supposed to be)
|
||||
|
||||
operator QJsonObject() const;
|
||||
RunePage(const QJsonObject& obj);
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream&, const RunePage&);
|
||||
QDebug operator<<(QDebug, const RunePage&);
|
|
@ -0,0 +1,73 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QListWidget>
|
||||
|
||||
#include "clientapi.h"
|
||||
#include "config.h"
|
||||
#include "datadragon.h"
|
||||
#include "runeaspekt.h"
|
||||
#include "runestyle.h"
|
||||
|
||||
namespace Ui {
|
||||
class RunePageList;
|
||||
}
|
||||
|
||||
class DropEvent;
|
||||
class ClientAPI;
|
||||
|
||||
class RunePageList : public QListWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static const uint32_t RoleId = Qt::UserRole;
|
||||
static const uint32_t RolePointer = Qt::UserRole + 1;
|
||||
|
||||
explicit RunePageList(QWidget* parent = nullptr);
|
||||
~RunePageList();
|
||||
|
||||
constexpr void setIsClient(bool b) { isClient = b; }
|
||||
constexpr void setClient(ClientAPI& client) { this->client = &client; }
|
||||
constexpr void setOther(QListWidget* other) { this->other = other; }
|
||||
constexpr void setDataDragon(DataDragon& dd) { this->dd = ⅆ }
|
||||
|
||||
void loadRunePages(const std::vector<ClientAPI::RunePage>& pages);
|
||||
void loadRunePages(const std::vector<std::shared_ptr<Config::RunePageConfig>>& pages);
|
||||
|
||||
void setRuneInfos(const std::vector<RuneAspekt>& runeInfo, const std::vector<RuneStyle>& runeStyles);
|
||||
|
||||
signals:
|
||||
void runepageChanged(int id, QString name, const RunePage& rp);
|
||||
void runepageDeleted(int id);
|
||||
|
||||
protected:
|
||||
virtual void dropEvent(QDropEvent* event) override;
|
||||
|
||||
private slots:
|
||||
void itemChangedCallback(QListWidgetItem* item);
|
||||
void openContextMenu(const QPoint&);
|
||||
void deleteCurrentItem();
|
||||
void editCurrentItem();
|
||||
void duplicateCurrentItem();
|
||||
void exportCurrentItem();
|
||||
void importItem();
|
||||
|
||||
private:
|
||||
void clearItems();
|
||||
void addRunepageItem(QString name, int id, const ::RunePage& rp, bool isCurrent = false);
|
||||
const DataDragon::ChampData& findChamp(const QString& name);
|
||||
|
||||
QString getRuneDescription(const ::RunePage& runepage);
|
||||
QString getRuneText(uint32_t id);
|
||||
QString getRuneStyleByID(uint32_t id);
|
||||
|
||||
const std::vector<RuneAspekt>* runeInfo = nullptr;
|
||||
const std::vector<RuneStyle>* runeStyles = nullptr;
|
||||
|
||||
Ui::RunePageList* ui;
|
||||
QListWidget* other = nullptr;
|
||||
DataDragon* dd = nullptr;
|
||||
ClientAPI* client = nullptr;
|
||||
bool isClient;
|
||||
};
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
// fwd.
|
||||
class QJsonObject;
|
||||
|
||||
struct RuneStyleSlot {
|
||||
std::vector<int> perks;
|
||||
QString type;
|
||||
|
||||
RuneStyleSlot();
|
||||
RuneStyleSlot(const QJsonObject& json);
|
||||
};
|
||||
|
||||
struct RuneStyle {
|
||||
uint32_t id;
|
||||
QString name;
|
||||
QString iconPath;
|
||||
QString tooltip;
|
||||
|
||||
std::vector<int> allowedSubStyles;
|
||||
QString idName;
|
||||
|
||||
std::vector<RuneStyleSlot> runeSlots;
|
||||
|
||||
RuneStyle();
|
||||
explicit RuneStyle(const QJsonObject& json);
|
||||
};
|
|
@ -1,29 +0,0 @@
|
|||
#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;
|
||||
|
||||
};
|
|
@ -0,0 +1,53 @@
|
|||
#ifndef SETTINGSTAB_H
|
||||
#define SETTINGSTAB_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "config.h"
|
||||
#include "datadragon.h"
|
||||
#include "lolautoaccept.h"
|
||||
#include "stagesettings.h"
|
||||
|
||||
namespace Ui {
|
||||
class SettingsTab;
|
||||
}
|
||||
|
||||
class SettingsTab : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(Position position MEMBER position READ getPosition)
|
||||
|
||||
public:
|
||||
explicit SettingsTab(QWidget *parent = nullptr);
|
||||
~SettingsTab();
|
||||
|
||||
void setup(Config::PositionConfig& conf, DataDragon* dd = nullptr);
|
||||
|
||||
std::vector<StageSettings::SelectedChamp> getChamps(LolAutoAccept::State s) const;
|
||||
bool getState(LolAutoAccept::State s) const;
|
||||
void setChamps(LolAutoAccept::State s, const std::vector<QString>&);
|
||||
void setState(LolAutoAccept::State s, bool b);
|
||||
|
||||
Position getPosition() const;
|
||||
|
||||
private slots:
|
||||
void banToggled(bool);
|
||||
void banChampsChanged();
|
||||
void pickToggled(bool);
|
||||
void pickChampsChanged();
|
||||
|
||||
signals:
|
||||
void changed(Position p, LolAutoAccept::State s);
|
||||
void toggled(Position p, LolAutoAccept::State s, bool newstate);
|
||||
|
||||
private:
|
||||
StageSettings* getStage(LolAutoAccept::State s) const;
|
||||
|
||||
Ui::SettingsTab *ui;
|
||||
|
||||
Config::PositionConfig* conf;
|
||||
DataDragon* dd = nullptr;
|
||||
Position position = Position::INVALID;
|
||||
};
|
||||
|
||||
#endif // SETTINGSTAB_H
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <QWidget>
|
||||
|
||||
#include "config.h"
|
||||
#include "datadragon.h"
|
||||
|
||||
namespace Ui {
|
||||
|
@ -26,16 +27,18 @@ public:
|
|||
void setState(bool);
|
||||
|
||||
struct SelectedChamp {
|
||||
SelectedChamp(std::string name, uint32_t id);
|
||||
std::string name;
|
||||
SelectedChamp(QString name, uint32_t id);
|
||||
QString name;
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
std::vector<SelectedChamp> getChampions() const;
|
||||
void setChampions(const std::vector<std::string>& champs);
|
||||
void setChampions(const std::vector<QString>& champs);
|
||||
|
||||
void setDataDragon(DataDragon* dd);
|
||||
void addChamp(const std::string& champname, uint32_t id, QPixmap icon);
|
||||
void addChamp(const DataDragon::ChampData& cd, QPixmap icon);
|
||||
|
||||
void loadConfig(Config::StageConfig& c);
|
||||
|
||||
private slots:
|
||||
void toggledinternal(int state);
|
||||
|
@ -49,7 +52,7 @@ signals:
|
|||
|
||||
private:
|
||||
// delete all items
|
||||
void resolveAndAddChamp(const std::string& name, bool emitchange = false);
|
||||
void resolveAndAddChamp(const QString& name, bool emitchange = false);
|
||||
void clear();
|
||||
void updateEnabled();
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef X11HELPER_H
|
||||
#define X11HELPER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
using Window = unsigned long;
|
||||
struct _XDisplay;
|
||||
using Display = struct _XDisplay;
|
||||
|
||||
class X11Helper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static const Window InvalidWindow;
|
||||
static const bool IsSupported;
|
||||
|
||||
explicit X11Helper(QObject* parent = nullptr);
|
||||
virtual ~X11Helper();
|
||||
|
||||
Window findWindow(const QString& name, float aspektRatio = 0.0);
|
||||
|
||||
public slots:
|
||||
void map(Window win);
|
||||
void unmap(Window win);
|
||||
void setMap(Window win, bool b);
|
||||
|
||||
private:
|
||||
Window searchWindows(Window top, const QString& search, float aspektRatio);
|
||||
|
||||
#ifdef X11SUPPORT
|
||||
Display* disp;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // X11HELPER_H
|
|
@ -1,6 +0,0 @@
|
|||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=LoLAutoAccept
|
||||
Exec=lolautoaccept
|
||||
Icon=lolautoaccept
|
||||
Categories=Utility;
|
|
@ -3,6 +3,15 @@ QT += core gui
|
|||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
CONFIG += c++17
|
||||
|
||||
# debugging
|
||||
CONFIG += debug
|
||||
|
||||
MOC_DIR = build/generated/
|
||||
UI_DIR = build/ui/
|
||||
RCC_DIR = build/rcc/
|
||||
OBJECTS_DIR = build/objects/
|
||||
|
||||
unix:LIBS += -lcurl -pthread -lrt
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
|
@ -10,12 +19,17 @@ unix:LIBS += -lcurl -pthread -lrt
|
|||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
DEFINES += LOG_ENABLEQT=1
|
||||
|
||||
# You can also make your code fail to compile if it uses deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
DEFINES += LOLAA_VERSION=\\\"0.0.8\\\"
|
||||
|
||||
QMAKE_CXXFLAGS += -Wall -Wpedantic -Wextra
|
||||
|
||||
# parameters: var, prepend, append
|
||||
defineReplace(prependAll) {
|
||||
for(a,$$1):result += $$2$${a}$$3
|
||||
|
@ -24,97 +38,133 @@ defineReplace(prependAll) {
|
|||
|
||||
SOURCES += \
|
||||
src/arg.cpp \
|
||||
src/blitzapi.cpp \
|
||||
src/champcache.cpp \
|
||||
src/championsearch.cpp \
|
||||
src/champrow.cpp \
|
||||
src/clientaccess.cpp \
|
||||
src/clientapi_json.cpp \
|
||||
src/clientapi.cpp \
|
||||
src/clipboardpopup.cpp \
|
||||
src/config.cpp \
|
||||
src/datadragon.cpp \
|
||||
src/datadragonimagecache.cpp \
|
||||
src/files.cpp \
|
||||
src/json.cpp \
|
||||
src/loadingwindow.cpp \
|
||||
src/lolautoaccept.cpp \
|
||||
src/main.cpp \
|
||||
src/mainwindow.cpp \
|
||||
src/memoryimagecache.cpp \
|
||||
src/restclient.cpp \
|
||||
src/runeaspektbutton.cpp \
|
||||
src/runeaspektbuttongroup.cpp \
|
||||
src/runedisplay.cpp \
|
||||
src/runeeditor.cpp \
|
||||
src/runemanager.cpp \
|
||||
src/runepage.cpp \
|
||||
src/runepagelist.cpp \
|
||||
src/settingstab.cpp \
|
||||
src/stagesettings.cpp \
|
||||
src/x11helper.cpp \
|
||||
thirdparty/Log/Log.cpp
|
||||
|
||||
# mainwindow.cpp
|
||||
# platform specific implementations
|
||||
win32:SOURCES += src/clientaccess_windows.cpp src/x11helper_other.cpp
|
||||
unix:SOURCES += src/clientaccess_linux.cpp src/x11helper_x11.cpp
|
||||
|
||||
HEADERS += \
|
||||
include/arg.h \
|
||||
include/blitzapi.h \
|
||||
include/champcache.h \
|
||||
include/championsearch.h \
|
||||
include/champrow.h \
|
||||
include/clientaccess.h \
|
||||
include/clientapi.h \
|
||||
include/clipboardpopup.h \
|
||||
include/config.h \
|
||||
include/datadragon.h \
|
||||
include/datadragonimagecache.h \
|
||||
include/defer.h \
|
||||
include/files.h \
|
||||
include/json.h \
|
||||
include/loadingwindow.h \
|
||||
include/lolautoaccept.h \
|
||||
include/mainwindow.h \
|
||||
include/memoryimagecache.h \
|
||||
include/restclient.h \
|
||||
include/runeaspektbutton.h \
|
||||
include/runeaspektbuttongroup.h \
|
||||
include/runedisplay.h \
|
||||
include/runeeditor.h \
|
||||
include/runemanager.h \
|
||||
include/runepage.h \
|
||||
include/runepagelist.h \
|
||||
include/settingstab.h \
|
||||
include/stagesettings.h \
|
||||
include/x11helper.h \
|
||||
thirdparty/Log/Log.h
|
||||
|
||||
# mainwindow.h
|
||||
|
||||
MOC_DIR = build/generated/
|
||||
UI_DIR = ui/
|
||||
OBJECTS_DIR = build/
|
||||
|
||||
FORMS += \
|
||||
ui/championsearch.ui \
|
||||
ui/clipboardpopup.ui \
|
||||
ui/loadingwindow.ui \
|
||||
ui/mainwindow.ui \
|
||||
ui/runeaspektbutton.ui \
|
||||
ui/runedisplay.ui \
|
||||
ui/runeeditor.ui \
|
||||
ui/runemanager.ui \
|
||||
ui/runepagelist.ui \
|
||||
ui/settingstab.ui \
|
||||
ui/stagesettings.ui
|
||||
|
||||
INCLUDEPATH += $$PWD/include/ \
|
||||
$$PWD/thirdparty/Log/
|
||||
|
||||
#TRANSLATIONS += \
|
||||
# ts/de_DE.ts \
|
||||
# ts/en.ts
|
||||
|
||||
# translations
|
||||
LANGUAGES = de_DE en
|
||||
CONFIG += lrelease embed_translations
|
||||
|
||||
TRANSLATIONS = $$prependAll(LANGUAGES, $$PWD/ts/, .ts)
|
||||
TRANSLATIONSQM = $$prependAll(LANGUAGES, $$PWD/ts/, .qm)
|
||||
TRANSLATIONS = $$prependAll(LANGUAGES, $$PWD/resources/ts/, .ts)
|
||||
|
||||
makelang.commands = lrelease $$_PRO_FILE_
|
||||
updatelang.commands = lupdate $$_PRO_FILE_
|
||||
QMAKE_EXTRA_TARGETS += makelang updatelang
|
||||
PRE_TARGETDEPS += makelang
|
||||
|
||||
QMAKE_CLEAN += $$TRANSLATIONSQM
|
||||
updatelang.commands = lupdate -locations none $$_PRO_FILE_
|
||||
QMAKE_EXTRA_TARGETS += updatelang
|
||||
|
||||
# build AppImage
|
||||
unix {
|
||||
DEFINES += X11SUPPORT=1
|
||||
LIBS += -lX11
|
||||
|
||||
linuxdeploy-x86_64.AppImage.commands = wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage && chmod u+x linuxdeploy-x86_64.AppImage
|
||||
|
||||
lolautoaccept.png.depends = lolautoaccept.svg
|
||||
lolautoaccept.png.commands = inkscape -z -elolautoaccept.png -w 512 -h 512 lolautoaccept.svg
|
||||
resources/lolautoaccept.png.depends = resources/lolautoaccept.svg
|
||||
resources/lolautoaccept.png.commands = rsvg-convert -w 512 -h 512 resources/lolautoaccept.svg -o resources/lolautoaccept.png
|
||||
|
||||
appimg.depends = linuxdeploy-x86_64.AppImage $${TARGET} lolautoaccept.png
|
||||
appimg.depends = linuxdeploy-x86_64.AppImage $${TARGET} resources/lolautoaccept.png
|
||||
appimg.commands = rm -rf AppDir ; \
|
||||
mkdir -p AppDir/ts AppDir/imgs; \
|
||||
cp ./ts/*.qm ./AppDir/ts ; \
|
||||
cp ./imgs/*.png ./AppDir/imgs; \
|
||||
./linuxdeploy-x86_64.AppImage --appdir=AppDir -e lolautoaccept -i lolautoaccept.png -d lolautoaccept.desktop --output appimage
|
||||
mkdir -p AppDir/ts ; \
|
||||
./linuxdeploy-x86_64.AppImage --appdir=AppDir -e lolautoaccept -i resources/lolautoaccept.png -d resources/lolautoaccept.desktop --output appimage
|
||||
|
||||
QMAKE_EXTRA_TARGETS += appimg linuxdeploy-x86_64.AppImage lolautoaccept.png
|
||||
QMAKE_EXTRA_TARGETS += appimg linuxdeploy-x86_64.AppImage resources/lolautoaccept.png
|
||||
|
||||
QMAKE_CLEAN += linuxdeploy-x86_64.AppImage lolautoaccept.png
|
||||
QMAKE_CLEAN += linuxdeploy-x86_64.AppImage resources/lolautoaccept.png
|
||||
}
|
||||
|
||||
win32 {
|
||||
INCLUDEPATH += $$PWD/../curl/include/
|
||||
LIBS += $$PWD/../curl/lib/libbrotlicommon.a $$PWD/../curl/lib/libbrotlidec.a $$PWD/../curl/lib/libcrypto.a $$PWD/../curl/lib/libcurl.a $$PWD/../curl/lib/libcurl.dll.a $$PWD/../curl/lib/libgsasl.a $$PWD/../curl/lib/libidn2.a $$PWD/../curl/lib/libnghttp2.a $$PWD/../curl/lib/libnghttp3.a $$PWD/../curl/lib/libngtcp2.a $$PWD/../curl/lib/libngtcp2_crypto_openssl.a $$PWD/../curl/lib/libssh2.a $$PWD/../curl/lib/libssl.a $$PWD/../curl/lib/libz.a $$PWD/../curl/lib/libzstd.a
|
||||
|
||||
# to create the ico: convert -density 300 -define icon:auto-resize=256,128,96,64,48,32,16 -background none resources/lolautoaccept.svg resources/lolautoaccept.ico
|
||||
RC_ICONS = resources/lolautoaccept.ico
|
||||
}
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /usr/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
|
||||
|
||||
# https://wiki.qt.io/Automating_generation_of_qm_files
|
||||
|
||||
RESOURCES += \
|
||||
resources/res.qrc
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M27.333 27.333H5.196l4.406-4.786h12.945V9.602l4.786-4.406v22.137z"></path>
|
||||
<path fill-opacity=".4"
|
||||
d="M4 4h20.94l-5.041 4.188H8.187v11.628l-4.188 4.526V4zm14.359 14.359h-5.983v-5.983h5.983v5.983z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 308 B |
|
@ -0,0 +1,85 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="1024"
|
||||
height="1024"
|
||||
viewBox="0 0 270.93333 270.93334"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="delete.svg"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.7"
|
||||
inkscape:cx="451.15206"
|
||||
inkscape:cy="659.53498"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:pagecheckerboard="true"
|
||||
borderlayer="true"
|
||||
inkscape:window-width="2528"
|
||||
inkscape:window-height="1381"
|
||||
inkscape:window-x="1952"
|
||||
inkscape:window-y="28"
|
||||
inkscape:window-maximized="1"
|
||||
showguides="false" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-26.06665)">
|
||||
<rect
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#fffffb;stroke-width:16.93333244;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
|
||||
id="rect1013"
|
||||
width="142.55424"
|
||||
height="161.20285"
|
||||
x="64.189545"
|
||||
y="100.63498" />
|
||||
<rect
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#fffffb;stroke-width:16.93333435;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
|
||||
id="rect1015"
|
||||
width="179.60214"
|
||||
height="20.944307"
|
||||
x="45.665596"
|
||||
y="79.216049"
|
||||
ry="6.992558"
|
||||
rx="0" />
|
||||
<rect
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#fffffb;stroke-width:16.93333244;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
|
||||
id="rect1017"
|
||||
width="30.616072"
|
||||
height="17.764881"
|
||||
x="120.15863"
|
||||
y="61.228806"
|
||||
ry="6.9925671" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
|
@ -0,0 +1,76 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="1024"
|
||||
height="1024"
|
||||
viewBox="0 0 270.93333 270.93334"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="duplicate.svg"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.49497475"
|
||||
inkscape:cx="-137.33323"
|
||||
inkscape:cy="973.74201"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:pagecheckerboard="true"
|
||||
borderlayer="true"
|
||||
inkscape:window-width="2528"
|
||||
inkscape:window-height="1381"
|
||||
inkscape:window-x="1952"
|
||||
inkscape:window-y="28"
|
||||
inkscape:window-maximized="1"
|
||||
showguides="false" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-26.06665)">
|
||||
<rect
|
||||
style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:16.93333435;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
|
||||
id="rect865-3"
|
||||
width="127.58046"
|
||||
height="172.03047"
|
||||
x="112.739"
|
||||
y="98.764053"
|
||||
inkscape:label="new" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:64;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 130.59961,81.945312 c -17.66933,0.0061 -31.99042,14.330669 -31.992188,31.999998 v 650.19727 c 0.0018,17.66933 14.322858,31.99392 31.992188,32 H 362.0957 v -64 H 162.60156 V 145.94727 h 418.19727 v 64.8125 h 64.00195 v -96.81446 c -0.002,-17.672379 -14.32762,-31.99823 -32,-31.999998 z"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,0,26.06665)"
|
||||
id="rect1910"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccccccccc" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.8 KiB |
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="1024"
|
||||
height="1024"
|
||||
viewBox="0 0 270.93333 270.93334"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="edit.svg"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.49497475"
|
||||
inkscape:cx="267.73794"
|
||||
inkscape:cy="973.74201"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:pagecheckerboard="true"
|
||||
borderlayer="true"
|
||||
inkscape:window-width="2528"
|
||||
inkscape:window-height="1381"
|
||||
inkscape:window-x="1952"
|
||||
inkscape:window-y="28"
|
||||
inkscape:window-maximized="1"
|
||||
showguides="false" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-26.06665)">
|
||||
<path
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
|
||||
d="M 191.78519,59.101843 46.234389,204.65213 92.347853,250.76559 237.89814,105.21479 Z M 42.32145,212.71572 l -9.286255,51.24907 51.250619,-9.28677 z"
|
||||
id="rect838"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
|
@ -0,0 +1,80 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="1024"
|
||||
height="1024"
|
||||
viewBox="0 0 270.93333 270.93334"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="export.svg"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.49497475"
|
||||
inkscape:cx="89.911358"
|
||||
inkscape:cy="1128.7865"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:pagecheckerboard="true"
|
||||
borderlayer="true"
|
||||
inkscape:window-width="2528"
|
||||
inkscape:window-height="1381"
|
||||
inkscape:window-x="1952"
|
||||
inkscape:window-y="28"
|
||||
inkscape:window-maximized="1"
|
||||
showguides="false" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-26.06665)">
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:36.93648148;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 43.435547,231.03711 c -10.201227,-3.4e-4 -18.471041,8.26947 -18.470703,18.4707 v 731.05664 c -3.44e-4,10.20123 8.269472,18.47105 18.470703,18.47071 H 774.49219 c 10.20123,3.4e-4 18.47104,-8.26948 18.4707,-18.47071 V 249.50781 c 3.4e-4,-10.20123 -8.26947,-18.47104 -18.4707,-18.4707 h -52.1543 c -3.3615,2.96416 -6.64075,6.0031 -9.81641,9.13867 -8.67079,8.56135 -16.71538,17.79803 -24.0996,27.79297 h 67.60937 V 962.0957 H 61.904297 V 267.96875 H 613.25586 c 6.92944,-13.03955 14.61015,-25.35573 23.02734,-36.93164 z"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,0,26.06665)"
|
||||
id="rect909"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:8.46666718;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 159.95132,132.72143 C 165.7499,90.045345 191.29939,68.478702 229.47904,60.410947"
|
||||
id="path911"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#fffffb;stroke-width:8.46666718;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 221.23258,38.481818 42.41883,18.747657 -41.87698,27.147964"
|
||||
id="path913"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:label="ArrowTop" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.4 KiB |
|
@ -0,0 +1,80 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="1024"
|
||||
height="1024"
|
||||
viewBox="0 0 270.93333 270.93334"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="import.svg"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.49497475"
|
||||
inkscape:cx="-490.64446"
|
||||
inkscape:cy="895.44453"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:pagecheckerboard="true"
|
||||
borderlayer="true"
|
||||
inkscape:window-width="2528"
|
||||
inkscape:window-height="1381"
|
||||
inkscape:window-x="1952"
|
||||
inkscape:window-y="28"
|
||||
inkscape:window-maximized="1"
|
||||
showguides="false" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-26.06665)">
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:36.93648148;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 43.435547,231.03711 a 18.470088,18.470088 0 0 0 -18.470703,18.4707 v 731.05664 a 18.470088,18.470088 0 0 0 18.470703,18.47071 H 774.49219 a 18.470088,18.470088 0 0 0 18.4707,-18.47071 V 249.50781 a 18.470088,18.470088 0 0 0 -18.4707,-18.4707 h -18.48047 c -14.21343,10.60781 -27.51005,22.92882 -39.94922,36.93164 h 39.96875 V 962.0957 H 61.904297 V 267.96875 H 635.49805 c 8.74524,-13.01432 18.04176,-25.34765 27.92187,-36.93164 z"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,0,26.06665)"
|
||||
id="rect909"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:8.46666718;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 253.90605,66.613651 C 211.10887,61.789428 183.94424,81.282492 166.77618,116.32578"
|
||||
id="path911"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#fffffb;stroke-width:8.46666718;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 147.53278,102.9623 7.79389,45.71747 36.57285,-33.95761"
|
||||
id="path913"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:label="ArrowTop" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.3 KiB |
|
@ -0,0 +1,5 @@
|
|||
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="m16.21 29.333-7.875-7.955A18.22 18.22 0 0 0 4 10.09c6.93 2.606 8.04 7.818 8.04 7.818 1.245-6.091-3.39-15.242-3.39-15.242 13.305 16.652 7.56 26.667 7.56 26.667zM16.57 13a37.966 37.966 0 0 1 6.765-10.333 49.874 49.874 0 0 0-4.365 15.5s-1.02-3.591-2.4-5.167zM28 9.879c-9.315 5.576-8.325 15.515-8.325 15.515l4.185-4.258C23.71 13.03 28 9.878 28 9.878z">
|
||||
</path>
|
||||
</svg>
|
After Width: | Height: | Size: 460 B |
|
@ -0,0 +1,6 @@
|
|||
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.333 26.667v-4.364l16.97-16.97h4.364v4.364l-16.97 16.97H5.333z"></path>
|
||||
<path fill-opacity=".4"
|
||||
d="m19.394 5.333-3.879 3.879H9.212v6.303l-3.879 3.879V5.333h14.061zm-6.788 21.334 3.879-3.879h6.303v-6.303l3.879-3.879v14.061H12.606z">
|
||||
</path>
|
||||
</svg>
|
After Width: | Height: | Size: 346 B |
|
@ -0,0 +1,5 @@
|
|||
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M19.03 4h-6.061l-1.061 1.417 4.091 5.037 4.091-5.037L19.029 4zm-7.878 4.88H2.667c1.167 1.144 2.514 2.221 3.939 2.991.572.185 1.068.313 1.667.315h2.273l-2.424 2.991 3.939 1.889 1.515-5.667-2.424-2.519zm9.696 0h8.485c-1.168 1.143-2.515 2.222-3.939 2.991-.572.185-1.068.313-1.667.315h-2.273l2.424 2.991-3.939 1.889-1.515-5.667 2.424-2.519zm-1.666 15.268-2.424-12.593a.863.863 0 0 1-.758.63.87.87 0 0 1-.758-.63l-2.424 12.593L16 26.667l3.182-2.519z">
|
||||
</path>
|
||||
</svg>
|
After Width: | Height: | Size: 558 B |
|
@ -0,0 +1,6 @@
|
|||
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 4h22.137l-4.406 4.786H8.786v12.945L4 26.137V4z"></path>
|
||||
<path fill-opacity=".4"
|
||||
d="M27.333 27.333H6.393l5.041-4.188h11.712V10.918l4.188-4.526v20.94zM12.974 12.974h5.983v5.983h-5.983v-5.983z">
|
||||
</path>
|
||||
</svg>
|
After Width: | Height: | Size: 307 B |
|
@ -0,0 +1,12 @@
|
|||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=LoLAutoAccept
|
||||
Exec=lolautoaccept
|
||||
Icon=lolautoaccept
|
||||
Version=1.5
|
||||
Categories=Game;Utility
|
||||
Terminal=false
|
||||
Hidden=false
|
||||
Keywords=lol;league of legends;lolaa;
|
||||
SingleMainWindow=true
|
||||
Comment=Automatically accept LoL games, pick and ban champions, and more.
|
After Width: | Height: | Size: 202 KiB |
|
@ -17,10 +17,19 @@
|
|||
<circle cx="512" cy="512" r="508" fill="none" stroke-width="4" stroke="black" />
|
||||
<circle cx="512" cy="512" r="500" fill="none" stroke-width="4" stroke="black" />
|
||||
|
||||
<!-- A A -->
|
||||
<text x="48" y="786" fill="black" font-size="768px" clip-path="url(#text-circle-cutoff)" font-family="monospace">
|
||||
<!-- A A (imagemagick convert does not like text in svg)-->
|
||||
<!--text x="48" y="786" fill="black" font-size="768px" clip-path="url(#text-circle-cutoff)" font-family="monospace">
|
||||
AA
|
||||
</text>
|
||||
</text-->
|
||||
|
||||
<!-- left A -->
|
||||
<polygon points="234,226 324,226 496,785 418,785 377,639 180,639 139,785 62,785" clip-path="url(#text-circle-cutoff)" />
|
||||
<polygon points="278,293 279,293 358,578 199,578" style="fill:#005e84;" />
|
||||
|
||||
<!-- right A -->
|
||||
<polygon points="697,226 787,226 959,785 881,785 840,639 643,639 602,785 525,785" clip-path="url(#text-circle-cutoff)" />
|
||||
<polygon points="741,293 742,293 821,578 662,578" style="fill:#005e84;" />
|
||||
|
||||
<!-- Pointer -->
|
||||
<polygon points="512,786 354,226 500,226 488,48 536,48 524,226 670,226" />
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.8 KiB |
|
@ -0,0 +1,16 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>lolautoaccept.png</file>
|
||||
<file>lolautoaccept.svg</file>
|
||||
<file>icons/top.svg</file>
|
||||
<file>icons/sup.svg</file>
|
||||
<file>icons/mid.svg</file>
|
||||
<file>icons/jgl.svg</file>
|
||||
<file>icons/bot.svg</file>
|
||||
<file>icons/delete.svg</file>
|
||||
<file>icons/duplicate.svg</file>
|
||||
<file>icons/edit.svg</file>
|
||||
<file>icons/export.svg</file>
|
||||
<file>icons/import.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -0,0 +1,291 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="de_DE">
|
||||
<context>
|
||||
<name>ChampionSearch</name>
|
||||
<message>
|
||||
<source>Champion Search</source>
|
||||
<translation>Champion Suche</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Champion:</source>
|
||||
<translation>Champion:</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ClipboardPopup</name>
|
||||
<message>
|
||||
<source>Clipboard Text</source>
|
||||
<translation>Zwischenablage</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy To Clipboard</source>
|
||||
<translation>In Zwischenablage kopieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Paste here</source>
|
||||
<translation>Hier einfügen</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>LoadingWindow</name>
|
||||
<message>
|
||||
<source>LoL-Auto-Accept</source>
|
||||
<translation>LoL-Auto-Accept</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Loading Champion: %0</source>
|
||||
<translation>Lade Champion: %0</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MainWindow</name>
|
||||
<message>
|
||||
<source>LoL-Auto-Accept</source>
|
||||
<translation>LoL-Auto-Accept</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Mainswitch</source>
|
||||
<translation>Hauptschalter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable LoL-Auto-Accept</source>
|
||||
<translation>Spiel automatisch annehmen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Spam "smite" in the chat when there is not exactly 1 player with smite equiped in champ select</source>
|
||||
<translation>Wenn nicht genau 1 Spieler Smite ausgewählt hat, wird "smite" in den Chat gespammt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto Accept</source>
|
||||
<translation>Auto Annehmen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Write a Text as soon as you are in a champ select lobby.</source>
|
||||
<translation>Einen Text schreiben, sobald du in der Champion Auswahl bist.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto Write</source>
|
||||
<translation>Automatisch Schreiben</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This controls the connection to the LoL client. As long as this is off, no interactions with the LoL client take place.</source>
|
||||
<translation>Dies kontrolliert die Verbindung zum LoL Client. Solange dies aus ist, wird nicht mit dem LoL Client interagiert.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Smite Warning</source>
|
||||
<translation>Smite Warnung</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developed by MrBesen</source>
|
||||
<translation type="vanished">Entwickelt von MrBesen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>autowriteText</source>
|
||||
<translation>Zu schreibender Text</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This Tab is used, when you are in a gamemode with no fixed roles</source>
|
||||
<translation>Dieser Tab wird verwendet, wenn der Gamemode keine festen Rollen hat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Default</source>
|
||||
<translation>Default</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Top</source>
|
||||
<translation>Top</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Jungle</source>
|
||||
<translation>Jungle</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Middle</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Bottom</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Support</source>
|
||||
<translation>Support</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Dodge without closing the client.
|
||||
You will still be punished.</source>
|
||||
<translation>Dodgen ohne den Client zu schließen
|
||||
Du wirst trotzdem bestraft.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Dodge</source>
|
||||
<translation>Dodge</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Runes</source>
|
||||
<translation>Runen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><html><head/><body><p>Developed by MrBesen</p><p><a href="https://lolautoacceptor.mrbesen.de/"><span style=" text-decoration: underline; color:#007af4;">Webseite</span></a></p><p>Version: %1</p></body></html></source>
|
||||
<translation><html><head/><body><p>Entwickelt von MrBesen</p><p><a href="https://lolautoacceptor.mrbesen.de/"><span style=" text-decoration: underline; color:#007af4;">Webseite</span></a></p><p>Version: %1</p></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>League of Legends Client not found!</source>
|
||||
<translation>League of Legends Client nicht gefunden!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto-Acceptor started!</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto-Acceptor stoped!</source>
|
||||
<translation>Auto Acceptor gestoppt!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Dodge?</source>
|
||||
<translation>Dodgen?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to dodge?</source>
|
||||
<translation>Bist du dir sicher, dass du dodgen möchtest?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto-Acceptor failed!</source>
|
||||
<translation>Auto-Acceptor fehlgeschlagen!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QWidget</name>
|
||||
<message>
|
||||
<source>Champion: %1
|
||||
Type: %2
|
||||
Title: %3
|
||||
ID: %4</source>
|
||||
<translation>Champion: %1
|
||||
Typ: %2
|
||||
Titel: %3
|
||||
ID: %4</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>RuneDisplay</name>
|
||||
<message>
|
||||
<source>Form</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><html><head/><body><p>Select a Runepage and modify it to this runes.<br/>The page used is the first that:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">matches this Runes</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">has a name starting with &quot;AA:&quot;</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">is currently selected</li></ol></body></html></source>
|
||||
<translation><html><head/><body><p>Eine Runenseite auswählen und entsprechend modifizieren.<br/>Die ausgewählte Seite ist die erste, die die erste der Eigenschaften erfüllt:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">schon die richtigen Runen enthält</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">einen Namen der mit &quot;AA:&quot; anfängt hat</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">gerade ausgewählt ist</li></ol></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Apply Runes</source>
|
||||
<translation>Runen Anwenden</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>RuneEditor</name>
|
||||
<message>
|
||||
<source>Runepage Editor</source>
|
||||
<translation>Runenseiten Editor</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>RuneManager</name>
|
||||
<message>
|
||||
<source>Runes in the Client</source>
|
||||
<translation>Runen im Client</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Runes in the Autoacceptor</source>
|
||||
<translation>Runen im Autoacceptor</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reload</source>
|
||||
<translation>Neuladen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Runes from the client get copied to the autoacceptor automatically.</source>
|
||||
<translation>Runen vom Client werden automatisch in den Autoacceptor kopiert.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto Copy Runes</source>
|
||||
<translation>Auto Runen kopieren</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>RunePageList</name>
|
||||
<message>
|
||||
<source>Edit</source>
|
||||
<translation>Bearbeiten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Duplicate</source>
|
||||
<translation>Dublizieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Export</source>
|
||||
<translation>Exportieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Import</source>
|
||||
<translation>Importerien</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete</source>
|
||||
<translation>Löschen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Loading runes</source>
|
||||
<translation>Lade Runnen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>with</source>
|
||||
<translation>mit</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsTab</name>
|
||||
<message>
|
||||
<source>Ban</source>
|
||||
<translation>Bannen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pick</source>
|
||||
<translation>Picken</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>StageSettings</name>
|
||||
<message>
|
||||
<source>Champion:</source>
|
||||
<translation type="vanished">Champion:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable %1</source>
|
||||
<translation>Aktiviere %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Champions matched: %1</source>
|
||||
<translation type="vanished">Übereinstimmende Champions: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Champion: %1
|
||||
Type: %2
|
||||
Title: %3
|
||||
ID: %4</source>
|
||||
<translation type="vanished">Champion: %1
|
||||
Typ: %2
|
||||
Titel: %3
|
||||
ID: %4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Add Champion</source>
|
||||
<translation>Champion hinzufügen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Remove Champion</source>
|
||||
<translation>Champion entfernen</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
|
@ -0,0 +1,291 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="en_US">
|
||||
<context>
|
||||
<name>ChampionSearch</name>
|
||||
<message>
|
||||
<source>Champion Search</source>
|
||||
<translation>Champion Search</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Champion:</source>
|
||||
<translation>Champion:</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ClipboardPopup</name>
|
||||
<message>
|
||||
<source>Clipboard Text</source>
|
||||
<translation>Clipboard Text</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy To Clipboard</source>
|
||||
<translation>Copy To Clipboard</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Paste here</source>
|
||||
<translation>Paste here</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>LoadingWindow</name>
|
||||
<message>
|
||||
<source>LoL-Auto-Accept</source>
|
||||
<translation>LoL-Auto-Accept</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Loading Champion: %0</source>
|
||||
<translation>Loading Champion: %0</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MainWindow</name>
|
||||
<message>
|
||||
<source>LoL-Auto-Accept</source>
|
||||
<translation>LoL-Auto-Accept</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Mainswitch</source>
|
||||
<translation>Mainswitch</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable LoL-Auto-Accept</source>
|
||||
<translation>Automatically accept game</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Spam "smite" in the chat when there is not exactly 1 player with smite equiped in champ select</source>
|
||||
<translation>Spam "smite" in the chat when there is not exactly 1 player with smite equiped in champ select</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto Accept</source>
|
||||
<translation>Auto Accept</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Write a Text as soon as you are in a champ select lobby.</source>
|
||||
<translation>Write a Text as soon as you are in the champ select lobby.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto Write</source>
|
||||
<translation>Auto write</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This controls the connection to the LoL client. As long as this is off, no interactions with the LoL client take place.</source>
|
||||
<translation>This controls the connection to the LoL client. As long as this is off, no interactions with the LoL client take place.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Smite Warning</source>
|
||||
<translation>Enable Smite Warning</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developed by MrBesen</source>
|
||||
<translation type="vanished">Developed by MrBesen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>autowriteText</source>
|
||||
<translation>Text to autowrite</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This Tab is used, when you are in a gamemode with no fixed roles</source>
|
||||
<translation>This Tab is used, when you are in a gamemode with no fixed roles</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Default</source>
|
||||
<translation>Default</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Top</source>
|
||||
<translation>Top</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Jungle</source>
|
||||
<translation>Jungle</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Middle</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Bottom</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Support</source>
|
||||
<translation>Support</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Dodge without closing the client.
|
||||
You will still be punished.</source>
|
||||
<translation>Dodge without closing the client.
|
||||
You will still be punished.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Dodge</source>
|
||||
<translation>Dodge</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Runes</source>
|
||||
<translation>Runes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><html><head/><body><p>Developed by MrBesen</p><p><a href="https://lolautoacceptor.mrbesen.de/"><span style=" text-decoration: underline; color:#007af4;">Webseite</span></a></p><p>Version: %1</p></body></html></source>
|
||||
<translation><html><head/><body><p>Developed by MrBesen</p><p><a href="https://lolautoacceptor.mrbesen.de/"><span style=" text-decoration: underline; color:#007af4;">Webseite</span></a></p><p>Version: %1</p></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>League of Legends Client not found!</source>
|
||||
<translation>League of Legends Client not found!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto-Acceptor started!</source>
|
||||
<translation>Auto-Acceptor started!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto-Acceptor stoped!</source>
|
||||
<translation>Auto-Acceptor stopped!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Dodge?</source>
|
||||
<translation>Dodge?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to dodge?</source>
|
||||
<translation>Are you sure you want to dodge?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto-Acceptor failed!</source>
|
||||
<translation>Auto-Acceptor failed!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QWidget</name>
|
||||
<message>
|
||||
<source>Champion: %1
|
||||
Type: %2
|
||||
Title: %3
|
||||
ID: %4</source>
|
||||
<translation>Champion: %1
|
||||
Type: %2
|
||||
Title: %3
|
||||
ID: %4</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>RuneDisplay</name>
|
||||
<message>
|
||||
<source>Form</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><html><head/><body><p>Select a Runepage and modify it to this runes.<br/>The page used is the first that:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">matches this Runes</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">has a name starting with &quot;AA:&quot;</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">is currently selected</li></ol></body></html></source>
|
||||
<translation><html><head/><body><p>Select a Runepage and modify it to this runes.<br/>The page used is the first that:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">matches this Runes</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">has a name starting with &quot;AA:&quot;</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">is currently selected</li></ol></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Apply Runes</source>
|
||||
<translation>Apply Runes</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>RuneEditor</name>
|
||||
<message>
|
||||
<source>Runepage Editor</source>
|
||||
<translation>Runepage Editor</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>RuneManager</name>
|
||||
<message>
|
||||
<source>Runes in the Client</source>
|
||||
<translation>Runes in the Client</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Runes in the Autoacceptor</source>
|
||||
<translation>Runes in the Autoacceptor</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reload</source>
|
||||
<translation>Reload</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Runes from the client get copied to the autoacceptor automatically.</source>
|
||||
<translation>Runes from the client get copied to the autoacceptor automatically.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto Copy Runes</source>
|
||||
<translation>Auto copy Runes</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>RunePageList</name>
|
||||
<message>
|
||||
<source>Edit</source>
|
||||
<translation>Edit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Duplicate</source>
|
||||
<translation>Duplicate</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Export</source>
|
||||
<translation>Export</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Import</source>
|
||||
<translation>Import</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete</source>
|
||||
<translation>Delete</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Loading runes</source>
|
||||
<translation>Loading runes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>with</source>
|
||||
<translation>with</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsTab</name>
|
||||
<message>
|
||||
<source>Ban</source>
|
||||
<translation>Ban</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pick</source>
|
||||
<translation>Pick</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>StageSettings</name>
|
||||
<message>
|
||||
<source>Champion:</source>
|
||||
<translation type="vanished">Champion:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable %1</source>
|
||||
<translation>Enable %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Champions matched: %1</source>
|
||||
<translation type="vanished">Champions matched: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Champion: %1
|
||||
Type: %2
|
||||
Title: %3
|
||||
ID: %4</source>
|
||||
<translation type="vanished">Champion: %1
|
||||
Type: %2
|
||||
Title: %3
|
||||
ID: %4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Add Champion</source>
|
||||
<translation>Add Champion</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Remove Champion</source>
|
||||
<translation>Remove Champion</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
|
@ -9,6 +9,7 @@ Args parseArgs(int argc, char** argv) {
|
|||
while (1) {
|
||||
static struct option long_options[] = {
|
||||
{"debug-log", no_argument, &a.debugLog, 1},
|
||||
{"access", no_argument, &a.access, 1},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
/* getopt_long stores the option index here. */
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
#include "blitzapi.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include <Log.h>
|
||||
|
||||
#include "json.h"
|
||||
|
||||
// curl 'https://league-champion-aggregate.iesdev.com/graphql?query=query%20ChampionBuilds%28%24championId%3AInt%21%2C%24queue%3AQueue%21%2C%24role%3ARole%2C%24opponentChampionId%3AInt%2C%24key%3AChampionBuildKey%29%7BchampionBuildStats%28championId%3A%24championId%2Cqueue%3A%24queue%2Crole%3A%24role%2CopponentChampionId%3A%24opponentChampionId%2Ckey%3A%24key%29%7BchampionId%20opponentChampionId%20queue%20role%20builds%7BcompletedItems%7Bgames%20index%20averageIndex%20itemId%20wins%7Dgames%20mythicId%20mythicAverageIndex%20primaryRune%20runes%7Bgames%20index%20runeId%20wins%20treeId%7DskillOrders%7Bgames%20skillOrder%20wins%7DstartingItems%7Bgames%20startingItemIds%20wins%7DsummonerSpells%7Bgames%20summonerSpellIds%20wins%7Dwins%7D%7D%7D&variables=%7B%22championId%22%3A25%2C%22role%22%3A%22SUPPORT%22%2C%22queue%22%3A%22RANKED_SOLO_5X5%22%2C%22opponentChampionId%22%3Anull%2C%22key%22%3A%22PUBLIC%22%7D' -H 'Accept: application/json'
|
||||
|
||||
// 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}}}
|
||||
// &variables={"championId":25,"role":"SUPPORT","queue":"RANKED_SOLO_5X5","opponentChampionId":null,"key":"PUBLIC"}
|
||||
|
||||
static const QString POSITIONNAMES[] = {"INVALID", "TOP", "JUNGLE", "MIDDLE", "BOTTOM", "SUPPORT"};
|
||||
|
||||
BlitzAPI::BlitzAPI() : RestClient("https://league-champion-aggregate.iesdev.com/graphql?") {}
|
||||
|
||||
BlitzAPI::ChampionInfo::ChampionInfo() {}
|
||||
BlitzAPI::ChampionInfo::ChampionInfo(const QJsonObject& json) {
|
||||
// kill order stuff
|
||||
auto skillordersref = json["skillOrders"];
|
||||
if(skillordersref.isArray()) {
|
||||
QJsonArray arr = skillordersref.toArray();
|
||||
if(!arr.empty()) {
|
||||
auto skillorderref = arr.at(0);
|
||||
if(skillorderref.isObject()) {
|
||||
QJsonObject skillorder = skillorderref.toObject();
|
||||
QJsonValueRef realorderref = skillorder["skillOrder"];
|
||||
if(realorderref.isArray()) {
|
||||
QJsonArray realorder = realorderref.toArray();
|
||||
this->skillorder.reserve(realorder.size());
|
||||
for(auto it : realorder) {
|
||||
if(it.isDouble()) {
|
||||
this->skillorder.push_back(it.toDouble());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
QJsonObject rune = it.toObject();
|
||||
uint32_t index = rune["index"].toInt();
|
||||
if(index <= 7) {
|
||||
if(runes.at(index+1) == 0) { // index not set yet
|
||||
auto runeid = rune["runeId"];
|
||||
if(runeid.isDouble()) {
|
||||
runes.at(index+1) = runeid.toDouble();
|
||||
qDebug() << "found rune: index: " << index << " +1 set to: " << runes.at(index+1);
|
||||
|
||||
if(index == 0) {
|
||||
runepage.primaryStyle = rune["treeId"].toInt();
|
||||
} else if(index == 3) {
|
||||
runepage.secondaryStyle = rune["treeId"].toInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add the primary rune
|
||||
runes.at(0) = getValue<uint32_t>(json, "primaryRune");
|
||||
}
|
||||
|
||||
BlitzAPI::ChampionInfo BlitzAPI::getChampionInfo(uint32_t championID, Position p, uint32_t enemyChampionID) {
|
||||
QJsonObject vars;
|
||||
|
||||
vars["championId"] = (int) championID;
|
||||
if(p != Position::INVALID) {
|
||||
vars["role"] = POSITIONNAMES[(int) p];
|
||||
}
|
||||
vars["queue"] = "RANKED_SOLO_5X5";
|
||||
|
||||
if(enemyChampionID == 0)
|
||||
vars["opponentChampionId"] = QJsonValue::Null;
|
||||
else
|
||||
vars["opponentChampionId"] = (int) enemyChampionID;
|
||||
vars["key"] = "PUBLIC"; // ? what does this do?
|
||||
|
||||
QJsonDocument jvars(vars);
|
||||
const QString variables = jvars.toJson(QJsonDocument::Compact);
|
||||
const QString 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 QString requeststr = "query=" + escape(query) + "&variables=" + escape(variables);
|
||||
qDebug() << "GetChampionInfo requestVariables: " << variables << " requeststr: " << requeststr;
|
||||
|
||||
QJsonDocument doc;
|
||||
try {
|
||||
doc = request(requeststr);
|
||||
} catch(RestClient::WebException& e) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if(!doc.isObject()) {
|
||||
// error
|
||||
qCritical() << "could not get ChampionInfo. Returned Response: " << doc.toJson();
|
||||
return {};
|
||||
}
|
||||
|
||||
qDebug() << "championinfo Response: " << doc.toJson().trimmed();
|
||||
|
||||
QJsonObject obj = doc.object();
|
||||
QJsonValueRef dataref = obj["data"];
|
||||
|
||||
if(!dataref.isObject()) return {};
|
||||
|
||||
QJsonObject data = dataref.toObject();
|
||||
QJsonValueRef buildstatsref = data["championBuildStats"];
|
||||
|
||||
if(!buildstatsref.isObject()) return{};
|
||||
|
||||
QJsonObject buildstats = buildstatsref.toObject();
|
||||
QJsonValueRef buildsref = buildstats["builds"];
|
||||
|
||||
if(!buildsref.isArray()) return {};
|
||||
|
||||
QJsonArray builds = buildsref.toArray();
|
||||
|
||||
if(builds.size() > 0) {
|
||||
// just take the first
|
||||
QJsonValue buildval = builds.at(0);
|
||||
if(buildval.isObject()) {
|
||||
return (ChampionInfo) buildval.toObject();
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
#include "champcache.h"
|
||||
|
||||
#include "files.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QDateTime>
|
||||
|
||||
#include <Log.h>
|
||||
|
||||
ChampCache::ChampCache() {
|
||||
basefolder = getCache();
|
||||
}
|
||||
|
||||
// the age of f in seconds
|
||||
static qint64 ageOfFile(QFile& f) {
|
||||
QFileInfo info(f);
|
||||
return info.lastModified().secsTo(QDateTime::currentDateTime());
|
||||
}
|
||||
|
||||
QString ChampCache::getVersion() {
|
||||
QFile versionfile(basefolder + "version");
|
||||
if(ageOfFile(versionfile) < (qint64) maxage) {
|
||||
versionfile.open(QFile::ReadOnly);
|
||||
return versionfile.readAll();
|
||||
}
|
||||
return {}; // empty string
|
||||
}
|
||||
|
||||
QJsonDocument ChampCache::getChamps() {
|
||||
QFile champsfile(basefolder + "champs.json");
|
||||
|
||||
if(ageOfFile(champsfile) < (qint64) maxage) {
|
||||
champsfile.open(QFile::ReadOnly);
|
||||
QByteArray bytes = champsfile.readAll();
|
||||
QJsonDocument doc = QJsonDocument::fromJson(bytes);
|
||||
return doc;
|
||||
}
|
||||
return {}; // empty document
|
||||
}
|
||||
|
||||
void ChampCache::saveChamps(QJsonDocument doc, const QString& version) {
|
||||
QByteArray arr = doc.toJson();
|
||||
QFile champsfile(basefolder + "champs.json");
|
||||
champsfile.open(QFile::WriteOnly | QFile::Truncate);
|
||||
champsfile.write(arr);
|
||||
|
||||
QFile versionfile(basefolder + "version");
|
||||
versionfile.open(QFile::WriteOnly | QFile::Truncate);
|
||||
versionfile.write(version.toLocal8Bit());
|
||||
versionfile.close();
|
||||
|
||||
qInfo() << "saved Champs and version Cache";
|
||||
}
|
|
@ -20,17 +20,17 @@ ChampRow* ChampionSearch::getSearchResult() {
|
|||
}
|
||||
|
||||
void ChampionSearch::searchChanged(QString str) {
|
||||
Log::info << "champion search: " << str.toStdString();
|
||||
qInfo() << "champion search: " << str;
|
||||
|
||||
auto champs = dd->getMatchingChamp(str.toStdString());
|
||||
Log::info << "found " << champs.size() << " champs";
|
||||
const std::vector<const DataDragon::ChampData*> champs = dd->getMatchingChamp(str);
|
||||
qInfo() << "found " << champs.size() << " champs";
|
||||
|
||||
clear();
|
||||
|
||||
for(auto it : champs) {
|
||||
dd->getImageAsnyc(it->id, [this, it](QPixmap img) {
|
||||
for(auto cd : champs) {
|
||||
dd->getImageAsnyc(cd->id, [this, cd](QPixmap img) {
|
||||
auto cr = new ChampRow();
|
||||
cr->setChamp(it->name, it->key, img);
|
||||
cr->setChamp(*cd, img);
|
||||
ui->championList->addItem(cr);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -6,11 +6,13 @@ ChampRow::ChampRow(QListWidget* parent) : QListWidgetItem(parent) {
|
|||
ChampRow::~ChampRow() {
|
||||
}
|
||||
|
||||
void ChampRow::setChamp(const std::string& name, uint32_t id, QPixmap icon) {
|
||||
setText(QString::fromStdString(name));
|
||||
champid = id;
|
||||
void ChampRow::setChamp(const DataDragon::ChampData& cd, QPixmap icon) {
|
||||
setText(cd.name);
|
||||
champid = cd.key;
|
||||
this->icon = icon;
|
||||
setIcon(QIcon(icon));
|
||||
|
||||
setToolTip(QWidget::tr("Champion: %1\nType: %2\nTitle: %3\nID: %4").arg(cd.name).arg(cd.partype).arg(cd.title).arg(cd.key));
|
||||
}
|
||||
|
||||
QString ChampRow::getChamp() const {
|
||||
|
|
|
@ -1,187 +1,47 @@
|
|||
#include "clientaccess.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <Log.h>
|
||||
|
||||
static bool endsWith(const std::string& all, const std::string& end) {
|
||||
return all.rfind(end) == all.size() - end.size();
|
||||
}
|
||||
|
||||
// reads a procfile into a vector (strings are \0 seperated)
|
||||
static std::vector<std::string> readProcFile(const std::string& path) {
|
||||
std::ifstream in(path);
|
||||
std::vector<std::string> out;
|
||||
std::string line;
|
||||
while(std::getline(in, line, '\0')) {
|
||||
if(!line.empty()) {
|
||||
out.push_back(line);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
ClientAccess::ClientAccess() {}
|
||||
|
||||
ClientAccess::ClientAccess(const std::string& token, uint16_t port) : authcode(token), port(port) {}
|
||||
|
||||
std::shared_ptr<ClientAccess> ClientAccess::find(bool uselockfile) {
|
||||
|
||||
DIR* procdir = opendir("/proc");
|
||||
if(!procdir) return nullptr;
|
||||
|
||||
dirent* entry = nullptr;
|
||||
while ((entry = readdir(procdir)) != NULL) {
|
||||
if (entry->d_type != DT_DIR) continue;
|
||||
|
||||
std::string name(entry->d_name);
|
||||
|
||||
pid_t pid = -1;
|
||||
try {
|
||||
pid = std::stoi(name);
|
||||
} catch(std::exception& e) {
|
||||
// could not parse -> not a pid
|
||||
continue;
|
||||
}
|
||||
|
||||
// get info on the exe
|
||||
std::string cmdfile = "/proc/" + std::to_string(pid) + "/cmdline";
|
||||
std::vector<std::string> args = readProcFile(cmdfile);
|
||||
|
||||
// Log::debug << "process: " << pid << " has " << args.size() << " args";
|
||||
|
||||
if(args.empty()) continue;
|
||||
|
||||
std::string& exename = args.at(0);
|
||||
if(endsWith(exename, "LeagueClientUx.exe")) {
|
||||
Log::info << "LeagueClientUx.exe found";
|
||||
|
||||
std::shared_ptr<ClientAccess> out;
|
||||
|
||||
if(uselockfile) {
|
||||
out = findUsingLockfile(args, pid);
|
||||
} else {
|
||||
out = findUsingArgs(args);
|
||||
}
|
||||
|
||||
if(out) {
|
||||
return out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(procdir);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string ClientAccess::parseArg(const std::string& input, std::string& value) {
|
||||
if(input.find("--") != 0) return {};
|
||||
|
||||
size_t pos = input.find('=');
|
||||
if(pos == std::string::npos) return {};
|
||||
|
||||
value = input.substr(pos+1);
|
||||
return input.substr(2, pos-2);
|
||||
}
|
||||
|
||||
std::shared_ptr<ClientAccess> ClientAccess::findUsingArgs(const std::vector<std::string>& cmdline) {
|
||||
// parse args
|
||||
std::shared_ptr<ClientAccess> access(new ClientAccess());
|
||||
for(const std::string& arg : cmdline) {
|
||||
std::string value;
|
||||
std::string argname = parseArg(arg, value);
|
||||
|
||||
if(argname == "riotclient-auth-token") {
|
||||
access->authcode = value;
|
||||
} else if(argname == "riotclient-app-port") {
|
||||
try {
|
||||
access->port = std::stoi(value);
|
||||
} catch(std::exception& e) {
|
||||
Log::warn << "could not parse port: " << std::quoted(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(access->port > 0 && !access->authcode.empty()) {
|
||||
return access;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<ClientAccess> ClientAccess::findUsingLockfile(const std::vector<std::string>& cmdline, pid_t pid) {
|
||||
// get WINEPREFIX env
|
||||
std::vector<std::string> envs = readProcFile("/proc/" + std::to_string(pid) + "/environ");
|
||||
|
||||
const static std::string WINEPREFIX = "WINEPREFIX=";
|
||||
|
||||
// find WINEPREFIX
|
||||
auto found = std::find_if(envs.begin(), envs.end(), [](const std::string& s) {
|
||||
return s.find(WINEPREFIX) == 0;
|
||||
});
|
||||
|
||||
// WINEPREFIX env not present
|
||||
if(found == envs.end()) {
|
||||
Log::debug << "WINEPREFIX environment variable not set";
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::string wineprefix = found->substr(WINEPREFIX.size());
|
||||
const std::string binarypath = cmdline.at(0);
|
||||
std::string gamefolder = binarypath.substr(2, binarypath.rfind('/')-1); // remove the "C:" and the name of the binary
|
||||
// TODO: gamefoldre could contain '\' so replacing every occurance with '/' would be a good idea
|
||||
const std::string lockfilepath = wineprefix + "/drive_c/" + gamefolder + "/lockfile";
|
||||
|
||||
Log::debug << "lockfilepath: " << std::quoted(lockfilepath);
|
||||
|
||||
// read lockfile
|
||||
std::ifstream lockfile(lockfilepath);
|
||||
std::vector<std::string> parts;
|
||||
std::string content;
|
||||
while(std::getline(lockfile, content, ':')) {
|
||||
parts.push_back(content);
|
||||
}
|
||||
|
||||
if(parts.size() != 5) {
|
||||
Log::error << "lockfile contained " << parts.size() << " parts, expected 5";
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::string portstr = parts.at(2);
|
||||
const std::string token = parts.at(3);
|
||||
|
||||
// try to parse port
|
||||
try {
|
||||
uint16_t port = std::stoi(portstr);
|
||||
|
||||
return std::shared_ptr<ClientAccess>(new ClientAccess(token, port));
|
||||
} catch(std::exception& e) {
|
||||
Log::error << "could not parse port: " << std::quoted(portstr);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string ClientAccess::getBasicAuth() const {
|
||||
return "riot:" + authcode;
|
||||
}
|
||||
|
||||
uint16_t ClientAccess::getPort() const {
|
||||
return port;
|
||||
}
|
||||
|
||||
std::string ClientAccess::getURL() const {
|
||||
return "https://127.0.0.1:" + std::to_string(port) + "/";
|
||||
}
|
||||
#include "clientaccess.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QStringList>
|
||||
|
||||
ClientAccess::ClientAccess() {}
|
||||
|
||||
ClientAccess::ClientAccess(const QString& token, uint16_t port) : authcode(token), port(port) {}
|
||||
|
||||
std::shared_ptr<ClientAccess> createFromLockfile(std::istream& lockfile) {
|
||||
|
||||
std::string content;
|
||||
std::getline(lockfile, content);
|
||||
QStringList parts = QString::fromStdString(content).split(':');
|
||||
|
||||
if(parts.size() != 5) {
|
||||
qCritical() << "lockfile contained " << parts.size() << " parts, expected 5";
|
||||
return {};
|
||||
}
|
||||
|
||||
const QString portstr = parts.at(2);
|
||||
const QString token = parts.at(3);
|
||||
|
||||
// try to parse port
|
||||
bool success = false;
|
||||
uint16_t port = portstr.toUInt(&success);
|
||||
if(!success) {
|
||||
qCritical() << "could not parse port: " << portstr;
|
||||
return nullptr;
|
||||
}
|
||||
return std::shared_ptr<ClientAccess>(new ClientAccess(token, port));
|
||||
}
|
||||
|
||||
QString ClientAccess::getBasicAuth() const {
|
||||
return "riot:" + authcode;
|
||||
}
|
||||
|
||||
uint16_t ClientAccess::getPort() const {
|
||||
return port;
|
||||
}
|
||||
|
||||
QString ClientAccess::getURL() const {
|
||||
return "https://127.0.0.1:" + QString::number(port) + "/";
|
||||
}
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
#include "clientaccess.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
# include <sys/mman.h>
|
||||
# include <dirent.h>
|
||||
# include <fcntl.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <Log.h>
|
||||
|
||||
#include "defer.h"
|
||||
|
||||
static const QString CLIENTNAME = "LeagueClientUx.exe"; // returns the name and value of a argument or empty string if it could not be parsed
|
||||
|
||||
static std::shared_ptr<ClientAccess> findUsingLockfile(const std::vector<QString>& cmdline, pid_t pid);
|
||||
|
||||
// reads a procfile into a vector (strings are \0 seperated)
|
||||
static std::vector<QString> readProcFile(const QString& path) {
|
||||
std::ifstream in(path.toStdString());
|
||||
std::vector<QString> out;
|
||||
std::string line;
|
||||
while(std::getline(in, line, '\0')) {
|
||||
if(!line.empty()) {
|
||||
out.push_back(QString::fromStdString(line));
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// test server
|
||||
#if 0
|
||||
std::shared_ptr<ClientAccess> ClientAccess::find() {
|
||||
return std::make_shared<ClientAccess>("password", 4443);
|
||||
}
|
||||
#else
|
||||
std::shared_ptr<ClientAccess> ClientAccess::find() {
|
||||
|
||||
DIR* procdir = opendir("/proc");
|
||||
if(!procdir) return nullptr;
|
||||
|
||||
defer( closedir(procdir) );
|
||||
|
||||
dirent* entry = nullptr;
|
||||
while ((entry = readdir(procdir)) != NULL) {
|
||||
if (entry->d_type != DT_DIR) continue;
|
||||
|
||||
QString name(entry->d_name);
|
||||
|
||||
pid_t pid = -1;
|
||||
bool success = false;
|
||||
pid = name.toULong(&success);
|
||||
if(!success) {
|
||||
// could not parse -> not a pid
|
||||
continue;
|
||||
}
|
||||
|
||||
// get info on the exe
|
||||
QString cmdfile = "/proc/" + QString::number(pid) + "/cmdline";
|
||||
std::vector<QString> args = readProcFile(cmdfile);
|
||||
|
||||
// qDebug() << "process: " << pid << " has " << args.size() << " args";
|
||||
|
||||
if(args.empty()) continue;
|
||||
|
||||
QString& exename = args.at(0);
|
||||
if(exename.endsWith(CLIENTNAME)) {
|
||||
qInfo() << CLIENTNAME << " found: " << exename;
|
||||
|
||||
std::shared_ptr<ClientAccess> out;
|
||||
|
||||
out = findUsingLockfile(args, pid);
|
||||
|
||||
if(out) {
|
||||
return out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::shared_ptr<ClientAccess> findUsingLockfile(const std::vector<QString>& cmdline, pid_t pid) {
|
||||
// get WINEPREFIX env
|
||||
std::vector<QString> envs = readProcFile("/proc/" + QString::number(pid) + "/environ");
|
||||
|
||||
const static QString WINEPREFIX = "WINEPREFIX=";
|
||||
|
||||
// find WINEPREFIX
|
||||
auto found = std::find_if(envs.begin(), envs.end(), [](const QString& s) {
|
||||
return s.startsWith(WINEPREFIX);
|
||||
});
|
||||
|
||||
// WINEPREFIX env not present
|
||||
if(found == envs.end()) {
|
||||
qDebug() << "WINEPREFIX environment variable not set";
|
||||
return {};
|
||||
}
|
||||
|
||||
const QString wineprefix = found->remove(0, WINEPREFIX.size());
|
||||
const QString binarypath = cmdline.at(0);
|
||||
QString gamefolder = binarypath.mid(2, binarypath.lastIndexOf('/')-1); // remove the "C:" and the name of the binary
|
||||
// TODO: gamefoldre could contain '\' so replacing every occurance with '/' would be a good idea
|
||||
const QString lockfilepath = wineprefix + "/drive_c/" + gamefolder + "/lockfile";
|
||||
|
||||
qDebug() << "lockfilepath: " << lockfilepath;
|
||||
|
||||
// read lockfile
|
||||
std::ifstream lockfile(lockfilepath.toStdString());
|
||||
return createFromLockfile(lockfile);
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
#include "clientaccess.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
# include <windows.h>
|
||||
# include <tlhelp32.h>
|
||||
# include <tchar.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <Log.h>
|
||||
|
||||
#include "defer.h"
|
||||
|
||||
static const QString CLIENTNAME = "LeagueClientUx.exe";
|
||||
|
||||
static QString narrow(WCHAR* str, size_t len) {
|
||||
QString out;
|
||||
out.reserve(len);
|
||||
for(uint32_t i = 0; i < len && str[i]; ++i) {
|
||||
out.append(1, (char) str[i]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static QString getProcessPath(DWORD dwPID) {
|
||||
// Take a snapshot of all modules in the specified process.
|
||||
HANDLE hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
|
||||
if(hModuleSnap == INVALID_HANDLE_VALUE) {
|
||||
qCritical() << "CreateToolhelp32Snapshot (of modules) failed";
|
||||
return {}; // empty string
|
||||
}
|
||||
|
||||
defer( CloseHandle(hModuleSnap) );
|
||||
|
||||
// Set the size of the structure before using it.
|
||||
MODULEENTRY32 me32;
|
||||
me32.dwSize = sizeof(MODULEENTRY32);
|
||||
|
||||
// Retrieve information about the first module,
|
||||
// and exit if unsuccessful
|
||||
if( !Module32First( hModuleSnap, &me32 ) ) {
|
||||
qCritical() << "Module32First";
|
||||
return {};
|
||||
}
|
||||
|
||||
return narrow((WCHAR*) me32.szExePath, sizeof(me32.szExePath));
|
||||
}
|
||||
|
||||
static std::shared_ptr<ClientAccess> findUsingLockfile(PROCESSENTRY32& proc) {
|
||||
const QString exepath = getProcessPath(proc.th32ProcessID);
|
||||
Log::note << "exepath: " << exepath;
|
||||
|
||||
// lockfile path
|
||||
const QString lockfilepath = exepath.substr(0, exepath.rfind('\\')+1) + "lockfile"; // possible out of bounds
|
||||
qDebug() << "Lockfile: " << lockfilepath;
|
||||
std::ifstream lockfile(lockfilepath);
|
||||
if(!lockfile) {
|
||||
qCritical() << "lockfile could not be opend";
|
||||
return nullptr;
|
||||
}
|
||||
return createFromLockfile(lockfile);
|
||||
}
|
||||
|
||||
std::shared_ptr<ClientAccess> ClientAccess::find() {
|
||||
// example code: https://docs.microsoft.com/de-de/windows/win32/toolhelp/taking-a-snapshot-and-viewing-processes
|
||||
|
||||
// Take a snapshot of all processes in the system.
|
||||
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (hProcessSnap == INVALID_HANDLE_VALUE) {
|
||||
qCritical() << "CreateToolhelp32Snapshot (of processes) failed";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
defer( CloseHandle(hProcessSnap) );
|
||||
|
||||
PROCESSENTRY32 pe32;
|
||||
// Set the size of the structure before using it.
|
||||
pe32.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
// Retrieve information about the first process,
|
||||
// and exit if unsuccessful
|
||||
if (!Process32First(hProcessSnap, &pe32)) {
|
||||
qCritical() << "Process32First failed"; // show cause of failure
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Now walk the snapshot of processes, and
|
||||
// display information about each process in turn
|
||||
do {
|
||||
QString exename = narrow((WCHAR*) pe32.szExeFile, sizeof(pe32.szExeFile));
|
||||
// Log::note << "found process: " << exename;
|
||||
|
||||
if(exename == CLIENTNAME) {
|
||||
qInfo() << CLIENTNAME << " found";
|
||||
|
||||
std::shared_ptr<ClientAccess> out;
|
||||
|
||||
out = findUsingLockfile(pe32);
|
||||
|
||||
if(out) {
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
} while(Process32Next(hProcessSnap, &pe32));
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include "json.h"
|
||||
|
||||
ClientAPI::ClientAPI(const ClientAccess& ca) : RestClient(ca.getURL()), access(ca) {
|
||||
ClientAPI::ClientAPI(const ClientAccess& ca) : RestClient(ca.getURL()), access(ca), memImageCache(40), imageCache("runes", "") {
|
||||
basicauth = ca.getBasicAuth();
|
||||
disableCertCheck = true;
|
||||
// enableDebugging();
|
||||
|
@ -30,9 +30,9 @@ 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();
|
||||
QString datastr = QString::fromLocal8Bit(data);
|
||||
if (data.size() > 2) {
|
||||
datastr = datastr.substr(1, datastr.size() -2);
|
||||
datastr = datastr.mid(1, datastr.size() -2);
|
||||
|
||||
return toGameflowPhase(datastr);
|
||||
}
|
||||
|
@ -63,25 +63,25 @@ bool ClientAPI::setChampSelectAction(int32_t actionid, int32_t champid, bool com
|
|||
requestj["completed"] = completed;
|
||||
requestj["id"] = actionid;
|
||||
QJsonDocument requestdoc(requestj);
|
||||
const std::string requeststr = requestdoc.toJson(QJsonDocument::JsonFormat::Compact).toStdString();
|
||||
Log::debug << "requeststr: " << requeststr;
|
||||
QJsonDocument doc = request("lol-champ-select/v1/session/actions/" + std::to_string(actionid), Method::PATCH, requeststr);
|
||||
const QString requeststr = QString::fromLocal8Bit(requestdoc.toJson(QJsonDocument::JsonFormat::Compact));
|
||||
qDebug().noquote() << "requeststr: " << requeststr;
|
||||
QJsonDocument doc = request("lol-champ-select/v1/session/actions/" + QString::number(actionid), Method::PATCH, requeststr);
|
||||
|
||||
std::string error;
|
||||
QString error;
|
||||
if(doc.isObject()) {
|
||||
QJsonObject obj = doc.object();
|
||||
auto errref = obj["errorCode"];
|
||||
auto msgref = obj["message"];
|
||||
if(errref.isString()) {
|
||||
error = errref.toString().toStdString() + " ";
|
||||
error = errref.toString() + " ";
|
||||
}
|
||||
if(msgref.isString()) {
|
||||
error += msgref.toString().toStdString();
|
||||
error += msgref.toString();
|
||||
}
|
||||
}
|
||||
|
||||
Log::note << "patching action: " << actionid << " error: " << error;
|
||||
return error.empty();
|
||||
qDebug() << "patching action: " << actionid << " error: " << error;
|
||||
return error.isEmpty();
|
||||
}
|
||||
|
||||
ClientAPI::PlayerInfo ClientAPI::getSelf() {
|
||||
|
@ -91,14 +91,15 @@ ClientAPI::PlayerInfo ClientAPI::getSelf() {
|
|||
QJsonObject obj = doc.object();
|
||||
|
||||
PlayerInfo info;
|
||||
info.gameName = getValue<std::string>(obj, "gameName");
|
||||
info.name = getValue<std::string>(obj, "name");
|
||||
info.statusMessage = getValue<std::string>(obj, "statusMessage", "");
|
||||
info.gameName = getValue<QString>(obj, "gameName");
|
||||
info.name = getValue<QString>(obj, "name");
|
||||
info.statusMessage = getValue<QString>(obj, "statusMessage", "");
|
||||
info.summonerid = getValue<uint64_t>(obj, "summonerId");
|
||||
|
||||
auto lolref = obj["lol"];
|
||||
if(lolref.isObject()) {
|
||||
QJsonObject lol = lolref.toObject();
|
||||
info.puuid = getValue<std::string>(lol, "puuid");
|
||||
info.puuid = getValue<QString>(lol, "puuid");
|
||||
info.level = getValue<int32_t>(lol, "level");
|
||||
}
|
||||
|
||||
|
@ -107,23 +108,9 @@ ClientAPI::PlayerInfo ClientAPI::getSelf() {
|
|||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::string> ClientAPI::getLog() {
|
||||
std::vector<std::string> out;
|
||||
QJsonDocument doc = request("LoggingGetEntries");
|
||||
if(doc.isArray()) {
|
||||
QJsonArray arr = doc.array();
|
||||
for(auto it : arr) {
|
||||
std::string message;
|
||||
if(it.isObject()) {
|
||||
QJsonObject logobj = it.toObject();
|
||||
message = getValue<std::string>(logobj, "severity");
|
||||
message += getValue<std::string>(logobj, "message");
|
||||
}
|
||||
out.push_back(message);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
void ClientAPI::dodge() {
|
||||
QJsonDocument doc = request("lol-login/v1/session/invoke?destination=lcdsServiceProxy&method=call&args=[\"\",\"teambuilder-draft\",\"quitV2\", \"\"]", Method::POST, "");
|
||||
qDebug() << "dodge result:" << doc;
|
||||
}
|
||||
|
||||
static std::vector<int32_t> fromArrayToVector(const QJsonArray& arr) {
|
||||
|
@ -165,3 +152,223 @@ ClientAPI::TimerInfo ClientAPI::getTimerInfo() {
|
|||
|
||||
return (TimerInfo) obj;
|
||||
}
|
||||
|
||||
std::vector<ClientAPI::Conversation> ClientAPI::getAllConversations() {
|
||||
std::vector<Conversation> 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 QString& chatid, const QString& messagebody) {
|
||||
QJsonObject requestj;
|
||||
requestj["body"] = messagebody;
|
||||
QJsonDocument requestdoc(requestj);
|
||||
const QString requeststr = QString::fromLocal8Bit(requestdoc.toJson(QJsonDocument::JsonFormat::Compact));
|
||||
qDebug().noquote() << "requeststr: " << requeststr;
|
||||
QJsonDocument doc = request("lol-chat/v1/conversations/" + chatid + "/messages", Method::POST, requeststr);
|
||||
|
||||
QString error;
|
||||
if(doc.isObject()) {
|
||||
QJsonObject obj = doc.object();
|
||||
auto errref = obj["errorCode"];
|
||||
auto msgref = obj["message"];
|
||||
if(errref.isString()) {
|
||||
error = errref.toString() + " ";
|
||||
}
|
||||
if(msgref.isString()) {
|
||||
error += msgref.toString();
|
||||
}
|
||||
|
||||
if(error.isEmpty()) {
|
||||
return (Message) obj;
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "send message error: " << error;
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
ClientAPI::RunePage ClientAPI::getCurrentRunePage() {
|
||||
QJsonDocument doc = request("lol-perks/v1/currentpage");
|
||||
|
||||
if(!doc.isObject()) return {};
|
||||
|
||||
return (RunePage) doc.object();
|
||||
}
|
||||
|
||||
std::vector<ClientAPI::RunePage> ClientAPI::getAllRunePages() {
|
||||
QJsonDocument doc = request("lol-perks/v1/pages");
|
||||
|
||||
if(!doc.isArray()) return {};
|
||||
|
||||
QJsonArray arr = doc.array();
|
||||
std::vector<RunePage> out;
|
||||
out.reserve(arr.size());
|
||||
for(auto it : arr) {
|
||||
if(it.isObject()) {
|
||||
out.push_back((RunePage) it.toObject());
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool ClientAPI::selectRunePage(uint64_t id) {
|
||||
QJsonDocument doc = request("lol-perks/v1/currentpage", Method::PUT, QString::number(id));
|
||||
|
||||
if(doc.isEmpty()) return true; // ok
|
||||
|
||||
// error
|
||||
qWarning() << "error selecting runepage: " << id << " " << doc.toJson();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ClientAPI::editRunePage(const RunePage& page) {
|
||||
QJsonObject pagereq;
|
||||
|
||||
pagereq["name"] = page.name;
|
||||
pagereq["primaryStyleId"] = (int) page.runepage.primaryStyle;
|
||||
pagereq["subStyleId"] = (int) page.runepage.secondaryStyle;
|
||||
|
||||
QJsonArray selected;
|
||||
for(uint32_t sel : page.runepage.selectedAspects) {
|
||||
selected.push_back((int) sel);
|
||||
}
|
||||
|
||||
pagereq["selectedPerkIds"] = selected;
|
||||
|
||||
QJsonDocument reqdoc(pagereq);
|
||||
const QString requestdocstr = QString::fromLocal8Bit(reqdoc.toJson(QJsonDocument::JsonFormat::Compact));
|
||||
qInfo().noquote() << "requeststr: " << requestdocstr;
|
||||
QJsonDocument doc = request("lol-perks/v1/pages/" + QString::number(page.id), Method::PUT, requestdocstr);
|
||||
|
||||
if(doc.isObject() && doc["isValid"].isBool() && doc["isValid"].toBool()) return true; // ok
|
||||
|
||||
// error
|
||||
qWarning() << "error editing runepage: " << page.id << " " << doc.toJson();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ClientAPI::createRunePage(const RunePage& page) {
|
||||
QJsonObject pagereq;
|
||||
|
||||
pagereq["name"] = page.name;
|
||||
pagereq["primaryStyleId"] = (int) page.runepage.primaryStyle;
|
||||
pagereq["subStyleId"] = (int) page.runepage.secondaryStyle;
|
||||
|
||||
QJsonArray selected;
|
||||
for(uint32_t sel : page.runepage.selectedAspects) {
|
||||
selected.push_back((int) sel);
|
||||
}
|
||||
|
||||
pagereq["selectedPerkIds"] = selected;
|
||||
|
||||
QJsonDocument reqdoc(pagereq);
|
||||
const QString requestdocstr = reqdoc.toJson(QJsonDocument::JsonFormat::Compact);
|
||||
qInfo() << "requeststr: " << requestdocstr;
|
||||
QJsonDocument doc = request("lol-perks/v1/pages/", Method::POST, requestdocstr);
|
||||
|
||||
if(doc.isObject() && doc["isValid"].isBool() && doc["isValid"].toBool()) return true; // ok
|
||||
|
||||
// error
|
||||
qWarning() << "error creating runepage: " << page.name << " " << doc.toJson();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ClientAPI::deleteRunePage(uint64_t id) {
|
||||
QJsonDocument doc = request("lol-perks/v1/pages/" + QString::number(id), Method::DELETE);
|
||||
|
||||
if(doc.isEmpty()) return true; // ok
|
||||
|
||||
// error
|
||||
qWarning() << "error deleteing runepage: " << id << " " << doc.toJson();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<RuneAspekt> ClientAPI::getAllRuneAspekts() {
|
||||
QJsonDocument doc = request("lol-perks/v1/perks");
|
||||
|
||||
if(!doc.isArray()) {
|
||||
qWarning() << __PRETTY_FUNCTION__ << " doc is not array";
|
||||
return {};
|
||||
}
|
||||
|
||||
QJsonArray arr = doc.array();
|
||||
std::vector<RuneAspekt> out;
|
||||
out.reserve(arr.size());
|
||||
for(auto it : arr) {
|
||||
if(it.isObject()) {
|
||||
out.push_back((RuneAspekt) it.toObject());
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<RuneStyle> ClientAPI::getAllRuneStyles() {
|
||||
QJsonDocument doc = request("lol-perks/v1/styles");
|
||||
|
||||
if(!doc.isArray()) {
|
||||
qWarning() << __PRETTY_FUNCTION__ << " doc is not array";
|
||||
return {};
|
||||
}
|
||||
|
||||
QJsonArray arr = doc.array();
|
||||
std::vector<RuneStyle> out;
|
||||
out.reserve(arr.size());
|
||||
for(auto it : arr) {
|
||||
if(it.isObject()) {
|
||||
out.push_back((RuneStyle) it.toObject());
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
QPixmap ClientAPI::getImageResource(QString path) {
|
||||
if(path.isEmpty()) return {};
|
||||
|
||||
QString simplePath;
|
||||
{
|
||||
QString simplePathQ = path;
|
||||
simplePath = simplePathQ.replace('/', '_');
|
||||
}
|
||||
|
||||
// query mem cache
|
||||
QPixmap img = memImageCache.getImage(path, 0);
|
||||
if(!img.isNull()) return img;
|
||||
|
||||
// query HDD cache
|
||||
img = imageCache.getImage(simplePath);
|
||||
if(!img.isNull()) {
|
||||
// update mem cache
|
||||
memImageCache.addImage(img, path, 0);
|
||||
return img;
|
||||
}
|
||||
|
||||
qInfo() << "requesting: " << path;
|
||||
QByteArray arr = requestRaw(path);
|
||||
QPixmap out;
|
||||
out.loadFromData(arr);
|
||||
|
||||
// store HDD cache
|
||||
imageCache.addImageRaw(arr, simplePath);
|
||||
|
||||
// store memchache
|
||||
memImageCache.addImage(out, path, 0);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "clientapi.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
|
@ -10,18 +9,19 @@
|
|||
|
||||
// calculate the size of a constant sized array
|
||||
#define ARRSIZE(ARRNAME) (sizeof(ARRNAME) / sizeof(ARRNAME[0]))
|
||||
#define ARR(NAME, ...) static const std::string NAME ## Names[] = {__VA_ARGS__}; \
|
||||
#define ARR(NAME, ...) static const QString NAME ## Names[] = {__VA_ARGS__}; \
|
||||
static const uint32_t NAME ## NamesCount = ARRSIZE(NAME ## Names);
|
||||
|
||||
ARR(ReadyCheckState, "Invalid", "None", "InProgress", "Accepted", "Declined");
|
||||
ARR(GameflowPhase, "None", "Lobby", "Matchmaking", "CheckedIntoTournament", "ReadyCheck", "ChampSelect", "GameStart", "FailedToLaunch", "InProgress", "Reconnect", "WaitingForStats", "PreEndOfGame", "EndOfGame", "TerminatedInError");
|
||||
ARR(ChampSelectPhase, "Invalid", "PLANNING", "BAN_PICK", "FINALIZATION");
|
||||
ARR(Position, "Invalid", "top", "middle", "bottom", "jungle", "utility");
|
||||
ARR(ChampSelectActionType, "Invalid", "ban", "pick", "ten_bans_reveal");
|
||||
ARR(ReadyCheckState, "Invalid", "None", "InProgress", "Accepted", "Declined")
|
||||
ARR(GameflowPhase, "None", "Lobby", "Matchmaking", "CheckedIntoTournament", "ReadyCheck", "ChampSelect", "GameStart", "FailedToLaunch", "InProgress", "Reconnect", "WaitingForStats", "PreEndOfGame", "EndOfGame", "TerminatedInError")
|
||||
ARR(ChampSelectPhase, "Invalid", "GAME_STARTING", "PLANNING", "BAN_PICK", "FINALIZATION")
|
||||
ARR(Position, "Invalid", "top", "jungle", "middle", "bottom", "utility")
|
||||
ARR(ShortPosition, "", "Top", "Jgl", "Mid", "Bot", "Sup")
|
||||
ARR(ChampSelectActionType, "Invalid", "ban", "pick", "ten_bans_reveal")
|
||||
|
||||
template<typename T>
|
||||
static T mapEnum(const std::string& input, const std::string* names, uint32_t count, T defaul) {
|
||||
if(input.empty()) return defaul;
|
||||
static T mapEnum(const QString& input, const QString* names, uint32_t count, T defaul) {
|
||||
if(input.isEmpty()) return defaul;
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (names[i] == input) {
|
||||
|
@ -29,16 +29,28 @@ static T mapEnum(const std::string& input, const std::string* names, uint32_t co
|
|||
}
|
||||
}
|
||||
|
||||
Log::warn << "no mapping of enum-string: " << std::quoted(input);
|
||||
qWarning() << "no mapping of enum-string: " << input << " using default: " << defaul << " type: " << typeid(T).name();
|
||||
return defaul;
|
||||
}
|
||||
|
||||
#define MAPENUM(VAR, ENUM, DEFAULT) \
|
||||
mapEnum(VAR, ENUM ## Names, ENUM ## NamesCount, ClientAPI:: ENUM :: DEFAULT)
|
||||
|
||||
template<typename T>
|
||||
static std::vector<T> readVector(QJsonArray arr) {
|
||||
std::vector<T> out;
|
||||
out.reserve(arr.size());
|
||||
|
||||
for(auto it : arr) {
|
||||
out.push_back(convert<T>((QJsonValue) it));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
ClientAPI::ReadyCheckState ClientAPI::toReadyCheckState(const QJsonObject& obj) {
|
||||
std::string searchState = getValue<std::string>(obj, "state", "Invalid");
|
||||
std::string playerresponse = getValue<std::string>(obj, "playerResponse", "None");
|
||||
QString searchState = getValue<QString>(obj, "state", "Invalid");
|
||||
QString playerresponse = getValue<QString>(obj, "playerResponse", "None");
|
||||
|
||||
ClientAPI::ReadyCheckState response = MAPENUM(playerresponse, ReadyCheckState, NONE);
|
||||
|
||||
|
@ -52,19 +64,27 @@ ClientAPI::ReadyCheckState ClientAPI::toReadyCheckState(const QJsonObject& obj)
|
|||
return response;
|
||||
}
|
||||
|
||||
ClientAPI::GameflowPhase ClientAPI::toGameflowPhase(const std::string& str) {
|
||||
ClientAPI::GameflowPhase ClientAPI::toGameflowPhase(const QString& str) {
|
||||
return MAPENUM(str, GameflowPhase, NONE);
|
||||
}
|
||||
|
||||
ClientAPI::ChampSelectPhase ClientAPI::toChampSelectPhase(const std::string& str) {
|
||||
ClientAPI::ChampSelectPhase ClientAPI::toChampSelectPhase(const QString& str) {
|
||||
return MAPENUM(str, ChampSelectPhase, INVALID);
|
||||
}
|
||||
|
||||
ClientAPI::Position ClientAPI::toPosition(const std::string& str) {
|
||||
return MAPENUM(str, Position, INVALID);
|
||||
Position toPosition(const QString& str) {
|
||||
return mapEnum(str, PositionNames, PositionNamesCount, Position::INVALID);
|
||||
}
|
||||
|
||||
ClientAPI::ChampSelectActionType ClientAPI::toChampSelectActionType(const std::string& str) {
|
||||
QString toString(Position p) {
|
||||
return PositionNames[(int) p];
|
||||
}
|
||||
|
||||
QString toShortString(Position p) {
|
||||
return ShortPositionNames[(int) p];
|
||||
}
|
||||
|
||||
ClientAPI::ChampSelectActionType ClientAPI::toChampSelectActionType(const QString& str) {
|
||||
return MAPENUM(str, ChampSelectActionType, INVALID);
|
||||
}
|
||||
|
||||
|
@ -74,7 +94,7 @@ ClientAPI::TimerInfo::TimerInfo(const QJsonObject& obj) {
|
|||
internalNowInEpochMs = getValue<int64_t>(obj, "internalNowInEpochMs", 0);
|
||||
isefinite = getValue<bool>(obj, "isefinite", 0);
|
||||
|
||||
phase = MAPENUM(getValue<std::string>(obj, "phase", "Invalid"), ChampSelectPhase, INVALID);
|
||||
phase = MAPENUM(getValue<QString>(obj, "phase", "Invalid"), ChampSelectPhase, INVALID);
|
||||
|
||||
totalTimeInPhase = getValue<int64_t>(obj, "totalTimeInPhase", 0);
|
||||
}
|
||||
|
@ -87,17 +107,19 @@ ClientAPI::ChampSelectAction::ChampSelectAction(const QJsonObject& json) {
|
|||
id = getValue<int32_t>(json, "id");
|
||||
isAllyAction = getValue<bool>(json, "isAllyAction");
|
||||
isInProgress = getValue<bool>(json, "isInProgress");
|
||||
const std::string typestr = getValue<std::string>(json, "type", "Invalid");
|
||||
const QString typestr = getValue<QString>(json, "type", "Invalid");
|
||||
type = toChampSelectActionType(typestr);
|
||||
}
|
||||
|
||||
ClientAPI::ChampSelectCell::ChampSelectCell() {}
|
||||
ClientAPI::ChampSelectCell::ChampSelectCell(const QJsonObject& json) {
|
||||
position = toPosition(getValue<std::string>(json, "assignedPosition"));
|
||||
position = toPosition(getValue<QString>(json, "assignedPosition"));
|
||||
cellID = getValue<int32_t>(json, "cellId");
|
||||
championID = getValue<int32_t>(json, "championId");
|
||||
championPickIntentID = getValue<int32_t>(json, "championPickIntent");
|
||||
summonerID = getValue<int32_t>(json, "summonerId");
|
||||
spell1Id = getValue<int64_t>(json, "spell1Id", 0);
|
||||
spell2Id = getValue<int64_t>(json, "spell2Id", 0);
|
||||
}
|
||||
|
||||
std::vector<ClientAPI::ChampSelectCell> ClientAPI::loadAllInfos(const QJsonArray& arr) {
|
||||
|
@ -166,16 +188,122 @@ ClientAPI::ChampSelectSession::operator bool() {
|
|||
return gameid != 0;
|
||||
}
|
||||
|
||||
ClientAPI::RunePage::RunePage() {}
|
||||
ClientAPI::RunePage::RunePage(const QJsonObject& json) {
|
||||
id = getValue<int32_t>(json, "id", 0);
|
||||
lastmodified = getValue<int64_t>(json, "lastModified", 0);
|
||||
runepage.primaryStyle = getValue<int32_t>(json, "primaryStyleId", 0);
|
||||
runepage.secondaryStyle = getValue<int32_t>(json, "subStyleId", 0);
|
||||
name = getValue<QString>(json, "name");
|
||||
isDeleteable = getValue<bool>(json, "isDeletable", false);
|
||||
isEditable = getValue<bool>(json, "isEditable", false);
|
||||
isActive = getValue<bool>(json, "isActive", false);
|
||||
isCurrent = getValue<bool>(json, "current", false);
|
||||
isValid = getValue<bool>(json, "isValid", false);
|
||||
order = getValue<int32_t>(json, "order", 0);
|
||||
|
||||
auto selectedref = json["selectedPerkIds"];
|
||||
if(selectedref.isArray()) {
|
||||
runepage.selectedAspects = readVector<uint32_t>(selectedref.toArray());
|
||||
}
|
||||
}
|
||||
|
||||
RuneStyleSlot::RuneStyleSlot() {}
|
||||
RuneStyleSlot::RuneStyleSlot(const QJsonObject& json) {
|
||||
type = getValue<QString>(json, "type");
|
||||
|
||||
auto perksj = json["perks"];
|
||||
if(perksj.isArray()) {
|
||||
perks = readVector<int>(perksj.toArray());
|
||||
}
|
||||
}
|
||||
|
||||
RuneStyle::RuneStyle() {}
|
||||
RuneStyle::RuneStyle(const QJsonObject& json) {
|
||||
id = getValue<int32_t>(json, "id", 0);
|
||||
name = getValue<QString>(json, "name");
|
||||
iconPath = getValue<QString>(json, "iconPath");
|
||||
tooltip = getValue<QString>(json, "tooltip");
|
||||
idName = getValue<QString>(json, "idName");
|
||||
|
||||
auto subStylesRef = json["allowedSubStyles"];
|
||||
if(subStylesRef.isArray()) {
|
||||
allowedSubStyles = readVector<int>(subStylesRef.toArray());
|
||||
}
|
||||
|
||||
auto runeSlotsRef = json["slots"];
|
||||
if(runeSlotsRef.isArray()) {
|
||||
runeSlots = readVector<RuneStyleSlot>(runeSlotsRef.toArray());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RuneAspekt::RuneAspekt() {}
|
||||
RuneAspekt::RuneAspekt(const QJsonObject& json) {
|
||||
id = getValue<int32_t>(json, "id", 0);
|
||||
name = getValue<QString>(json, "name");
|
||||
shortDesc = getValue<QString>(json, "shortDesc");
|
||||
longDesc = getValue<QString>(json, "longDesc");
|
||||
tooltip = getValue<QString>(json, "tooltip");
|
||||
iconPath = getValue<QString>(json, "iconPath");
|
||||
}
|
||||
|
||||
ClientAPI::Message::Message() {}
|
||||
ClientAPI::Message::Message(const QJsonObject& json) {
|
||||
body = getValue<QString>(json, "body");
|
||||
fromId = getValue<QString>(json, "fromId");
|
||||
fromPid = getValue<QString>(json, "fromPid");
|
||||
fromSummonerId = getValue<int64_t>(json, "fromSummonerId");
|
||||
id = getValue<QString>(json, "id");
|
||||
isHistorical = getValue<bool>(json, "isHistorical", true);
|
||||
timestamp = getValue<QString>(json, "timestamp");
|
||||
type = getValue<QString>(json, "type");
|
||||
}
|
||||
|
||||
ClientAPI::Conversation::Conversation() {}
|
||||
ClientAPI::Conversation::Conversation(const QJsonObject& json) : lastMessage(nullptr) {
|
||||
gameName = getValue<QString>(json, "gameName");
|
||||
gameTag = getValue<QString>(json, "gameTag");
|
||||
id = getValue<QString>(json, "id");
|
||||
isMuted = getValue<bool>(json, "isMuted");
|
||||
name = getValue<QString>(json, "name");
|
||||
password = getValue<QString>(json, "password");
|
||||
pid = getValue<QString>(json, "pid");
|
||||
targetRegion = getValue<QString>(json, "targetRegion");
|
||||
type = getValue<QString>(json, "type");
|
||||
unreadMessageCount = getValue<int64_t>(json, "unreadMessageCount");
|
||||
|
||||
auto msgref = json["lastMessage"];
|
||||
if(msgref.isObject()) {
|
||||
lastMessage = std::make_shared<Message>(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].toStdString() << " (" << (uint32_t) state << ')'; \
|
||||
} \
|
||||
\
|
||||
QDebug operator<<(QDebug str, const ClientAPI:: ENUMNAME & state) { \
|
||||
assert(((uint32_t) state) < ENUMNAME ## NamesCount); \
|
||||
return str << ENUMNAME ## Names[(uint32_t) state] << " (" << (uint32_t) state << ')'; \
|
||||
}
|
||||
|
||||
|
||||
PRINTENUM(ReadyCheckState)
|
||||
PRINTENUM(GameflowPhase)
|
||||
PRINTENUM(ChampSelectPhase)
|
||||
PRINTENUM(Position)
|
||||
PRINTENUM(ChampSelectActionType)
|
||||
|
||||
// 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].toStdString() << " (" << (uint32_t) state << ')';
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug str, const Position & state) {
|
||||
assert(((uint32_t) state) < PositionNamesCount);
|
||||
return str << PositionNames[(uint32_t) state] << " (" << (uint32_t) state << ')';
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
#include "clipboardpopup.h"
|
||||
#include "ui_clipboardpopup.h"
|
||||
|
||||
#include <QClipboard>
|
||||
|
||||
ClipboardPopup::ClipboardPopup(Direction dir, QWidget* parent) : QDialog(parent), ui(new Ui::ClipboardPopup), direction(dir) {
|
||||
ui->setupUi(this);
|
||||
|
||||
if(direction == Direction::Paste) {
|
||||
this->ui->copyButton->hide();
|
||||
this->ui->text->setPlaceholderText(ClipboardPopup::tr("Paste here"));
|
||||
this->ui->buttonBox->setStandardButtons(QDialogButtonBox::Cancel);
|
||||
|
||||
QObject::connect(this->ui->text, &QTextEdit::textChanged, this, &ClipboardPopup::textPasted);
|
||||
} else {
|
||||
// copy
|
||||
this->ui->text->setReadOnly(true);
|
||||
}
|
||||
|
||||
QObject::connect(this->ui->copyButton, &QPushButton::pressed, this, &ClipboardPopup::copyButton);
|
||||
}
|
||||
|
||||
ClipboardPopup::~ClipboardPopup() {
|
||||
delete this->ui;
|
||||
}
|
||||
|
||||
void ClipboardPopup::textPasted() {
|
||||
int newTextSize = this->getText().size();
|
||||
if(newTextSize - 1 > lastKnownTextSize && newTextSize > 1) {
|
||||
// asume that something was pasted
|
||||
accept();
|
||||
return;
|
||||
}
|
||||
|
||||
if(newTextSize > 0) {
|
||||
this->ui->buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
|
||||
}
|
||||
|
||||
lastKnownTextSize = newTextSize;
|
||||
}
|
||||
|
||||
void ClipboardPopup::setText(QString text) {
|
||||
this->ui->text->setText(text);
|
||||
this->ui->text->selectAll();
|
||||
}
|
||||
|
||||
QString ClipboardPopup::getText() const {
|
||||
return this->ui->text->toPlainText();
|
||||
}
|
||||
|
||||
void ClipboardPopup::copyButton() {
|
||||
QClipboard* clip = qApp->clipboard();
|
||||
clip->setText(this->ui->text->toPlainText());
|
||||
|
||||
// close this dialog
|
||||
accept();
|
||||
}
|
168
src/config.cpp
|
@ -9,11 +9,17 @@
|
|||
|
||||
#include "json.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#define CONFPATH "lolautoacceptor/"
|
||||
#else
|
||||
#define CONFPATH ".config/lolautoaccept/"
|
||||
#endif
|
||||
|
||||
Config::StageConfig::StageConfig() : enabled(false) {}
|
||||
|
||||
Config::StageConfig::StageConfig(const QJsonObject& j) {
|
||||
if(j["champ"].isString()) {
|
||||
champs.push_back(getValue<std::string>(j, "champ", ""));
|
||||
champs.push_back(getValue<QString>(j, "champ"));
|
||||
}
|
||||
if(j["champs"].isArray()) {
|
||||
QJsonArray jchamps = j["champs"].toArray();
|
||||
|
@ -21,7 +27,7 @@ Config::StageConfig::StageConfig(const QJsonObject& j) {
|
|||
if(jchamp.isString()) {
|
||||
QString jchampstr = jchamp.toString();
|
||||
if(!jchampstr.isEmpty()) {
|
||||
champs.push_back(jchampstr.toStdString());
|
||||
champs.push_back(jchampstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,9 +39,9 @@ Config::StageConfig::operator QJsonObject() const {
|
|||
QJsonObject out;
|
||||
|
||||
QJsonArray jchamps;
|
||||
for(const std::string& champ : champs) {
|
||||
if(!champ.empty()) {
|
||||
jchamps.push_back(QString::fromStdString(champ));
|
||||
for(const QString& champ : champs) {
|
||||
if(!champ.isEmpty()) {
|
||||
jchamps.push_back(champ);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,70 +51,186 @@ Config::StageConfig::operator QJsonObject() const {
|
|||
return out;
|
||||
}
|
||||
|
||||
Config::RootConfig::RootConfig() {}
|
||||
|
||||
Config::RootConfig::RootConfig(const QJsonObject& j) {
|
||||
prepick = getValue<Config::StageConfig>(j, "prepick");
|
||||
Config::PositionConfig::PositionConfig() {}
|
||||
Config::PositionConfig::PositionConfig(const QJsonObject& j) {
|
||||
ban = getValue<Config::StageConfig>(j, "ban");
|
||||
pick = getValue<Config::StageConfig>(j, "pick");
|
||||
enabledAutoAccept = getValue(j, "enabledAutoAccept", false);
|
||||
position = toPosition(getValue<QString>(j, "position"));
|
||||
if((int) position < 0 || position > Position::UTILITY) {
|
||||
qWarning() << "invalid config value \"position\"";
|
||||
position = Position::MIDDLE;
|
||||
}
|
||||
}
|
||||
Config::PositionConfig::operator QJsonObject() const {
|
||||
QJsonObject out;
|
||||
|
||||
out["ban"] = (QJsonObject) ban;
|
||||
out["pick"] = (QJsonObject) pick;
|
||||
out["position"] = toString(position);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Config::RunePageConfig::RunePageConfig() {}
|
||||
Config::RunePageConfig::RunePageConfig(const QJsonObject& j) {
|
||||
name = getValue<QString>(j, "name");
|
||||
runepage = getValue<::RunePage>(j, "runepage");
|
||||
}
|
||||
Config::RunePageConfig::operator QJsonObject() const {
|
||||
QJsonObject out;
|
||||
|
||||
out["name"] = name;
|
||||
out["runepage"] = static_cast<QJsonObject>(runepage);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Config::RootConfig::RootConfig() {}
|
||||
|
||||
Config::RunePageConfig::RunePageConfig(QString name, const RunePage& rp) : name(name), runepage(rp) {}
|
||||
|
||||
Config::GeneralRunePageConfig::GeneralRunePageConfig() {}
|
||||
Config::GeneralRunePageConfig::GeneralRunePageConfig(const QJsonObject& j) {
|
||||
auto runepagesRef = j["pages"];
|
||||
if(runepagesRef.isArray()) {
|
||||
QJsonArray jpages = runepagesRef.toArray();
|
||||
|
||||
runePages.reserve(jpages.size());
|
||||
for(QJsonValue val : jpages) {
|
||||
if(val.isObject()) {
|
||||
runePages.push_back(std::make_shared<RunePageConfig>(val.toObject()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
autoSync = getValue(j, "autosync", true);
|
||||
}
|
||||
Config::GeneralRunePageConfig::operator QJsonObject() const {
|
||||
QJsonObject out;
|
||||
|
||||
QJsonArray runepagesArr;
|
||||
for(std::shared_ptr<RunePageConfig> rp : runePages) {
|
||||
runepagesArr.push_back((QJsonObject) *rp);
|
||||
}
|
||||
out.insert("pages", runepagesArr);
|
||||
out.insert("autosync", autoSync);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Config::RootConfig::RootConfig(const QJsonObject& j) {
|
||||
if(j.contains("version")) {
|
||||
int version = j["version"].toInt();
|
||||
if(version > 1) {
|
||||
// error
|
||||
qCritical() << "config version is not known: " << version << " using the config might corrupt it.";
|
||||
|
||||
// TODO: make backup of config or something
|
||||
}
|
||||
|
||||
// add migrations here if required
|
||||
}
|
||||
|
||||
auto jposref = j["positions"];
|
||||
if(jposref.isArray()) {
|
||||
QJsonArray jpos = jposref.toArray();
|
||||
|
||||
positionConfigs.reserve(jpos.size());
|
||||
for(QJsonValue val : jpos) {
|
||||
if(val.isObject()) {
|
||||
positionConfigs.push_back(std::make_shared<Config::PositionConfig>(val.toObject())); // implicit cast to PositionConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
runepagesConfig = getValue<GeneralRunePageConfig>(j, "runepages");
|
||||
|
||||
enabledAutoAccept = getValue(j, "enabledAutoAccept", true);
|
||||
enabledSmiteWarn = getValue(j, "enabledSmiteWarn", true);
|
||||
enabledAutoWrite = getValue(j, "enabledAutoWrite", false);
|
||||
autoWriteText = getValue<QString>(j, "autoWriteText");
|
||||
}
|
||||
|
||||
Config::RootConfig::operator QJsonObject() const {
|
||||
QJsonObject out;
|
||||
|
||||
out.insert("prepick", (QJsonObject) prepick);
|
||||
out.insert("ban", (QJsonObject) ban);
|
||||
out.insert("pick", (QJsonObject) pick);
|
||||
QJsonArray positionarr;
|
||||
for(auto pos : positionConfigs) {
|
||||
positionarr.push_back((QJsonObject) *pos.get());
|
||||
}
|
||||
|
||||
out["positions"] = positionarr;
|
||||
out["runepages"] = (QJsonObject) runepagesConfig;
|
||||
out.insert("enabledAutoAccept", enabledAutoAccept);
|
||||
out.insert("enabledSmiteWarn", enabledSmiteWarn);
|
||||
out.insert("enabledAutoWrite", enabledAutoWrite);
|
||||
out.insert("autoWriteText", autoWriteText);
|
||||
out.insert("version", 1);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::shared_ptr<Config::PositionConfig> Config::RootConfig::getPositionConfig(Position position) {
|
||||
// find existing configuration with given position
|
||||
for(auto posc : positionConfigs) {
|
||||
if(posc->position == position) {
|
||||
return posc;
|
||||
}
|
||||
}
|
||||
|
||||
// add a new config
|
||||
auto posconfig = std::make_shared<Config::PositionConfig>();
|
||||
positionConfigs.push_back(posconfig);
|
||||
posconfig->position = position;
|
||||
return posconfig;
|
||||
}
|
||||
|
||||
Config::Config() {
|
||||
configFolderPath = getHome() + ".config/lolautoaccept/";
|
||||
configFolderPath = getHome() + CONFPATH;
|
||||
configFilePath = configFolderPath + "config.json";
|
||||
mkdirs(configFolderPath);
|
||||
}
|
||||
|
||||
Config::~Config() {}
|
||||
|
||||
bool Config::load() {
|
||||
QFile conffile(QString::fromStdString(configFilePath));
|
||||
QFile conffile(configFilePath);
|
||||
if(!conffile.open(QIODevice::ReadOnly)) {
|
||||
Log::error << "could not open configfile: " << configFilePath;
|
||||
qCritical() << "could not open configfile: " << configFilePath;
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonParseError err;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(conffile.readAll(), &err);
|
||||
if(err.error != QJsonParseError::NoError) {
|
||||
Log::error << "config parse error: " << err.errorString().toStdString() << " position: " << err.offset;
|
||||
qCritical() << "config parse error: " << err.errorString() << " position: " << err.offset;
|
||||
return false;
|
||||
}
|
||||
if(doc.isObject()) {
|
||||
// implicit cast
|
||||
root = doc.object();
|
||||
Log::info << "config loaded";
|
||||
|
||||
qInfo() << "config loaded";
|
||||
return true;
|
||||
}
|
||||
|
||||
Log::error << "config is not a json object!";
|
||||
qCritical() << "config is not a json object!";
|
||||
return false;
|
||||
}
|
||||
|
||||
void Config::save() {
|
||||
Log::note << "Config::save()";
|
||||
mkdirs(configFolderPath);
|
||||
|
||||
QFile conffile(QString::fromStdString(configFilePath));
|
||||
QFile conffile(configFilePath);
|
||||
if(!conffile.open(QIODevice::WriteOnly)) {
|
||||
Log::error << "could not open configfile: " << configFilePath;
|
||||
qCritical() << "could not open configfile: " << configFilePath;
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonDocument doc;
|
||||
doc.setObject(root);
|
||||
conffile.write(doc.toJson());
|
||||
Log::info << "config saved";
|
||||
qInfo() << "config saved";
|
||||
}
|
||||
|
||||
Config::RootConfig& Config::getConfig() {
|
||||
|
|
|
@ -6,18 +6,20 @@
|
|||
#include <curl/easy.h>
|
||||
#include <Log.h>
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QThread>
|
||||
|
||||
#include <algorithm> // std::max, champ matching
|
||||
|
||||
#include "json.h"
|
||||
|
||||
static const std::string BASEURL = "https://ddragon.leagueoflegends.com/";
|
||||
static const QString BASEURL = "https://ddragon.leagueoflegends.com/";
|
||||
const DataDragon::ChampData DataDragon::EMPTYCHAMP;
|
||||
|
||||
DataDragon::DataDragon(const std::string& locale) : RestClient(BASEURL), locale(locale), cache({{"square", ".png"}, {"loading", "_0.jpg"}, {"splash", "_0.jpg"}}) {
|
||||
startThread();
|
||||
DataDragon::DataDragon(const QString& locale) : RestClient(BASEURL), locale(locale), cache{{"square", ".png"}, {"loading", "_0.jpg"}, {"splash", "_0.jpg"}} {
|
||||
this->setObjectName("DataDragon");
|
||||
}
|
||||
|
||||
DataDragon::~DataDragon() {
|
||||
|
@ -27,16 +29,16 @@ DataDragon::~DataDragon() {
|
|||
DataDragon::ChampData::ChampData() : key(-1) {}
|
||||
|
||||
DataDragon::ChampData::ChampData(const QJsonObject& source) {
|
||||
name = getValue<std::string>(source, "name", "");
|
||||
id = getValue<std::string>(source, "id", "");
|
||||
name = getValue<QString>(source, "name", "");
|
||||
id = getValue<QString>(source, "id", "");
|
||||
key = getValue<int>(source, "key", -1);
|
||||
partype = getValue<std::string>(source, "partype", "");
|
||||
title = getValue<std::string>(source, "title", "");
|
||||
partype = getValue<QString>(source, "partype", "");
|
||||
title = getValue<QString>(source, "title", "");
|
||||
}
|
||||
|
||||
const std::string& DataDragon::getVersion() {
|
||||
const QString& DataDragon::getVersion() {
|
||||
std::unique_lock lock(cachedatamutex);
|
||||
while(version.empty() && shouldrun) {
|
||||
while(version.isEmpty() && shouldrun) {
|
||||
cachedatacv.wait(lock);
|
||||
}
|
||||
return version;
|
||||
|
@ -50,8 +52,8 @@ const std::vector<DataDragon::ChampData>& DataDragon::getChamps() {
|
|||
return champs;
|
||||
}
|
||||
|
||||
QPixmap DataDragon::getImage(const std::string& champid, ImageType imgtype) {
|
||||
if(champid.empty()) return {};
|
||||
QPixmap DataDragon::getImage(const QString& champid, ImageType imgtype, bool writeMemcache) {
|
||||
if(champid.isEmpty()) return {};
|
||||
|
||||
// query mem cache
|
||||
QPixmap img = memcache.getImage(champid, (int) imgtype);
|
||||
|
@ -65,35 +67,44 @@ QPixmap DataDragon::getImage(const std::string& champid, ImageType imgtype) {
|
|||
return img;
|
||||
}
|
||||
|
||||
const std::string url = getImageUrl(champid, imgtype);
|
||||
if(url.empty()) return {};
|
||||
const QString url = getImageUrl(champid, imgtype);
|
||||
if(url.isEmpty()) 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";
|
||||
qCritical() << "image could not be loaded";
|
||||
return {};
|
||||
}
|
||||
|
||||
// propably an error
|
||||
if(arr.size() < 1000) {
|
||||
Log::info << "small icon url: " << url;
|
||||
Log::info << "content: " << std::string(arr.data(), arr.size());
|
||||
qInfo() << "small icon url: " << url;
|
||||
qInfo() << "content: " << QString::fromLocal8Bit(arr);
|
||||
return {};
|
||||
}
|
||||
|
||||
// store HDD cache
|
||||
cache[(int) imgtype].addImageRaw(arr, champid);
|
||||
|
||||
// remove from notDownloadedList
|
||||
notDownloadedImages.erase(champid);
|
||||
|
||||
QPixmap decodedImage;
|
||||
decodedImage.loadFromData(arr);
|
||||
|
||||
// store mem cache
|
||||
memcache.addImage(decodedImage, champid, (int) imgtype);
|
||||
if(writeMemcache) {
|
||||
memcache.addImage(decodedImage, champid, (int) imgtype);
|
||||
}
|
||||
|
||||
return decodedImage;
|
||||
}
|
||||
|
||||
void DataDragon::getImageAsnyc(const std::string& champid, notifyImgfunc_t func, ImageType imgtype) {
|
||||
void DataDragon::getImageAsnyc(const QString& champid, notifyImgfunc_t func, ImageType imgtype) {
|
||||
if(!func) return;
|
||||
|
||||
{
|
||||
|
@ -103,44 +114,40 @@ void DataDragon::getImageAsnyc(const std::string& champid, notifyImgfunc_t func,
|
|||
tasksnotemptycv.notify_one();
|
||||
}
|
||||
|
||||
static std::string toLower(const std::string& in) {
|
||||
return QString::fromStdString(in).toLower().toStdString();
|
||||
}
|
||||
|
||||
static size_t startinglength(const std::string& original, const std::string& prefix) {
|
||||
size_t i = 0;
|
||||
static int startinglength(const QString& original, const QString& prefix) {
|
||||
int i = 0;
|
||||
for(; i < original.size() && i < prefix.size(); ++i) {
|
||||
if(original.substr(0, i+1) != prefix.substr(0, i+1)) {
|
||||
if(original.left(i+1) != prefix.left(i+1)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static size_t matchChamp(const DataDragon::ChampData& champ, const std::string& lower) {
|
||||
std::string lowerid = toLower(champ.id);
|
||||
std::string lowername = toLower(champ.name);
|
||||
static size_t matchChamp(const DataDragon::ChampData& champ, const QString& lower) {
|
||||
QString lowerid = champ.id.toLower();
|
||||
QString lowername = champ.name.toLower();
|
||||
if(lowerid == lower || lowername == lower) {
|
||||
return lower.size();
|
||||
}
|
||||
|
||||
size_t lengtha = startinglength(lowerid, lower);
|
||||
size_t lengthb = startinglength(lowername, lower);
|
||||
int lengtha = startinglength(lowerid, lower);
|
||||
int lengthb = startinglength(lowername, lower);
|
||||
|
||||
return std::max(lengtha, lengthb);
|
||||
return qMax(lengtha, lengthb);
|
||||
}
|
||||
|
||||
const DataDragon::ChampData& DataDragon::getBestMatchingChamp(const std::string& name, int* count) {
|
||||
const DataDragon::ChampData& DataDragon::getBestMatchingChamp(const QString& name, int* count) {
|
||||
getChamps();
|
||||
// for now: just check for a perfect hit
|
||||
std::string lower = toLower(name);
|
||||
QString lower = name.toLower();
|
||||
int bestmatchingoffset = -1;
|
||||
size_t bestmatchinglength = 0;
|
||||
int bestmatchinglength = 0;
|
||||
uint32_t bestmatchingcount = 0;
|
||||
for(size_t offset = 0; offset < champs.size(); ++offset) {
|
||||
const ChampData& it = champs.at(offset);
|
||||
|
||||
size_t match = matchChamp(it, lower);
|
||||
int match = matchChamp(it, lower);
|
||||
if(match > bestmatchinglength) {
|
||||
bestmatchinglength = match;
|
||||
bestmatchingcount = 1;
|
||||
|
@ -162,12 +169,12 @@ const DataDragon::ChampData& DataDragon::getBestMatchingChamp(const std::string&
|
|||
return EMPTYCHAMP;
|
||||
}
|
||||
|
||||
std::vector<const DataDragon::ChampData*> DataDragon::getMatchingChamp(const std::string& name, uint32_t limit) {
|
||||
std::vector<const DataDragon::ChampData*> DataDragon::getMatchingChamp(const QString& name, uint32_t limit) {
|
||||
if(limit == 0) return {};
|
||||
if(name.empty()) return {};
|
||||
if(name.isEmpty()) return {};
|
||||
|
||||
getChamps();
|
||||
std::string lower = toLower(name);
|
||||
QString lower = name.toLower();
|
||||
|
||||
std::vector<size_t> matches;
|
||||
matches.resize(champs.size());
|
||||
|
@ -192,10 +199,50 @@ std::vector<const DataDragon::ChampData*> DataDragon::getMatchingChamp(const std
|
|||
return out;
|
||||
}
|
||||
|
||||
std::string DataDragon::getImageUrl(const std::string& champid, ImageType type) {
|
||||
const DataDragon::ChampData* DataDragon::getChampByID(uint32_t id) {
|
||||
getChamps();
|
||||
|
||||
auto it = std::find_if(champs.begin(), champs.end(), [id](const ChampData& cd) { return cd.key == (int) id; });
|
||||
|
||||
// nothing found
|
||||
if(it == champs.end()) return nullptr;
|
||||
|
||||
return &*it;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> DataDragon::resolveChampIDs(const std::vector<QString>& champnames) {
|
||||
std::vector<uint32_t> out;
|
||||
out.reserve(champnames.size());
|
||||
|
||||
std::transform(champnames.begin(), champnames.end(), std::insert_iterator(out, out.begin()), [this](const QString& champname) {
|
||||
auto cd = getBestMatchingChamp(champname);
|
||||
return cd.key; // might be 0 (invalid)
|
||||
});
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void DataDragon::startThread() {
|
||||
shouldrun = true;
|
||||
bgthread = QThread::create(&DataDragon::threadLoop, this);
|
||||
bgthread->setObjectName("DataDragonThread");
|
||||
bgthread->start();
|
||||
this->moveToThread(bgthread);
|
||||
}
|
||||
|
||||
void DataDragon::stop() {
|
||||
qDebug() << "stop DataDragon";
|
||||
shouldrun = false;
|
||||
std::unique_lock lock(tasksmutex);
|
||||
|
||||
tasks.clear();
|
||||
notDownloadedImages.clear(); // this is a possible race condition!
|
||||
}
|
||||
|
||||
QString DataDragon::getImageUrl(const QString& champid, ImageType type) {
|
||||
switch(type) {
|
||||
case ImageType::SQUARE: {
|
||||
if(getVersion().empty()) {
|
||||
if(getVersion().isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -212,64 +259,82 @@ std::string DataDragon::getImageUrl(const std::string& champid, ImageType type)
|
|||
return {};
|
||||
}
|
||||
|
||||
std::string DataDragon::getCDNString() const {
|
||||
QString DataDragon::getCDNString() const {
|
||||
return "cdn/" + version + "/";
|
||||
}
|
||||
|
||||
void DataDragon::prefetchChampImage(const QString& champid, ImageType imgtype) {
|
||||
if(!cache[(int) imgtype].hasImage(champid)) {
|
||||
qDebug() << "prefetch " << champid << " type: " << (int) imgtype;
|
||||
getImage(champid, imgtype, false);
|
||||
}
|
||||
}
|
||||
|
||||
void DataDragon::getVersionInternal() {
|
||||
std::unique_lock lock(cachedatamutex);
|
||||
|
||||
if(!version.empty()) return;
|
||||
if(!version.isEmpty()) 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;
|
||||
version = champCache.getVersion();
|
||||
if(!version.isEmpty()) return;
|
||||
|
||||
lock.unlock();
|
||||
cachedatacv.notify_all();
|
||||
return;
|
||||
try {
|
||||
QJsonDocument jversions = request("api/versions.json");
|
||||
if(jversions.isArray()) {
|
||||
QJsonArray jverarr = jversions.array();
|
||||
if(!jverarr.empty()) {
|
||||
version = jverarr.at(0).toString();
|
||||
qInfo() << "got League version: " << version;
|
||||
|
||||
lock.unlock();
|
||||
cachedatacv.notify_all();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Log::error << "error parsing version object";
|
||||
qCritical() << "error parsing version object";
|
||||
} catch(RestClient::WebException& e) {}
|
||||
}
|
||||
|
||||
void DataDragon::getChampsInternal() {
|
||||
std::unique_lock lock(cachedatamutex);
|
||||
if(!champs.empty() && version.empty()) {
|
||||
if(!champs.empty() && version.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonDocument 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");
|
||||
QJsonDocument jchamps = champCache.getChamps();
|
||||
bool cacheSuccessfull = !jchamps.isEmpty();
|
||||
if(!cacheSuccessfull) {
|
||||
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
|
||||
if(!cacheSuccessfull) {
|
||||
champCache.saveChamps(jchamps, version);
|
||||
}
|
||||
|
||||
QJsonObject obj = jchamps.object();
|
||||
auto it = obj.constFind("data");
|
||||
if(it != obj.constEnd() && it.value().isObject()) {
|
||||
QJsonObject jchampsdata = it.value().toObject();
|
||||
for(auto champit = jchampsdata.constBegin(); champit != jchampsdata.constEnd(); champit++) {
|
||||
if(champit.value().isObject()) {
|
||||
champs.emplace_back(champit.value().toObject());
|
||||
if(it != obj.constEnd() && it->isObject()) {
|
||||
for(auto&& champdata : it->toObject()) {
|
||||
if(champdata.isObject()) {
|
||||
auto& dataobj = champs.emplace_back(champdata.toObject());
|
||||
notDownloadedImages.insert(dataobj.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Log::info << "loaded " << champs.size() << " champs";
|
||||
qInfo() << "loaded " << champs.size() << " champs from cache: " << cacheSuccessfull;
|
||||
lock.unlock();
|
||||
cachedatacv.notify_all();
|
||||
}
|
||||
|
||||
void DataDragon::startThread() {
|
||||
shouldrun = true;
|
||||
bgthread = std::thread(&DataDragon::threadLoop, this);
|
||||
}
|
||||
|
||||
void DataDragon::stopThread() {
|
||||
shouldrun = false;
|
||||
tasksnotemptycv.notify_all();
|
||||
|
@ -278,11 +343,12 @@ void DataDragon::stopThread() {
|
|||
void DataDragon::stopAndJoinThread() {
|
||||
stopThread();
|
||||
|
||||
if(bgthread.joinable())
|
||||
bgthread.join();
|
||||
bgthread->wait();
|
||||
}
|
||||
|
||||
void DataDragon::threadLoop() {
|
||||
QEventLoop loop;
|
||||
|
||||
// init version and champ list
|
||||
getVersionInternal();
|
||||
getChampsInternal();
|
||||
|
@ -293,20 +359,54 @@ void DataDragon::threadLoop() {
|
|||
{
|
||||
std::unique_lock lock(tasksmutex);
|
||||
if(tasks.empty()) {
|
||||
tasksnotemptycv.wait(lock);
|
||||
if(notDownloadedImages.empty()) {
|
||||
tasksnotemptycv.wait(lock);
|
||||
} else {
|
||||
Log::note << "DataDragon background thread is idleing - prefetching champion images TODO: " << notDownloadedImages.size();
|
||||
|
||||
while(shouldrun && !notDownloadedImages.empty() && tasks.empty()) {
|
||||
lock.unlock();
|
||||
|
||||
auto it = notDownloadedImages.begin();
|
||||
auto champid = std::move(notDownloadedImages.extract(it).value());
|
||||
|
||||
prefetchChampImage(champid, ImageType::SQUARE);
|
||||
|
||||
emit this->loading(1.0 - (notDownloadedImages.size() / (float) champs.size()));
|
||||
emit this->fetchingChamp(champid);
|
||||
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
if(notDownloadedImages.empty() && tasks.empty()) {
|
||||
// everything prefetched, but nothing more to do
|
||||
static bool once = false;
|
||||
if(!once) {
|
||||
once = true;
|
||||
Log::note << "all champs are prefetched now";
|
||||
emit this->loading( 1.0 );
|
||||
}
|
||||
|
||||
tasksnotemptycv.wait(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(tasks.empty()) continue;
|
||||
|
||||
t = tasks.front();
|
||||
tasks.pop_front();
|
||||
}
|
||||
|
||||
loop.processEvents();
|
||||
|
||||
QPixmap img = getImage(t.champid, t.type);
|
||||
t.func(img);
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "DataDragon Thread terminated";
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& str, const DataDragon::ChampData& cd) {
|
||||
return str << "[n: " << cd.name << " " << " k: " << cd.key << " id: " << cd.id << "]";
|
||||
return str << "[n: " << cd.name.toStdString() << " " << " k: " << cd.key << " id: " << cd.id.toStdString() << "]";
|
||||
}
|
||||
|
|
|
@ -7,24 +7,29 @@
|
|||
|
||||
#include "files.h"
|
||||
|
||||
DataDragonImageCache::DataDragonImageCache(const std::string& folderextra, const std::string& imageext) : imageext(imageext) {
|
||||
DataDragonImageCache::DataDragonImageCache(const QString& folderextra, const QString& imageext) : imageext(imageext) {
|
||||
// init cache dir
|
||||
cacheDir = getHome() + ".cache/lolautoaccept/" + folderextra + "/";
|
||||
cacheDir = getCache() + folderextra + "/";
|
||||
|
||||
mkdirs(cacheDir);
|
||||
}
|
||||
DataDragonImageCache::~DataDragonImageCache() {}
|
||||
|
||||
QPixmap DataDragonImageCache::getImage(const std::string& name) {
|
||||
return QPixmap(QString::fromStdString(getFilepath(name)));
|
||||
bool DataDragonImageCache::hasImage(const QString& name) {
|
||||
QFile file(getFilepath(name));
|
||||
return file.size() > 1024; // a image with less than 1KiB? assume it would be readable (r-Permissions)
|
||||
}
|
||||
|
||||
void DataDragonImageCache::addImageRaw(const QByteArray& arr, const std::string& name) {
|
||||
QFile file(QString::fromStdString(getFilepath(name)));
|
||||
QPixmap DataDragonImageCache::getImage(const QString& name) {
|
||||
return QPixmap(getFilepath(name));
|
||||
}
|
||||
|
||||
void DataDragonImageCache::addImageRaw(const QByteArray& arr, const QString& name) {
|
||||
QFile file(getFilepath(name));
|
||||
file.open(QIODevice::WriteOnly);
|
||||
file.write(arr);
|
||||
}
|
||||
|
||||
std::string DataDragonImageCache::getFilepath(const std::string& name) const {
|
||||
QString DataDragonImageCache::getFilepath(const QString& name) const {
|
||||
return cacheDir + name + imageext;
|
||||
}
|
||||
|
|
|
@ -2,28 +2,42 @@
|
|||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <QDir>
|
||||
|
||||
#include <Log.h>
|
||||
|
||||
bool mkdirs(const std::string& path) {
|
||||
size_t offset = 0;
|
||||
while(offset < path.size()) {
|
||||
offset = path.find('/', offset+1);
|
||||
int res = mkdir(path.substr(0, offset).c_str(), S_IRWXU | S_IRWXG); // 770
|
||||
if(res == -1 && errno != EEXIST) {
|
||||
// mkdirs failed
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#ifdef WIN32
|
||||
#define CACHEPATH "lolautoacceptor/cache/"
|
||||
#else
|
||||
#define CACHEPATH ".cache/lolautoaccept/"
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
#ifdef WIN32
|
||||
|
||||
|
||||
std::string getHome() {
|
||||
const char* homevar = getenv("HOME");
|
||||
QString getHome() {
|
||||
const char* homevar = getenv("appdata");
|
||||
if(homevar == nullptr) {
|
||||
Log::warn << "$HOME is not set! Defaulting to ./";
|
||||
qWarning() << "%appdata% is not set! Defaulting to ./";
|
||||
return "./";
|
||||
}
|
||||
return std::string(homevar) + "/";
|
||||
}
|
||||
return QString(homevar) + "/";
|
||||
}
|
||||
#else
|
||||
|
||||
QString getHome() {
|
||||
const char* homevar = getenv("HOME");
|
||||
if(homevar == nullptr) {
|
||||
qWarning() << "$HOME is not set! Defaulting to ./";
|
||||
return "./";
|
||||
}
|
||||
return QString(homevar) + "/";
|
||||
}
|
||||
#endif
|
||||
|
||||
bool mkdirs(const QString& path) {
|
||||
return QDir::root().mkpath(path);
|
||||
}
|
||||
|
||||
QString getCache() {
|
||||
return getHome() + CACHEPATH;
|
||||
}
|
||||
|
|
19
src/json.cpp
|
@ -7,6 +7,13 @@ int convert(const QJsonValue& val) {
|
|||
return val.toInt();
|
||||
}
|
||||
|
||||
template<>
|
||||
uint32_t convert(const QJsonValue& val) {
|
||||
if(val.isString())
|
||||
return val.toString().toUInt();
|
||||
return (uint32_t) val.toDouble();
|
||||
}
|
||||
|
||||
template<>
|
||||
int64_t convert(const QJsonValue& val) {
|
||||
if(val.isString())
|
||||
|
@ -14,11 +21,23 @@ int64_t convert(const QJsonValue& val) {
|
|||
return (int64_t) val.toDouble();
|
||||
}
|
||||
|
||||
template<>
|
||||
uint64_t convert(const QJsonValue& val) {
|
||||
if(val.isString())
|
||||
return val.toString().toULongLong();
|
||||
return (uint64_t) val.toDouble();
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string convert(const QJsonValue& val) {
|
||||
return val.toString().toStdString();
|
||||
}
|
||||
|
||||
template<>
|
||||
QString convert(const QJsonValue& val) {
|
||||
return val.toString();
|
||||
}
|
||||
|
||||
template<>
|
||||
bool convert(const QJsonValue& val) {
|
||||
if(val.isString())
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#include "loadingwindow.h"
|
||||
#include "ui_loadingwindow.h"
|
||||
|
||||
LoadingWindow::LoadingWindow(QWidget* parent) : QWidget(parent), ui(new Ui::LoadingWindow) {
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
LoadingWindow::~LoadingWindow() {
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void LoadingWindow::setChampion(QString championName) {
|
||||
this->setText(LoadingWindow::tr("Loading Champion: %0").arg(championName));
|
||||
}
|
||||
|
||||
void LoadingWindow::setText(QString text) {
|
||||
ui->label->setText(text);
|
||||
}
|
||||
|
||||
void LoadingWindow::setProgress(float val) {
|
||||
ui->progressBar->setValue(val * 100);
|
||||
}
|
||||
|
||||
void LoadingWindow::closeEvent(QCloseEvent* event) {
|
||||
QWidget::closeEvent(event);
|
||||
emit this->closed();
|
||||
}
|
|
@ -1,46 +1,52 @@
|
|||
#include "lolautoaccept.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
#include <Log.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
LolAutoAccept::Stage::Stage() {}
|
||||
LolAutoAccept::Stage::~Stage() {}
|
||||
|
||||
LolAutoAccept::LolAutoAccept() {
|
||||
stages.reserve(4);
|
||||
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(Config::RootConfig& config, DataDragon& dd, QObject* parent) : QObject(parent), config(config), dd(dd) {
|
||||
qRegisterMetaType<LolAutoAccept::Status>();
|
||||
|
||||
std::lock_guard lock(stagesMutex);
|
||||
stages.resize(3); // accept, ban, pick
|
||||
}
|
||||
|
||||
LolAutoAccept::~LolAutoAccept() {
|
||||
stopJoinThread();
|
||||
|
||||
for(auto s : stages) {
|
||||
delete s;
|
||||
}
|
||||
}
|
||||
|
||||
void LolAutoAccept::setChamps(const std::vector<uint32_t>& champs, State s) {
|
||||
if(s == State::LOBBY || s >= State::GAME) {
|
||||
Log::warn << "setChamps() called on invalid State";
|
||||
if(s == State::LOBBY || s >= State::PICK) {
|
||||
qWarning() << "setChamps() called on invalid State";
|
||||
return;
|
||||
}
|
||||
qDebug() << "LolAutoAccept::setChamps";
|
||||
|
||||
stages.at((int) s)->champids = champs;
|
||||
stages.at((int) s)->currentOffset = 0;
|
||||
Log::info << "set champs on state: " << (int) s << " count: " << champs.size();
|
||||
{
|
||||
std::lock_guard lock(stagesMutex);
|
||||
stages.at((int) s).champids = champs;
|
||||
stages.at((int) s).currentOffset = 0;
|
||||
}
|
||||
qInfo() << "set champs on state: " << (int) s << " count: " << champs.size();
|
||||
}
|
||||
|
||||
void LolAutoAccept::setEnabled(bool b, State s) {
|
||||
if(s >= State::GAME) {
|
||||
Log::warn << "setEnabled() called on invalid State";
|
||||
if(s > State::PICK) {
|
||||
qWarning() << "setEnabled() called on invalid State";
|
||||
return;
|
||||
}
|
||||
|
||||
stages.at((int) s)->enabled = b;
|
||||
std::lock_guard lock(stagesMutex);
|
||||
stages.at((int) s).enabled = b;
|
||||
}
|
||||
|
||||
void LolAutoAccept::setSmiteWarn(bool b) {
|
||||
smiteWarnEnabled = b;
|
||||
}
|
||||
|
||||
bool LolAutoAccept::init() {
|
||||
|
@ -50,8 +56,7 @@ bool LolAutoAccept::init() {
|
|||
if(ca) {
|
||||
clientapi = std::make_shared<ClientAPI>(*ca.get());
|
||||
auto selfinfo = clientapi->getSelf();
|
||||
summonerid = selfinfo.summonerid;
|
||||
Log::info << "selfinfo: gameName: " << selfinfo.gameName << " name: " << selfinfo.name << " summonerid: " << selfinfo.summonerid << " statusMessage: " << selfinfo.statusMessage << " puuid: " << selfinfo.puuid << " level: " << selfinfo.level;
|
||||
qInfo() << "selfinfo: gameName: " << selfinfo.gameName << " name: " << selfinfo.name << " summonerid: " << selfinfo.summonerid << " statusMessage: " << selfinfo.statusMessage << " puuid: " << selfinfo.puuid << " level: " << selfinfo.level;
|
||||
}
|
||||
|
||||
return (bool) clientapi;
|
||||
|
@ -70,6 +75,51 @@ void LolAutoAccept::stop() {
|
|||
shouldrun = false;
|
||||
}
|
||||
|
||||
LolAutoAccept::Status LolAutoAccept::getStatus() {
|
||||
return shouldrun ? Status::Running : Status::Off;
|
||||
}
|
||||
|
||||
void LolAutoAccept::reload() {
|
||||
Log::note << "reload LolAutoAccept";
|
||||
if(currentPositionSet)
|
||||
loadPosition(currentPosition);
|
||||
}
|
||||
|
||||
const std::vector<RuneAspekt>& LolAutoAccept::getRuneAspekts() {
|
||||
if(runeaspekts.empty()) {
|
||||
if(clientapi) {
|
||||
runeaspekts = clientapi->getAllRuneAspekts();
|
||||
qInfo() << "Loaded " << runeaspekts.size() << " rune aspekts";
|
||||
}
|
||||
}
|
||||
|
||||
return runeaspekts;
|
||||
}
|
||||
|
||||
const std::vector<RuneStyle>& LolAutoAccept::getRuneStyles() {
|
||||
if(runestyles.empty()) {
|
||||
if(clientapi) {
|
||||
runestyles = clientapi->getAllRuneStyles();
|
||||
qInfo() << "Loaded " << runestyles.size() << " rune styles";
|
||||
}
|
||||
}
|
||||
|
||||
return runestyles;
|
||||
}
|
||||
|
||||
void LolAutoAccept::setAutoWriteText(bool enabled, const QString& text) {
|
||||
if ( enabled && !autoWriteTextEnabled ) {
|
||||
// only re-write on rising edge
|
||||
autoWriteTextDone = false;
|
||||
}
|
||||
autoWriteTextEnabled = enabled;
|
||||
autoWriteText = text;
|
||||
}
|
||||
|
||||
void LolAutoAccept::dodge() {
|
||||
dodgeNow = true;
|
||||
}
|
||||
|
||||
void LolAutoAccept::stopJoinThread() {
|
||||
stop();
|
||||
|
||||
|
@ -82,72 +132,164 @@ void LolAutoAccept::stopJoinThread() {
|
|||
void LolAutoAccept::innerRun() {
|
||||
shouldrun = true;
|
||||
|
||||
while(shouldrun) {
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
try {
|
||||
auto convs = clientapi->getAllConversations();
|
||||
qInfo() << "got " << convs.size() << " conversations";
|
||||
|
||||
auto phase = clientapi->getGameflowPhase();
|
||||
Log::info << "current Gameflowphase: " << phase;
|
||||
emit statusChanged(Status::Running);
|
||||
while(shouldrun) {
|
||||
uint32_t extrasleep = 800;
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// do processing
|
||||
if(phase == ClientAPI::GameflowPhase::READYCHECK) {
|
||||
if(stages.at(0)->enabled) { // auto accept enabled
|
||||
auto state = clientapi->getReadyCheckState();
|
||||
auto phase = clientapi->getGameflowPhase();
|
||||
qInfo() << "current Gameflowphase: " << phase;
|
||||
|
||||
Log::info << "readychack state: " << state;
|
||||
if(state == ClientAPI::ReadyCheckState::INPROGRESS) {
|
||||
Log::info << "auto accepting";
|
||||
clientapi->acceptMatch();
|
||||
// do processing
|
||||
if(phase == ClientAPI::GameflowPhase::LOBBY) {
|
||||
resetAllOffsets();
|
||||
} else if(phase == ClientAPI::GameflowPhase::MATCHMAKING) {
|
||||
extrasleep = 200;
|
||||
resetAllOffsets();
|
||||
} else if(phase == ClientAPI::GameflowPhase::READYCHECK) {
|
||||
if(stages.at(0).enabled) { // auto accept enabled
|
||||
auto state = clientapi->getReadyCheckState();
|
||||
|
||||
qInfo() << "readychack state: " << state;
|
||||
if(state == ClientAPI::ReadyCheckState::INPROGRESS) {
|
||||
qInfo() << "auto accepting";
|
||||
clientapi->acceptMatch();
|
||||
}
|
||||
}
|
||||
resetAllOffsets();
|
||||
extrasleep = 0; // no extra sleep
|
||||
} else if(phase == ClientAPI::GameflowPhase::CHAMPSELECT) {
|
||||
champSelect();
|
||||
extrasleep = 0; // no extra sleep
|
||||
|
||||
// first time champselect phase -> enable dodge button
|
||||
if(lastPhase != phase) {
|
||||
dodgeNow = false;
|
||||
emit this->dodgePossible(true);
|
||||
} else if (dodgeNow) {
|
||||
// this makes sure that the event comes after the phase was entered and is not lingering from before
|
||||
dodgeNow = false;
|
||||
clientapi->dodge();
|
||||
}
|
||||
} else if(phase == ClientAPI::GameflowPhase::INPROGRESS) {
|
||||
extrasleep = 30000; // 30s bonus sleep
|
||||
resetAllOffsets();
|
||||
} else if(phase == ClientAPI::GameflowPhase::ENDOFGAME) {
|
||||
extrasleep = 2000; // 2 s bonus sleep
|
||||
resetAllOffsets();
|
||||
} else if(phase == ClientAPI::GameflowPhase::PREENDOFGAME) {
|
||||
extrasleep = 4000; // 4 s bonus sleep
|
||||
resetAllOffsets();
|
||||
} else if(phase == ClientAPI::GameflowPhase::WAITINGFORSTATS) {
|
||||
extrasleep = 4000; // 4 s bonus sleep
|
||||
resetAllOffsets();
|
||||
} else if(phase == ClientAPI::GameflowPhase::NONE) {
|
||||
extrasleep = 10000; // 10 s bonus sleep - no lobby
|
||||
resetAllOffsets();
|
||||
}
|
||||
resetAllOffsets();
|
||||
} else if(phase == ClientAPI::GameflowPhase::CHAMPSELECT) {
|
||||
champSelect();
|
||||
|
||||
// change phase to non champselect phase -> disable dodge button
|
||||
if(phase != ClientAPI::GameflowPhase::CHAMPSELECT && lastPhase != phase) {
|
||||
emit this->dodgePossible(false);
|
||||
}
|
||||
|
||||
lastPhase = phase;
|
||||
|
||||
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));
|
||||
}
|
||||
emit statusChanged(Status::Off);
|
||||
} catch(RestClient::WebException& e) {
|
||||
qCritical() << "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";
|
||||
// disable this thread
|
||||
shouldrun = false;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1200));
|
||||
}
|
||||
// notify the ui
|
||||
emit statusChanged(Status::Failed);
|
||||
}
|
||||
}
|
||||
|
||||
void LolAutoAccept::resetPickOffsets() {
|
||||
for(Stage& stage : stages) {
|
||||
stage.currentOffset = 0;
|
||||
}
|
||||
lastPickedChamp = 0;
|
||||
}
|
||||
|
||||
void LolAutoAccept::resetAllOffsets() {
|
||||
for(Stage* stage : stages) {
|
||||
stage->currentOffset = 0;
|
||||
}
|
||||
resetPickOffsets();
|
||||
currentPosition = Position::INVALID;
|
||||
currentPositionSet = false;
|
||||
chatid.clear();
|
||||
autoWriteTextDone = false;
|
||||
dodgeNow = false;
|
||||
}
|
||||
|
||||
void LolAutoAccept::applyConfigToStage(Stage& stage, const Config::StageConfig& stageconf) {
|
||||
stage.champids = dd.resolveChampIDs(stageconf.champs);
|
||||
stage.enabled = stageconf.enabled;
|
||||
stage.currentOffset = 0;
|
||||
}
|
||||
|
||||
void LolAutoAccept::loadPosition(Position pos) {
|
||||
Log::trace << __PRETTY_FUNCTION__ << " pos: " << pos;
|
||||
|
||||
// reinit the stages
|
||||
std::lock_guard lock(stagesMutex);
|
||||
stages.resize(1); // first stage does not change
|
||||
stages.resize(3);
|
||||
|
||||
std::shared_ptr<Config::PositionConfig> posconf = config.getPositionConfig(pos);
|
||||
|
||||
applyConfigToStage(stages.at((int) State::BAN), posconf->ban);
|
||||
applyConfigToStage(stages.at((int) State::PICK), posconf->pick);
|
||||
|
||||
currentPosition = pos;
|
||||
currentPositionSet = true;
|
||||
}
|
||||
|
||||
uint32_t LolAutoAccept::getChampOfState(State s) {
|
||||
assert(((int) s) >= 0 && s <= State::PICK);
|
||||
assert(s > State::LOBBY && s <= State::PICK);
|
||||
|
||||
auto stage = stages[(int) s];
|
||||
uint32_t size = stage->champids.size();
|
||||
if(stage->currentOffset >= size) {
|
||||
Stage& stage = stages[(int) s];
|
||||
uint32_t size = stage.champids.size();
|
||||
if(stage.currentOffset >= size) {
|
||||
// no champ to try left
|
||||
Log::warn << "no champ left at stage: " << (int) s;
|
||||
Log::warn << "stage size: " << stage->champids.size();
|
||||
qWarning() << "no champ left at stage: " << (int) s;
|
||||
qWarning() << "stage size: " << stage.champids.size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return stage->champids[stage->currentOffset];
|
||||
return stage.champids[stage.currentOffset];
|
||||
}
|
||||
|
||||
void LolAutoAccept::nextChampOfState(State s) {
|
||||
assert(((int) s) >= 0 && s <= State::PICK);
|
||||
assert(s > State::LOBBY && s <= State::PICK);
|
||||
|
||||
auto stage = stages[(int) s];
|
||||
uint32_t size = stage->champids.size();
|
||||
Stage& stage = stages[(int) s];
|
||||
uint32_t size = stage.champids.size();
|
||||
|
||||
stage->currentOffset++;
|
||||
stage.currentOffset++;
|
||||
|
||||
if(stage->currentOffset >= size) {
|
||||
if(stage.currentOffset >= size) {
|
||||
// no champ to try left
|
||||
Log::warn << "no champ left at stage: " << (int) s;
|
||||
Log::warn << "stage size: " << stage->champids.size();
|
||||
qWarning() << "no champ left at stage: " << (int) s;
|
||||
qWarning() << "stage size: " << stage.champids.size();
|
||||
|
||||
stage->currentOffset = 0;
|
||||
stage.currentOffset = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +297,16 @@ void LolAutoAccept::nextChampOfState(State s) {
|
|||
bool LolAutoAccept::isChampIntentofTeammate(uint32_t champid, const ClientAPI::ChampSelectSession& session) {
|
||||
for(const ClientAPI::ChampSelectCell& player : session.myTeam) {
|
||||
if(player.championID == (int32_t) champid || player.championPickIntentID == (int32_t) champid) {
|
||||
Log::info << "player " << player.cellID << " @ " << player.position << " wants to play " << champid;
|
||||
qInfo() << "player " << player.cellID << " @ " << toString(player.position) << " wants to play " << champid;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LolAutoAccept::isChampBanned(uint32_t champid, const ClientAPI::ChampSelectSession& session) {
|
||||
for(const ClientAPI::ChampSelectAction& act : session.actions) {
|
||||
if(act.type == ClientAPI::ChampSelectActionType::BAN && act.championID == (int32_t) champid && act.completed) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +317,7 @@ LolAutoAccept::ownactions_t LolAutoAccept::getOwnActions(int32_t cellid, const s
|
|||
ownactions_t out;
|
||||
for(const auto& it : actions) {
|
||||
if(it.actorCellID == cellid) {
|
||||
Log::debug << "ownaction: id: " << it.id << " champid: " << it.championID << " completed: " << it.completed << " type: " << it.type;
|
||||
qDebug() << "ownaction: id: " << it.id << " champid: " << it.championID << " completed: " << it.completed << " type: " << it.type;
|
||||
if(!it.completed) { // completed cant be interacted anyways, so just ignore them.
|
||||
out.push_back(it);
|
||||
}
|
||||
|
@ -176,12 +327,12 @@ LolAutoAccept::ownactions_t LolAutoAccept::getOwnActions(int32_t cellid, const s
|
|||
}
|
||||
|
||||
void LolAutoAccept::prepickPhase(const ownactions_t& ownactions) {
|
||||
phase(ownactions, ClientAPI::ChampSelectActionType::PICK, State::PREPICK, false);
|
||||
phase(ownactions, ClientAPI::ChampSelectActionType::PICK, State::PICK, false);
|
||||
}
|
||||
|
||||
void LolAutoAccept::banPhase(const ownactions_t& ownactions, const ClientAPI::ChampSelectSession& session) {
|
||||
phase(ownactions, ClientAPI::ChampSelectActionType::BAN, State::BAN, true, [session](uint32_t champid) {
|
||||
return !isChampIntentofTeammate(champid, session);
|
||||
return !isChampIntentofTeammate(champid, session) && !isChampBanned(champid, session);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -190,22 +341,28 @@ void LolAutoAccept::pickPhase(const ownactions_t& ownactions) {
|
|||
}
|
||||
|
||||
void LolAutoAccept::phase(const ownactions_t& ownactions, ClientAPI::ChampSelectActionType type, State s, bool complete, std::function<bool(uint32_t)> filter) {
|
||||
if ( !( stages.at((int) s).enabled ) ) {
|
||||
qDebug() << (int) s << " stage is disabled. skipping";
|
||||
return;
|
||||
}
|
||||
|
||||
for(auto it : ownactions) {
|
||||
if(it.type == type) {
|
||||
Log::info << type << " action anvailable: " << it.id << " champid: " << it.championID;
|
||||
qInfo() << type << " action anvailable: " << it.id << " champid: " << it.championID;
|
||||
uint32_t champid = getChampOfState(s);
|
||||
|
||||
if(filter) {
|
||||
// filter says no
|
||||
if(!filter(champid)) {
|
||||
Log::trace << "champid: " << champid << " filter says no - next champ";
|
||||
nextChampOfState(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(it.championID != (int32_t) champid || !it.completed) {
|
||||
if((it.championID != (int32_t) champid || !it.completed) && champid != 0) {
|
||||
// try to prepick a champion
|
||||
Log::info << "try to pick champ: " << champid;
|
||||
qInfo() << "try to pick champ: " << champid;
|
||||
|
||||
if(!clientapi->setChampSelectAction(it.id, champid, complete)) {
|
||||
nextChampOfState(s);
|
||||
|
@ -216,29 +373,81 @@ void LolAutoAccept::phase(const ownactions_t& ownactions, ClientAPI::ChampSelect
|
|||
}
|
||||
}
|
||||
|
||||
int32_t LolAutoAccept::getBestRunePage(const std::vector<ClientAPI::RunePage>& pages) {
|
||||
qDebug() << "searching RunePages: " << pages.size();
|
||||
for(uint32_t i = 0; i < pages.size(); ++i) {
|
||||
qDebug() << i << ": " << pages[i].id << " " << pages[i].name << " " << pages[i].isCurrent;
|
||||
}
|
||||
|
||||
// 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.left(4) == "AA: ") {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// search for a selected rune page
|
||||
for(uint32_t i = 0; i < pages.size(); ++i) {
|
||||
const ClientAPI::RunePage& rp = pages.at(i);
|
||||
if(rp.isCurrent) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
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;
|
||||
const int32_t cellid = session.localPlayerCellId;
|
||||
|
||||
if(cellid != lastCellId && lastCellId != -1) {
|
||||
resetPickOffsets();
|
||||
}
|
||||
lastCellId = cellid;
|
||||
|
||||
// find own cellid info
|
||||
const ClientAPI::ChampSelectCell* me = nullptr;
|
||||
uint32_t pickedChamp = 0;
|
||||
for(const auto& it : session.myTeam) {
|
||||
if(it.cellID == cellid) {
|
||||
me = ⁢
|
||||
pickedChamp = it.championID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ClientAPI::Position pos = me ? me->position : ClientAPI::Position::INVALID;
|
||||
Position pos = me ? me->position : Position::INVALID;
|
||||
|
||||
Log::debug << "cellid: " << cellid << " position: " << pos << " counter: " << session.counter << " timer: timeleftip: " << session.timer.adjustedTimeLeftInPhase << " totaltimephase: " << session.timer.totalTimeInPhase;
|
||||
// check if runes need adjustment
|
||||
if(pickedChamp != lastPickedChamp) {
|
||||
qInfo() << "picked champ changed from: " << lastPickedChamp << " to: " << pickedChamp;
|
||||
lastPickedChamp = pickedChamp;
|
||||
}
|
||||
|
||||
// reload config based on position if changed
|
||||
if(pos != currentPosition || !currentPositionSet) {
|
||||
Log::note << "LolAutoAccept reloading config for position: " << pos << " because it was: " << currentPosition;
|
||||
loadPosition(pos);
|
||||
|
||||
emit positionChanged(pos);
|
||||
}
|
||||
|
||||
qDebug() << "cellid: " << cellid << " position: " << toString(pos) << " counter: " << session.counter << " timer: timeleftip: " << session.timer.adjustedTimeLeftInPhase << " totaltimephase: " << session.timer.totalTimeInPhase;
|
||||
// find actions for own cell
|
||||
auto ownactions = getOwnActions(cellid, session.actions);
|
||||
Log::debug << "ownactions: " << ownactions.size();
|
||||
qDebug() << "ownactions: " << ownactions.size();
|
||||
|
||||
// try to prepick champ
|
||||
Log::info << "champselectphase: " << session.timer.phase;
|
||||
qInfo() << "champselectphase: " << session.timer.phase;
|
||||
|
||||
std::lock_guard lock(stagesMutex);
|
||||
if(session.timer.phase == ClientAPI::ChampSelectPhase::PLANNING) {
|
||||
prepickPhase(ownactions);
|
||||
} else if(session.timer.phase == ClientAPI::ChampSelectPhase::BAN_PICK) {
|
||||
|
@ -246,5 +455,59 @@ void LolAutoAccept::champSelect() {
|
|||
pickPhase(ownactions);
|
||||
} else if(session.timer.phase == ClientAPI::ChampSelectPhase::FINALIZATION) {
|
||||
// trade?
|
||||
|
||||
// check for smite
|
||||
if(smiteWarnEnabled) {
|
||||
smiteWarning(session.myTeam);
|
||||
}
|
||||
}
|
||||
|
||||
// check for autowriteText
|
||||
if(autoWriteTextEnabled && !autoWriteTextDone && !autoWriteText.isEmpty()) {
|
||||
const QString& chatid = getChatid();
|
||||
if(!chatid.isEmpty()) {
|
||||
clientapi->sendMessage(chatid, autoWriteText);
|
||||
autoWriteTextDone = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LolAutoAccept::smiteWarning(const std::vector<ClientAPI::ChampSelectCell>& cells) {
|
||||
uint32_t smiteCount = 0;
|
||||
for(const ClientAPI::ChampSelectCell& member : cells) {
|
||||
qInfo() << "position: " << toString(member.position) << " spells: " << member.spell1Id << " " << member.spell2Id;
|
||||
smiteCount += (member.spell1Id == 11 || member.spell2Id == 11);
|
||||
}
|
||||
|
||||
if(smiteCount != 1) {
|
||||
// check timeout
|
||||
std::chrono::time_point<std::chrono::system_clock> currenttime = std::chrono::system_clock::now();
|
||||
if((currenttime - lastMessageSent) < std::chrono::seconds(2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
qInfo() << "smite warning: " << smiteCount;
|
||||
const QString& chatid = getChatid();
|
||||
if(!chatid.isEmpty()) {
|
||||
clientapi->sendMessage(chatid, "smite");
|
||||
lastMessageSent = currenttime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const QString& LolAutoAccept::getChatid() {
|
||||
if(chatid.isEmpty()) {
|
||||
std::vector<ClientAPI::Conversation> convs = clientapi->getAllConversations();
|
||||
qInfo() << "got " << convs.size() << " conversations";
|
||||
|
||||
for(const ClientAPI::Conversation& conv : convs) {
|
||||
qInfo() << " id: " << conv.id << " type: " << conv.type << " name: " << conv.name << " gameName: " << conv.gameName;
|
||||
if(conv.type == "championSelect" && conv.name.isEmpty()) {
|
||||
qInfo() << "groupchat found";
|
||||
chatid = conv.id;
|
||||
return chatid;
|
||||
}
|
||||
}
|
||||
}
|
||||
return chatid; //might be empty string
|
||||
}
|
||||
|
|
54
src/main.cpp
|
@ -8,67 +8,47 @@
|
|||
#include <QTranslator>
|
||||
|
||||
#include <Log.h>
|
||||
#include <QDebug>
|
||||
|
||||
#include "arg.h"
|
||||
#include "mainwindow.h"
|
||||
#include "lolautoaccept.h"
|
||||
#include "clientaccess.h"
|
||||
#include "clientapi.h"
|
||||
|
||||
static std::string getBaseString(char** argv) {
|
||||
std::string base;
|
||||
|
||||
char* appbase = getenv("APPDIR");
|
||||
if(appbase) {
|
||||
return std::string(appbase) + '/';
|
||||
}
|
||||
|
||||
char* cresolved = realpath(argv[0], NULL);
|
||||
std::string resolved(cresolved);
|
||||
free(cresolved);
|
||||
return resolved.substr(0, resolved.rfind('/')+1);
|
||||
}
|
||||
#include "mainwindow.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Log::init();
|
||||
Log::setConsoleLogLevel(Log::Level::INFO);
|
||||
Log::setConsoleLogLevel(Log::Level::info);
|
||||
#if __unix__
|
||||
Log::setColoredOutput(true);
|
||||
#endif
|
||||
|
||||
if(argc == 0) {
|
||||
Log::fatal << "arg[0] is not set";
|
||||
return 1;
|
||||
}
|
||||
|
||||
Args args = parseArgs(argc, argv);
|
||||
if(args.debugLog) {
|
||||
Log::setConsoleLogLevel(Log::Level::TRACE);
|
||||
Log::addLogfile("log.txt", Log::Level::TRACE);
|
||||
Log::debug << "debug Log enabled";
|
||||
Log::setConsoleLogLevel(Log::Level::trace);
|
||||
Log::addLogfile("log.txt", Log::Level::trace);
|
||||
qDebug() << "debug Log enabled";
|
||||
}
|
||||
|
||||
Log::info << "Hello, World!";
|
||||
Log::note << "Using Locale: " << QLocale().name().toStdString();
|
||||
qInfo() << "Hello, World!";
|
||||
qInfo() << "Using Locale: " << QLocale().name();
|
||||
|
||||
std::string base = getBaseString(argv);
|
||||
Log::info << "appbase: " << base;
|
||||
if(args.access) {
|
||||
auto access = ClientAccess::find();
|
||||
qInfo() << "Access: port=" << access->getPort() << " basicAuth=" << access->getBasicAuth();
|
||||
return 0;
|
||||
}
|
||||
|
||||
LolAutoAccept lolaa;
|
||||
QApplication app(argc, argv);
|
||||
QTranslator translator;
|
||||
if(translator.load(QLocale().name(), QString::fromStdString(base + "ts"))) {
|
||||
if(translator.load(QLocale().name(), ":/i18n")) {
|
||||
app.installTranslator(&translator);
|
||||
} else {
|
||||
Log::warn << "translation not found";
|
||||
qWarning() << "translation not found";
|
||||
}
|
||||
MainWindow win(lolaa);
|
||||
QIcon icon(QString::fromStdString(base + "lolautoaccept.png"));
|
||||
win.setWindowIcon(icon);
|
||||
MainWindow win;
|
||||
|
||||
win.show();
|
||||
int ret = app.exec();
|
||||
|
||||
Log::stop();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,130 +1,238 @@
|
|||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QTimer>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <Log.h>
|
||||
|
||||
static void applySetting(const Config::StageConfig& sc, StageSettings* ss) {
|
||||
ss->setState(sc.enabled);
|
||||
ss->setChampions(sc.champs);
|
||||
}
|
||||
#include "loadingwindow.h"
|
||||
#include "x11helper.h"
|
||||
|
||||
MainWindow::MainWindow(LolAutoAccept& lolaa, QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), lolaa(lolaa), dd(QLocale().name().toStdString()) {
|
||||
#ifdef X11SUPPORT
|
||||
#define INIT_X11HELPER new X11Helper(this)
|
||||
#else
|
||||
#define INIT_X11HELPER nullptr
|
||||
#endif
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), loading(true), ui(new Ui::MainWindow), saveTimer(new QTimer(this)), dd(QLocale().name()),
|
||||
lolaa(conf.getConfig(), dd), lwin(new LoadingWindow(nullptr)),
|
||||
dodgeQuestion(new QMessageBox(QMessageBox::Icon::Warning, MainWindow::tr("Dodge?"), MainWindow::tr("Are you sure you want to dodge?"), QMessageBox::Cancel | QMessageBox::Yes, this)),
|
||||
x11Helper(INIT_X11HELPER) {
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->hideLeague->setEnabled(X11Helper::IsSupported);
|
||||
|
||||
QObject::connect(&dd, &DataDragon::fetchingChamp, lwin, &LoadingWindow::setChampion);
|
||||
QObject::connect(&dd, &DataDragon::loading, lwin, &LoadingWindow::setProgress);
|
||||
QObject::connect(&dd, &DataDragon::loading, this, &MainWindow::loadingStatus);
|
||||
QObject::connect(lwin, &LoadingWindow::closed, &dd, &DataDragon::stop);
|
||||
QObject::connect(lwin, &LoadingWindow::closed, qApp, &QCoreApplication::quit, Qt::ConnectionType::QueuedConnection);
|
||||
dd.startThread();
|
||||
|
||||
QObject::connect(&lolaa, &LolAutoAccept::dodgePossible, ui->dodgeBtn, &QAbstractButton::setEnabled);
|
||||
QObject::connect(ui->dodgeBtn, &QAbstractButton::pressed, dodgeQuestion, &QMessageBox::show);
|
||||
QObject::connect(dodgeQuestion, &QMessageBox::accepted, &lolaa, &LolAutoAccept::dodge);
|
||||
QObject::connect(&lolaa, &LolAutoAccept::statusChanged, this, &MainWindow::lolaaStatusChanged);
|
||||
QObject::connect(&lolaa, &LolAutoAccept::positionChanged, this, &MainWindow::onPosChange);
|
||||
|
||||
QObject::connect(ui->hideLeague, &QCheckBox::stateChanged, this, &MainWindow::toggleLeagueVisibility);
|
||||
|
||||
saveTimer->setInterval(std::chrono::minutes(1));
|
||||
saveTimer->setSingleShot(true);
|
||||
QObject::connect(saveTimer, &QTimer::timeout, this, &MainWindow::saveConfig);
|
||||
|
||||
ui->copyrightlabel->setText(ui->copyrightlabel->text().arg(LOLAA_VERSION));
|
||||
|
||||
conf.load();
|
||||
Config::RootConfig& rc = conf.getConfig();
|
||||
|
||||
ui->prepickstage->setDataDragon(&dd);
|
||||
ui->banstage->setDataDragon(&dd);
|
||||
ui->pickstage->setDataDragon(&dd);
|
||||
|
||||
const Config::RootConfig& rc = conf.getConfig();
|
||||
ui->enableAll->setChecked(rc.enabledAutoAccept);
|
||||
lolaa.setEnabled(rc.enabledAutoAccept, LolAutoAccept::State::LOBBY);
|
||||
applySetting(rc.prepick, ui->prepickstage);
|
||||
applySetting(rc.ban, ui->banstage);
|
||||
applySetting(rc.pick, ui->pickstage);
|
||||
|
||||
ui->enableSmiteWarning->setChecked(rc.enabledSmiteWarn);
|
||||
lolaa.setSmiteWarn(rc.enabledSmiteWarn);
|
||||
|
||||
ui->enableAutoWrite->setChecked(rc.enabledAutoWrite);
|
||||
ui->autoWriteText->setText(rc.autoWriteText);
|
||||
lolaa.setAutoWriteText(rc.enabledAutoWrite, rc.autoWriteText);
|
||||
|
||||
resizeEvent(nullptr);
|
||||
|
||||
lwin->show();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {
|
||||
lolaa.stop();
|
||||
conf.save();
|
||||
|
||||
delete ui;
|
||||
delete this->ui;
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent([[maybe_unused]] QCloseEvent* event) {
|
||||
lolaa.stop();
|
||||
conf.save();
|
||||
}
|
||||
|
||||
void MainWindow::resizeEvent([[maybe_unused]] QResizeEvent *event) {
|
||||
ui->verticalLayoutWidget->setMinimumSize(ui->centralwidget->size());
|
||||
ui->verticalLayoutWidget->setMaximumSize(ui->centralwidget->size());
|
||||
ui->verticalLayoutWidget->setMinimumSize(ui->centralwidget->size());
|
||||
void MainWindow::resetSaveTimer() {
|
||||
saveTimer->start();
|
||||
qDebug() << "resetTimer";
|
||||
}
|
||||
|
||||
void MainWindow::loadingStatus(float f) {
|
||||
if(f >= 1.0 && lwin) {
|
||||
// loading complete
|
||||
|
||||
// for all tabs - set their config and datadragon
|
||||
Config::RootConfig& rc = conf.getConfig();
|
||||
for(int32_t tabnr = 0; tabnr < ui->tabWidget->count(); ++tabnr) {
|
||||
SettingsTab* tab = (SettingsTab*) ui->tabWidget->widget(tabnr);
|
||||
tab->setup(*rc.getPositionConfig(tab->getPosition()), &dd);
|
||||
|
||||
QObject::connect(tab, &SettingsTab::changed, this, &MainWindow::tabchanged);
|
||||
QObject::connect(tab, &SettingsTab::toggled, this, &MainWindow::tabtoggled);
|
||||
}
|
||||
|
||||
// load runepage images
|
||||
ui->runesPage->setDataDragon(dd);
|
||||
ui->runesPage->setConfig(conf);
|
||||
|
||||
// switch from loading window to main window
|
||||
lwin->hide();
|
||||
this->show();
|
||||
lwin->deleteLater();
|
||||
lwin = nullptr;
|
||||
|
||||
// a timer to delay the loading flag a short time until all other signals are processed
|
||||
QTimer::singleShot(std::chrono::milliseconds(1), this, &MainWindow::initDone);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::toggleLeagueVisibility() {
|
||||
if(x11Helper) {
|
||||
const bool shouldBeHidden = ui->hideLeague->isChecked();
|
||||
Window win = x11Helper->findWindow("League of Legends", 1280.0/720.0);
|
||||
qInfo() << "LeagueClient win id:" << win;
|
||||
if(win != 0) {
|
||||
x11Helper->setMap(win, shouldBeHidden);
|
||||
} else {
|
||||
// TODO: show error in status bar?
|
||||
// TODO: reset checkbox to unchecked?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::toggleMainswitch(bool state) {
|
||||
Log::info << "mainswitch toggled: " << state;
|
||||
qDebug() << "mainswitch toggled: " << state;
|
||||
|
||||
if(state) {
|
||||
ui->mainswitch->setCheckState(Qt::CheckState::PartiallyChecked);
|
||||
ui->mainswitch->setEnabled(false);
|
||||
|
||||
// make sure the changes to the mainswitch are rendered, before going into the blocking call
|
||||
QCoreApplication::processEvents();
|
||||
|
||||
// TODO: make this non blocking
|
||||
if(!lolaa.init()) {
|
||||
Log::error << "League Client not found!";
|
||||
qCritical() << "League Client not found!";
|
||||
ui->statusbar->showMessage(tr("League of Legends Client not found!"));
|
||||
ui->mainswitch->setCheckState(Qt::CheckState::Unchecked);
|
||||
ui->mainswitch->setEnabled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
lolaa.run();
|
||||
ui->statusbar->showMessage(tr("Auto-Acceptor started!"));
|
||||
} else {
|
||||
lolaa.stop();
|
||||
ui->statusbar->showMessage(tr("Auto-Acceptor stoped!"));
|
||||
ui->mainswitch->setCheckState(Qt::CheckState::PartiallyChecked);
|
||||
ui->mainswitch->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::aatoggled(bool state) {
|
||||
Log::info << "enableAll checkbox toggled " << state;
|
||||
if( loading ) return;
|
||||
|
||||
qDebug() << "enableAll checkbox toggled " << state;
|
||||
|
||||
lolaa.setEnabled(state, LolAutoAccept::State::LOBBY);
|
||||
conf.getConfig().enabledAutoAccept = state;
|
||||
resetSaveTimer();
|
||||
}
|
||||
|
||||
static std::vector<std::string> toChampionNameList(const std::vector<StageSettings::SelectedChamp>& scs) {
|
||||
std::vector<std::string> out;
|
||||
void MainWindow::smitewarntoggled(bool state) {
|
||||
if( loading ) return;
|
||||
|
||||
for(const StageSettings::SelectedChamp& sc : scs) {
|
||||
out.push_back(sc.name);
|
||||
qDebug() << "smitewarn checkbox toggled " << state;
|
||||
|
||||
lolaa.setSmiteWarn(state);
|
||||
conf.getConfig().enabledSmiteWarn = state;
|
||||
resetSaveTimer();
|
||||
}
|
||||
|
||||
void MainWindow::tabtoggled(Position p, LolAutoAccept::State s, bool state) {
|
||||
if( loading ) return;
|
||||
|
||||
qDebug() << "checkbox toggled " << state << " position: " << p << " state: " << (int) s;
|
||||
|
||||
lolaa.setEnabled(state, s);
|
||||
lolaa.reload();
|
||||
resetSaveTimer();
|
||||
}
|
||||
|
||||
void MainWindow::tabchanged(Position p, LolAutoAccept::State s) {
|
||||
if( loading ) return;
|
||||
|
||||
qDebug() << "edited position: " << p << " state: " << (int) s;
|
||||
|
||||
lolaa.reload();
|
||||
resetSaveTimer();
|
||||
}
|
||||
|
||||
void MainWindow::autoWriteChanged() {
|
||||
if( loading ) return;
|
||||
|
||||
bool enabled = ui->enableAutoWrite->isChecked();
|
||||
const QString text = ui->autoWriteText->toPlainText();
|
||||
|
||||
lolaa.setAutoWriteText(enabled, text);
|
||||
|
||||
conf.getConfig().enabledAutoWrite = enabled;
|
||||
conf.getConfig().autoWriteText = text;
|
||||
|
||||
resetSaveTimer();
|
||||
}
|
||||
|
||||
void MainWindow::saveConfig() {
|
||||
conf.save();
|
||||
}
|
||||
|
||||
void MainWindow::initDone() {
|
||||
loading = false;
|
||||
qDebug() << "loading done";
|
||||
}
|
||||
|
||||
void MainWindow::onPosChange(Position newpos) {
|
||||
assert(newpos <= Position::UTILITY);
|
||||
|
||||
emit requestTabChange((int) newpos);
|
||||
}
|
||||
|
||||
void MainWindow::lolaaStatusChanged(LolAutoAccept::Status status) {
|
||||
qDebug() << "new status: " << (int) status;
|
||||
|
||||
switch(status) {
|
||||
case LolAutoAccept::Status::Off:
|
||||
this->ui->statusbar->showMessage(tr("Auto-Acceptor stoped!"));
|
||||
break;
|
||||
case LolAutoAccept::Status::Running:
|
||||
this->ui->statusbar->showMessage(tr("Auto-Acceptor started!"));
|
||||
break;
|
||||
case LolAutoAccept::Status::Failed:
|
||||
this->ui->statusbar->showMessage(tr("Auto-Acceptor failed!"));
|
||||
break;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static std::vector<uint32_t> toChampionIDList(const std::vector<StageSettings::SelectedChamp>& scs) {
|
||||
std::vector<uint32_t> out;
|
||||
|
||||
for(const StageSettings::SelectedChamp& sc : scs) {
|
||||
out.push_back(sc.id);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void MainWindow::pptoggled(bool state) {
|
||||
Log::info << "enablePrePick checkbox toggled " << state;
|
||||
lolaa.setEnabled(state, LolAutoAccept::State::PREPICK);
|
||||
conf.getConfig().prepick.enabled = state;
|
||||
}
|
||||
|
||||
void MainWindow::ppedited() {
|
||||
Log::info << "prepick edited";
|
||||
auto champs = ui->prepickstage->getChampions();
|
||||
lolaa.setChamps(toChampionIDList(champs), LolAutoAccept::State::PREPICK);
|
||||
conf.getConfig().prepick.champs = toChampionNameList(champs);
|
||||
}
|
||||
|
||||
void MainWindow::bantoggled(bool state) {
|
||||
Log::info << "enableBan checkbox toggled " << state;
|
||||
lolaa.setEnabled(state, LolAutoAccept::State::BAN);
|
||||
conf.getConfig().ban.enabled = state;
|
||||
}
|
||||
|
||||
void MainWindow::banedited() {
|
||||
Log::info << "ban edited";
|
||||
auto champs = ui->banstage->getChampions();
|
||||
lolaa.setChamps(toChampionIDList(champs), LolAutoAccept::State::BAN);
|
||||
conf.getConfig().ban.champs = toChampionNameList(champs);
|
||||
}
|
||||
|
||||
void MainWindow::picktoggled(bool state) {
|
||||
Log::info << "enablePick checkbox toggled " << state;
|
||||
lolaa.setEnabled(state, LolAutoAccept::State::PICK);
|
||||
conf.getConfig().pick.enabled = state;
|
||||
}
|
||||
|
||||
void MainWindow::pickedited() {
|
||||
Log::info << "pick edited";
|
||||
auto champs = ui->pickstage->getChampions();
|
||||
lolaa.setChamps(toChampionIDList(champs), LolAutoAccept::State::PICK);
|
||||
conf.getConfig().pick.champs = toChampionNameList(champs);
|
||||
this->ui->mainswitch->setEnabled(true);
|
||||
this->ui->mainswitch->setChecked(status == LolAutoAccept::Status::Running);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
MemoryImageCache::MemoryImageCache(size_t maxsize) : maxsize(maxsize) {}
|
||||
|
||||
void MemoryImageCache::addImage(QPixmap img, const std::string& title, int type) {
|
||||
void MemoryImageCache::addImage(QPixmap img, const QString& title, int type) {
|
||||
auto it = std::find_if(cache.begin(), cache.end(), getImageMatcher(title, type));
|
||||
if(it == cache.end()) {
|
||||
// insert new
|
||||
|
@ -19,7 +19,7 @@ void MemoryImageCache::addImage(QPixmap img, const std::string& title, int type)
|
|||
it->imageref = img;
|
||||
}
|
||||
|
||||
QPixmap MemoryImageCache::getImage(const std::string& title, int type) {
|
||||
QPixmap MemoryImageCache::getImage(const QString& title, int type) {
|
||||
auto it = std::find_if(cache.begin(), cache.end(), getImageMatcher(title, type));
|
||||
if(it == cache.end()) {
|
||||
return {};
|
||||
|
@ -40,7 +40,7 @@ bool MemoryImageCache::CachedImage::operator<(const MemoryImageCache::CachedImag
|
|||
return lastaccessed < other.lastaccessed;
|
||||
}
|
||||
|
||||
std::function<bool(const MemoryImageCache::CachedImage&)> MemoryImageCache::getImageMatcher(const std::string& title, int type) {
|
||||
std::function<bool(const MemoryImageCache::CachedImage&)> MemoryImageCache::getImageMatcher(const QString& title, int type) {
|
||||
return [title, type](const MemoryImageCache::CachedImage& img) -> bool {
|
||||
return img.type == type && img.title == title;
|
||||
};
|
||||
|
|
|
@ -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:
|
||||
|
@ -62,7 +63,7 @@ static int my_trace(CURL* handle, curl_infotype type, char* data, size_t size, v
|
|||
return 0;
|
||||
}
|
||||
|
||||
RestClient::RestClient(const std::string& base) : baseurl(base) {
|
||||
RestClient::RestClient(const QString& base) : baseurl(base) {
|
||||
curl = curl_easy_init();
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, arrayWriteCallback);
|
||||
|
@ -73,30 +74,34 @@ RestClient::~RestClient() {
|
|||
curl = nullptr;
|
||||
}
|
||||
|
||||
QByteArray RestClient::requestRaw(const std::string& url, Method m, const std::string& data) {
|
||||
RestClient::WebException::WebException(CURLcode c) : curlresponse(c) {
|
||||
}
|
||||
|
||||
QByteArray RestClient::requestRaw(const QString& url, Method m, const QString& data) {
|
||||
if (!curl) return {};
|
||||
|
||||
std::string requrl = baseurl + url;
|
||||
QByteArray ba; //buffer
|
||||
// std::cout << "[DEBUG] requrl is: " << requrl << std::endl;
|
||||
curl_easy_setopt(curl, CURLOPT_URL, requrl.c_str());
|
||||
QString requrl = baseurl + url;
|
||||
const QByteArray reqArr = requrl.toLocal8Bit();
|
||||
curl_easy_setopt(curl, CURLOPT_URL, reqArr.data());
|
||||
|
||||
// curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); //Prevent "longjmp causes uninitialized stack frame" bug
|
||||
// set callback data
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ba);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_USERPWD, basicauth.c_str());
|
||||
const QByteArray basicArr = basicauth.toLocal8Bit();
|
||||
curl_easy_setopt(curl, CURLOPT_USERPWD, basicArr.data());
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
||||
if (disableCertCheck) {
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
}
|
||||
|
||||
// restore default HTTP Options
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL);
|
||||
|
||||
// curl header
|
||||
struct curl_slist* headerlist = NULL;
|
||||
|
||||
headerlist = curl_slist_append(headerlist, "Accept: application/json");
|
||||
const QByteArray dataArr = data.toLocal8Bit();
|
||||
|
||||
switch (m) {
|
||||
default:
|
||||
|
@ -104,26 +109,25 @@ QByteArray RestClient::requestRaw(const std::string& url, Method m, const std::s
|
|||
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); break;
|
||||
case Method::POST:
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
|
||||
headerlist = curl_slist_append(headerlist, "Content-Type: application/json");
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, dataArr.data());
|
||||
if(!dataArr.isEmpty()) {
|
||||
headerlist = curl_slist_append(headerlist, "Content-Type: application/json");
|
||||
}
|
||||
break;
|
||||
case Method::PUT:
|
||||
curl_easy_setopt(curl, CURLOPT_PUT, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
|
||||
headerlist = curl_slist_append(headerlist, "Content-Type: application/json");
|
||||
break;
|
||||
case Method::PATCH:
|
||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
|
||||
case Method::DELETE:
|
||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, toString(m)); // to use the POSTFIELDS (do not use CURLOPT_PUT, it does not support POSTFIELDS)
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, dataArr.data());
|
||||
headerlist = curl_slist_append(headerlist, "Content-Type: application/json");
|
||||
break;
|
||||
case Method::DELETE:
|
||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); break;
|
||||
}
|
||||
|
||||
if (headerlist) {
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
|
||||
}
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
|
||||
|
||||
QByteArray ba; //buffer
|
||||
// set callback data
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ba);
|
||||
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
if (headerlist) {
|
||||
|
@ -134,24 +138,26 @@ QByteArray RestClient::requestRaw(const std::string& url, Method m, const std::s
|
|||
if (res == CURLE_HTTP_RETURNED_ERROR) {
|
||||
long responsecode = -1;
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responsecode);
|
||||
Log::warn << "API request failed: " << baseurl << " " << url << " -> " << responsecode;
|
||||
}
|
||||
else {
|
||||
Log::warn << "API request failed: " << baseurl << " " << url << " " << curl_easy_strerror(res);
|
||||
qWarning() << "API request failed: " << baseurl << " " << url << " -> " << responsecode;
|
||||
} else {
|
||||
qWarning() << "API request failed: " << baseurl << " " << url << " " << curl_easy_strerror(res);
|
||||
if(res == CURLE_COULDNT_CONNECT) {
|
||||
throw WebException(res);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
return ba;
|
||||
}
|
||||
|
||||
QJsonDocument RestClient::request(const std::string& url, Method m, const std::string& data) {
|
||||
QJsonDocument RestClient::request(const QString& url, Method m, const QString& data) {
|
||||
QByteArray arr = requestRaw(url, m, data);
|
||||
if (arr.isEmpty()) return {};
|
||||
|
||||
QJsonParseError err;
|
||||
QJsonDocument parsed = QJsonDocument::fromJson(arr, &err);
|
||||
if (parsed.isNull() || err.error != QJsonParseError::NoError) {
|
||||
Log::error << "API Json parse error " << err.errorString().toStdString() << " offset: " << err.offset;
|
||||
qCritical() << "API Json parse error " << err.errorString() << " offset: " << err.offset;
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -168,3 +174,16 @@ void RestClient::enableDebugging(bool enabled) {
|
|||
curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);
|
||||
}
|
||||
}
|
||||
|
||||
QString RestClient::escape(const QString& in) const {
|
||||
char* e = curl_easy_escape(curl, in.toLocal8Bit().data(), in.length());
|
||||
QString esc(e);
|
||||
curl_free(e);
|
||||
return esc;
|
||||
}
|
||||
|
||||
const char* toString(RestClient::Method m) {
|
||||
static const char* MethodNames[] = {"GET", "POST", "PUT", "PATCH", "DELETE"};
|
||||
|
||||
return MethodNames[(int) m];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
#include "runeaspektbutton.h"
|
||||
#include "ui_runeaspektbutton.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include "runeaspektbuttongroup.h"
|
||||
|
||||
RuneAspektButton::RuneAspektButton(QWidget* parent) : QPushButton(parent), ui(new Ui::RuneAspektButton) {
|
||||
ui->setupUi(this);
|
||||
|
||||
QObject::connect(this, &QPushButton::pressed, this, &RuneAspektButton::buttonPressed);
|
||||
}
|
||||
|
||||
RuneAspektButton::~RuneAspektButton() {
|
||||
delete this->ui;
|
||||
}
|
||||
|
||||
void RuneAspektButton::setAspektId(uint32_t id) {
|
||||
aspektId = id;
|
||||
|
||||
dataChanged();
|
||||
}
|
||||
|
||||
void RuneAspektButton::setButtonGroup(RuneAspektButtonGroup* group) {
|
||||
this->group = group;
|
||||
}
|
||||
|
||||
bool RuneAspektButton::isSelected() const {
|
||||
return group && group->getSelectedRunes().contains(aspektId);
|
||||
}
|
||||
|
||||
void RuneAspektButton::buttonPressed() {
|
||||
emit aspektToggled(aspektId);
|
||||
}
|
||||
|
||||
void RuneAspektButton::dataChanged() {
|
||||
bool selection = isSelected();
|
||||
|
||||
qDebug() << text() << " datachanged - isSelected: " << selection;
|
||||
|
||||
setShowSelection(selection);
|
||||
}
|
||||
|
||||
void RuneAspektButton::checkSelection(uint32_t aspekt) {
|
||||
qDebug() << "checkSelection: " << text() << aspekt << aspektId;
|
||||
setShowSelection(aspekt == this->aspektId);
|
||||
}
|
||||
|
||||
void RuneAspektButton::setShowSelection(bool selected) {
|
||||
if(selected) {
|
||||
setStyleSheet("border: 1px solid red;");
|
||||
} else {
|
||||
setStyleSheet("");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
#include "runeaspektbuttongroup.h"
|
||||
|
||||
#include "runeaspektbutton.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
const int RuneAspektButtonGroup::INVALID_ASPEKT_ID = 0;
|
||||
|
||||
RuneAspektButtonGroup::RuneAspektButtonGroup(QObject* parent, uint32_t size) : QObject(parent), selectedRune(), size(size) {
|
||||
selectedRune.reserve(size*2);
|
||||
}
|
||||
|
||||
RuneAspektButtonGroup::~RuneAspektButtonGroup() {}
|
||||
|
||||
void RuneAspektButtonGroup::addButton(RuneAspektButton* button) {
|
||||
QObject::connect(this, &RuneAspektButtonGroup::changed, button, &RuneAspektButton::dataChanged);
|
||||
QObject::connect(button, &RuneAspektButton::aspektToggled, this, &RuneAspektButtonGroup::buttonPressed);
|
||||
|
||||
button->setButtonGroup(this);
|
||||
}
|
||||
|
||||
void RuneAspektButtonGroup::setSelectedRunes(const QVector<int>& newRunes) {
|
||||
selectedRune = newRunes;
|
||||
|
||||
qDebug() << "selectedRunes changed to: " << selectedRune << " refesching buttons";
|
||||
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void RuneAspektButtonGroup::setSubgroups(const QVector<QVector<int>>& newSubgroups) {
|
||||
subgroups = newSubgroups;
|
||||
}
|
||||
|
||||
void RuneAspektButtonGroup::buttonPressed(int aspektId) {
|
||||
if(selectedRune.contains(aspektId)) {
|
||||
selectedRune.removeAll(aspektId);
|
||||
} else {
|
||||
// check subgroups first
|
||||
int otherSubgroupMember = getOtherSubgroupMemeber(aspektId);
|
||||
if(otherSubgroupMember != INVALID_ASPEKT_ID) {
|
||||
// collision in subgroup -> remove other member
|
||||
selectedRune.removeAll(otherSubgroupMember);
|
||||
}
|
||||
|
||||
selectedRune.push_back(aspektId);
|
||||
|
||||
if((uint32_t) selectedRune.size() > size) {
|
||||
selectedRune.removeFirst();
|
||||
}
|
||||
}
|
||||
|
||||
emit changed();
|
||||
}
|
||||
|
||||
int RuneAspektButtonGroup::getOtherSubgroupMemeber(int aspektId) {
|
||||
if(subgroups.empty()) {
|
||||
return INVALID_ASPEKT_ID;
|
||||
}
|
||||
|
||||
for(const QVector<int>& subgroup : subgroups) {
|
||||
if(subgroup.contains(aspektId)) {
|
||||
for(const int& subgroupMember : subgroup) {
|
||||
if(aspektId != subgroupMember && selectedRune.contains(subgroupMember)) {
|
||||
return subgroupMember;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return INVALID_ASPEKT_ID;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
#include "runedisplay.h"
|
||||
#include "ui_runedisplay.h"
|
||||
|
||||
#include <QTextStream>
|
||||
|
||||
const static QString EMPTY;
|
||||
|
||||
RuneDisplay::RuneDisplay(QWidget *parent) : QWidget(parent), ui(new Ui::RuneDisplay) {
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
RuneDisplay::~RuneDisplay() {
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void RuneDisplay::setRuneMeta(const std::vector<RuneAspekt>& ri) {
|
||||
runeinfo = ri;
|
||||
}
|
||||
|
||||
void RuneDisplay::setStyles(const std::vector<RuneStyle>& styleinfos) {
|
||||
runestyles = styleinfos;
|
||||
}
|
||||
|
||||
void RuneDisplay::setRunes(const RunePage& rp) {
|
||||
runepage = rp;
|
||||
|
||||
updateText();
|
||||
}
|
||||
|
||||
void RuneDisplay::applyRunesClicked() {
|
||||
emit applyRunes();
|
||||
}
|
||||
|
||||
void RuneDisplay::updateText() {
|
||||
QString outStr;
|
||||
QTextStream out(&outStr);
|
||||
|
||||
if(! (bool) runepage) {
|
||||
ui->runetext->setText("");
|
||||
ui->applyRunesBtn->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
out << getRuneStyleByID(runepage.primaryStyle) << " with " << getRuneStyleByID(runepage.secondaryStyle) << '\n';
|
||||
|
||||
for(uint32_t rune : runepage.selectedAspects) {
|
||||
out << getRuneText(rune) << '\n';
|
||||
}
|
||||
ui->runetext->setText(outStr);
|
||||
ui->applyRunesBtn->setEnabled(true);
|
||||
}
|
||||
|
||||
QString RuneDisplay::getRuneText(uint32_t id) {
|
||||
for(const RuneAspekt& ra : runeinfo) {
|
||||
if(ra.id == id) {
|
||||
return ra.name;
|
||||
}
|
||||
}
|
||||
|
||||
return "(" + QString::number(id) + ")";
|
||||
}
|
||||
|
||||
QString RuneDisplay::getRuneStyleByID(uint32_t id) {
|
||||
auto it = std::find_if(runestyles.begin(), runestyles.end(), [id](const RuneStyle& rs) { return rs.id == id; });
|
||||
if(it == runestyles.end()) {
|
||||
return '(' + QString::number(id) + ')';
|
||||
}
|
||||
|
||||
return it->name;
|
||||
}
|
|
@ -0,0 +1,281 @@
|
|||
#include "runeeditor.h"
|
||||
#include "ui_runeeditor.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
#include <QGridLayout>
|
||||
#include <QPixmap>
|
||||
#include <QPushButton>
|
||||
|
||||
#include "clientapi.h"
|
||||
#include "runeaspektbutton.h"
|
||||
#include "runeaspektbuttongroup.h"
|
||||
|
||||
RuneEditor::RuneEditor(QWidget* parent) : QDialog(parent), ui(new Ui::RuneEditor), groups(8, nullptr) {
|
||||
ui->setupUi(this);
|
||||
|
||||
QObject::connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &RuneEditor::accept);
|
||||
QObject::connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &RuneEditor::reject);
|
||||
}
|
||||
|
||||
RuneEditor::~RuneEditor() {
|
||||
delete this->ui;
|
||||
}
|
||||
|
||||
void RuneEditor::setClient(ClientAPI& client) {
|
||||
this->client = &client;
|
||||
|
||||
if(!this->client) return;
|
||||
|
||||
try {
|
||||
// build ui
|
||||
aspekts = client.getAllRuneAspekts();
|
||||
styles = client.getAllRuneStyles();
|
||||
|
||||
for(const RuneStyle& rs : styles) {
|
||||
RuneAspektButton* runeStyleBtn = createStyleButton(rs, rs.id == runepage.primaryStyle);
|
||||
|
||||
if(!runeStyleBtn) continue;
|
||||
|
||||
QObject::connect(runeStyleBtn, &QPushButton::pressed, [this, id = rs.id](){
|
||||
selectStyle(id);
|
||||
});
|
||||
QObject::connect(this, &RuneEditor::selectPrimary, runeStyleBtn, &RuneAspektButton::checkSelection);
|
||||
|
||||
ui->style->addWidget(runeStyleBtn);
|
||||
}
|
||||
} catch(RestClient::WebException& e) {
|
||||
qCritical() << "webexception: " << e.curlresponse;
|
||||
|
||||
if(e.curlresponse == CURLE_COULDNT_CONNECT) {
|
||||
this->client = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RuneEditor::setRunepage(const ::RunePage& rp) {
|
||||
qInfo() << "runepage: " << rp.selectedAspects.size();
|
||||
|
||||
selectStyle(rp.primaryStyle);
|
||||
selectSubStyle(rp.secondaryStyle);
|
||||
|
||||
runepage = rp;
|
||||
uint32_t offset = 0;
|
||||
for(RuneAspektButtonGroup* group : groups) {
|
||||
if(!group) continue;
|
||||
|
||||
QVector<int> selected(group->getSize(), 0);
|
||||
for(uint32_t i = 0; i < group->getSize(); ++i) {
|
||||
selected.replace(i, rp.selectedAspects.at(offset));
|
||||
offset++;
|
||||
}
|
||||
group->setSelectedRunes(selected);
|
||||
}
|
||||
|
||||
emit selectionChanged();
|
||||
}
|
||||
|
||||
void RuneEditor::selectStyle(uint32_t id) {
|
||||
if(runepage.primaryStyle == id) return;
|
||||
|
||||
const RuneStyle* style = getRuneStyle(id);
|
||||
|
||||
if(style) {
|
||||
runepage.primaryStyle = id;
|
||||
runepage.secondaryStyle = 0;
|
||||
runepage.selectedAspects.clear();
|
||||
runepage.selectedAspects.resize(9, 0);
|
||||
|
||||
emit selectPrimary(id);
|
||||
|
||||
clearLayout(ui->substyle);
|
||||
clearLayout(ui->stylePerks);
|
||||
clearLayout(ui->substylePerks);
|
||||
|
||||
// populate substyles
|
||||
for(int subStyleId : style->allowedSubStyles) {
|
||||
const RuneStyle* substyle = getRuneStyle(subStyleId);
|
||||
RuneAspektButton* subStyleBtn = createStyleButton(*substyle, false);
|
||||
|
||||
if(!subStyleBtn) continue;
|
||||
|
||||
QObject::connect(subStyleBtn, &QPushButton::pressed, [this, subStyleId](){
|
||||
selectSubStyle(subStyleId);
|
||||
});
|
||||
|
||||
QObject::connect(this, &RuneEditor::selectSecondary, subStyleBtn, &RuneAspektButton::checkSelection);
|
||||
|
||||
ui->substyle->addWidget(subStyleBtn);
|
||||
}
|
||||
|
||||
// populate perks
|
||||
fillRuneStyle(ui->stylePerks, *style);
|
||||
}
|
||||
}
|
||||
|
||||
void RuneEditor::selectSubStyle(uint32_t id) {
|
||||
if(runepage.secondaryStyle == id) return;
|
||||
|
||||
const RuneStyle* substyle = getRuneStyle(id);
|
||||
|
||||
if(substyle) {
|
||||
runepage.secondaryStyle = id;
|
||||
|
||||
emit selectSecondary(id);
|
||||
|
||||
clearLayout(ui->substylePerks);
|
||||
delete groups.at(4);
|
||||
|
||||
QVector<QVector<int>> subgroups;
|
||||
subgroups.reserve(substyle->runeSlots.size());
|
||||
|
||||
// populate perks
|
||||
RuneAspektButtonGroup* group = new RuneAspektButtonGroup(this, 2);
|
||||
for(size_t idx = 0; idx < substyle->runeSlots.size(); ++idx) {
|
||||
const RuneStyleSlot& rss = substyle->runeSlots.at(idx);
|
||||
QVector<int> subgroup;
|
||||
subgroup.reserve(rss.perks.size());
|
||||
|
||||
if(rss.type != "kMixedRegularSplashable") continue;
|
||||
|
||||
for(int perkNr = 0; perkNr < (int) rss.perks.size(); ++perkNr) {
|
||||
uint32_t perk = rss.perks.at(perkNr);
|
||||
subgroup.append((int) perk);
|
||||
|
||||
RuneAspektButton* aspektBtn = createAspektButton(perk);
|
||||
if(!aspektBtn) continue;
|
||||
|
||||
group->addButton(aspektBtn);
|
||||
|
||||
ui->substylePerks->addWidget(aspektBtn, idx, perkNr);
|
||||
}
|
||||
|
||||
subgroups.append(subgroup);
|
||||
}
|
||||
group->setSubgroups(subgroups);
|
||||
groups.replace(4, group);
|
||||
}
|
||||
}
|
||||
|
||||
void RuneEditor::clearLayout(QLayout* layout) {
|
||||
while(layout->count()) {
|
||||
QLayoutItem* item = layout->takeAt(0);
|
||||
delete item->widget();
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
void RuneEditor::setName(QString text) {
|
||||
ui->runepageName->setText(text);
|
||||
}
|
||||
|
||||
QString RuneEditor::getName() const {
|
||||
return ui->runepageName->text();
|
||||
}
|
||||
|
||||
const RunePage& RuneEditor::getRunepage() {
|
||||
runepage.selectedAspects.clear();
|
||||
runepage.selectedAspects.resize(9, 0);
|
||||
|
||||
uint_fast8_t index = 0;
|
||||
for(const RuneAspektButtonGroup* group : groups) {
|
||||
if(!group) continue;
|
||||
|
||||
const QVector<int>& selected = group->getSelectedRunes();
|
||||
for(uint32_t i = 0; i < group->getSize(); ++i) {
|
||||
runepage.selectedAspects.at(index) = (selected.at(i));
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
return runepage;
|
||||
}
|
||||
|
||||
const RuneStyle* RuneEditor::getRuneStyle(uint32_t id) const {
|
||||
auto it = std::find_if(styles.cbegin(), styles.cend(), [id](const RuneStyle& rs) {
|
||||
return rs.id == id;
|
||||
});
|
||||
|
||||
return it == styles.cend() ? nullptr : &*it;
|
||||
}
|
||||
|
||||
RuneAspektButton* RuneEditor::createStyleButton(const RuneStyle& rs, bool selected) {
|
||||
RuneAspektButton* styleBtn = createButtonFromResource(rs.iconPath);
|
||||
|
||||
if(!styleBtn) return nullptr;
|
||||
|
||||
styleBtn->setText(rs.name);
|
||||
styleBtn->setToolTip(rs.tooltip);
|
||||
|
||||
styleBtn->setAspektId(rs.id);
|
||||
|
||||
if(selected) {
|
||||
styleBtn->setStyleSheet("border: 1px solid red;");
|
||||
}
|
||||
|
||||
return styleBtn;
|
||||
}
|
||||
|
||||
RuneAspektButton* RuneEditor::createAspektButton(uint32_t perk) {
|
||||
auto itFound = std::find_if(aspekts.cbegin(), aspekts.cend(), [perk](const RuneAspekt& ra) {
|
||||
return ra.id == perk;
|
||||
});
|
||||
|
||||
if(itFound == aspekts.cend()) {
|
||||
return nullptr;
|
||||
}
|
||||
RuneAspektButton* aspektBtn = createButtonFromResource(itFound->iconPath);
|
||||
|
||||
aspektBtn->setText(itFound->name);
|
||||
aspektBtn->setToolTip(itFound->tooltip);
|
||||
|
||||
aspektBtn->setAspektId(itFound->id);
|
||||
|
||||
return aspektBtn;
|
||||
}
|
||||
|
||||
RuneAspektButton* RuneEditor::createButtonFromResource(QString resource) {
|
||||
if(!client) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QPixmap icon;
|
||||
try {
|
||||
icon = client->getImageResource(resource.remove(0, 1));
|
||||
} catch(RestClient::WebException& e) {
|
||||
qCritical() << "webexception: " << e.curlresponse;
|
||||
|
||||
if(e.curlresponse == CURLE_COULDNT_CONNECT) {
|
||||
client = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
RuneAspektButton* rab = new RuneAspektButton(this);
|
||||
rab->setIcon(icon);
|
||||
|
||||
return rab;
|
||||
}
|
||||
|
||||
void RuneEditor::fillRuneStyle(QGridLayout* target, const RuneStyle& rs) {
|
||||
for(size_t idx = 0; idx < rs.runeSlots.size(); ++idx) {
|
||||
const RuneStyleSlot& rss = rs.runeSlots.at(idx);
|
||||
RuneAspektButtonGroup* group = new RuneAspektButtonGroup(this, 1);
|
||||
|
||||
for(int perkNr = 0; perkNr < (int) rss.perks.size(); ++perkNr) {
|
||||
uint32_t perk = rss.perks.at(perkNr);
|
||||
|
||||
RuneAspektButton* aspektBtn = createAspektButton(perk);
|
||||
if(!aspektBtn) continue;
|
||||
|
||||
group->addButton(aspektBtn);
|
||||
|
||||
target->addWidget(aspektBtn, idx, perkNr);
|
||||
}
|
||||
|
||||
groups.replace(idx + (idx > 3), group);
|
||||
}
|
||||
}
|
||||
|
||||
QString RuneEditor::fixString(QString text) {
|
||||
return text.replace(" ", "").replace("</?.*?>", "");
|
||||
}
|
|
@ -0,0 +1,259 @@
|
|||
#include "runemanager.h"
|
||||
#include "ui_runemanager.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QListWidgetItem>
|
||||
#include <QTimer>
|
||||
|
||||
#include "clientapi.h"
|
||||
|
||||
RuneManager::RuneManager(QWidget* parent) : QWidget(parent), ui(new Ui::RuneManager) {
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->listClientRunes->setIsClient(true);
|
||||
ui->listaaRunes->setIsClient(false);
|
||||
ui->listClientRunes->setOther(ui->listaaRunes);
|
||||
ui->listaaRunes->setOther(ui->listClientRunes);
|
||||
|
||||
QObject::connect(ui->listaaRunes, &RunePageList::runepageChanged, this, &RuneManager::saveRunePageAA);
|
||||
QObject::connect(ui->listClientRunes, &RunePageList::runepageChanged, this, &RuneManager::saveRunePageClient);
|
||||
|
||||
QObject::connect(ui->listaaRunes, &RunePageList::runepageDeleted, this, &RuneManager::deleteRunepageAA);
|
||||
QObject::connect(ui->listClientRunes, &RunePageList::runepageDeleted, this, &RuneManager::deleteRunepageClient);
|
||||
|
||||
QObject::connect(ui->chkAutoCopy, &QCheckBox::clicked, this, &RuneManager::autoSyncToggled);
|
||||
|
||||
|
||||
initialLoadTimer = new QTimer(this);
|
||||
QObject::connect(initialLoadTimer, &QTimer::timeout, this, &RuneManager::loadRunes);
|
||||
initialLoadTimer->setInterval(std::chrono::milliseconds(1));
|
||||
initialLoadTimer->setSingleShot(true);
|
||||
initialLoadTimer->start();
|
||||
}
|
||||
|
||||
RuneManager::~RuneManager() {
|
||||
delete this->ui;
|
||||
}
|
||||
|
||||
void RuneManager::setConfig(Config& config) {
|
||||
this->config = &config;
|
||||
Config::GeneralRunePageConfig& rpc = config.getConfig().runepagesConfig;
|
||||
ui->listaaRunes->loadRunePages(rpc.runePages);
|
||||
ui->chkAutoCopy->setChecked(rpc.autoSync);
|
||||
|
||||
if(rpc.autoSync) {
|
||||
syncRunes();
|
||||
}
|
||||
}
|
||||
|
||||
void RuneManager::setDataDragon(DataDragon& dd) {
|
||||
ui->listaaRunes->setDataDragon(dd);
|
||||
ui->listClientRunes->setDataDragon(dd);
|
||||
}
|
||||
|
||||
void RuneManager::loadRunes() {
|
||||
if(initialLoadTimer) {
|
||||
initialLoadTimer->deleteLater();
|
||||
initialLoadTimer = nullptr;
|
||||
}
|
||||
|
||||
this->ui->btnRetry->setEnabled(false);
|
||||
QCoreApplication::processEvents();
|
||||
|
||||
if(!client) {
|
||||
auto ca = ClientAccess::find();
|
||||
|
||||
if(ca) {
|
||||
client = std::make_shared<ClientAPI>(*ca.get());
|
||||
}
|
||||
}
|
||||
|
||||
if(client) {
|
||||
try {
|
||||
// load meta data
|
||||
runeInfo = client->getAllRuneAspekts();
|
||||
QCoreApplication::processEvents();
|
||||
runeStyles = client->getAllRuneStyles();
|
||||
QCoreApplication::processEvents();
|
||||
|
||||
ui->listClientRunes->setClient(*client);
|
||||
ui->listaaRunes->setClient(*client);
|
||||
|
||||
this->ui->listClientRunes->setRuneInfos(runeInfo, runeStyles);
|
||||
this->ui->listaaRunes->setRuneInfos(runeInfo, runeStyles);
|
||||
|
||||
// load runepages
|
||||
reloadClientRunes();
|
||||
|
||||
// reload runepages - so they ids can get their names
|
||||
reloadAARunes();
|
||||
|
||||
// check if autosync is enabled
|
||||
if(config && config->getConfig().runepagesConfig.autoSync) {
|
||||
syncRunes();
|
||||
}
|
||||
} catch(RestClient::WebException& e) {
|
||||
qCritical() << "webexception: " << e.curlresponse;
|
||||
|
||||
if(e.curlresponse == CURLE_COULDNT_CONNECT) {
|
||||
client.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setRunesEnabled(!!client); // cast to bool
|
||||
this->ui->btnRetry->setEnabled(true);
|
||||
}
|
||||
|
||||
void RuneManager::reloadClientRunes() {
|
||||
if(client) {
|
||||
const std::vector<ClientAPI::RunePage> runePages = client->getAllRunePages();
|
||||
ui->listClientRunes->loadRunePages(runePages);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RuneManager::setRunesEnabled(bool enabled) {
|
||||
this->ui->lblClientRunes->setEnabled(enabled);
|
||||
this->ui->listClientRunes->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void RuneManager::saveRunePageClient(int id, QString name, const RunePage& rp) {
|
||||
if(client) {
|
||||
ClientAPI::RunePage newPage;
|
||||
newPage.name = name;
|
||||
newPage.runepage = rp;
|
||||
newPage.id = id;
|
||||
|
||||
try {
|
||||
if(id == -1) {
|
||||
// create new page
|
||||
if(!client->createRunePage(newPage)) {
|
||||
// TODO: some error occured
|
||||
}
|
||||
} else {
|
||||
// edit existing page
|
||||
if(!client->editRunePage(newPage)) {
|
||||
// TODO: some error occured
|
||||
}
|
||||
}
|
||||
reloadClientRunes();
|
||||
} catch(RestClient::WebException& e) {
|
||||
qCritical() << "webexception: " << e.curlresponse;
|
||||
|
||||
if(e.curlresponse == CURLE_COULDNT_CONNECT) {
|
||||
client.reset();
|
||||
|
||||
setRunesEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RuneManager::saveRunePageAA(int id, QString name, const RunePage& rp) {
|
||||
if(!config) return;
|
||||
|
||||
Config::RootConfig& rc = config->getConfig();
|
||||
auto& pages = rc.runepagesConfig.runePages;
|
||||
if(id == -1) {
|
||||
// int newId = pages.size();
|
||||
pages.push_back(std::make_shared<Config::RunePageConfig>(name, rp));
|
||||
} else {
|
||||
if((int) pages.size() > id && id >= 0) {
|
||||
pages.at(id)->runepage = rp;
|
||||
pages.at(id)->name = name;
|
||||
} else {
|
||||
// unkown id
|
||||
qWarning() << "unknown runepage id:" << id;
|
||||
}
|
||||
}
|
||||
|
||||
config->save();
|
||||
|
||||
// reload runes
|
||||
ui->listaaRunes->loadRunePages(pages);
|
||||
}
|
||||
|
||||
void RuneManager::deleteRunepageClient(int id) {
|
||||
if(client) {
|
||||
try {
|
||||
if(!client->deleteRunePage(id)) {
|
||||
// TODO: some error occured
|
||||
}
|
||||
} catch(RestClient::WebException& e) {
|
||||
qCritical() << "webexception: " << e.curlresponse;
|
||||
|
||||
if(e.curlresponse == CURLE_COULDNT_CONNECT) {
|
||||
client.reset();
|
||||
|
||||
setRunesEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RuneManager::deleteRunepageAA(int id) {
|
||||
if(!config) return;
|
||||
|
||||
Config::RootConfig& rc = config->getConfig();
|
||||
auto& pages = rc.runepagesConfig.runePages;
|
||||
if((int) pages.size() > id && id >= 0) {
|
||||
pages.erase(pages.begin() + id);
|
||||
|
||||
config->save();
|
||||
|
||||
ui->listaaRunes->loadRunePages(pages);
|
||||
} else {
|
||||
// unkown id
|
||||
qWarning() << "unknown runepage id:" << id;
|
||||
}
|
||||
}
|
||||
|
||||
void RuneManager::autoSyncToggled() {
|
||||
bool autoSync = (ui->chkAutoCopy->isChecked());
|
||||
if(config) {
|
||||
config->getConfig().runepagesConfig.autoSync = autoSync;
|
||||
config->save();
|
||||
}
|
||||
|
||||
if(autoSync) {
|
||||
syncRunes();
|
||||
}
|
||||
}
|
||||
|
||||
void RuneManager::syncRunes() {
|
||||
qInfo() << "syncing" << ui->listClientRunes->count() << "runes";
|
||||
|
||||
std::vector<std::shared_ptr<Config::RunePageConfig>>& configs = config->getConfig().runepagesConfig.runePages;
|
||||
bool changed = false;
|
||||
|
||||
for(int i = 0; i < ui->listClientRunes->count(); ++i) {
|
||||
const QListWidgetItem* item = ui->listClientRunes->item(i);
|
||||
QString name = item->text();
|
||||
const RunePage* rp = (RunePage*) item->data(RunePageList::RolePointer).toULongLong();
|
||||
|
||||
auto itFound = std::find_if(configs.cbegin(), configs.cend(), [name, rp](const std::shared_ptr<Config::RunePageConfig>& rpc){
|
||||
return rpc->name == name && *rp == rpc->runepage;
|
||||
});
|
||||
|
||||
if(itFound == configs.cend()) {
|
||||
// no duplicate found -> add it
|
||||
configs.push_back(std::make_shared<Config::RunePageConfig>(name, *rp));
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(changed) {
|
||||
config->save();
|
||||
ui->listaaRunes->loadRunePages(configs);
|
||||
}
|
||||
}
|
||||
|
||||
void RuneManager::reloadAARunes() {
|
||||
if(!config) return;
|
||||
|
||||
const auto& pages = config->getConfig().runepagesConfig.runePages;
|
||||
|
||||
// reload runes
|
||||
ui->listaaRunes->loadRunePages(pages);
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
#include "runepage.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "json.h"
|
||||
|
||||
RunePage::RunePage() {}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
RunePage::operator bool() const {
|
||||
return primaryStyle != 0 && secondaryStyle != 0 && selectedAspects.size() == 9;
|
||||
}
|
||||
|
||||
RunePage::operator QJsonObject() const {
|
||||
QJsonObject obj;
|
||||
|
||||
obj.insert("primary", (int) primaryStyle);
|
||||
obj.insert("secondary", (int) secondaryStyle);
|
||||
|
||||
QJsonArray aspects;
|
||||
for(uint32_t aspect : selectedAspects) {
|
||||
aspects.push_back((int) aspect);
|
||||
}
|
||||
obj.insert("aspects", aspects);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
RunePage::RunePage(const QJsonObject& obj) :
|
||||
primaryStyle(getValue(obj, "primary", 0)),
|
||||
secondaryStyle(getValue(obj, "secondary", 0))
|
||||
{
|
||||
if(obj.contains("aspects") && obj["aspects"].isArray() && obj["aspects"].toArray().size() == 9) {
|
||||
selectedAspects.clear();
|
||||
selectedAspects.reserve(9);
|
||||
QJsonArray arr = obj["aspects"].toArray();
|
||||
for(QJsonValueRef aspect : arr) {
|
||||
if(aspect.isDouble()) {
|
||||
selectedAspects.push_back(aspect.toDouble());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& str, const RunePage& rp) {
|
||||
return str << "Primary: " << rp.primaryStyle << " Secondary: " << rp.secondaryStyle << " aspects: " << rp.selectedAspects.size();
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug str, const RunePage& rp) {
|
||||
return str << "Primary: " << rp.primaryStyle << " Secondary: " << rp.secondaryStyle << " aspects: " << rp.selectedAspects.size();
|
||||
}
|
|
@ -0,0 +1,315 @@
|
|||
#include "runepagelist.h"
|
||||
#include "ui_runepagelist.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDropEvent>
|
||||
#include <QMenu>
|
||||
#include <QMimeData>
|
||||
#include <QTextStream>
|
||||
|
||||
#include "clipboardpopup.h"
|
||||
#include "loadingwindow.h"
|
||||
#include "runeeditor.h"
|
||||
|
||||
RunePageList::RunePageList(QWidget* parent) : QListWidget(parent), ui(new Ui::RunePageList) {
|
||||
ui->setupUi(this);
|
||||
|
||||
QObject::connect(this, &QListWidget::itemChanged, this, &RunePageList::itemChangedCallback);
|
||||
QObject::connect(this, &QListWidget::customContextMenuRequested, this, &RunePageList::openContextMenu);
|
||||
}
|
||||
|
||||
RunePageList::~RunePageList() {
|
||||
delete this->ui;
|
||||
}
|
||||
|
||||
void RunePageList::loadRunePages(const std::vector<ClientAPI::RunePage>& pages) {
|
||||
clearItems();
|
||||
for(const ClientAPI::RunePage& rp : pages) {
|
||||
addRunepageItem(rp.name, rp.id, rp.runepage, rp.isCurrent);
|
||||
}
|
||||
}
|
||||
|
||||
void RunePageList::loadRunePages(const std::vector<std::shared_ptr<Config::RunePageConfig>>& pages) {
|
||||
clearItems();
|
||||
for(size_t i = 0; i < pages.size(); ++i) {
|
||||
std::shared_ptr<Config::RunePageConfig> rp = pages.at(i);
|
||||
addRunepageItem(rp->name, i, rp->runepage);
|
||||
}
|
||||
}
|
||||
|
||||
void RunePageList::setRuneInfos(const std::vector<RuneAspekt>& runeInfo, const std::vector<RuneStyle>& runeStyles) {
|
||||
this->runeInfo = &runeInfo;
|
||||
this->runeStyles = &runeStyles;
|
||||
}
|
||||
|
||||
void RunePageList::dropEvent(QDropEvent* event) {
|
||||
if(event->source() == nullptr || event->source() != other) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
auto selected = other->selectedItems();
|
||||
if(selected.size() != 1) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
QListWidgetItem* item = selected.at(0);
|
||||
|
||||
// compare rune pages for duplicates?
|
||||
|
||||
// QListWidget::dropEvent(event);
|
||||
|
||||
// save change
|
||||
QString name = item->text();
|
||||
const RunePage* oldPage = (RunePage*) item->data(RolePointer).toULongLong();
|
||||
|
||||
emit runepageChanged(-1, name, *oldPage);
|
||||
}
|
||||
|
||||
void RunePageList::itemChangedCallback(QListWidgetItem* item) {
|
||||
int pageId = item->data(RunePageList::RoleId).toUInt();
|
||||
QString newName = item->text();
|
||||
const ::RunePage* page = (::RunePage*) item->data(RunePageList::RolePointer).toULongLong();
|
||||
emit runepageChanged(pageId, newName, *page);
|
||||
}
|
||||
|
||||
void RunePageList::openContextMenu(const QPoint& pos) {
|
||||
QPoint globalPos = mapToGlobal(pos);
|
||||
|
||||
QMenu menu;
|
||||
menu.addAction(QIcon(":/icons/edit.svg"), RunePageList::tr("Edit"), this, &RunePageList::editCurrentItem);
|
||||
menu.addAction(QIcon(":/icons/duplicate.svg"), RunePageList::tr("Duplicate"), this, &RunePageList::duplicateCurrentItem);
|
||||
menu.addAction(QIcon(":/icons/export.svg"), RunePageList::tr("Export"), this, &RunePageList::exportCurrentItem);
|
||||
menu.addAction(QIcon(":/icons/import.svg"), RunePageList::tr("Import"), this, &RunePageList::importItem);
|
||||
menu.addAction(QIcon(":/icons/delete.svg"), RunePageList::tr("Delete"), this, &RunePageList::deleteCurrentItem);
|
||||
|
||||
menu.exec(globalPos);
|
||||
}
|
||||
|
||||
void RunePageList::deleteCurrentItem() {
|
||||
QListWidgetItem* item = currentItem();
|
||||
if (item) {
|
||||
uint32_t id = item->data(RoleId).toUInt();
|
||||
RunePage* page = (RunePage*) item->data(RolePointer).toULongLong();
|
||||
removeItemWidget(item);
|
||||
|
||||
delete item;
|
||||
delete page;
|
||||
|
||||
emit runepageDeleted(id);
|
||||
}
|
||||
}
|
||||
|
||||
void RunePageList::editCurrentItem() {
|
||||
QListWidgetItem* item = currentItem();
|
||||
if(!item) return;
|
||||
|
||||
RunePage* rp = (RunePage*) item->data(RolePointer).toULongLong();
|
||||
const uint32_t id = item->data(RoleId).toUInt();
|
||||
|
||||
LoadingWindow lw;
|
||||
lw.setText(RunePageList::tr("Loading runes"));
|
||||
lw.setProgress(0.5f);
|
||||
lw.show();
|
||||
|
||||
// make sure the Loading window is rendered
|
||||
QApplication::processEvents();
|
||||
RuneEditor re;
|
||||
re.setName(item->text());
|
||||
QApplication::processEvents();
|
||||
re.setClient(*client);
|
||||
QApplication::processEvents();
|
||||
re.setRunepage(*rp);
|
||||
|
||||
lw.close();
|
||||
|
||||
int result = re.exec();
|
||||
|
||||
// check result - save
|
||||
if(result == QDialog::Accepted) {
|
||||
|
||||
// update config
|
||||
emit runepageChanged(id, re.getName(), re.getRunepage());
|
||||
}
|
||||
}
|
||||
|
||||
void RunePageList::duplicateCurrentItem() {
|
||||
QListWidgetItem* item = currentItem();
|
||||
if(!item) return;
|
||||
|
||||
const RunePage* rp = (RunePage*) item->data(RolePointer).toULongLong();
|
||||
|
||||
QString name = item->text();
|
||||
|
||||
static const QRegularExpression regex(".*(\\d)+$");
|
||||
QRegularExpressionMatchIterator regexIt = regex.globalMatch(name);
|
||||
int num = 0;
|
||||
if(regexIt.hasNext()) {
|
||||
QRegularExpressionMatch match = regexIt.next();
|
||||
QStringRef ref = match.capturedRef(1);
|
||||
name.chop(ref.size());
|
||||
num = ref.toInt();
|
||||
}
|
||||
name += QString::number(num+1);
|
||||
|
||||
emit runepageChanged(-1, name, *rp);
|
||||
}
|
||||
|
||||
void RunePageList::exportCurrentItem() {
|
||||
QListWidgetItem* item = currentItem();
|
||||
if(!item) return;
|
||||
|
||||
const RunePage* rp = (RunePage*) item->data(RolePointer).toULongLong();
|
||||
|
||||
Config::RunePageConfig rpc;
|
||||
rpc.name = item->text();
|
||||
rpc.runepage = *rp;
|
||||
|
||||
QJsonDocument rpcDoc(rpc); // cast to QJsonObject
|
||||
QByteArray jsonBytes = rpcDoc.toJson(QJsonDocument::Compact).toBase64();
|
||||
QString runePageString = QString::fromLocal8Bit(jsonBytes);
|
||||
|
||||
ClipboardPopup popup(ClipboardPopup::Direction::Copy);
|
||||
popup.setText(runePageString);
|
||||
popup.exec();
|
||||
}
|
||||
|
||||
void RunePageList::importItem() {
|
||||
ClipboardPopup popup(ClipboardPopup::Direction::Paste);
|
||||
if(popup.exec() != QDialog::Accepted) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString text = popup.getText();
|
||||
QByteArray jsonBytes = QByteArray::fromBase64(text.toLocal8Bit());
|
||||
QJsonDocument rpcDoc = QJsonDocument::fromJson(jsonBytes);
|
||||
if(rpcDoc.isObject()) {
|
||||
QJsonObject rpcJson = rpcDoc.object();
|
||||
Config::RunePageConfig rpc = rpcJson; // implicit cast
|
||||
|
||||
if(rpc.name.isEmpty() || !rpc.runepage) {
|
||||
// invalid
|
||||
return;
|
||||
}
|
||||
|
||||
emit runepageChanged(-1, rpc.name, rpc.runepage);
|
||||
}
|
||||
}
|
||||
|
||||
void RunePageList::clearItems() {
|
||||
while(count()) {
|
||||
QListWidgetItem* item = takeItem(0);
|
||||
delete (RunePage*) item->data(RolePointer).toULongLong();
|
||||
delete item;
|
||||
}
|
||||
|
||||
clear();
|
||||
}
|
||||
|
||||
void RunePageList::addRunepageItem(QString name, int id, const ::RunePage& rp, bool isCurrent) {
|
||||
QListWidgetItem* item = new QListWidgetItem(name);
|
||||
item->setData(RoleId, (uint) id);
|
||||
item->setData(RolePointer, (qulonglong) new ::RunePage(rp));
|
||||
|
||||
const DataDragon::ChampData& champData = findChamp(name);
|
||||
if(champData.key != -1) {
|
||||
QPixmap iamge = dd->getImage(champData.id);
|
||||
item->setIcon(iamge);
|
||||
}
|
||||
|
||||
QString tooltipStr;
|
||||
if(id != -1) {
|
||||
tooltipStr = QString("id: %0\n").arg(id);
|
||||
}
|
||||
tooltipStr += getRuneDescription(rp);
|
||||
item->setToolTip(tooltipStr);
|
||||
|
||||
item->setFlags(item->flags() | Qt::ItemIsEditable);
|
||||
if(isCurrent) {
|
||||
item->setSelected(true);
|
||||
}
|
||||
addItem(item);
|
||||
}
|
||||
|
||||
const DataDragon::ChampData& RunePageList::findChamp(const QString& name) {
|
||||
if(!dd) {
|
||||
return DataDragon::EMPTYCHAMP;
|
||||
}
|
||||
|
||||
// try direct
|
||||
int count = 0;
|
||||
const DataDragon::ChampData& directChampData = dd->getBestMatchingChamp(name, &count);
|
||||
if(directChampData.key != -1) {
|
||||
return directChampData;
|
||||
}
|
||||
|
||||
// not specific
|
||||
if(count > 1) {
|
||||
return DataDragon::EMPTYCHAMP;
|
||||
}
|
||||
|
||||
// try for substrings
|
||||
static const QRegularExpression splittingRegex("\\W+");
|
||||
QStringList list = name.split(splittingRegex, QString::SplitBehavior::SkipEmptyParts);
|
||||
QSet<int> matchedIds;
|
||||
const DataDragon::ChampData* lastMatched = nullptr;
|
||||
for(const QString& entry : list) {
|
||||
count = 0;
|
||||
const DataDragon::ChampData& splitChampData = dd->getBestMatchingChamp(entry, &count);
|
||||
if(count == 1) {
|
||||
matchedIds.insert(splitChampData.key);
|
||||
lastMatched = &splitChampData;
|
||||
} else if(count > 1) {
|
||||
// not specific
|
||||
return DataDragon::EMPTYCHAMP;
|
||||
}
|
||||
}
|
||||
|
||||
if(lastMatched && matchedIds.size() == 1) {
|
||||
return *lastMatched;
|
||||
}
|
||||
|
||||
// not specific or not found
|
||||
return DataDragon::EMPTYCHAMP;
|
||||
}
|
||||
|
||||
QString RunePageList::getRuneDescription(const ::RunePage& runepage) {
|
||||
QString outStr;
|
||||
outStr.reserve(100);
|
||||
QTextStream out(&outStr);
|
||||
|
||||
if(! (bool) runepage) {
|
||||
return {};
|
||||
}
|
||||
|
||||
out << getRuneStyleByID(runepage.primaryStyle) << ' ' << RunePageList::tr("with") << ' ' << getRuneStyleByID(runepage.secondaryStyle);
|
||||
|
||||
for(uint32_t rune : runepage.selectedAspects) {
|
||||
out << '\n' << getRuneText(rune);
|
||||
}
|
||||
return outStr;
|
||||
}
|
||||
|
||||
QString RunePageList::getRuneText(uint32_t id) {
|
||||
if(runeInfo != nullptr) {
|
||||
for(const RuneAspekt& ra : *runeInfo) {
|
||||
if(ra.id == id) {
|
||||
return ra.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QString("(%0)").arg(id);
|
||||
}
|
||||
|
||||
QString RunePageList::getRuneStyleByID(uint32_t id) {
|
||||
if(runeStyles != nullptr) {
|
||||
auto it = std::find_if(runeStyles->begin(), runeStyles->end(), [id](const RuneStyle& rs) { return rs.id == id; });
|
||||
|
||||
if(it != runeStyles->end()) {
|
||||
return it->name;
|
||||
}
|
||||
}
|
||||
|
||||
return QString("(%0)").arg(id);
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
#include "settingstab.h"
|
||||
#include "ui_settingstab.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <Log.h>
|
||||
|
||||
static std::vector<QString> toChampionNameList(const std::vector<StageSettings::SelectedChamp>& scs) {
|
||||
std::vector<QString> out;
|
||||
out.reserve(scs.size());
|
||||
|
||||
std::transform(scs.begin(), scs.end(), std::insert_iterator(out, out.begin()), [](const StageSettings::SelectedChamp& sc) { return sc.name; });
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
SettingsTab::SettingsTab(QWidget *parent) : QWidget(parent), ui(new Ui::SettingsTab) {
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
SettingsTab::~SettingsTab() {
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void SettingsTab::setup(Config::PositionConfig& conf, DataDragon* dd) {
|
||||
this->conf = &conf;
|
||||
this->dd = dd;
|
||||
|
||||
ui->banstage->setDataDragon(dd);
|
||||
ui->pickstage->setDataDragon(dd);
|
||||
|
||||
// load config
|
||||
ui->banstage->loadConfig(conf.ban);
|
||||
ui->pickstage->loadConfig(conf.pick);
|
||||
}
|
||||
|
||||
std::vector<StageSettings::SelectedChamp> SettingsTab::getChamps(LolAutoAccept::State s) const {
|
||||
return getStage(s)->getChampions();
|
||||
}
|
||||
|
||||
bool SettingsTab::getState(LolAutoAccept::State s) const {
|
||||
auto stage = getStage(s);
|
||||
return stage->getState();
|
||||
}
|
||||
|
||||
void SettingsTab::setChamps(LolAutoAccept::State s, const std::vector<QString>& c) {
|
||||
getStage(s)->setChampions(c);
|
||||
}
|
||||
|
||||
void SettingsTab::setState(LolAutoAccept::State s, bool b) {
|
||||
auto stage = getStage(s);
|
||||
return stage->setState(b);
|
||||
}
|
||||
|
||||
Position SettingsTab::getPosition() const {
|
||||
return position;
|
||||
}
|
||||
|
||||
void SettingsTab::banToggled(bool b) {
|
||||
conf->ban.enabled = b;
|
||||
emit toggled(position, LolAutoAccept::State::BAN, b);
|
||||
}
|
||||
|
||||
void SettingsTab::banChampsChanged() {
|
||||
conf->ban.champs = toChampionNameList(ui->banstage->getChampions());
|
||||
emit changed(position, LolAutoAccept::State::BAN);
|
||||
}
|
||||
|
||||
void SettingsTab::pickToggled(bool b) {
|
||||
conf->pick.enabled = b;
|
||||
emit toggled(position, LolAutoAccept::State::PICK, b);
|
||||
}
|
||||
|
||||
void SettingsTab::pickChampsChanged() {
|
||||
auto champs = ui->pickstage->getChampions();
|
||||
auto champnames = toChampionNameList(champs);
|
||||
conf->pick.champs.swap(champnames);
|
||||
emit changed(position, LolAutoAccept::State::BAN);
|
||||
}
|
||||
|
||||
StageSettings* SettingsTab::getStage(LolAutoAccept::State s) const {
|
||||
switch(s) {
|
||||
case LolAutoAccept::State::BAN: return ui->banstage;
|
||||
case LolAutoAccept::State::PICK: return ui->pickstage;
|
||||
default: break;
|
||||
}
|
||||
assert(false); // "invalid" stage (Lobby or Game)
|
||||
return nullptr;
|
||||
}
|
|
@ -10,6 +10,10 @@
|
|||
|
||||
StageSettings::StageSettings(QWidget *parent) : QWidget(parent), ui(new Ui::StageSettings) {
|
||||
ui->setupUi(this);
|
||||
|
||||
auto champsmodel = ui->championList->model();
|
||||
|
||||
QObject::connect(champsmodel, &QAbstractItemModel::rowsMoved, this, &StageSettings::moved);
|
||||
}
|
||||
|
||||
StageSettings::~StageSettings() {
|
||||
|
@ -35,23 +39,23 @@ void StageSettings::setState(bool b) {
|
|||
updateEnabled();
|
||||
}
|
||||
|
||||
StageSettings::SelectedChamp::SelectedChamp(std::string name, uint32_t id) : name(name), id(id) {}
|
||||
StageSettings::SelectedChamp::SelectedChamp(QString name, uint32_t id) : name(name), id(id) {}
|
||||
|
||||
std::vector<StageSettings::SelectedChamp> StageSettings::getChampions() const {
|
||||
std::vector<SelectedChamp> out;
|
||||
out.reserve(ui->championList->count());
|
||||
for(int32_t i = 0; i < ui->championList->count(); ++i) {
|
||||
ChampRow* cr = (ChampRow*) ui->championList->item(i);
|
||||
out.emplace_back(cr->getChamp().toStdString(), cr->getChampID());
|
||||
out.emplace_back(cr->getChamp(), cr->getChampID());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void StageSettings::setChampions(const std::vector<std::string>& champs) {
|
||||
void StageSettings::setChampions(const std::vector<QString>& champs) {
|
||||
clear();
|
||||
|
||||
// add new champs
|
||||
for(const std::string& champ : champs) {
|
||||
for(const QString& champ : champs) {
|
||||
resolveAndAddChamp(champ, champ == champs.back());
|
||||
}
|
||||
}
|
||||
|
@ -60,11 +64,16 @@ void StageSettings::setDataDragon(DataDragon* dd_) {
|
|||
dd = dd_;
|
||||
}
|
||||
|
||||
void StageSettings::addChamp(const std::string& champname, uint32_t id, QPixmap icon) {
|
||||
void StageSettings::addChamp(const DataDragon::ChampData& cd, QPixmap icon) {
|
||||
auto champr = new ChampRow();
|
||||
ui->championList->addItem(champr);
|
||||
|
||||
champr->setChamp(champname, id, icon);
|
||||
champr->setChamp(cd, icon);
|
||||
}
|
||||
|
||||
void StageSettings::loadConfig(Config::StageConfig& c) {
|
||||
setChampions(c.champs);
|
||||
setState(c.enabled);
|
||||
}
|
||||
|
||||
void StageSettings::toggledinternal(int state) {
|
||||
|
@ -78,7 +87,7 @@ void StageSettings::addChamp() {
|
|||
// popup with champion search
|
||||
ChampionSearch cs(dd, this);
|
||||
int res = cs.exec();
|
||||
Log::info << "championsearch result: " << res;
|
||||
qInfo() << "championsearch result: " << res;
|
||||
if(res == QDialog::Accepted) {
|
||||
auto cr = cs.getSearchResult();
|
||||
if(cr) {
|
||||
|
@ -101,19 +110,19 @@ void StageSettings::moved() {
|
|||
emit championsChanged();
|
||||
}
|
||||
|
||||
void StageSettings::resolveAndAddChamp(const std::string& name, bool emitchange) {
|
||||
void StageSettings::resolveAndAddChamp(const QString& name, bool emitchange) {
|
||||
if(dd) {
|
||||
int count = 0;
|
||||
auto cd = dd->getBestMatchingChamp(name, &count);
|
||||
|
||||
dd->getImageAsnyc(cd.id, [this, name, cd, emitchange](QPixmap img) {
|
||||
addChamp(name, cd.key, img);
|
||||
addChamp(cd, img);
|
||||
if(emitchange) {
|
||||
emit championsChanged();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Log::error << __PRETTY_FUNCTION__ << " Datadragon not set!";
|
||||
qCritical() << __PRETTY_FUNCTION__ << " Datadragon not set!";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
#include "x11helper.h"
|
||||
|
||||
const Window X11Helper::InvalidWindow = 0;
|
|
@ -0,0 +1,25 @@
|
|||
#include "x11helper.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
const bool X11Helper::IsSupported = false;
|
||||
|
||||
X11Helper::X11Helper(QObject *parent) : QObject(parent) {
|
||||
|
||||
}
|
||||
|
||||
X11Helper::~X11Helper() {}
|
||||
|
||||
Window X11Helper::findWindow(const QString&, float) {
|
||||
return InvalidWindow;
|
||||
}
|
||||
|
||||
Window X11Helper::searchWindows(Window, const QString&, float) {
|
||||
return InvalidWindow;
|
||||
}
|
||||
|
||||
void X11Helper::map(Window win) {}
|
||||
|
||||
void X11Helper::unmap(Window win) {}
|
||||
|
||||
void X11Helper::setMap(Window win, bool b) {}
|
|
@ -0,0 +1,77 @@
|
|||
#include "x11helper.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
const bool X11Helper::IsSupported = true;
|
||||
|
||||
X11Helper::X11Helper(QObject *parent) : QObject(parent), disp(XOpenDisplay(nullptr)) {
|
||||
|
||||
}
|
||||
|
||||
X11Helper::~X11Helper() {
|
||||
XCloseDisplay(this->disp);
|
||||
}
|
||||
|
||||
Window X11Helper::findWindow(const QString& name, float aspektRatio) {
|
||||
return searchWindows(DefaultRootWindow(disp), name, aspektRatio);
|
||||
}
|
||||
|
||||
Window X11Helper::searchWindows(Window top, const QString& search, float aspektRatio) {
|
||||
{
|
||||
char* window_name;
|
||||
if (XFetchName(disp, top, &window_name)) {
|
||||
QString winName(window_name);
|
||||
XFree(window_name);
|
||||
if (search == winName) {
|
||||
|
||||
if(aspektRatio == 0.0) {
|
||||
return top; // dont look for kids
|
||||
}
|
||||
|
||||
XWindowAttributes attribs;
|
||||
if(XGetWindowAttributes(disp, top, &attribs)) {
|
||||
const float winAspektRation = attribs.width / (float) attribs.height;
|
||||
if(qAbs(winAspektRation - aspektRatio) < aspektRatio/10.0) {
|
||||
return top;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Window* children = nullptr;
|
||||
Window dummy;
|
||||
unsigned int nchildren;
|
||||
if (!XQueryTree(disp, top, &dummy, &dummy, &children, &nchildren)) {
|
||||
return InvalidWindow;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < nchildren; i++) {
|
||||
Window res = searchWindows(children[i], search, aspektRatio);
|
||||
if(res != InvalidWindow) {
|
||||
XFree((char*) children);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
if (children) {
|
||||
XFree((char*) children);
|
||||
}
|
||||
|
||||
return InvalidWindow;
|
||||
}
|
||||
|
||||
void X11Helper::map(Window win) {
|
||||
XMapRaised(disp, win);
|
||||
}
|
||||
|
||||
void X11Helper::unmap(Window win) {
|
||||
XUnmapWindow(disp, win);
|
||||
}
|
||||
|
||||
void X11Helper::setMap(Window win, bool b) {
|
||||
if(b) {
|
||||
map(win);
|
||||
} else {
|
||||
unmap(win);
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
Subproject commit 96d10d6e72ddaffd8b688db5ef2705e38aff3a75
|
||||
Subproject commit 9a43d50969ecc34d9a3bc8944bc2182e55f7a712
|
113
ts/de_DE.ts
|
@ -1,113 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="de_DE">
|
||||
<context>
|
||||
<name>ChampionSearch</name>
|
||||
<message>
|
||||
<location filename="../ui/championsearch.ui" line="14"/>
|
||||
<source>Champion Search</source>
|
||||
<translation>Champion Suche</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/championsearch.ui" line="20"/>
|
||||
<source>Champion:</source>
|
||||
<translation>Champion:</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MainWindow</name>
|
||||
<message>
|
||||
<location filename="../ui/mainwindow.ui" line="20"/>
|
||||
<source>LoL-Auto-Accept</source>
|
||||
<translation>LoL-Auto-Accept</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/mainwindow.ui" line="45"/>
|
||||
<source>Mainswitch</source>
|
||||
<translation>Hautpschalter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/mainwindow.ui" line="52"/>
|
||||
<source>Enable LoL-Auto-Accept</source>
|
||||
<translation>Spiel automatisch annehmen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/mainwindow.ui" line="74"/>
|
||||
<source>Pre Pick</source>
|
||||
<translation>Pre Pick</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/mainwindow.ui" line="118"/>
|
||||
<source>Pick</source>
|
||||
<translation>Pick</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PrePick</source>
|
||||
<translation type="vanished">Pre Pick</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable PrePick</source>
|
||||
<translation type="vanished">Aktivire Pre Pick</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Champion:</source>
|
||||
<translation type="vanished">Champion:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/mainwindow.ui" line="96"/>
|
||||
<source>Ban</source>
|
||||
<translation>Bannen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainwindow.cpp" line="53"/>
|
||||
<source>League of Legends Client not found!</source>
|
||||
<translation>League of Legends Client nicht gefunden!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainwindow.cpp" line="59"/>
|
||||
<source>Auto-Acceptor started!</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainwindow.cpp" line="62"/>
|
||||
<source>Auto-Acceptor stoped!</source>
|
||||
<translation>Auto Acceptor gestoppt!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>StageSettings</name>
|
||||
<message>
|
||||
<source>Champion:</source>
|
||||
<translation type="vanished">Champion:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/stagesettings.cpp" line="25"/>
|
||||
<source>Enable %1</source>
|
||||
<translation>Aktiviere %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Champions matched: %1</source>
|
||||
<translation type="vanished">Übereinstimmende Champions: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Champion: %1
|
||||
Type: %2
|
||||
Title: %3
|
||||
ID: %4</source>
|
||||
<translation type="vanished">Champion: %1
|
||||
Typ: %2
|
||||
Titel: %3
|
||||
ID: %4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/stagesettings.ui" line="74"/>
|
||||
<source>Add Champion</source>
|
||||
<translation>Champion hinzufügen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/stagesettings.ui" line="87"/>
|
||||
<source>Remove Champion</source>
|
||||
<translation>Champion entfernen</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
113
ts/en.ts
|
@ -1,113 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="en_US">
|
||||
<context>
|
||||
<name>ChampionSearch</name>
|
||||
<message>
|
||||
<location filename="../ui/championsearch.ui" line="14"/>
|
||||
<source>Champion Search</source>
|
||||
<translation>Champion Search</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/championsearch.ui" line="20"/>
|
||||
<source>Champion:</source>
|
||||
<translation>Champion:</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MainWindow</name>
|
||||
<message>
|
||||
<location filename="../ui/mainwindow.ui" line="20"/>
|
||||
<source>LoL-Auto-Accept</source>
|
||||
<translation>LoL-Auto-Accept</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/mainwindow.ui" line="45"/>
|
||||
<source>Mainswitch</source>
|
||||
<translation>Mainswitch</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/mainwindow.ui" line="52"/>
|
||||
<source>Enable LoL-Auto-Accept</source>
|
||||
<translation>Automatically accept game</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/mainwindow.ui" line="74"/>
|
||||
<source>Pre Pick</source>
|
||||
<translation>Pre Pick</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/mainwindow.ui" line="118"/>
|
||||
<source>Pick</source>
|
||||
<translation>Pick</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PrePick</source>
|
||||
<translation type="vanished">Pre Pick</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable PrePick</source>
|
||||
<translation type="vanished">Enable Pre Pick</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Champion:</source>
|
||||
<translation type="vanished">Champion:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/mainwindow.ui" line="96"/>
|
||||
<source>Ban</source>
|
||||
<translation>Ban</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainwindow.cpp" line="53"/>
|
||||
<source>League of Legends Client not found!</source>
|
||||
<translation>League of Legends Client not found!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainwindow.cpp" line="59"/>
|
||||
<source>Auto-Acceptor started!</source>
|
||||
<translation>Auto-Acceptor started!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/mainwindow.cpp" line="62"/>
|
||||
<source>Auto-Acceptor stoped!</source>
|
||||
<translation>Auto-Acceptor stopped!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>StageSettings</name>
|
||||
<message>
|
||||
<source>Champion:</source>
|
||||
<translation type="vanished">Champion:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/stagesettings.cpp" line="25"/>
|
||||
<source>Enable %1</source>
|
||||
<translation>Enable %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Champions matched: %1</source>
|
||||
<translation type="vanished">Champions matched: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Champion: %1
|
||||
Type: %2
|
||||
Title: %3
|
||||
ID: %4</source>
|
||||
<translation type="vanished">Champion: %1
|
||||
Type: %2
|
||||
Title: %3
|
||||
ID: %4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/stagesettings.ui" line="74"/>
|
||||
<source>Add Champion</source>
|
||||
<translation>Add Champion</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/stagesettings.ui" line="87"/>
|
||||
<source>Remove Champion</source>
|
||||
<translation>Remove Champion</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|