#include "lotromanager.h" #include "filesystem.h" #include "LotroDat/Subfiles/TextSubFile.h" #include #include #include #include #include #include Q_DECLARE_METATYPE(LOTRO_DAT::FILE_TYPE) Q_DECLARE_METATYPE(LOTRO_DAT::SubfileData) LotroManager::LotroManager(QSettings* app_settings_, QObject *parent) : QObject(parent), app_settings(app_settings_) { qRegisterMetaType(); qRegisterMetaType(); } void LotroManager::initialiseDatFile(QString file_path) { emit processStarted("initialiseDatFile", {file_path}); qDebug() << "Initialising file " << file_path; if (!FileSystem::fileExists(file_path)) { emit caughtError(QString("initialiseDatFile"), {QString("Ошибка инициализации"), QString("Файл " + file_path + " несуществует! Невозможно инициализировать файл ресурсов.")}); emit processFinished("initialiseDatFile", {QString("Error"), file_path}); return; } file.Initialise((file_path).toStdString(), 0); emit processFinished("initialiseDatFile", {QString("Success"), file_path}); } void LotroManager::deinitialiseDatFile() { emit processStarted("deintialiseDatFile", {}); qDebug() << "Deinitialising file..."; file.Deinitialize(); emit processFinished("deinitialiseDatFile", {}); } void LotroManager::changeLocale() { qDebug() << "Changing locale of dat file..."; // Setting locale, opposite to current auto current_locale = file.GetLocaleManager().GetCurrentLocale(); auto new_locale = current_locale == LOTRO_DAT::DatLocaleManager::PATCHED ? LOTRO_DAT::DatLocaleManager::ORIGINAL : LOTRO_DAT::DatLocaleManager::PATCHED; QString old_locale_name = (current_locale == LOTRO_DAT::DatLocaleManager::PATCHED ? "Русифицированная" : "Оригинальная"); QString new_locale_name = (new_locale == LOTRO_DAT::DatLocaleManager::PATCHED ? "Русифицированная" : "Оригинальная"); emit processStarted("changeLocale", {old_locale_name, new_locale_name}); auto operation = file.GetLocaleManager().SetLocale(new_locale); auto new_current_locale = file.GetLocaleManager().GetCurrentLocale(); QString new_current_locale_name = (new_current_locale == LOTRO_DAT::DatLocaleManager::PATCHED ? "Русифицированная" : "Оригинальная"); if (operation.result == LOTRO_DAT::SUCCESS) { emit processFinished("changeLocale", {"Success", new_current_locale_name}); } else { emit caughtError("changeLocale", {"Ошибка смены локали!", QString("Не удалось сменить локаль игры! Текущая локаль: ") + new_current_locale_name}); emit processFinished("changeLocale", {"Error", new_current_locale_name}); } } void LotroManager::getLocaleFileContents(long long file_id, int locale) { emit processStarted("getLocaleFileContents", {file_id, locale}); auto getfile_op = file.GetLocaleManager().GetLocaleFile(file_id, (LOTRO_DAT::DatLocaleManager::LOCALE)locale); if (!getfile_op.result) { emit caughtError("getLocaleFileContents", {"Файл не найден!", QString("Не удаётся найти файл с id ") + QString::number(file_id)}); emit processFinished("getLocaleFileContents", {"Error"}); return; } LOTRO_DAT::SubFile subfile = getfile_op.value; auto getrealfile_op = file.GetFileSystem().GetFile(file_id); if (!getfile_op.result) { emit caughtError("getLocaleFileContents", {"Файл не найден!", QString("Не удаётся найти в словаре файл с id ") + QString::number(file_id)}); emit processFinished("getLocaleFileContents", {"Error"}); return; } if (getrealfile_op.value->FileType() != LOTRO_DAT::TEXT) { emit caughtError("getLocaleFileContents", {"Некорректный формат!", QString("Получение данных локали доступно только для текстовых файлов!")}); emit processFinished("getLocaleFileContents", {"Error"}); return; } LOTRO_DAT::TextSubFile text_subfile(subfile); auto getfiledata_op = file.GetFileSystem().GetFileData(subfile, 8); if (getfile_op.result == LOTRO_DAT::ERROR) { emit caughtError("getLocaleFileContents", {"Ошибка извлечения!", QString("Обнаружены некорректные данные файла в словаре! Файл ресурсов мог быть повреждён!\nid = ") + QString::number(file_id) + ", locale_id = " + QString::number(locale)}); emit processFinished("getLocaleFileContents", {"Error"}); return; } LOTRO_DAT::SubfileData result = text_subfile.PrepareForExport(getfiledata_op.value); emit localeFileContentsReceived(locale, result); emit processFinished("getLocaleFileContents", {"Success", file_id, locale}); } void LotroManager::importFilesFromDatabase(QString database_path) { emit processStarted("importFilesFromDatabase", {database_path}); if (!FileSystem::fileExists(database_path)) { emit caughtError(QString("importFilesFromDatabase"), {QString("Ошибка импорта!"), QString("Файл " + database_path + " не существует! Невозможно инициализировать базу данных!")}); emit processFinished("importFilesFromDatabase", {QString("Error")}); return; } LOTRO_DAT::Database db; if (!db.InitDatabase(database_path.toStdString())) { emit caughtError("importFilesFromDatabase", {QString("Ошибка импорта!"), QString("Внутренняя ошибка инициализации базы данных!")}); emit processFinished("importFilesFromDatabase", {QString("Error")}); return; } auto patch_operation = file.GetPatcher().PatchAllDatabase(&db); if (patch_operation.result == LOTRO_DAT::SUCCESS) { file.GetFileSystem().CommitDirectories(); file.GetLocaleManager().CommitLocales(); emit processFinished("importFilesFromDatabase", {QString("Success"), patch_operation.value}); } else { emit processFinished("importFilesFromDatabase", {QString("Error"), 0}); } } void LotroManager::importFile(long long file_id, QString file_path) { emit processStarted("importFile", {file_id, file_path}); if (!FileSystem::fileExists(file_path)) { emit caughtError("importFile", {QString("Ошибка импорта!"), QString("Файл ") + file_path + QString(" не существует!")}); emit processFinished("importFile", {QString("Error")}); return; } LOTRO_DAT::SubfileData data; data.options["fid"] = file_id; auto getfile_op = file.GetFileSystem().GetFile(file_id); if (getfile_op.result == LOTRO_DAT::ERROR) { emit caughtError("importFile", {QString("Ошибка импорта!"), QString("Файл с id ") + QString::number(file_id) + QString(" не существует в ресурсах игры! Невозможно импортировать :/")}); emit processFinished("importFile", {QString("Error")}); return; } LOTRO_DAT::SubFile subfile = *(getfile_op.value); data.options["ext"] = subfile.Extension(); data.options["cat"] = subfile.category; if (subfile.FileType() == LOTRO_DAT::TEXT) { std::basic_ifstream input_stream(file_path.toStdString(), std::ios::in); if (!input_stream.is_open()) { emit caughtError("importFile", {QString("Ошибка импорта!"), QString("Текстовый файл ") + file_path + QString(" не удаётся открыть!")}); emit processFinished("importFile", {QString("Error")}); return; } std::basic_stringstream strStream; strStream << input_stream.rdbuf();//read the file data.text_data = strStream.str();//str holds the content of the file input_stream.close(); } else { QFile data_file(file_path); data_file.open(QIODevice::ReadOnly); if (!data_file.isOpen()) { emit caughtError("importFile", {QString("Ошибка импорта!"), QString("Файл ") + file_path + QString(" не удаётся открыть!")}); emit processFinished("importFile", {QString("Error")}); return; } QByteArray contents = data_file.readAll(); data.binary_data = LOTRO_DAT::BinaryData(contents.constData(), contents.size()); } auto patchfile_op = file.GetPatcher().PatchFile(data); if (patchfile_op.result == LOTRO_DAT::SUCCESS) { file.GetFileSystem().CommitDirectories(); file.GetLocaleManager().CommitLocales(); emit processFinished("importFile", {QString("Success")}); } else { emit caughtError("importFile", {QString("Ошибка импорта!"), QString("Возникла внутренняя ошибка применения патча. Импорт завершился с ошибкой")}); emit processFinished("importFile", {QString("Error")}); } return; } void LotroManager::importTextFragment(long long file_id, long long fragment_id, QString fragment_contents, QString arguments) { emit processStarted("importTextFragment", {file_id, fragment_id}); if (fragment_contents.contains("DO_NOT_TOUCH-1!")) { emit caughtError("importTextFragment", {"Ошибка формата!", QString("Текстовые данные содержат указатели на аргументы DO_NOT_TOUCH! с встроенным указанием порядка аргументов (как на сайте) Такого быть не должно! Пользуйтесь порядком перечисления аргументов внизу")}); emit processFinished("importTextFragment", {"Error"}); return; } auto getfile_op = file.GetFileSystem().GetFile(file_id); if (!getfile_op.result) { emit caughtError("importTextFragment", {"Файл не найден!", QString("Не удаётся найти в ресурсах файл с id ") + QString::number(file_id)}); emit processFinished("importTextFragment", {"Error"}); return; } auto subfile = getfile_op.value; auto getfiledata_op = file.GetFileSystem().GetFileData(*subfile, 8); if (getfile_op.result == LOTRO_DAT::ERROR) { emit caughtError("importTextFragment", {"Ошибка импорта!", QString("Обнаружены некорректные данные файла в словаре! Файл ресурсов мог быть повреждён!\nid = ") + QString::number(file_id)}); emit processFinished("importTextFragment", {"Error"}); return; } LOTRO_DAT::SubfileData data = subfile->PrepareForExport(getfiledata_op.value); if (data.Empty()) { emit caughtError("importTextFragment", {"Ошибка импорта!", QString("Не удалось подготовить файл к изменению фрагмента!\nid = ") + QString::number(file_id)}); emit processFinished("importTextFragment", {"Error"}); return; } unsigned beginning = data.text_data.find(QString::number(fragment_id).toStdU16String(), 0); if (beginning == std::u16string::npos) { emit caughtError("importTextFragment", {"Ошибка импорта!", QString("Не удалось найти фрагмент в файле!\nid = ") + QString::number(file_id) + "\nfragment_id = " + QString::number(fragment_id)}); emit processFinished("importTextFragment", {"Error"}); return; } unsigned ending = data.text_data.find(QString("|||").toStdU16String(), beginning); QString new_fragment = QString::number(fragment_id) + ":::" + arguments + ":::" + fragment_contents; std::u16string new_text = data.text_data.substr(0, beginning) + new_fragment.toStdU16String() + data.text_data.substr(ending); data.text_data = new_text; auto patchfile_op = file.GetPatcher().PatchFile(data); if (patchfile_op.result == LOTRO_DAT::SUCCESS) { file.GetFileSystem().CommitDirectories(); file.GetLocaleManager().CommitLocales(); emit processFinished("importTextFragment", {QString("Success")}); } else { emit caughtError("importTextFragment", {QString("Ошибка импорта!"), QString("Возникла внутренняя ошибка применения патча. Импорт завершился с ошибкой")}); emit processFinished("importTextFragment", {QString("Error")}); } } void LotroManager::getTextFragment(long long file_id, long long fragment_id) { emit processStarted("getTextFragment", {file_id, fragment_id}); auto getfile_op = file.GetFileSystem().GetFile(file_id); if (!getfile_op.result) { emit caughtError("getTextFragment", {"Файл не найден!", QString("Не удаётся найти в ресурсах файл с id ") + QString::number(file_id)}); emit processFinished("getTextFragment", {"Error"}); return; } auto subfile = getfile_op.value; auto getfiledata_op = file.GetFileSystem().GetFileData(*subfile, 8); if (getfile_op.result == LOTRO_DAT::ERROR) { emit caughtError("getTextFragment", {"Ошибка импорта!", QString("Обнаружены некорректные данные файла в словаре! Файл ресурсов мог быть повреждён!\nid = ") + QString::number(file_id)}); emit processFinished("getTextFragment", {"Error"}); return; } LOTRO_DAT::SubfileData data = subfile->PrepareForExport(getfiledata_op.value); if (data.Empty()) { emit caughtError("getTextFragment", {"Ошибка импорта!", QString("Не удалось подготовить файл к изменению фрагмента!\nid = ") + QString::number(file_id)}); emit processFinished("getTextFragment", {"Error"}); return; } unsigned beginning = data.text_data.find(QString::number(fragment_id).toStdU16String(), 0); if (beginning == std::u16string::npos) { emit caughtError("getTextFragment", {"Ошибка импорта!", QString("Не удалось найти фрагмент в файле!\nid = ") + QString::number(file_id) + "\nfragment_id = " + QString::number(fragment_id)}); emit processFinished("getTextFragment", {"Error"}); return; } unsigned ending = data.text_data.find(QString("|||").toStdU16String(), beginning); unsigned size = std::u16string::npos; if (ending != std::u16string::npos) size = ending - beginning; std::u16string str = data.text_data.substr(beginning, size); QStringList splitted_fragment = QString::fromStdU16String(str).split(":::"); if (splitted_fragment.size() != 3) { emit caughtError("getTextFragment", {"Ошибка импорта!", QString("Получены некорректные данные фрагмента!\nДанные:") + QString::fromStdU16String(str)}); emit processFinished("getTextFragment", {"Error"}); return; } emit textFragmentReceived(splitted_fragment.at(1), splitted_fragment.at(2)); emit processFinished("getTextFragment", {"Success"}); } void LotroManager::createCoreStatusFile(QString output_filename) { emit processStarted("createCoreStatusFile", {output_filename}); auto gatherinfo_op = file.GatherInformation(output_filename.toStdString()); if (gatherinfo_op.result == LOTRO_DAT::SUCCESS) { emit processFinished("createCoreStatusFile", {"Success", output_filename}); } else { emit caughtError("createCoreStatusFile", {"Ошибка сбора информации!", QString("Не удаётся создать файл информации ядра")}); emit processFinished("createCoreStatusFile", {"Error", output_filename}); } } void LotroManager::extractSingleFile(QString output_filename, long long file_id) { emit processStarted("extractSingleFile", {output_filename, file_id}); auto extractfile_op = file.GetExporter().ExtractFileById(file_id, output_filename.toStdString()); if (extractfile_op.result == LOTRO_DAT::SUCCESS) { emit processFinished("extractSingleFile", {"Success", output_filename, file_id}); } else { emit caughtError("extractSingleFile", {"Ошибка экспорта!", QString("Не удаётся экспортировать файл " + QString::number(file_id) + " в файл " + output_filename)}); emit processFinished("extractSingleFile", {"Error", output_filename}); } } void LotroManager::extractSingleFileToDatabase(QString database_path, long long file_id) { emit processStarted("extractSingleFileToDatabase", {database_path, file_id}); LOTRO_DAT::Database db; if (!db.InitDatabase(database_path.toStdString())) { emit caughtError("extractSingleFileToDatabase", {"Ошибка экспорта!", QString("Не удаётся создать/открыть базу данных " + database_path)}); emit processFinished("extractSingleFileToDatabase", {"Error", database_path}); return; } auto extractfile_op = file.GetExporter().ExtractFileById(file_id, &db); if (extractfile_op.result == LOTRO_DAT::SUCCESS) { emit processFinished("extractSingleFileToDatabase", {"Success", database_path, file_id}); } else { emit caughtError("extractSingleFileToDatabase", {"Ошибка экспорта!", QString("Не удаётся экспортировать файл " + QString::number(file_id) + " в базу данных " + database_path)}); emit processFinished("extractSingleFileToDatabase", {"Error", database_path}); } } void LotroManager::extractGrouppedFiles(QString output_foldername, LOTRO_DAT::FILE_TYPE type) { emit processStarted("extractGrouppedFiles", {output_foldername, type}); auto extractfile_op = file.GetExporter().ExtractAllFilesByType(type, output_foldername.toStdString()); if (extractfile_op.result == LOTRO_DAT::SUCCESS) { emit processFinished("extractGrouppedFiles", {"Success", output_foldername, type, extractfile_op.value}); } else { emit caughtError("extractGrouppedFiles", {"Ошибка экспорта!", QString("Не удаётся экспортировать файлы с типом " + QString::number(type) + " в папку " + output_foldername)}); emit processFinished("extractGrouppedFiles", {"Error", output_foldername, type, extractfile_op.value}); } } void LotroManager::extractGrouppedFilesToDatabase(QString database_path, LOTRO_DAT::FILE_TYPE type) { emit processStarted(QString("extractGrouppedFilesToDatabase"), {database_path, type}); LOTRO_DAT::Database db; if (!db.InitDatabase(database_path.toStdString())) { emit caughtError("extractGrouppedFilesToDatabase", {"Ошибка экспорта!", QString("Не удаётся создать/открыть базу данных " + database_path)}); emit processFinished("extractGrouppedFilesToDatabase", {"Error", database_path}); return; } auto extractfile_op = file.GetExporter().ExtractAllFilesByType(type, &db); if (extractfile_op.result == LOTRO_DAT::SUCCESS) { emit processFinished("extractGrouppedFilesToDatabase", {"Success", database_path, type, extractfile_op.value}); } else { emit caughtError("extractGrouppedFilesToDatabase", {"Ошибка экспорта!", QString("Не удаётся экспортировать файлы с типом " + QString::number(type) + " в базу данных " + database_path)}); emit processFinished("extractGrouppedFilesToDatabase", {"Error", database_path, extractfile_op.value}); } } void LotroManager::getUnactiveCategories() { emit processStarted("getUnactiveCategories", {}); const std::set& categories = file.GetLocaleManager().GetInactiveCategories(); QStringList result; for (long long category : categories) { result << QString::number(category); } emit unactiveCategoriesReceived(result); emit processFinished("getUnactiveCategories", {"Success"}); } void LotroManager::startGame() { emit processStarted("startGame", {}); QStringList args; args << "-skiprawdownload" << "-nosplash"; if (file.GetLocaleManager().GetCurrentLocale() == LOTRO_DAT::DatLocaleManager::PATCHED) args << "-disablePatch"; file.Deinitialize(); if(FileSystem::fileExists(QApplication::applicationDirPath() + "/user.ini")){ QSettings login(QApplication::applicationDirPath() + "/user.ini", QSettings::IniFormat ); login.beginGroup("Account"); QString username = login.value("username", "").toString(); QString password = login.value("password", "").toString(); login.endGroup(); args << "-username" << username << "-password" << password; } qDebug() << "Запускаем игру со следующими аргументами: " << args; QFile f(app_settings->value("Local", "folder").toString() + "/LotroLauncher.exe"); QProcess process; if (FileSystem::fileExists(f.fileName())) { if(f.fileName().contains(" ")) f.setFileName("\"" + f.fileName() + "\""); process.startDetached(f.fileName(), args); process.waitForFinished(-1); emit processFinished("startGame", {}); } else { emit caughtError("startGame", {"Ошибка запуска игры!", QString("Не удалось найти файл LotroLauncher в папке: ") + app_settings->value("Local", "folder").toString()}); emit processFinished("startGame", {"Error"}); } } void LotroManager::getLocaleFileInfo(long long file_id, int locale) { emit processStarted("getLocaleFileInfo", {file_id, locale}); auto getfile_op = file.GetLocaleManager().GetLocaleFile(file_id, (LOTRO_DAT::DatLocaleManager::LOCALE)locale); if (!getfile_op.result) { emit caughtError("getLocaleFileInfo", {"Файл не найден!", QString("Не удаётся найти в ресурсах файл с id ") + QString::number(file_id)}); emit processFinished("getLocaleFileInfo", {"Error"}); return; } LOTRO_DAT::SubFile subfile = getfile_op.value; QString result = "Locale file info:\n " "dictionary_offset: " + QString::number(subfile.dictionary_offset()) + "\n" "unknown1: " + QString::number(subfile.unknown1()) + "\n" "file_id: " + QString::number(subfile.file_id()) + "\n" "file_offset: " + QString::number(subfile.file_offset()) + "\n" "file_size: " + QString::number(subfile.file_size()) + "\n" "timestamp: " + QString::number(subfile.timestamp()) + "\n" "version: " + QString::number(subfile.version()) + "\n" "block_size: " + QString::number(subfile.block_size()) + "\n" "unknown2: " + QString::number(subfile.file_id()) + "\n" "category: " + QString::number(subfile.category) + "\n"; emit localeFileInfoReceived(locale, result); emit processFinished("getLocaleFileInfo", {"Success"}); } void LotroManager::getFileInfo(long long file_id) { emit processStarted(QString("getFileInfo"), {file_id}); auto getfile_op = file.GetFileSystem().GetFile(file_id); if (!getfile_op.result) { emit caughtError("getFileInfo", {"Файл не найден!", QString("Не удаётся найти файл с id ") + QString::number(file_id)}); emit processFinished("getFileInfo", {"Error"}); return; } LOTRO_DAT::SubFile subfile = *getfile_op.value; QString result = "Locale file info:\n " "dictionary_offset: " + QString::number(subfile.dictionary_offset()) + "\n" "unknown1: " + QString::number(subfile.unknown1()) + "\n" "file_id: " + QString::number(subfile.file_id()) + "\n" "file_offset: " + QString::number(subfile.file_offset()) + "\n" "file_size: " + QString::number(subfile.file_size()) + "\n" "timestamp: " + QString::number(subfile.timestamp()) + "\n" "version: " + QString::number(subfile.version()) + "\n" "block_size: " + QString::number(subfile.block_size()) + "\n" "unknown2: " + QString::number(subfile.file_id()) + "\n"; emit fileInfoReceived(result); emit processFinished("getFileInfo", {"Success"}); } LOTRO_DAT::DatStatus *LotroManager::getStatusModule() { return &file.GetStatusModule(); } bool LotroManager::initialised() { return file.Initialized(); } int LotroManager::currentLocale() { return file.GetLocaleManager().GetCurrentLocale(); } bool LotroManager::notPatched() { return file.GetStatusModule().CheckIfNotPatched(); }