diff --git a/.gitmodules b/.gitmodules index 467e2ed1d..b484aea8e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,7 @@ path = AI/FuzzyLite url = https://github.com/fuzzylite/fuzzylite.git branch = release +[submodule "innoextract"] + path = launcher/lib/innoextract + url = https://github.com/vcmi/innoextract.git + branch = vcmi diff --git a/CI/ios/before_install.sh b/CI/ios/before_install.sh index 5f47b58f0..350730cb4 100755 --- a/CI/ios/before_install.sh +++ b/CI/ios/before_install.sh @@ -3,5 +3,5 @@ echo DEVELOPER_DIR=/Applications/Xcode_14.2.app >> $GITHUB_ENV mkdir ~/.conan ; cd ~/.conan -curl -L 'https://github.com/vcmi/vcmi-ios-deps/releases/download/1.2/ios-arm64.txz' \ +curl -L 'https://github.com/vcmi/vcmi-ios-deps/releases/download/1.2.1/ios-arm64.txz' \ | tar -xf - diff --git a/CI/linux-qt6/before_install.sh b/CI/linux-qt6/before_install.sh index 2b68caf4f..089bd4658 100644 --- a/CI/linux-qt6/before_install.sh +++ b/CI/linux-qt6/before_install.sh @@ -3,7 +3,7 @@ sudo apt-get update # Dependencies -sudo apt-get install libboost-dev libboost-filesystem-dev libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-locale-dev \ +sudo apt-get install libboost-dev libboost-filesystem-dev libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-locale-dev libboost-iostreams-dev \ libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev \ qt6-base-dev qt6-base-dev-tools qt6-tools-dev qt6-tools-dev-tools qt6-l10n-tools \ ninja-build zlib1g-dev libavformat-dev libswscale-dev libtbb-dev libluajit-5.1-dev \ diff --git a/CI/linux/before_install.sh b/CI/linux/before_install.sh index 17435929f..4b995ae6f 100644 --- a/CI/linux/before_install.sh +++ b/CI/linux/before_install.sh @@ -3,7 +3,7 @@ sudo apt-get update # Dependencies -sudo apt-get install libboost-dev libboost-filesystem-dev libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-locale-dev \ +sudo apt-get install libboost-dev libboost-filesystem-dev libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-locale-dev libboost-iostreams-dev \ libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev \ qtbase5-dev \ ninja-build zlib1g-dev libavformat-dev libswscale-dev libtbb-dev libluajit-5.1-dev \ diff --git a/CI/mac/before_install.sh b/CI/mac/before_install.sh index b4c46a693..e1f53b145 100755 --- a/CI/mac/before_install.sh +++ b/CI/mac/before_install.sh @@ -5,5 +5,5 @@ echo DEVELOPER_DIR=/Applications/Xcode_14.2.app >> $GITHUB_ENV brew install ninja mkdir ~/.conan ; cd ~/.conan -curl -L "https://github.com/vcmi/vcmi-deps-macos/releases/download/1.2/$DEPS_FILENAME.txz" \ +curl -L "https://github.com/vcmi/vcmi-deps-macos/releases/download/1.2.1/$DEPS_FILENAME.txz" \ | tar -xf - diff --git a/CI/mingw-32/before_install.sh b/CI/mingw-32/before_install.sh index 2bb40f7d1..3b41ed86d 100644 --- a/CI/mingw-32/before_install.sh +++ b/CI/mingw-32/before_install.sh @@ -12,5 +12,5 @@ curl -O -L http://mirrors.kernel.org/ubuntu/pool/universe/m/mingw-w64/mingw-w64- && sudo dpkg -i mingw-w64-i686-dev_10.0.0-3_all.deb; mkdir ~/.conan ; cd ~/.conan -curl -L "https://github.com/vcmi/vcmi-deps-windows-conan/releases/download/1.1/vcmi-deps-windows-conan-w32.tgz" \ +curl -L "https://github.com/vcmi/vcmi-deps-windows-conan/releases/download/1.2/vcmi-deps-windows-conan-w32.tgz" \ | tar -xzf - diff --git a/CI/mingw/before_install.sh b/CI/mingw/before_install.sh index 37babba74..09318d85b 100755 --- a/CI/mingw/before_install.sh +++ b/CI/mingw/before_install.sh @@ -12,5 +12,5 @@ curl -O -L http://mirrors.kernel.org/ubuntu/pool/universe/m/mingw-w64/mingw-w64- && sudo dpkg -i mingw-w64-x86-64-dev_10.0.0-3_all.deb; mkdir ~/.conan ; cd ~/.conan -curl -L "https://github.com/vcmi/vcmi-deps-windows-conan/releases/download/1.1/vcmi-deps-windows-conan-w64.tgz" \ +curl -L "https://github.com/vcmi/vcmi-deps-windows-conan/releases/download/1.2/vcmi-deps-windows-conan-w64.tgz" \ | tar -xzf - diff --git a/CMakeLists.txt b/CMakeLists.txt index ed961f298..1c7f54c11 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,6 +88,9 @@ if(ENABLE_ERM AND NOT ENABLE_LUA) set(ENABLE_LUA ON) endif() +include(CMakeDependentOption) +cmake_dependent_option(ENABLE_INNOEXTRACT "Enable innoextract for GOG file extraction in launcher" ON "ENABLE_LAUNCHER" OFF) + ############################################ # Miscellaneous options # ############################################ @@ -190,6 +193,10 @@ else() endmacro(enable_pch) endif() +if(NOT ENABLE_INNOEXTRACT) + add_definitions(-DVCMI_NO_INNOEXTRACT) +endif() + ############################################ # Documentation section # ############################################ @@ -448,7 +455,11 @@ endif() # Finding packages # ############################################ -find_package(Boost 1.48.0 REQUIRED COMPONENTS date_time filesystem locale program_options system thread) +set(BOOST_COMPONENTS date_time filesystem locale program_options system thread) +if(ENABLE_INNOEXTRACT) + list(APPEND BOOST_COMPONENTS iostreams) +endif() +find_package(Boost 1.48.0 REQUIRED COMPONENTS ${BOOST_COMPONENTS}) find_package(ZLIB REQUIRED) # Conan compatibility diff --git a/conanfile.py b/conanfile.py index 0054645f7..c6d60b2db 100644 --- a/conanfile.py +++ b/conanfile.py @@ -63,7 +63,7 @@ class VCMI(ConanFile): return # we need only the following Boost parts: - # date_time filesystem locale program_options system thread + # date_time filesystem locale program_options system thread iostreams # some other parts are also enabled because they're dependents # see e.g. conan-center-index/recipes/boost/all/dependencies self.options["boost"].without_context = True @@ -72,15 +72,15 @@ class VCMI(ConanFile): self.options["boost"].without_fiber = True self.options["boost"].without_graph = True self.options["boost"].without_graph_parallel = True - self.options["boost"].without_iostreams = True + self.options["boost"].without_iostreams = self.settings.os == "Android" # TODO: Line have to be removed after porting the launcher to android self.options["boost"].without_json = True self.options["boost"].without_log = True self.options["boost"].without_math = True self.options["boost"].without_mpi = True self.options["boost"].without_nowide = True self.options["boost"].without_python = True - self.options["boost"].without_random = True - self.options["boost"].without_regex = True + self.options["boost"].without_random = self.settings.os == "Android" # TODO: Line have to be removed after porting the launcher to android + self.options["boost"].without_regex = self.settings.os == "Android" # TODO: Line have to be removed after porting the launcher to android self.options["boost"].without_serialization = True self.options["boost"].without_stacktrace = True self.options["boost"].without_test = True diff --git a/docs/developers/Building_Linux.md b/docs/developers/Building_Linux.md index 559527f1b..d08e617ab 100644 --- a/docs/developers/Building_Linux.md +++ b/docs/developers/Building_Linux.md @@ -27,7 +27,7 @@ To compile, the following packages (and their development counterparts) are need For Ubuntu and Debian you need to install this list of packages: -`sudo apt-get install cmake g++ clang libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsdl2-mixer-dev zlib1g-dev libavformat-dev libswscale-dev libboost-dev libboost-filesystem-dev libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-locale-dev qtbase5-dev libtbb-dev libluajit-5.1-dev qttools5-dev ninja-build ccache` +`sudo apt-get install cmake g++ clang libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsdl2-mixer-dev zlib1g-dev libavformat-dev libswscale-dev libboost-dev libboost-filesystem-dev libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-locale-dev libboost-iostreams-dev qtbase5-dev libtbb-dev libluajit-5.1-dev qttools5-dev ninja-build ccache` Alternatively if you have VCMI installed from repository or PPA you can use: @@ -35,7 +35,7 @@ Alternatively if you have VCMI installed from repository or PPA you can use: ## On RPM-based distributions (e.g. Fedora) -`sudo yum install cmake gcc-c++ SDL2-devel SDL2_image-devel SDL2_ttf-devel SDL2_mixer-devel boost boost-devel boost-filesystem boost-system boost-thread boost-program-options boost-locale zlib-devel ffmpeg-devel ffmpeg-libs qt5-qtbase-devel tbb-devel luajit-devel fuzzylite-devel ccache` +`sudo yum install cmake gcc-c++ SDL2-devel SDL2_image-devel SDL2_ttf-devel SDL2_mixer-devel boost boost-devel boost-filesystem boost-system boost-thread boost-program-options boost-locale boost-iostreams zlib-devel ffmpeg-devel ffmpeg-libs qt5-qtbase-devel tbb-devel luajit-devel fuzzylite-devel ccache` NOTE: `fuzzylite-devel` package is no longer available in recent version of Fedora, for example Fedora 38. It's not a blocker because VCMI bundles fuzzylite lib in its source code. diff --git a/docs/players/Installation_Linux.md b/docs/players/Installation_Linux.md index 009522776..4597a819e 100644 --- a/docs/players/Installation_Linux.md +++ b/docs/players/Installation_Linux.md @@ -96,6 +96,10 @@ flatpak run --command=vcmibuilder eu.vcmi.VCMI --data /path/to/h3/data` ## Install data using gog.com offline installer Download both files for the "offline backup game installers" and extract them using innoextract tool + +You can select both downloaded files in launcher to extract automatically. + +Alternativly you can use the classic way: ``` innoextract --output-dir=~/Downloads/HoMM3 "setup_heroes_of_might_and_magic_3_complete_4.0_(28740).exe" ``` diff --git a/docs/players/Installation_iOS.md b/docs/players/Installation_iOS.md index a57eef464..6e25070ac 100644 --- a/docs/players/Installation_iOS.md +++ b/docs/players/Installation_iOS.md @@ -24,17 +24,21 @@ To install the signed ipa on your device, you can use Xcode or Apple Configurato Note: if you don't need in-game videos, you can omit downloading/copying file VIDEO.VID from data folder - it will save your time and space. The same applies to the Mp3 directory. -### Step 2.a: Installing data files with Finder or Windows explorer +### Step 2.a: Installing data files with GOG offline installer + +If you buyed HoMM3 on [GOG](https://www.gog.com/de/game/heroes_of_might_and_magic_3_complete_edition) you can download the files directly with the browser and install it in launcher. You need to select the exe file first and afterwards the bin file. This process takes a few seconds. Be patient. + +### Step 2.b: Installing data files with Finder or Windows explorer To play the game, you need to upload HoMM3 data files - **Data**, **Maps** and **Mp3** directories - to the device. Use Finder (or iTunes, if you're on Windows or your macOS is 10.14 or earlier) for that. You can also add various mods by uploading **Mods** directory. Follow [official Apple guide](https://support.apple.com/en-us/HT210598) and place files into VCMI app. Unfortunately, Finder doesn't display copy progress, give it about 10 minutes to finish. -### Step 2.b: Installing data files using iOS device only +### Step 2.c: Installing data files using iOS device only If you have data somewhere on device or in shared folder or you have downloaded it, you can copy it directly on your iPhone/iPad using Files application. Place **Data**, **Maps** and **Mp3** folders into vcmi application - it will be visible in Files along with other applications' folders. -### Step 2.c: Installing data files with Xcode on macOS +### Step 2.d: Installing data files with Xcode on macOS You can also upload files with Xcode. You need to prepare "container" for that. diff --git a/docs/players/Installation_macOS.md b/docs/players/Installation_macOS.md index 9a9adcd97..add359c93 100644 --- a/docs/players/Installation_macOS.md +++ b/docs/players/Installation_macOS.md @@ -15,5 +15,11 @@ Please report about gameplay problem on forums: [Help & Bugs](https://forum.vcmi # Step 2: Installing Heroes III data files +### Step 2.a: Installing data files with GOG offline installer + +If you buyed HoMM3 on [GOG](https://www.gog.com/de/game/heroes_of_might_and_magic_3_complete_edition) you can download the files directly with the browser and install it in launcher. You need to select the exe file first and afterwards the bin file. This process takes a few seconds. Be patient. + +### Step 2.b: Installing by the classic way + 1. Find a way to unpack Windows Heroes III or GOG installer. For example, use `vcmibuilder` script inside app bundle or install the game with [CrossOver](https://www.codeweavers.com/crossover) or [Wineskin](https://github.com/Gcenx/WineskinServer). 2. Place or symlink **Data**, **Maps** and **Mp3** directories from Heroes III to:`~/Library/Application\ Support/vcmi/` diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 9622ff6d2..01696f8dd 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -1,3 +1,7 @@ +if(ENABLE_INNOEXTRACT) + add_subdirectory("lib/innoextract") +endif() + set(launcher_SRCS StdInc.cpp aboutProject/aboutproject_moc.cpp @@ -142,6 +146,10 @@ target_include_directories(vcmilauncher vcmi_set_output_dir(vcmilauncher "") enable_pch(vcmilauncher) +if(ENABLE_INNOEXTRACT) + target_link_libraries(vcmilauncher innoextract) +endif() + if(APPLE_IOS) set(RESOURCES_DESTINATION ${DATA_DIR}) diff --git a/launcher/StdInc.h b/launcher/StdInc.h index 2d2eadc9f..506773a9a 100644 --- a/launcher/StdInc.h +++ b/launcher/StdInc.h @@ -18,6 +18,7 @@ #include #include #include +#include VCMI_LIB_USING_NAMESPACE diff --git a/launcher/firstLaunch/firstlaunch_moc.cpp b/launcher/firstLaunch/firstlaunch_moc.cpp index 5a30b5c62..47d5605bd 100644 --- a/launcher/firstLaunch/firstlaunch_moc.cpp +++ b/launcher/firstLaunch/firstlaunch_moc.cpp @@ -21,6 +21,10 @@ #include "../../lib/filesystem/Filesystem.h" #include "../languages.h" +#ifndef VCMI_NO_INNOEXTRACT +#include "cli/extract.hpp" +#endif + FirstLaunchView::FirstLaunchView(QWidget * parent) : QWidget(parent) , ui(new Ui::FirstLaunchView) @@ -32,6 +36,10 @@ FirstLaunchView::FirstLaunchView(QWidget * parent) ui->lineEditDataSystem->setText(pathToQString(boost::filesystem::absolute(VCMIDirs::get().dataPaths().front()))); ui->lineEditDataUser->setText(pathToQString(boost::filesystem::absolute(VCMIDirs::get().userDataPath()))); + +#ifdef VCMI_NO_INNOEXTRACT + ui->pushButtonGogInstall->hide(); +#endif } void FirstLaunchView::on_buttonTabLanguage_clicked() @@ -95,6 +103,11 @@ void FirstLaunchView::on_pushButtonDataHelp_clicked() QDesktopServices::openUrl(vcmibuilderWiki); } +void FirstLaunchView::on_pushButtonGogInstall_clicked() +{ + extractGogData(); +} + void FirstLaunchView::on_comboBoxLanguage_currentIndexChanged(int index) { forceHeroesLanguage(ui->comboBoxLanguage->itemData(index).toString()); @@ -218,6 +231,7 @@ void FirstLaunchView::heroesDataDetected() ui->labelDataSearch->setVisible(false); ui->labelDataCopy->setVisible(false); + ui->pushButtonGogInstall->setVisible(false); if(hasVCMIBuilderScript) { @@ -279,7 +293,69 @@ QString FirstLaunchView::getHeroesInstallDir() return QString{}; } -void FirstLaunchView::copyHeroesData(const QString & path) +void FirstLaunchView::extractGogData() +{ +#ifndef VCMI_NO_INNOEXTRACT + QString filterExe = tr("GOG executable") + " (*.exe)"; + QString fileExe = QFileDialog::getOpenFileName(this, tr("Select a GOG installer (exe) file..."), QDir::homePath(), filterExe); + if(fileExe.isEmpty()) + return; + + QString filterBin = tr("GOG bin file") + " (*.bin)"; + QString fileBin = QFileDialog::getOpenFileName(this, tr("Select a GOG data (bin) file..."), QFileInfo(fileExe).absolutePath(), filterBin); + if(fileBin.isEmpty()) + return; + + if(QFileInfo(fileExe).completeBaseName() + QString("-1") != QFileInfo(fileBin).completeBaseName()) + { + QMessageBox::critical(this, tr("File name error!"), tr("The filename of exe and bin has to be compatible!"), QMessageBox::Ok, QMessageBox::Ok); + return; + } + + QTimer::singleShot(100, this, [this, fileExe, fileBin](){ // background to make sure FileDialog is closed... + QTemporaryDir dir; + if(dir.isValid() && QFile::exists(fileExe) && QFile::exists(fileBin)) { + ui->pushButtonGogInstall->setText(tr("Installing... Please wait!")); + QPalette pal = ui->pushButtonGogInstall->palette(); + pal.setColor(QPalette::Button, QColor(Qt::yellow)); + ui->pushButtonGogInstall->setAutoFillBackground(true); + ui->pushButtonGogInstall->setPalette(pal); + ui->pushButtonGogInstall->update(); + ui->pushButtonGogInstall->repaint(); + + QString tmpFileExe = dir.filePath(QFileInfo(fileExe).fileName()); + QFile(fileExe).copy(tmpFileExe); + QFile(fileBin).copy(dir.filePath(QFileInfo(fileBin).fileName())); + + ::extract_options o; + o.extract = true; + + // standard settings + o.gog_galaxy = true; + o.codepage = (uint32_t)0; + o.output_dir = dir.path().toStdString(); + o.extract_temp = true; + o.extract_unknown = true; + o.filenames.set_expand(true); + + o.preserve_file_times = true; // also correctly closes file -> without it: on Windows the files are not written completly + + process_file(tmpFileExe.toStdString(), o); + + QStringList dirData = QDir(dir.path()).entryList({"data"}, QDir::Filter::Dirs); + if(dirData.empty() || QDir(QDir(dir.path()).filePath(dirData.front())).entryList({"*.lod"}, QDir::Filter::Files).empty()) + { + QMessageBox::critical(this, tr("No Heroes III data!"), tr("Selected files does not contain Heroes III data!"), QMessageBox::Ok, QMessageBox::Ok); + ui->pushButtonGogInstall->setText(tr("Install GOG files")); + return; + } + copyHeroesData(dir.path(), true); + } + }); +#endif +} + +void FirstLaunchView::copyHeroesData(const QString & path, bool move) { QDir sourceRoot = QDir(path); @@ -359,7 +435,10 @@ void FirstLaunchView::copyHeroesData(const QString & path) for(const QString & filename : sourceDir.entryList(QDir::Filter::Files)) { QFile sourceFile(sourceDir.filePath(filename)); - sourceFile.copy(targetDir.filePath(filename)); + if(move) + sourceFile.rename(targetDir.filePath(filename)); + else + sourceFile.copy(targetDir.filePath(filename)); } } diff --git a/launcher/firstLaunch/firstlaunch_moc.h b/launcher/firstLaunch/firstlaunch_moc.h index d17438000..71dd4329b 100644 --- a/launcher/firstLaunch/firstlaunch_moc.h +++ b/launcher/firstLaunch/firstlaunch_moc.h @@ -52,7 +52,8 @@ class FirstLaunchView : public QWidget void forceHeroesLanguage(const QString & language); QString getHeroesInstallDir(); - void copyHeroesData(const QString & path = {}); + void extractGogData(); + void copyHeroesData(const QString & path = {}, bool move = false); // Tab Mod Preset void modPresetUpdate(); @@ -88,6 +89,8 @@ private slots: void on_pushButtonDataHelp_clicked(); + void on_pushButtonGogInstall_clicked(); + void on_comboBoxLanguage_currentIndexChanged(int index); void on_pushButtonPresetBack_clicked(); diff --git a/launcher/firstLaunch/firstlaunch_moc.ui b/launcher/firstLaunch/firstlaunch_moc.ui index 62fd64d1f..e8518408f 100644 --- a/launcher/firstLaunch/firstlaunch_moc.ui +++ b/launcher/firstLaunch/firstlaunch_moc.ui @@ -277,6 +277,19 @@ Heroes® of Might and Magic® III HD is currently not supported! 6 + + + + 25 + 0 + + + + Install GOG files + + + + diff --git a/launcher/lib/innoextract b/launcher/lib/innoextract new file mode 160000 index 000000000..46adb5762 --- /dev/null +++ b/launcher/lib/innoextract @@ -0,0 +1 @@ +Subproject commit 46adb5762331aa3f19113fe09c72fc2d37caf90c