still WIP, but closer

master
Tibor 11 months ago
parent 6bc7d02145
commit 51551fcc8d
  1. 181
      giantswdefimporter.cpp
  2. 37
      giantswdefimporter.h
  3. 62
      main.cpp
  4. 69
      mainwindow.cpp
  5. 16
      mainwindow.h
  6. 30
      mainwindow.ui
  7. 4
      wdef-importer.pro

@ -0,0 +1,181 @@
#include "giantswdefimporter.h"
#include <QOperatingSystemVersion>
#include <QSettings>
#include <QMessageBox>
#include <QFileDialog>
#include <QFile>
#include <QProcess>
#include <vector>
#include <string>
GiantsWdefImporter::GiantsWdefImporter()
{
}
fs::path GiantsWdefImporter::askGiantsDirectory()
{
QMessageBox::information(
nullptr,
"wdefs",
"Could not locate your Giants installation automatically.\nPlease browse to your Giants folder and select GiantsMain.exe."
);
QString filename { QFileDialog::getOpenFileName(nullptr, "wdefs", "C:\\", "GiantsMain.exe") };
if (!filename.isEmpty()) {
return fs::path(filename.toStdString()).parent_path();
}
return fs::path();
}
fs::path GiantsWdefImporter::locateGiantsFolder()
{
if (QOperatingSystemVersion::Windows == QOperatingSystemVersion::currentType()) {
std::vector<std::string> possiblePaths {
"C:\\Program Files (x86)\\GOG Galaxy\\Games\\Giants - Citizen Kabuto",
"C:\\Program Files\\GOG Galaxy\\Games\\Giants - Citizen Kabuto",
"C:\\Program Files (x86)\\GOG.com\\Games\\Giants - Citizen Kabuto",
"C:\\Program Files\\GOG.com\\Games\\Giants - Citizen Kabuto",
"C:\\Program Files (x86)\\Steam\\steamapps\\common\\Giants Citizen Kabuto",
"C:\\Program Files\\Steam\\steamapps\\common\\Giants Citizen Kabuto"
};
for (auto& path : possiblePaths) {
if (fs::exists(path + "\\GiantsMain.exe")) {
return fs::path(path);
}
}
QSettings reg {"HKEY_CURRENT_USER\\Software\\PlanetMoon\\Giants", QSettings::NativeFormat };
QString regPath { reg.value("DestDir", QString()).toString().replace("\\", "\\\\") };
std::string fullPath { regPath.toStdString() + "\\GiantsMain.exe" };
if (fs::exists(fullPath)) {
return fs::path(regPath.toStdString());
}
}
return askGiantsDirectory();
}
void GiantsWdefImporter::backupFile(fs::path const& path)
{
std::string parent = path.parent_path().string();
std::string stem = path.stem().string();
std::string dest { fs::path(path.parent_path() / path.stem()).string().append("_original").append(path.extension().string()) };
if (fs::exists(dest)) {
return;
}
// TODO implement error handling
fs::copy(path, dest);
}
void GiantsWdefImporter::revertFile(const std::filesystem::path& path)
{
std::string dest { fs::path(path.parent_path() / path.stem()).string().append("_original").append(path.extension().string()) };
if (!fs::exists(dest)) {
QMessageBox::critical(nullptr, "wdefs", "There was a critical error while applying the mod. Your game couldn't be restored to original state. Please message the mods on Discord.");
exit(-1);
}
// TODO implement error handling
fs::copy(dest, path);
}
void GiantsWdefImporter::setParent(QObject* parent)
{
_parent = parent;
}
QByteArray GiantsWdefImporter::newExeBytes(const QByteArray& wdefsBytes, const std::filesystem::path& giantsMainPath)
{
QByteArray checksum { "\x78\x05\x44\xb6" }; // should be at offset 0x152bff in giantsmain.exe
QFile exeFile { QString::fromStdString(giantsMainPath.string()) };
if (!exeFile.exists()) {
QMessageBox::critical(nullptr, "wdefs", "GiantsMain.exe doesn't exist in " + QString::fromStdString(giantsMainPath.string()) + "!");
}
if (!exeFile.open(QIODevice::ReadOnly)) {
QMessageBox::critical(nullptr, "wdefs", "Unable to open GiantsMain.exe for reading.");
}
QByteArray content { exeFile.readAll() };
int index { content.indexOf(checksum) };
if (index < 0) {
QMessageBox::critical(nullptr, "wdefs", "Could not find wdefs checksum in embedded GiantsMain.exe. If you are 100% sure this is unmodded Giants 1.502.1 please report this to Amazed#0001 on Discord or create an issue on the Git project.");
exit(-1);
}
// TODO go on here: https://git.hipstercat.fr/hipstercat/giants-wdefs-importer-gui/src/branch/master/main.py#L162
Q_UNUSED(wdefsBytes);
return QByteArray();
}
GiantsWdefImporter::StartResult GiantsWdefImporter::startGiantsWithWdefsBytes(QByteArray const& wdefsBytes, fs::path const& wdefsPath, fs::path const& giantsMainPath, QPushButton* button)
{
// switching to QFile here from filesystem for ease of use
QFile wdefsFile(QString::fromStdString(wdefsPath.string()));
wdefsFile.open(QIODevice::WriteOnly);
bool wasWriteSuccess = -1 != wdefsFile.write(wdefsBytes);
if (!wasWriteSuccess) {
return StartResult::FAILURE;
}
QByteArray newBytes = newExeBytes(wdefsBytes, giantsMainPath);
QFile exeFile(QString::fromStdString(giantsMainPath.string()));
exeFile.open(QIODevice::WriteOnly);
wasWriteSuccess = -1 != exeFile.write(newBytes);
if (!wasWriteSuccess) {
return StartResult::FAILURE;
}
auto giantsFinished = [&]() {
revertFile(giantsMainPath);
revertFile(wdefsPath);
QMessageBox::information(nullptr, "wdefs", "Giants has been reverted to original state.");
button->setText("Play");
button->setEnabled(true);
};
QProcess process(_parent);
QObject::connect(&process, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), [&]() {
giantsFinished();
});
process.setWorkingDirectory(QString::fromStdString(giantsMainPath.parent_path().string()));
if (QOperatingSystemVersion::Windows != QOperatingSystemVersion::currentType()) {
QMessageBox::warning(nullptr, "wdefs", "For now, this program only works on Windows. Please consider contacting taibsu#1841 or Amazed#0001 in the GiantsWD Discord channel for further usage.");
return StartResult::FAILURE;
}
button->setText("Game started");
process.start(QString::fromStdString(giantsMainPath.string()), { "-launcher" });
return StartResult::SUCCESS;
}

