mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-24 03:47:18 +02:00
extract lod
This commit is contained in:
parent
b1de501716
commit
0e500efe5a
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
|
@ -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())
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user