Загрузка...

[СОФТ] Урок. Работа со Steam WEB Api на C++ Qt

Тема в разделе C/C++ создана пользователем DSTR2 1 дек 2018. 3760 просмотров

Загрузка...
  1. DSTR2
    DSTR2 Автор темы 1 дек 2018 ? 49 19 май 2017
    Доброго времени суток!
    Хотел бы немного рассказать (и показать) о взаимодействии со Steam WEB Api средствами Qt и C++.
    Пишите, если хотите продолжение: статью о работе с инвентарем Steam: получение цены предметов и т.п
    Буду очень благодарен за префикс "Авторская статья".



    Версия, которую мы получим в конце этого урока отлично подходит для повседневного использования тем пользователям, кому часто необходимо узнать оригинальный SteamID64 и дату регистрации.

    Ниже пример окончательной программы:
    [IMG]

    Исходный код, а также скомпилированный проект доступен по ссылке: https://goo.gl/TCivNm
    ВЕРСИИ:
    — SteamUserInfoFull — скомпилированная полная версия этой программы (как на скриншоте выше).
    — SteamUserInfoLite — скомпилированная версия из статьи.
    — SteamUserInfoSource — исходный код из статьи.

    В этой статье описана самая малая часть, так как всего очень много и за один раз всё не покажешь.
    Мы не будем рассматривать то, как устроен формат ответа Json-файла от Steam.
    Всё это можете посмотреть самостоятельно, вставив запрос в браузер.

    Я использую компилятор MinGW32.
    У вас должна быть поддержка SSL (если нет - скачайте эти два файла и добавьте в папку с компилируемым проектом): https://yadi.sk/d/lZZrpzoH3afXY8

    Итак, мы рассмотрим:
    — получение оригинальной ссылки на профиль (SteamID64);
    — получение аватарки профиля;
    — получение даты регистрации аккаунта;
    — получение даты последней активности;
    — получение статуса VAC, количество игровых блокировок, дней с момента последней блокировки и статус профиля в сообществе Steam (в простонародье — КТ).


    Приступим.
    1)
    Для начала работы нам понадобится наш уникальный API ключ для доступа к сервисам Steam.
    Чтобы его получить нужен БЕЗЛИМИТНЫЙ аккаунт Steam.
    Переходим по ссылке https://steamcommunity.com/dev/apikey и вводим рандомный адрес (к примеру, qwertyabc@abcd.com), нажимаем на кнопочку регистрации и сохраняем наш ключ.

    2)
    Теперь запускаем Qt, создаем проект Qt Widgets Application -> указываем название как у меня, чтобы не было разногласий: SteamUserInfo и дальше указываете свой путь.
    Проект создался.
    В файле SteamUserInfo.pro прописываете: QT += network (скрин)
    [IMG]

    3)
    Теперь создаем первый класс. Кликаем на название проекта -> Add new... -> слева выбираем C++, а справа C++ Class.
    Назовем его SteamUserProfileLink
    [IMG]

    4)
    Реализуем наш класс.
    В файле SteamUserProfileLink.h создаем переменные и прототипы функций:
    Код

    #include <QtNetwork/QtNetwork>
    #include <QString>

    class SteamUserProfileLink
    {
    QString apiKey;
    QString steamID64;
    public:
    SteamUserProfileLink();

    void setApiKey(QString key);

    bool setConnection(const QString &steamUrl);

    QString getSteamID64() const;
    };


    Реализуем эти функции.
    Файл SteamUserProfileLink.cpp:

    Код

    #include "SteamUserProfileLink.h"

    SteamUserProfileLink::SteamUserProfileLink() { }

    void SteamUserProfileLink::setApiKey(QString key)
    {
    apiKey = key;
    }

    //true - соединение успешно: вся информация загружена.
    //false - не удалось получить ответ от сервера.
    bool SteamUserProfileLink::setConnection(const QString &steamUrl)
    {
    QNetworkAccessManager manager;
    QNetworkReply *reply = manager.get(
    //Отправляем запрос.
    QNetworkRequest(QString
    ("http://api.steampowered.com/ISteamUser/ResolveVanityURL/v0001/?key=%1&vanityurl=%2").arg(apiKey).arg(steamUrl)));

    QEventLoop loop; //Ждем ответ от сервера.
    QObject::connect(&manager, &QNetworkAccessManager::finished, &loop, &QEventLoop::quit);
    loop.exec();
    reply->deleteLater();

    const QJsonDocument document = QJsonDocument::fromJson(reply.readAll()); //Загружаем Json документ.
    //Если ответ равен 1, значит SteamID64 успешно получен.
    if (document.object().value("response").toObject().value("success").toDouble() == 1.0) {
    steamID64 = document.object().value("response").toObject().value("steamid").toString(); //Запоминаем.
    return true; //Возвращаем true: успешно.
    }
    //Иначе считаем, что такого steamUrl не существует и возвращаем false.
    return false;
    }

    QString SteamUserProfileLink::getSteamID64() const
    {
    return steamID64;
    }


    5)
    Теперь по той же схеме создаем следующий класс SteamPlayerSummaries
    Файл SteamPlayerSummaries.h:
    Код

    #include <QtNetwork/QtNetwork>
    #include <QString>
    #include <QPixmap>

    class SteamPlayerSummaries
    {
    QString apiKey;
    uint timeCreated;//Дата создания аккаунта в формате UTC.
    uint lastLogOff; //Дата последней активности в формате UTC.
    QPixmap avatar; //Аватарка профиля.
    void loadAvatar(const QString &avatarUrl);
    public:
    SteamPlayerSummaries();

    void setApiKey(QString key);

    bool setConnection(const QString &steamID64);

    QString getLastLofOff() const; //Дата последней активности в формате дата-месяц-год.
    QString getTimeCreated() const; //Дата создания профиля в формате дата-месяц-год.
    QPixmap getAvatar() const;
    };

    Файл SteamPlayerSummaries.cpp:

    Код

    #include "SteamPlayerSummaries.h"

    SteamPlayerSummaries::SteamPlayerSummaries() { }
    void SteamPlayerSummaries::setApiKey(QString key)
    {
    apiKey = key;
    }

    //true - соединение успешно: вся информация загружена.
    //false - не удалось получить ответ от сервера.
    bool SteamPlayerSummaries::setConnection(const QString &steamID64)
    {
    QNetworkAccessManager manager;
    QNetworkReply *reply = manager.get(
    //Отправляем запрос.
    QNetworkRequest(QString
    ("http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=%1&steamids=%2").arg(apiKey).arg(steamID64)));

    QEventLoop loop; //Ждем ответ от сервера.
    QObject::connect(&manager, &QNetworkAccessManager::finished, &loop, &QEventLoop::quit);
    loop.exec();
    reply->deleteLater();
    const QJsonDocument document = QJsonDocument::fromJson(reply.readAll());

    if (document.isEmpty()) //ApiKey неправильный.
    return false;
    //Конвертируем массив в object для обращения к элементам по имени, а не индексах.
    const QJsonObject object = document.object().value("response").toObject().value("players").toArray()[0].toObject();
    if (object.isEmpty()) //SteamID не найден.
    return false;

    loadAvatar(object["avatarfull"].toString()); //Загружаем аватарку.

    timeCreated = static_cast<unsigned int>(object["timecreated"].toInt()); //Получаем дату регистрации аккаунта.

    lastLogOff = static_cast<unsigned int>(object["lastlogoff"].toInt()); //Последняя активность.

    return true; //Возвращаем true: успешно загружено.
    }

    void SteamPlayerSummaries::loadAvatar(const QString &avatarUrl) //Загрузка аватарки.
    {
    QNetworkAccessManager manager;
    QNetworkReply *reply = manager.get(QNetworkRequest(avatarUrl));
    QEventLoop loop; //Ждем ответ от сервера.
    QObject::connect(&manager, &QNetworkAccessManager::finished, &loop, &QEventLoop::quit);
    loop.exec();
    reply->deleteLater();
    const QByteArray header = reply.readAll();
    avatar.loadFromData(header,"jpg");
    }

    QString SteamPlayerSummaries::getLastLofOff() const
    {
    //Конвертируем UTC в обычное представление времени.
    static const QString c = QDateTime::fromTime_t(lastLogOff).toString("dd-MM-yyyy");
    return c;
    }

    QString SteamPlayerSummaries::getTimeCreated() const
    {
    //Конвертируем UTC в обычное представление времени.
    static const QString c = QDateTime::fromTime_t(timeCreated).toString("dd-MM-yyyy");
    return c;
    }

    QPixmap SteamPlayerSummaries::getAvatar() const
    {
    return avatar;
    }



    6)
    Теперь создадим файлик для получения информации о блокировках аккаунта.
    Создадим класс SteamPlayerBans:
    Файл SteamPlayerBans.h:
    Код

    #include <QtNetwork/QtNetwork>

    class SteamPlayerBans
    {
    QString apiKey;
    bool communityBanned; //Блокировка в сообществе (КТ).
    bool VACBanned; //Блокировка VAC.
    QString economyBanned;//Блокировка обмена.
    int numberOfGameBans;//Количество игровых блокировок.
    int numberOfVACBans; //Количество VAC блокировок.
    int daysSinceLastBan;//Дней с момента последней блокировки.
    public:
    SteamPlayerBans();

    void setApiKey(QString key);

    bool setConnection(const QString &steamID64);

    bool isCommunityBanned() const;
    bool isVACBanned() const;
    QString getEconomyBan() const;
    int getNumberOfGameBans() const;
    int getNumberOfVACBans() const;
    int getDaysSinceLastBan() const;
    };

    Реализация SteamPlayerBans.cpp

    Код

    #include "SteamPlayerBans.h"

    SteamPlayerBans::SteamPlayerBans() { }

    void SteamPlayerBans::setApiKey(QString key)
    {
    apiKey = key;
    }

    //true - соединение успешно: вся информация загружена.
    //false - не удалось получить ответ от сервера.
    bool SteamPlayerBans::setConnection(const QString &steamID64)
    {
    QNetworkAccessManager manager;
    QNetworkReply *reply = manager.get(
    //Отправляем запрос.
    QNetworkRequest(QString
    ("http://api.steampowered.com/ISteamUser/GetPlayerBans/v1/?key=%1&steamids=%2&format=json").arg(apiKey).arg(steamID64)));

    QEventLoop loop; //Ждем ответ от сервера.
    QObject::connect(&manager, &QNetworkAccessManager::finished, &loop, &QEventLoop::quit);
    loop.exec();
    reply->deleteLater();
    QJsonDocument document = QJsonDocument::fromJson(reply.readAll());

    if (document.isEmpty()) //ApiKey неправильный.
    return false;

    const QJsonObject object = document.object().value("players")[0].toObject();

    if (object.isEmpty()) //SteamID не найден.
    return false;

    communityBanned = object["CommunityBanned"].toBool();
    VACBanned = object["VACBanned"].toBool();
    economyBanned = object["EconomyBan"].toBool();
    numberOfGameBans = object["NumberOfGameBans"].toInt();
    numberOfVACBans = object["NumberOfVACBans"].toInt();
    daysSinceLastBan = object["DaysSinceLastBan"].toInt();
    return true;
    }

    bool SteamPlayerBans::isCommunityBanned() const
    {
    return communityBanned;
    }

    bool SteamPlayerBans::isVACBanned() const
    {
    return VACBanned;
    }

    QString SteamPlayerBans::getEconomyBan() const
    {
    return economyBanned;
    }

    int SteamPlayerBans::getNumberOfGameBans() const
    {
    return numberOfGameBans;
    }

    int SteamPlayerBans::getNumberOfVACBans() const
    {
    return numberOfVACBans;
    }

    int SteamPlayerBans::getDaysSinceLastBan() const
    {
    return daysSinceLastBan;
    }

    Теперь осталось самое простое — создать графический интерфейс для взаимодействия.

    Файл MainWindow.h

    Код

    #include <QMainWindow>
    #include <QLineEdit>
    #include <QWidget>
    #include <QPushButton>
    #include <QLabel>
    #include <QLayout>
    #include <QGroupBox>
    #include <QMessageBox>

    #include "SteamUserProfileLink.h"
    #include "SteamPlayerSummaries.h"
    #include "SteamPlayerBans.h"

    namespace Ui {
    class MainWindow;
    }

    class MainWindow : public QMainWindow
    {
    Q_OBJECT

    public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    //Функция обработки.
    void setup();

    //Парс ссылки: получаем только url: steamcommunity.com/id/abcd -> abcd
    QString getUrl(QString steamProfileUrl);
    private:
    Ui::MainWindow *ui;
    };

    Файл MainWindow.cpp:
    Код

    #include "MainWindow.h"
    #include "ui_MainWindow.h"

    MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
    {
    ui->setupUi(this);

    QFont font;
    setWindowTitle("SteamUserInfo");
    font.setPointSize(10);
    setFont(font);

    QPalette palette;
    palette.setBrush(QPalette::Background, QColor(0xFCE7FC));
    setPalette(palette);

    setFixedSize(500, 600);
    setup();
    }

    MainWindow::~MainWindow()
    {
    delete ui;
    }

    void MainWindow::setup()
    {
    QWidget *mainWidget = new QWidget(this);
    QVBoxLayout *mainLayout = new QVBoxLayout(mainWidget);
    mainLayout->setSizeConstraint(QLayout::SetFixedSize);

    QGroupBox *boxSettings = new QGroupBox("Конфигурация:");
    QGridLayout *boxLayout = new QGridLayout(boxSettings);

    boxLayout->addWidget(new QLabel("Вставьте ApiKey:"), 0, 0);

    QLineEdit *lineApiKey = new QLineEdit();
    boxLayout->addWidget(lineApiKey, 0, 1);

    boxLayout->addWidget(new QLabel("Вставьте ссылку на аккаунт:"), 1, 0);

    QLineEdit *lineSteamProfileLink = new QLineEdit();
    boxLayout->addWidget(lineSteamProfileLink, 1, 1);

    QPushButton *btnFind = new QPushButton("Найти профиль");
    boxLayout->addWidget(btnFind);

    mainLayout->addWidget(boxSettings);

    QGroupBox *boxAccountInfo = new QGroupBox("Информация про аккаунт");
    QGridLayout *layoutAccount = new QGridLayout(boxAccountInfo);

    layoutAccount->addWidget(new QLabel("Аватарка:"), 0, 0);

    QLabel *lblAvatar = new QLabel();
    lblAvatar->setFixedSize(184, 184);
    layoutAccount->addWidget(lblAvatar, 0, 1);

    layoutAccount->addWidget(new QLabel("Оригинальная ссылка (SteamID64):"), 1, 0);

    QLineEdit *lineOriginalSteamLink = new QLineEdit();
    lineOriginalSteamLink->setReadOnly(true);
    layoutAccount->addWidget(lineOriginalSteamLink, 1, 1);

    layoutAccount->addWidget(new QLabel("Дата регистрации:"), 2, 0);

    QLineEdit *lineTimeCreated = new QLineEdit();
    lineTimeCreated->setReadOnly(true);
    layoutAccount->addWidget(lineTimeCreated, 2, 1);

    layoutAccount->addWidget(new QLabel("Последняя активность:"), 3, 0);

    QLineEdit *lineLastLogOff = new QLineEdit();
    lineLastLogOff->setReadOnly(true);
    layoutAccount->addWidget(lineLastLogOff, 3, 1);

    layoutAccount->addWidget(new QLabel("VAC блокировка:"), 4, 0);

    QLineEdit *lineVacBanned = new QLineEdit();
    lineVacBanned->setReadOnly(true);
    layoutAccount->addWidget(lineVacBanned, 4, 1);

    layoutAccount->addWidget(new QLabel("Кол-во игровых блокировок:"), 5, 0);

    QLineEdit *lineGamebans = new QLineEdit();
    lineGamebans->setReadOnly(true);
    layoutAccount->addWidget(lineGamebans, 5, 1);

    layoutAccount->addWidget(new QLabel("Дней с последней блокировки:"), 6, 0);

    QLineEdit *lineDaysSinceLastBan = new QLineEdit();
    lineDaysSinceLastBan->setReadOnly(true);
    layoutAccount->addWidget(lineDaysSinceLastBan, 6, 1);

    layoutAccount->addWidget(new QLabel("Блокировка в сообществе (КТ):"), 7, 0);

    QLineEdit *lineCommunityBan = new QLineEdit();
    lineCommunityBan ->setReadOnly(true);
    layoutAccount->addWidget(lineCommunityBan , 7, 1);

    mainLayout->addWidget(boxAccountInfo);

    connect(btnFind, &QPushButton::clicked, this, [=]() {
    btnFind->setEnabled(false);
    const QString apiKey = lineApiKey->text();
    const QString steamName = MainWindow::getUrl(lineSteamProfileLink->text());
    QString steamID64;
    if (lineSteamProfileLink->text().contains("id")) {
    SteamUserProfileLink steamLink;
    steamLink.setApiKey(apiKey);
    if (steamLink.setConnection(steamName)) {
    steamID64 = steamLink.getSteamID64();
    }
    else {
    QMessageBox::information(this, "Сообщение", "Ошибка. Пользователя найти не удалось.\nПроверье ApiKey и ссылку на профиль.");
    btnFind->setEnabled(true);
    return ;
    }
    }
    else
    steamID64 = steamName;

    SteamPlayerSummaries playerSummaries;
    playerSummaries.setApiKey(apiKey);
    if (!playerSummaries.setConnection(steamID64)) {
    QMessageBox::information(this, "Сообщение", "Ошибка. Пользователя найти не удалось.\nПроверье ApiKey и ссылку на профиль.");
    btnFind->setEnabled(true);
    return ;
    }

    lineOriginalSteamLink->setText("https://steamcommunity.com/profiles/" + steamID64);

    lblAvatar->setPixmap(playerSummaries.getAvatar());
    lineTimeCreated->setText(playerSummaries.getTimeCreated());
    lineLastLogOff->setText(playerSummaries.getLastLofOff());

    SteamPlayerBans bans;
    bans.setApiKey(apiKey);
    bans.setConnection(steamID64);
    lineVacBanned->setText(bans.isVACBanned()? "ДА | " + QString::number(bans.getNumberOfVACBans()): "НЕТ");
    lineGamebans->setText(QString::number(bans.getNumberOfGameBans()));
    lineDaysSinceLastBan->setText(QString::number(bans.getDaysSinceLastBan()));
    lineCommunityBan->setText(bans.isCommunityBanned()? "ДА" : "НЕТ");
    btnFind->setEnabled(true);
    });
    }

    QString MainWindow::getUrl(QString steamProfileUrl)
    {
    if (steamProfileUrl.back() == '/')
    steamProfileUrl = steamProfileUrl.left(steamProfileUrl.length() - 1);

    steamProfileUrl = steamProfileUrl.right(steamProfileUrl.length() - steamProfileUrl.lastIndexOf('/') - 1);
    return steamProfileUrl;
    }



















    Готово! Теперь компилируем и любуемся результатом:
    [IMG]

    Как оцените эту статью? Заслуживает ли статья продолжения, где можно будет рассмотреть получение списка игр, стоимость инвентаря и много других вещей?

    Спасибо за уделенное время! Давайте кодить вместе.
     
    1 дек 2018 Изменено
  2. GITEM
    Очень круто,но я не шарю в кодинге,поэтому просто прочитал для интереса. Я считаю,что если это не паста,то заслуживает авторской
     
  3. DSTR2
    DSTR2 Автор темы 1 дек 2018 ? 49 19 май 2017
    Спасибо!
    Всё писал сам, конечно же.
     
  4. ARE$
    ARE$ 1 дек 2018 Заблокирован(а) 14 5 ноя 2018
    Интересно - но Qt ,хоть C++ Builder был=)
     
  5. WA1Jl
    WA1Jl 1 дек 2018 不要相信別人 226 8 сен 2018
    Нечего не понял, но выглядит достойно!
     
  6. MorSalve
    MorSalve 1 дек 2018 Заблокирован(а) 16 16 апр 2018
    Выглядит годно, может кому то понадобица. Авторку этому человеку, жыво!
     
  7. I_Know_inactive61395
    I_Know_inactive61395 1 дек 2018 Заблокирован(а) 205 25 ноя 2016
    Годно, авторка тут была бы не лишней!
     
  8. 0_0
    0_0 1 дек 2018 XX YEARS | Путь к гаранту! 44 7 ноя 2018
    От души)
     
  9. NDqODXha
    NDqODXha 5 дек 2018 0 9 фев 2018
    Очень годно, однозначно авторку и продолжение)
     
  10. Maksum1
    Maksum1 5 дек 2018 Услуги кодера С/С++ 21 17 янв 2018
    Авторку ему ) Годнота API , топ что сказать )
     
  11. GRAFON11
    GRAFON11 9 дек 2018 68 7 июн 2017
    +Годнота, авторку в студию
     
  12. Alishka471
    Alishka471 9 дек 2018 Живи для себя,но не забывай что есть добро. 36 17 сен 2018
    Да хз я не разбираюсь толком и комменты здесь с такими же симпами как я,так что верить я тут не буду ни кому
     
  13. Alishka471
    Alishka471 9 дек 2018 Живи для себя,но не забывай что есть добро. 36 17 сен 2018
    Достоиных комментов нет которым можно было прислушатся и проверить инфу,только и пишут класс,круто и всякую херню
     
  14. Shellar
    Shellar 11 дек 2018 Заблокирован(а)
    На самом деле годно :roflanBuldiga:
     
  15. Proxylist
    Proxylist 3 янв 2019 Заблокирован(а) 324 11 янв 2018
    Интересно, для ознакомления очень даже отлично!
     
  16. Maikez
    Maikez 3 янв 2019 Сливаю лохов на Низине Арати 435 4 мар 2018
    Неплохо, хороший урок!
     
  17. Metafroud
    Metafroud 3 янв 2019 Разработка - lolz.guru/threads/3346631/ 227 28 фев 2017
    Блять,вот нихуя не понял,но было очень интересно.
    #авторку
     
  18. Metafroud
    Metafroud 8 фев 2019 Разработка - lolz.guru/threads/3346631/ 227 28 фев 2017
    там скомпиленная версия есть,проверь
     
  19. Maksum1
    Maksum1 14 фев 2019 Услуги кодера С/С++ 21 17 янв 2018
    Спасибо автору за даное чудо , смотивировал меня на создание market.dota2.net Helper , жду пока проверят)
     
  20. Lancaster
    Lancaster 7 мар 2019 Быстро накачаться? - lolz.guru/threads/2538866/ 302 1 ноя 2018
    авторку)
     
Top