This commit is contained in:
DanielSvoboda 2024-09-12 18:20:13 -03:00
parent b911c70d35
commit 875363a8da
9 changed files with 428 additions and 15 deletions

View file

@ -11,15 +11,18 @@ on:
env:
BUILD_TYPE: Release
TARGET_REPO: "DanielSvoboda/teste"
SHADPS4_TOKEN: ${{ secrets.SHADPS4_TOKEN }}
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
submodules: recursive
- name: Setup Qt
uses: jurplel/install-qt-action@v4
@ -33,35 +36,86 @@ jobs:
- name: Cache CMake dependency source code
uses: actions/cache@v4
env:
cache-name: ${{ runner.os }}-qt-cache-cmake-dependency-sources
cache-name: ${{ runner.os }}-qt-cache-cmake-dependency-sources
with:
path: |
${{github.workspace}}/build
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
restore-keys: |
${{ env.cache-name }}-
path: |
${{ github.workspace }}/build
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
restore-keys: |
${{ env.cache-name }}-
- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -T ClangCL -DENABLE_QT_GUI=ON
run: cmake -B ${{ github.workspace }}/build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -T ClangCL -DENABLE_QT_GUI=ON
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel
run: cmake --build ${{ github.workspace }}/build --config ${{ env.BUILD_TYPE }} --parallel
- name: Deploy
run: |
mkdir upload
move build/Release/shadPS4.exe upload
windeployqt --dir upload upload/shadPS4.exe
- name: Get date and git hash
id: vars
shell: pwsh
run: |
echo "date=$(Get-Date -Format 'yyyy-MM-dd')" >> $env:GITHUB_OUTPUT
echo "shorthash=$(git rev-parse --short HEAD)" >> $env:GITHUB_OUTPUT
$date = Get-Date -Format 'yyyy-MM-dd'
$shorthash = git rev-parse --short HEAD
echo "date=$date" >> $env:GITHUB_ENV
echo "shorthash=$shorthash" >> $env:GITHUB_ENV
- name: Create Zip Archive
if: github.event_name == 'push'
run: |
$zipName = "shadPS4-win64-qt-$($env:date)-$($env:shorthash).zip"
Compress-Archive -Path upload/* -DestinationPath $zipName
echo "zipName=$zipName" >> $env:GITHUB_ENV
- name: Upload executable
uses: actions/upload-artifact@v4
with:
name: shadps4-win64-qt-${{ steps.vars.outputs.date }}-${{ steps.vars.outputs.shorthash }}
path: upload
- name: Upload Zip Archive
if: github.event_name == 'push'
uses: actions/upload-artifact@v4
with:
name: ${{ env.zipName }}
path: ${{ env.zipName }}
- name: Create GitHub Release
if: github.event_name == 'push'
id: create_release
shell: pwsh
run: |
$date = $env:date
$shorthash = $env:shorthash
$uri = "https://api.github.com/repos/${{ env.TARGET_REPO }}/releases"
$headers = @{
"Authorization" = "token $($env:SHADPS4_TOKEN)"
"Accept" = "application/vnd.github.v3+json"
}
$body = @{
"tag_name" = "build-$date-$shorthash"
"name" = "shadPS4-win64-qt-$($env:date)-$($env:shorthash)"
"draft" = $false
"prerelease" = $false
} | ConvertTo-Json
$response = Invoke-RestMethod -Uri $uri -Method Post -Headers $headers -Body $body -ContentType "application/json"
$response.id | Out-File -FilePath release_id.txt
- name: Upload to GitHub Release
if: github.event_name == 'push'
shell: pwsh
run: |
$release_id = Get-Content release_id.txt
$filePath = $env:zipName
$url = "https://uploads.github.com/repos/${{ env.TARGET_REPO }}/releases/$release_id/assets?name=$filePath"
Write-Output "Uploading $filePath to $url"
Invoke-RestMethod -Uri $url -Method Post -Headers @{
"Authorization" = "token $($env:SHADPS4_TOKEN)"
"Content-Type" = "application/octet-stream"
} -InFile $filePath

View file

@ -628,6 +628,8 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
src/qt_gui/about_dialog.ui
src/qt_gui/cheats_patches.cpp
src/qt_gui/cheats_patches.h
src/qt_gui/checkUpdate.cpp
src/qt_gui/checkUpdate.h
src/qt_gui/memory_patcher.cpp
src/qt_gui/memory_patcher.h
src/qt_gui/main_window_ui.h

View file

@ -21,6 +21,7 @@ static bool useSpecialPad = false;
static int specialPadClass = 1;
static bool isDebugDump = false;
static bool isShowSplash = false;
static bool isAutoUpdate = true;
static bool isNullGpu = false;
static bool shouldCopyGPUBuffers = false;
static bool shouldDumpShaders = false;
@ -102,6 +103,10 @@ bool showSplash() {
return isShowSplash;
}
bool autoUpdate() {
return isAutoUpdate;
}
bool nullGpu() {
return isNullGpu;
}
@ -170,6 +175,10 @@ void setShowSplash(bool enable) {
isShowSplash = enable;
}
void setAutoUpdate(bool enable) {
isAutoUpdate = enable;
}
void setNullGpu(bool enable) {
isNullGpu = enable;
}
@ -365,6 +374,7 @@ void load(const std::filesystem::path& path) {
logType = toml::find_or<std::string>(general, "logType", "sync");
userName = toml::find_or<std::string>(general, "userName", "shadPS4");
isShowSplash = toml::find_or<bool>(general, "showSplash", true);
isAutoUpdate = toml::find_or<bool>(general, "autoUpdate", true);
}
if (data.contains("Input")) {
@ -457,6 +467,7 @@ void save(const std::filesystem::path& path) {
data["General"]["logType"] = logType;
data["General"]["userName"] = userName;
data["General"]["showSplash"] = isShowSplash;
data["General"]["autoUpdate"] = isAutoUpdate;
data["Input"]["useSpecialPad"] = useSpecialPad;
data["Input"]["specialPadClass"] = specialPadClass;
data["GPU"]["screenWidth"] = screenWidth;
@ -511,6 +522,7 @@ void setDefaultValues() {
specialPadClass = 1;
isDebugDump = false;
isShowSplash = false;
isAutoUpdate = true;
isNullGpu = false;
shouldDumpShaders = false;
shouldDumpPM4 = false;
@ -526,4 +538,4 @@ void setDefaultValues() {
gpuId = -1;
}
} // namespace Config
} // namespace Config

View file

@ -26,6 +26,7 @@ s32 getGpuId();
bool debugDump();
bool showSplash();
bool autoUpdate();
bool nullGpu();
bool copyGPUCmdBuffers();
bool dumpShaders();
@ -35,6 +36,7 @@ u32 vblankDiv();
void setDebugDump(bool enable);
void setShowSplash(bool enable);
void setAutoUpdate(bool enable);
void setNullGpu(bool enable);
void setCopyGPUCmdBuffers(bool enable);
void setDumpShaders(bool enable);

289
src/qt_gui/checkUpdate.cpp Normal file
View file

@ -0,0 +1,289 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <filesystem>
#include <fstream>
#include <iostream>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QLabel>
#include <QMessageBox>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QPushButton>
#include <QString>
#include <QVBoxLayout>
#include <common/config.h>
#include <common/path_util.h>
#include <common/scm_rev.h>
#include "checkUpdate.h"
//#include "externals/minizip-ng/mz.h"
//#include "externals/minizip-ng/mz_strm.h"
//#include "externals/minizip-ng/mz_strm_buf.h"
//#include "externals/minizip-ng/mz_strm_mem.h"
//#include "externals/minizip-ng/mz_strm_os.h"
//#include "externals/minizip-ng/mz_zip.h"
using namespace Common::FS;
namespace fs = std::filesystem;
CheckUpdate::CheckUpdate(QWidget* parent) : QDialog(parent) {
setWindowTitle("Update Check");
CheckForUpdates();
}
void CheckUpdate::CheckForUpdates() {
QNetworkAccessManager* manager = new QNetworkAccessManager(this);
QNetworkRequest request(
QUrl("https://api.github.com/repos/DanielSvoboda/teste/releases/latest"));
QNetworkReply* reply = manager->get(request);
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
if (reply->error() != QNetworkReply::NoError) {
QMessageBox::warning(this, tr("Error"),
QString(tr("Network error: ") + "\n%1").arg(reply->errorString()));
reply->deleteLater();
return;
}
QByteArray response = reply->readAll();
QJsonDocument jsonDoc(QJsonDocument::fromJson(response));
QJsonObject jsonObj = jsonDoc.object();
QString downloadUrl =
jsonObj["assets"].toArray().first().toObject()["browser_download_url"].toString();
QString latestVersion = QFileInfo(downloadUrl).baseName();
QString latestRev = latestVersion.right(7);
QString currentRev = QString::fromStdString(Common::g_scm_rev).left(7);
if (latestRev == currentRev) {
setupUI_NoUpdate();
} else {
updateDownloadUrl = downloadUrl;
setupUI_UpdateAvailable(downloadUrl);
}
reply->deleteLater();
});
}
void CheckUpdate::setupUI_NoUpdate() {
QVBoxLayout* layout = new QVBoxLayout(this);
QLabel* noUpdateLabel = new QLabel("Your version is already up to date!.", this);
layout->addWidget(noUpdateLabel);
autoUpdateCheckBox = new QCheckBox("Auto Update", this);
layout->addWidget(autoUpdateCheckBox);
autoUpdateCheckBox->setChecked(Config::autoUpdate());
connect(autoUpdateCheckBox, &QCheckBox::stateChanged, this, [](int state) {
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
Config::setAutoUpdate(state == Qt::Checked);
Config::save(user_dir / "config.toml");
});
setLayout(layout);
}
void CheckUpdate::setupUI_UpdateAvailable(const QString& downloadUrl) {
QVBoxLayout* layout = new QVBoxLayout(this);
QLabel* updateLabel =
new QLabel("An update is available!\nDo you want to download and install it?", this);
updateLabel->setAlignment(Qt::AlignCenter);
layout->addWidget(updateLabel);
// Criar um layout horizontal para os botões
QHBoxLayout* buttonLayout = new QHBoxLayout();
yesButton = new QPushButton("Yes", this);
noButton = new QPushButton("No", this);
// Adicionar os botões ao layout horizontal
buttonLayout->addWidget(yesButton);
buttonLayout->addWidget(noButton);
// Adicionar o layout horizontal ao layout principal
layout->addLayout(buttonLayout);
connect(yesButton, &QPushButton::clicked, this,
[this]() { DownloadAndInstallUpdate(updateDownloadUrl); });
connect(noButton, &QPushButton::clicked, this, [this]() { close(); });
autoUpdateCheckBox = new QCheckBox("Auto Update (Check at Startup)", this);
layout->addWidget(autoUpdateCheckBox);
autoUpdateCheckBox->setChecked(Config::autoUpdate());
connect(autoUpdateCheckBox, &QCheckBox::stateChanged, this, [](int state) {
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
Config::setAutoUpdate(state == Qt::Checked);
Config::save(user_dir / "config.toml");
});
setLayout(layout);
}
void CheckUpdate::DownloadAndInstallUpdate(const QString& url) {
QNetworkAccessManager* manager = new QNetworkAccessManager(this);
QNetworkRequest request(url);
QNetworkReply* reply = manager->get(request);
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
if (reply->error() != QNetworkReply::NoError) {
QMessageBox::warning(this, tr("Error"),
QString(tr("Network error: ") + "\n%1").arg(reply->errorString()));
reply->deleteLater();
return;
}
QString userPath =
QString::fromStdString(Common::FS::GetUserPath(Common::FS::PathType::UserDir).string());
QString tempDownloadPath = userPath + "/temp_download_update";
QDir dir(tempDownloadPath);
if (!dir.exists()) {
dir.mkpath(".");
}
QString downloadPath = tempDownloadPath + "/temp_download_update.zip";
QFile file(downloadPath);
if (file.open(QIODevice::WriteOnly)) {
file.write(reply->readAll());
file.close();
QMessageBox::information(this, tr("Download Complete"),
tr("The update has been downloaded. Starting installation."));
Unzip();
} else {
QMessageBox::warning(
this, tr("Error"),
QString(tr("Failed to save the update file at") + "\n%1").arg(downloadPath));
}
reply->deleteLater();
});
}
void CheckUpdate::Unzip() {
//QString userPath =
// QString::fromStdString(Common::FS::GetUserPath(Common::FS::PathType::UserDir).string());
//QString tempDirPath = userPath + "/temp_download_update";
//QString zipFilePath = tempDirPath + "/temp_download_update.zip";
//if (!fs::exists(zipFilePath.toStdString())) {
// QMessageBox::warning(this, tr("Error"),
// QString(tr("Arquivo zip não encontrado:") + "\n%1").arg(zipFilePath));
// return;
//}
//void* zip_reader = NULL;
//void* stream = NULL;
//mz_stream_os_create();
//if (mz_stream_os_open(stream, zipFilePath.toStdString().c_str(), MZ_OPEN_MODE_READ) != MZ_OK) {
// QMessageBox::warning(this, tr("Error"),
// QString(tr("Erro ao abrir o arquivo zip") + "\n%1").arg(zipFilePath));
// mz_stream_os_delete(&stream);
// return;
//}
//// Criar o leitor do ZIP
//mz_zip_create();
//if (mz_zip_open(zip_reader, stream, MZ_OPEN_MODE_READ) != MZ_OK) {
// QMessageBox::warning(
// this, tr("Error"),
// QString(tr("Erro ao abrir o arquivo zip com mz_zip_open") + "\n%1").arg(zipFilePath));
// mz_zip_delete(&zip_reader);
// mz_stream_os_delete(&stream);
// return;
//}
//// Passa por (arquivo ou diretório) no arquivo zip
//while (mz_zip_goto_next_entry(zip_reader) == MZ_OK) {
// mz_zip_file* file_info = nullptr;
// if (mz_zip_entry_get_info(zip_reader, &file_info) != MZ_OK) {
// QMessageBox::warning(
// this, tr("Error"),
// QString(tr("Erro ao obter informações da entrada no zip.") + "\n%1")
// .arg(zipFilePath));
// continue;
// }
// QString caminho_arquivo = tempDirPath + "/" + file_info->filename;
// // Verifique se a entrada do zip é um diretório
// if (mz_zip_entry_is_dir(zip_reader) == MZ_OK) {
// fs::create_directories(caminho_arquivo.toStdString());
// QMessageBox::warning(this, tr("Error"),
// QString(tr("Diretório criado:") + "\n%1").arg(caminho_arquivo));
// } else {
// // Certifique-se de que o diretório pai do arquivo exista
// fs::create_directories(fs::path(caminho_arquivo.toStdString()).parent_path());
// // Abra o arquivo de saída para gravação
// std::ofstream arquivo_saida(caminho_arquivo.toStdString(), std::ios::binary);
// if (!arquivo_saida) {
// QMessageBox::warning(
// this, tr("Error"),
// QString(tr("Erro ao abrir o arquivo de saída:") + "\n%1").arg(caminho_arquivo));
// mz_zip_entry_close(zip_reader);
// continue;
// }
// // Buffer temporário para leitura dos dados
// char buffer[4096];
// int32_t bytes_lidos;
// // Leia os dados do arquivo zip e escreva no arquivo de saída
// while ((bytes_lidos = mz_zip_entry_read(zip_reader, buffer, sizeof(buffer))) > 0) {
// arquivo_saida.write(buffer, bytes_lidos);
// }
// arquivo_saida.close();
// QMessageBox::warning(this, tr("Error"),
// QString(tr("Arquivo extraído:") + "\n%1").arg(caminho_arquivo));
// }
// mz_zip_entry_close(zip_reader);
//}
//// Fechar o arquivo zip
//mz_zip_close(zip_reader);
//mz_zip_delete(&zip_reader);
//mz_stream_os_close(stream);
//mz_stream_os_delete(&stream);
//QMessageBox::warning(this, tr("Error"),
// QString(tr("Descompactação concluída em:") + "\n%1").arg(tempDirPath));
}
//// Criar e executar o arquivo batch para atualizar
// QFile batFile(tempDirPath + "/update.bat");
// if (batFile.open(QIODevice::WriteOnly)) {
// QTextStream out(&batFile);
// out << "@echo off\n";
// out << "taskkill /IM shadps4.exe /F\n";
// out << "move /Y \"" << tempDirPath << "\\*\" \"" << userPath << "\"\n";
// out << "start \"\" \"" << userPath << "\\shadps4.exe\"\n";
// batFile.close();
// if (!QProcess::startDetached(batFile.fileName())) {
// QMessageBox::warning(
// this, tr("Error"),
// tr("Failed to start the update batch file:\n%1").arg(batFile.fileName()));
// }
//} else {
// QMessageBox::warning(
// this, tr("Error"),
// tr("Failed to create the update batch file:\n%1").arg(batFile.fileName()));
//}

31
src/qt_gui/checkUpdate.h Normal file
View file

@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef CHECKUPDATE_H
#define CHECKUPDATE_H
#include <QCheckBox>
#include <QDialog>
class CheckUpdate : public QDialog {
Q_OBJECT
public:
explicit CheckUpdate(QWidget* parent = nullptr);
private slots:
void CheckForUpdates();
void DownloadAndInstallUpdate(const QString& url);
void Unzip();
private:
void setupUI_NoUpdate();
void setupUI_UpdateAvailable(const QString& downloadUrl);
QCheckBox* autoUpdateCheckBox;
QPushButton* yesButton;
QPushButton* noButton;
QString updateDownloadUrl;
};
#endif // CHECKUPDATE_H

View file

@ -6,6 +6,7 @@
#include "about_dialog.h"
#include "cheats_patches.h"
#include "checkUpdate.h"
#include "common/io_file.h"
#include "common/string_util.h"
#include "common/version.h"
@ -46,6 +47,7 @@ bool MainWindow::Init() {
this->show();
// load game list
LoadGameLists();
CheckUpdateMain(true);
auto end = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
@ -160,6 +162,18 @@ void MainWindow::LoadGameLists() {
}
}
void MainWindow::CheckUpdateMain(bool check) {
#ifdef _WIN64
if (check) {
if (!Config::autoUpdate()) {
return;
}
}
auto checkUpdate = new CheckUpdate(this);
checkUpdate->show();
#endif
}
void MainWindow::GetPhysicalDevices() {
Vulkan::Instance instance(false, false);
auto physical_devices = instance.GetPhysicalDevices();
@ -221,6 +235,8 @@ void MainWindow::CreateConnects() {
settingsDialog->exec();
});
connect(ui->updaterAct, &QAction::triggered, this, [this]() { CheckUpdateMain(false); });
connect(ui->aboutAct, &QAction::triggered, this, [this]() {
auto aboutDialog = new AboutDialog(this);
aboutDialog->exec();
@ -845,6 +861,7 @@ void MainWindow::SetUiIcons(bool isWhite) {
ui->bootInstallPkgAct->setIcon(RecolorIcon(ui->bootInstallPkgAct->icon(), isWhite));
ui->bootGameAct->setIcon(RecolorIcon(ui->bootGameAct->icon(), isWhite));
ui->exitAct->setIcon(RecolorIcon(ui->exitAct->icon(), isWhite));
ui->updaterAct->setIcon(RecolorIcon(ui->updaterAct->icon(), isWhite));
ui->aboutAct->setIcon(RecolorIcon(ui->aboutAct->icon(), isWhite));
ui->setlistModeListAct->setIcon(RecolorIcon(ui->setlistModeListAct->icon(), isWhite));
ui->setlistModeGridAct->setIcon(RecolorIcon(ui->setlistModeGridAct->icon(), isWhite));
@ -949,4 +966,4 @@ void MainWindow::OnLanguageChanged(const std::string& locale) {
Config::setEmulatorLanguage(locale);
LoadTranslation();
}
}

View file

@ -54,6 +54,7 @@ private:
void CreateDockWindows();
void GetPhysicalDevices();
void LoadGameLists();
void CheckUpdateMain(bool check);
void CreateConnects();
void SetLastUsedTheme();
void SetLastIconSizeBullet();

View file

@ -26,6 +26,7 @@ public:
QAction* downloadCheatsPatchesAct;
QAction* dumpGameListAct;
QAction* pkgViewerAct;
QAction* updaterAct;
QAction* aboutAct;
QAction* configureAct;
QAction* setThemeDark;
@ -127,6 +128,8 @@ public:
pkgViewerAct = new QAction(MainWindow);
pkgViewerAct->setObjectName("pkgViewer");
pkgViewerAct->setIcon(QIcon(":images/file_icon.png"));
updaterAct = new QAction(MainWindow);
updaterAct->setObjectName("updaterAct");
aboutAct = new QAction(MainWindow);
aboutAct->setObjectName("aboutAct");
aboutAct->setIcon(QIcon(":images/about_icon.png"));
@ -285,6 +288,7 @@ public:
menuUtils->addAction(downloadCheatsPatchesAct);
menuUtils->addAction(dumpGameListAct);
menuUtils->addAction(pkgViewerAct);
menuAbout->addAction(updaterAct);
menuAbout->addAction(aboutAct);
retranslateUi(MainWindow);
@ -299,6 +303,7 @@ public:
bootInstallPkgAct->setText(
QCoreApplication::translate("MainWindow", "Install Packages (PKG)", nullptr));
bootGameAct->setText(QCoreApplication::translate("MainWindow", "Boot Game", nullptr));
updaterAct->setText(QCoreApplication::translate("MainWindow", "Check Update", nullptr));
aboutAct->setText(QCoreApplication::translate("MainWindow", "About shadPS4", nullptr));
configureAct->setText(QCoreApplication::translate("MainWindow", "Configure...", nullptr));
#if QT_CONFIG(tooltip)