@ -0,0 +1,37 @@
#ifndef GIANTSWDEFIMPORTER_H
#define GIANTSWDEFIMPORTER_H
#include <filesystem>
#include <QByteArray>
#include <QPushButton>
namespace fs = std::filesystem;
class GiantsWdefImporter
{
public:
enum class StartResult {
SUCCESS,
FAILURE
};
GiantsWdefImporter();
fs::path askGiantsDirectory();
fs::path locateGiantsFolder();
void backupFile(fs::path const& path);
void revertFile(fs::path const& path);
void setParent(QObject* parent);
QByteArray newExeBytes(QByteArray const& wdefsBytes, fs::path const& giantsMainPath);
StartResult startGiantsWithWdefsBytes(QByteArray const& wdefsBytes, fs::path const& wdefsPath, fs::path const& giantsMainPath, QPushButton* button);
private:
QObject* _parent { nullptr };
};
#endif // GIANTSWDEFIMPORTER_H

@ -1,67 +1,7 @@
#include "mainwindow.h"
#include <QApplication>
#include <QOperatingSystemVersion>
#include <QSettings>
#include <QMessageBox>
#include <QFileDialog>
#include <filesystem>
#include <vector>
#include <string>
#include <iostream>
namespace fs = std::filesystem;
fs::path askGiantsDirectory()
{
QMessageBox::information(
nullptr,
"wdefs",
"Could not locate your Giants installation automatically.\nPlease browse to your Giants folder and select GiantsMain.exe."
);
QString filename { QFileDialog::getOpenFileName(nullptr, "wdefs", "C:\\", "GiantsMain.exe") };
if (!filename.isEmpty()) {
return fs::path(filename.toStdString()).parent_path();
}
return fs::path();
}
fs::path locateGiantsFolder()
{
if (QOperatingSystemVersion::Windows == QOperatingSystemVersion::currentType()) {
std::vector<std::string> possiblePaths {
"C:\\Program Files (x86)\\GOG Galaxy\\Games\\Giants - Citizen Kabuto",
"C:\\Program Files\\GOG Galaxy\\Games\\Giants - Citizen Kabuto",
"C:\\Program Files (x86)\\GOG.com\\Games\\Giants - Citizen Kabuto",
"C:\\Program Files\\GOG.com\\Games\\Giants - Citizen Kabuto",
"C:\\Program Files (x86)\\Steam\\steamapps\\common\\Giants Citizen Kabuto",
"C:\\Program Files\\Steam\\steamapps\\common\\Giants Citizen Kabuto",
// "D:\\Games\\Giants - Citizen Kabuto"
};
for (auto& path : possiblePaths) {
if (fs::exists(path.append("\\GiantsMain.exe"))) {
return fs::path(path);
}
}
QSettings reg {"HKEY_CURRENT_USER\\Software\\PlanetMoon\\Giants", QSettings::NativeFormat };
QString regPath { reg.value("DestDir", QString()).toString().replace("\\", "\\\\") };
std::string fullPath { regPath.append("\\GiantsMain.exe").toStdString() };
if (fs::exists(fullPath)) {
return fs::path(fullPath);
}
}
return askGiantsDirectory();
}
int main(int argc, char *argv[])
{
@ -69,7 +9,5 @@ int main(int argc, char *argv[])
MainWindow w;
w.show();
fs::path folder = locateGiantsFolder();
return a.exec();
}

