1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-24 03:47:18 +02:00

extract lod

This commit is contained in:
Laserlicht 2024-08-31 00:44:20 +02:00
parent b1de501716
commit 0e500efe5a
5 changed files with 106 additions and 23 deletions

View File

@ -12,6 +12,7 @@
#include "chroniclesextractor.h"
#include "../../lib/VCMIDirs.h"
#include "../../lib/filesystem/CArchiveLoader.h"
#ifdef ENABLE_INNOEXTRACT
#include "cli/extract.hpp"
@ -60,16 +61,6 @@ int ChroniclesExtractor::getChronicleNo(QFile & file)
}
QByteArray dataBegin = file.read(1'000'000);
const std::map<int, QByteArray> chronicles = {
{1, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - Warlords of the Wasteland"), 90}},
{2, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - Conquest of the Underworld"), 92}},
{3, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - Masters of the Elements"), 86}},
{4, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - Clash of the Dragons"), 80}},
{5, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - The World Tree"), 68}},
{6, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - The Fiery Moon"), 68}},
{7, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - Revolt of the Beastmasters"), 92}},
{8, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - The Sword of Frost"), 76}}
};
int chronicle = 0;
for (const auto& kv : chronicles) {
if(dataBegin.contains(kv.second))
@ -142,6 +133,69 @@ bool ChroniclesExtractor::extractGogInstaller(QString file)
#endif
}
void ChroniclesExtractor::createBaseMod()
{
QDir dir(pathToQString(VCMIDirs::get().userDataPath() / "Mods"));
dir.mkdir("chronicles");
dir.cd("chronicles");
dir.mkdir("Mods");
QJsonObject mod
{
{ "modType", "Extension" },
{ "name", "Heroes Chronicles" },
{ "description", "" },
{ "author", "3DO" },
{ "version", "1.0" },
};
QFile jsonFile(dir.filePath("mod.json"));
jsonFile.open(QFile::WriteOnly);
jsonFile.write(QJsonDocument(mod).toJson());
}
void ChroniclesExtractor::createChronicleMod(int no)
{
QDir dir(pathToQString(VCMIDirs::get().userDataPath() / "Mods" / "chronicles" / "Mods"));
dir.mkdir("chronicles_" + QString::number(no));
dir.cd("chronicles_" + QString::number(no));
QJsonObject mod
{
{ "modType", "Extension" },
{ "name", "Heroes Chronicles - " + QString::number(no) },
{ "description", "" },
{ "author", "3DO" },
{ "version", "1.0" },
};
QFile jsonFile(dir.filePath("mod.json"));
jsonFile.open(QFile::WriteOnly);
jsonFile.write(QJsonDocument(mod).toJson());
dir.mkdir("Data");
dir.mkdir("Sprites");
extractFiles(no);
}
void ChroniclesExtractor::extractFiles(int no)
{
QByteArray tmpChronicles = chronicles.at(no);
tmpChronicles.replace('\0', "");
QDir tmpDir = tempDir.filePath(tempDir.entryList({"app"}, QDir::Filter::Dirs).front());
tmpDir.setPath(tmpDir.filePath(tmpDir.entryList({QString(tmpChronicles)}, QDir::Filter::Dirs).front()));
tmpDir.setPath(tmpDir.filePath(tmpDir.entryList({"data"}, QDir::Filter::Dirs).front()));
QDir outDirData(pathToQString(VCMIDirs::get().userDataPath() / "Mods" / "chronicles" / "Mods" / ("chronicles_" + std::to_string(no)) / "Data"));
QDir outDirSprites(pathToQString(VCMIDirs::get().userDataPath() / "Mods" / "chronicles" / "Mods" / ("chronicles_" + std::to_string(no)) / "Sprites"));
CArchiveLoader archive("", tmpDir.filePath("xBitmap.lod").toStdString(), false);
for(auto & entry : archive.getEntries())
archive.extractToFolder(outDirData.absolutePath().toStdString(), "", entry.second, true);
for(auto & entry : outDirData.entryList())
outDirData.rename(entry, "Hc" + QString::number(no) + "_" + entry);
}
void ChroniclesExtractor::installChronicles(QStringList exe)
{
extractionFile = -1;
@ -160,8 +214,10 @@ void ChroniclesExtractor::installChronicles(QStringList exe)
if(!extractGogInstaller(f))
continue;
createBaseMod();
createChronicleMod(chronicleNo);
if(!handleTempDir(false))
continue;
handleTempDir(false);
}
}

View File

@ -25,6 +25,20 @@ class ChroniclesExtractor : public QObject
bool handleTempDir(bool create);
int getChronicleNo(QFile & file);
bool extractGogInstaller(QString filePath);
void createBaseMod();
void createChronicleMod(int no);
void extractFiles(int no);
const std::map<int, QByteArray> chronicles = {
{1, QByteArray{reinterpret_cast<const char*>(u"Warlords of the Wasteland"), 50}},
{2, QByteArray{reinterpret_cast<const char*>(u"Conquest of the Underworld"), 52}},
{3, QByteArray{reinterpret_cast<const char*>(u"Masters of the Elements"), 46}},
{4, QByteArray{reinterpret_cast<const char*>(u"Clash of the Dragons"), 40}},
{5, QByteArray{reinterpret_cast<const char*>(u"The World Tree"), 28}},
{6, QByteArray{reinterpret_cast<const char*>(u"The Fiery Moon"), 28}},
{7, QByteArray{reinterpret_cast<const char*>(u"Revolt of the Beastmasters"), 52}},
{8, QByteArray{reinterpret_cast<const char*>(u"The Sword of Frost"), 36}}
};
public:
void installChronicles(QStringList exe);

View File

@ -30,6 +30,7 @@
#include "../../lib/CConfigHandler.h"
#include "../../lib/texts/Languages.h"
#include "../../lib/modding/CModVersion.h"
#include "../../lib/filesystem/Filesystem.h"
static double mbToBytes(double mb)
{
@ -838,8 +839,14 @@ void CModListView::installFiles(QStringList files)
if(!exe.empty())
{
ChroniclesExtractor ce(this);
ce.installChronicles(exe, [](float progress) { });
ChroniclesExtractor ce(this, [](float progress) { });
ce.installChronicles(exe);
//update
CResourceHandler::get("initial")->updateFilteredFiles([](const std::string &){ return true; });
manager->loadMods();
modModel->reloadRepositories();
emit modsChanged();
}
if(!images.empty())

View File

@ -197,6 +197,11 @@ std::string CArchiveLoader::getMountPoint() const
return mountPoint;
}
std::unordered_map<ResourcePath, ArchiveEntry> CArchiveLoader::getEntries() const
{
return entries;
}
std::unordered_set<ResourcePath> CArchiveLoader::getFilteredFiles(std::function<bool(const ResourcePath &)> filter) const
{
std::unordered_set<ResourcePath> foundID;
@ -209,7 +214,7 @@ std::unordered_set<ResourcePath> CArchiveLoader::getFilteredFiles(std::function<
return foundID;
}
void CArchiveLoader::extractToFolder(const std::string & outputSubFolder, CInputStream & fileStream, const ArchiveEntry & entry) const
void CArchiveLoader::extractToFolder(const std::string & outputSubFolder, CInputStream & fileStream, const ArchiveEntry & entry, bool absolute) const
{
si64 currentPosition = fileStream.tell(); // save filestream position
@ -217,7 +222,7 @@ void CArchiveLoader::extractToFolder(const std::string & outputSubFolder, CInput
fileStream.seek(entry.offset);
fileStream.read(data.data(), entry.fullSize);
boost::filesystem::path extractedFilePath = createExtractedFilePath(outputSubFolder, entry.name);
boost::filesystem::path extractedFilePath = createExtractedFilePath(outputSubFolder, entry.name , absolute);
// writeToOutputFile
std::ofstream out(extractedFilePath.string(), std::ofstream::binary);
@ -227,17 +232,17 @@ void CArchiveLoader::extractToFolder(const std::string & outputSubFolder, CInput
fileStream.seek(currentPosition); // restore filestream position
}
void CArchiveLoader::extractToFolder(const std::string & outputSubFolder, const std::string & mountPoint, ArchiveEntry entry) const
void CArchiveLoader::extractToFolder(const std::string & outputSubFolder, const std::string & mountPoint, ArchiveEntry entry, bool absolute) const
{
std::unique_ptr<CInputStream> inputStream = load(ResourcePath(mountPoint + entry.name));
entry.offset = 0;
extractToFolder(outputSubFolder, *inputStream, entry);
extractToFolder(outputSubFolder, *inputStream, entry, absolute);
}
boost::filesystem::path createExtractedFilePath(const std::string & outputSubFolder, const std::string & entryName)
boost::filesystem::path createExtractedFilePath(const std::string & outputSubFolder, const std::string & entryName, bool absolute)
{
boost::filesystem::path extractionFolderPath = VCMIDirs::get().userExtractedPath() / outputSubFolder;
boost::filesystem::path extractionFolderPath = absolute ? outputSubFolder : VCMIDirs::get().userExtractedPath() / outputSubFolder;
boost::filesystem::path extractedFilePath = extractionFolderPath / entryName;
boost::filesystem::create_directories(extractionFolderPath);

View File

@ -63,12 +63,13 @@ public:
std::unique_ptr<CInputStream> load(const ResourcePath & resourceName) const override;
bool existsResource(const ResourcePath & resourceName) const override;
std::string getMountPoint() const override;
std::unordered_map<ResourcePath, ArchiveEntry> getEntries() const;
void updateFilteredFiles(std::function<bool(const std::string &)> filter) const override {}
std::unordered_set<ResourcePath> getFilteredFiles(std::function<bool(const ResourcePath &)> filter) const override;
/** Extracts one archive entry to the specified subfolder. Used for Video and Sound */
void extractToFolder(const std::string & outputSubFolder, CInputStream & fileStream, const ArchiveEntry & entry) const;
void extractToFolder(const std::string & outputSubFolder, CInputStream & fileStream, const ArchiveEntry & entry, bool absolute = false) const;
/** Extracts one archive entry to the specified subfolder. Used for Images, Sprites, etc */
void extractToFolder(const std::string & outputSubFolder, const std::string & mountPoint, ArchiveEntry entry) const;
void extractToFolder(const std::string & outputSubFolder, const std::string & mountPoint, ArchiveEntry entry, bool absolute = false) const;
private:
/**
@ -105,6 +106,6 @@ private:
};
/** Constructs the file path for the extracted file. Creates the subfolder hierarchy aswell **/
boost::filesystem::path createExtractedFilePath(const std::string & outputSubFolder, const std::string & entryName);
boost::filesystem::path createExtractedFilePath(const std::string & outputSubFolder, const std::string & entryName, bool absolute);
VCMI_LIB_NAMESPACE_END