# include "giantswdefimporter.h"
# include <QOperatingSystemVersion>
# include <QSettings>
# include <QMessageBox>
# include <QFileDialog>
# include <QFile>
# include <QProcess>
# include <QDebug>
# include <vector>
# include <string>
# include "zlib.h"
GiantsWdefImporter : : GiantsWdefImporter ( )
{
}
fs : : path GiantsWdefImporter : : askGiantsDirectory ( )
{
QMessageBox : : information (
nullptr ,
" wdefs " ,
" Could not locate your Giants installation automatically. \n Please 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 , fs : : copy_options : : overwrite_existing ) ;
}
void GiantsWdefImporter : : giantsFinished ( const std : : filesystem : : path & giantsMainPath , const std : : filesystem : : path & wdefsPath , QPushButton * btn )
{
revertFile ( giantsMainPath ) ;
revertFile ( wdefsPath ) ;
QMessageBox : : information ( nullptr , " wdefs " , " Giants has been reverted to original state. " ) ;
btn - > setText ( " Play " ) ;
btn - > setEnabled ( true ) ;
}
void GiantsWdefImporter : : setParent ( QObject * parent )
{
_parent = parent ;
}
int GiantsWdefImporter : : crc ( const QByteArray & bytes )
{
uLong prev { crc32 ( 0L , reinterpret_cast < const unsigned char * > ( bytes . data ( ) ) , bytes . length ( ) ) } ;
return static_cast < int > ( prev ) ;
}
QByteArray GiantsWdefImporter : : newExeBytes ( const QByteArray & wdefsBytes , const std : : filesystem : : path & giantsMainPath )
{
// Look for checksum in exe file
// subject to change
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 ) ;
}
int wdefsCrc { crc ( wdefsBytes ) } ;
QByteArray wdefsCrcBytes ;
wdefsCrcBytes . setNum ( wdefsCrc ) ;
content . replace ( index , checksum . length ( ) , wdefsCrcBytes ) ;
return content ;
}
GiantsWdefImporter : : StartResult GiantsWdefImporter : : startGiantsWithWdefsBytes ( QByteArray const & wdefsBytes , fs : : path const & wdefsPath , fs : : path const & giantsMainPath , QPushButton * button )
{
// Try writing the wdefs file
// 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 ;
}
// Try writing the exe file
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 ;
}
// Try starting GiantsMain.exe
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 ;
}
_giantsMainProcess = new QProcess ( _parent ) ;
QObject : : connect ( _giantsMainProcess , & QProcess : : stateChanged , [ & ] ( QProcess : : ProcessState state ) {
qDebug ( ) < < " [STATE] " < < state ;
switch ( state ) {
case QProcess : : ProcessState : : Starting :
button - > setText ( " Starting " ) ;
break ;
case QProcess : : ProcessState : : Running :
button - > setText ( " Running. " ) ;
break ;
default :
button - > setText ( " Not running. " ) ;
break ;
}
} ) ;
QObject : : connect ( _giantsMainProcess , QOverload < int , QProcess : : ExitStatus > : : of ( & QProcess : : finished ) , [ & ] ( ) {
qDebug ( ) < < " [FINISHED] " ;
giantsFinished ( giantsMainPath , wdefsPath , button ) ;
} ) ;
QObject : : connect ( _giantsMainProcess , & QProcess : : errorOccurred , [ & ] ( ) {
qDebug ( ) < < " [ERROR] " < < _giantsMainProcess - > errorString ( ) ;
giantsFinished ( giantsMainPath , wdefsPath , button ) ;
} ) ;
_giantsMainProcess - > setWorkingDirectory ( QString : : fromStdString ( giantsMainPath . parent_path ( ) . string ( ) ) ) ;
_giantsMainProcess - > start ( QString : : fromStdString ( giantsMainPath . string ( ) ) , { " -launcher " } ) ;
// temporary
_giantsMainProcess - > waitForFinished ( ) ;
return StartResult : : SUCCESS ;
}