@ -1,11 +1,38 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QTextEdit>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <fstream>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
_importer.setParent(this);
_giantsPath = _importer.locateGiantsFolder();
if (_giantsPath.empty()) {
QMessageBox::critical(
nullptr,
"Critical error",
"Unable to locate Giants folder! Please install Giants and try again."
);
QApplication::exit(-1);
}
_wdefsPath = _giantsPath / "Bin" / "wdefs.bin";
_giantsMainPath = _giantsPath / "GiantsMain.exe";
QMetaObject::connectSlotsByName(this);
}
MainWindow::~MainWindow()
@ -13,3 +40,45 @@ MainWindow::~MainWindow()
delete ui;
}
void MainWindow::on_lineEdit_textEdited(const QString &text)
{
ui->pushButton->setEnabled(!text.isEmpty());
}
void MainWindow::on_pushButton_clicked()
{
ui->pushButton->setEnabled(false);
_importer.backupFile(_wdefsPath);
_importer.backupFile(_giantsMainPath);
QString text { ui->lineEdit->text() };
// this should never happen
if (text.isEmpty()) {
QMessageBox::critical(nullptr, "wdefs", "URL is empty!");
return;
}
QNetworkAccessManager manager;
QNetworkRequest request(text);
QNetworkReply* reply { manager.get(request) };
if (!reply) {
QMessageBox::critical(nullptr, "wdefs", "Could not download wdefs at URL.");
return;
}
QByteArray answer { reply->readAll() };
GiantsWdefImporter::StartResult giantsStartResult = _importer.startGiantsWithWdefsBytes(answer, _wdefsPath, _giantsMainPath, ui->pushButton);
if (GiantsWdefImporter::StartResult::SUCCESS != giantsStartResult) {
_importer.revertFile(_giantsMainPath);
_importer.revertFile(_wdefsPath);
QMessageBox::warning(nullptr, "Wdefs", "There was a problem while applying mod. Your game has been restored to original state.");
}
}

@ -3,6 +3,12 @@
#include <QMainWindow>
#include <filesystem>
#include "giantswdefimporter.h"
namespace fs = std::filesystem;
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
@ -15,7 +21,17 @@ public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_lineEdit_textEdited(const QString &text);
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
fs::path _giantsPath;
fs::path _wdefsPath;
fs::path _giantsMainPath;
GiantsWdefImporter _importer;
};
#endif // MAINWINDOW_H

@ -30,17 +30,17 @@
<item row="0" column="2">
<widget class="QPushButton" name="pushButton">
<property name="enabled">
<bool>false</bool>
<bool>false</bool>
</property>
<property name="text">
<string>Play</string>
<string>Play</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>URL to wdefs file</string>
<string>URL to wdefs file</string>
</property>
</widget>
</item>
@ -53,11 +53,31 @@
<x>0</x>
<y>0</y>
<width>548</width>
<height>21</height>
<height>20</height>
</rect>
</property>
</widget>
</widget>
<resources/>
<connections/>
<connections>
<connection>
<sender>lineEdit</sender>
<signal>textEdited(QString)</signal>
<receiver>MainWindow</receiver>
<slot>onTextEditChanged(QString)</slot>
<hints>
<hint type="sourcelabel">
<x>275</x>
<y>60</y>
</hint>
<hint type="destinationlabel">
<x>273</x>
<y>52</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>onTextEditChanged(QString)</slot>
</slots>
</ui>

@ -1,4 +1,4 @@
QT += core gui
QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
@ -9,10 +9,12 @@ CONFIG += c++17
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
giantswdefimporter.cpp \
main.cpp \
mainwindow.cpp
HEADERS += \
giantswdefimporter.h \
mainwindow.h
FORMS += \

Loading…
Cancel
Save