lotrodatmanager.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. #include "lotrodatmanager.h"
  2. #include "filesystem.h"
  3. #include "LotroDat/Subfiles/TextSubFile.h"
  4. #include "models/patchdownloader.h"
  5. #include <QtConcurrent/QtConcurrent>
  6. #include <QFontDatabase>
  7. #include <QMessageBox>
  8. #include <QDebug>
  9. #include <string>
  10. #include <iostream>
  11. #include <fstream>
  12. Q_DECLARE_METATYPE(LOTRO_DAT::DatLocaleManager::LOCALE)
  13. LotroDatManager::LotroDatManager(QSettings* settings, PatchDownloader* downloader, QObject *parent) :
  14. QObject(parent), app_settings(settings), patch_downloader(downloader) {
  15. qRegisterMetaType<LOTRO_DAT::DatLocaleManager::LOCALE>();
  16. }
  17. bool LotroDatManager::Initialised()
  18. {
  19. return client_local_file.Initialized() && client_general_file.Initialized();
  20. }
  21. bool LotroDatManager::NotPatched()
  22. {
  23. return !client_local_file.GetStatusModule().CheckIfNotPatched() && !client_local_file.GetStatusModule().CheckIfNotPatched();
  24. }
  25. void LotroDatManager::InitialiseManager()
  26. {
  27. qDebug() << "Initialising .dat manager";
  28. emit processStarted("InitialiseManager");
  29. QString game_folder = app_settings->value("General/game_folder_path", QString()).toString();
  30. QString locale_prefix = app_settings->value("General/original_locale", "English").toString();
  31. if (game_folder.isEmpty() || !FileSystem::fileExists(game_folder + "client_local_" + locale_prefix + ".dat")
  32. || !FileSystem::fileExists(game_folder + "client_general.dat")) {
  33. qDebug() << "Finished initialisation .dat manager - error: required files not found!";
  34. emit caughtError(QString("InitialiseManager"), {"FileNotFound"});
  35. emit processFinished("InitialiseManager");
  36. return;
  37. }
  38. // Updating file permissions to be sure, that they're not in read-only mode
  39. if (!QFile::setPermissions((game_folder + "/client_local_" + locale_prefix + ".dat"), QFileDevice::Permission(0x6666))) {
  40. qDebug() << "Unable to update permissions on client_local_* file!";
  41. emit caughtError(QString("InitialiseManager"), {"PermissionsError"});
  42. emit processFinished("InitialiseManager");
  43. return;
  44. }
  45. if (!QFile::setPermissions((game_folder + "/client_general.dat"), QFileDevice::Permission(0x6666))) {
  46. qDebug() << "Unable to update permissions on client_general* file!";
  47. emit caughtError(QString("InitialiseManager"), {"PermissionsError"});
  48. emit processFinished("InitialiseManager");
  49. return;
  50. }
  51. // Initialising client_local_*.dat file and client_general.dat
  52. auto client_local_init_res = client_local_file.Initialise((game_folder + "/client_local_" + locale_prefix + ".dat").toStdString(), 0);
  53. auto client_general_init_res = client_general_file.Initialise((game_folder + "/client_general.dat").toStdString(), 1);
  54. if (client_local_init_res.result != LOTRO_DAT::SUCCESS
  55. || client_general_init_res.result != LOTRO_DAT::SUCCESS) {
  56. client_local_file.Deinitialize();
  57. client_general_file.Deinitialize();
  58. qDebug() << "Finished initialisation .dat manager - error: DatFile initialisation error!";
  59. emit caughtError(QString("InitialiseManager"), {"InitialisationError"});
  60. emit processFinished("InitialiseManager");
  61. return;
  62. }
  63. emit processFinished("InitialiseManager");
  64. }
  65. void LotroDatManager::DeinitialiseManager()
  66. {
  67. emit processStarted("DeinitialiseManager");
  68. qDebug() << "Started DEinitialisation .dat manager.";
  69. client_local_file.Deinitialize();
  70. client_general_file.Deinitialize();
  71. qDebug() << "Finished DEinitialisation .dat manager.";
  72. emit processFinished("DeinitialiseManager");
  73. }
  74. void LotroDatManager::StartGame(LOTRO_DAT::DatLocaleManager::LOCALE locale)
  75. {
  76. emit processStarted("StartGame");
  77. qDebug() << "Starting game!";
  78. client_general_file.GetLocaleManager().SetLocale(locale);
  79. client_local_file.GetLocaleManager().SetLocale(locale);
  80. QString game_folder = app_settings->value("General/game_folder_path", QString()).toString();
  81. if (!FileSystem::fileExists(QApplication::applicationDirPath() + "/Launcher.exe")) {
  82. emit caughtError("StartGame", {"NoGameLauncherInLegacyDir"});
  83. qDebug() << "Starting game FAILED - no game launcher in legacy directory found!";
  84. emit processFinished("StartGame");
  85. return;
  86. }
  87. if (locale == LOTRO_DAT::DatLocaleManager::PATCHED) {
  88. QFile::remove(game_folder + "/lotro_ru.exe");
  89. if (!QFile::copy(QApplication::applicationDirPath() + "/LotroLauncher.exe", game_folder + "/lotro_ru.exe")) {
  90. emit caughtError("StartGame", {"NoAccessToGameLauncher"});
  91. qDebug() << "Starting game FAILED - cannot copy LotroLauncher to LotroLauncher_fwd!!";
  92. emit processFinished("StartGame");
  93. return;
  94. }
  95. QFile::remove(game_folder + "/LotroLauncher.exe");
  96. if (!QFile::copy(QApplication::applicationDirPath() + "/Launcher.exe", game_folder + "/LotroLauncher.exe")) {
  97. emit caughtError("StartGame", {"NoAccessToGameLauncher"});
  98. qDebug() << "Starting game FAILED - cannot copy GameLauncher to LotroLauncher!!";
  99. emit processFinished("StartGame");
  100. return;
  101. }
  102. QFile file(game_folder + "/legacy_path.txt");
  103. file.open(QIODevice::WriteOnly);
  104. QTextStream out(&file);
  105. out << QApplication::applicationDirPath() + "/LegacyLauncher.exe";
  106. file.close();
  107. } else {
  108. QFile::remove(game_folder + "/LotroLauncher.exe");
  109. if (!QFile::copy(QApplication::applicationDirPath() + "/LotroLauncher.exe", game_folder + "/LotroLauncher.exe")) {
  110. qDebug() << QApplication::applicationDirPath() + "/LotroLauncher.exe";
  111. qDebug() << game_folder + "/LotroLauncher.exe";
  112. emit caughtError("StartGame", {"NoAccessToGameLauncher"});
  113. qDebug() << "Starting game FAILED - cannot copy LotroLauncher from working dir to LotroLauncher in lotro dir!!";
  114. emit processFinished("StartGame");
  115. return;
  116. }
  117. }
  118. qDebug() << "Starting game finished!!";
  119. startLotroLauncherWithParameters(locale);
  120. emit processFinished("StartGame");
  121. }
  122. void LotroDatManager::ChangeTranslationLanguage()
  123. {
  124. DeinitialiseManager();
  125. InitialiseManager();
  126. }
  127. void LotroDatManager::InstallActivePatches()
  128. {
  129. InstallPatches(); // Installing means inserting necessary data
  130. ApplyTexts(); // Applying means activating patched data
  131. ApplyImages();
  132. ApplySounds();
  133. InstallLoadscreens();
  134. InstallVideos();
  135. }
  136. void LotroDatManager::InstallPatches()
  137. {
  138. emit processStarted("InstallPatches");
  139. const QStringList all_patch_names = {"sound", "text", "image", "texture"};
  140. foreach (QString patch_name, all_patch_names) {
  141. if (app_settings->value("patch_databases/" + patch_name, "Disabled").toString() == "Disabled")
  142. continue;
  143. QString database_path = patch_downloader->getDatabasePathByPatchName(patch_name);
  144. LOTRO_DAT::Database db;
  145. if (!db.InitDatabase(database_path.toStdString())) {
  146. emit caughtError("InstallPatches", {"ErrorInitDatabase"});
  147. continue;
  148. }
  149. if (client_local_file.GetPatcher().PatchAllDatabase(&db).result != LOTRO_DAT::SUCCESS)
  150. emit caughtError("InstallPatches", {"ErrorCannotPatch", "client_local"});
  151. if (client_general_file.GetPatcher().PatchAllDatabase(&db).result != LOTRO_DAT::SUCCESS)
  152. emit caughtError("InstallPatches", {"ErrorCannotPatch", "client_general"});
  153. db.CloseDatabase();
  154. }
  155. emit processFinished("InstallPatches");
  156. }
  157. void LotroDatManager::InstallLoadscreens()
  158. {
  159. emit processStarted("InstallLoadscreens");
  160. if (app_settings->value("patch_databases/loadscreen", "Disabled").toString() == "Disabled")
  161. return;
  162. QString game_folder = app_settings->value("General/game_folder_path", QString()).toString();
  163. QString locale_prefix = app_settings->value("General/original_locale", "English").toString();
  164. QString raw_folder;
  165. if (locale_prefix == "English")
  166. raw_folder = "en";
  167. if (locale_prefix == "DE")
  168. raw_folder = "de";
  169. if (locale_prefix == "FR")
  170. raw_folder = "fr";
  171. QString folder = game_folder + "/raw/" + raw_folder + "/logo/";
  172. QString mainscreen =
  173. game_folder == "en"
  174. ? "lotro_ad_pregame.jpg"
  175. : "lotro_ad_pregame_" + game_folder + ".jpg";
  176. QStringList filenames;
  177. filenames << mainscreen
  178. << "lotro_generic_teleport_screen_01.jpg"
  179. << "lotro_generic_teleport_screen_02.jpg"
  180. << "lotro_generic_teleport_screen_03.jpg"
  181. << "lotro_generic_teleport_screen_04.jpg"
  182. << "lotro_generic_teleport_screen_05.jpg"
  183. << "lotro_generic_teleport_screen_06.jpg"
  184. << "lotro_generic_teleport_screen_07.jpg"
  185. << "lotro_generic_teleport_screen_08.jpg"
  186. << "lotro_generic_teleport_screen_09.jpg"
  187. << "lotro_generic_teleport_screen_10.jpg";
  188. QString database_path = patch_downloader->getDatabasePathByPatchName("loadscreen");
  189. LOTRO_DAT::Database db;
  190. if (!db.InitDatabase(database_path.toStdString())) {
  191. emit caughtError("InstallLoadscreens", {"ErrorInitDatabase"});
  192. emit processFinished("InstallLoadscreens");
  193. return;
  194. }
  195. for (size_t i = 0; i < qMin(db.CountRows(), size_t(filenames.size())); i++) {
  196. LOTRO_DAT::SubfileData subfile = db.GetNextFile();
  197. if (subfile.binary_data.Empty())
  198. continue;
  199. QFile::remove(folder + filenames[i]);
  200. subfile.binary_data.WriteToFile((folder + filenames[i]).toStdString());
  201. }
  202. db.CloseDatabase();
  203. emit processFinished("InstallLoadscreens");
  204. }
  205. void LotroDatManager::InstallVideos()
  206. {
  207. emit processStarted("InstallVideos");
  208. if (app_settings->value("patch_databases/video", "Disabled").toString() == "Disabled")
  209. return;
  210. QString game_folder = app_settings->value("General/game_folder_path", QString()).toString();
  211. QString database_path = patch_downloader->getDatabasePathByPatchName("loadscreen");
  212. LOTRO_DAT::Database db;
  213. if (!db.InitDatabase(database_path.toStdString())) {
  214. emit caughtError("InstallVideos", {"ErrorInitDatabase"});
  215. emit processFinished("InstallVideos");
  216. return;
  217. }
  218. for(size_t i = 0; i < db.CountRows(); i++) {
  219. LOTRO_DAT::SubfileData subfile = db.GetNextFile();
  220. if (subfile.Empty())
  221. continue;
  222. QString filename = QString::fromStdString(subfile.options["name"].as<std::string>());
  223. QUrl url = QString::fromStdString(subfile.options["url"].as<std::string>());
  224. QString hash = QString::fromStdString(subfile.options["hash"].as<std::string>());
  225. QString target_folder = game_folder + "/" + QString::fromStdString(subfile.options["folder"].as<std::string>()) + "/";
  226. if (!QDir(target_folder).exists())
  227. QDir(target_folder).mkpath(target_folder);
  228. if (FileSystem::fileExists(target_folder + filename)) {
  229. if (FileSystem::fileHash(target_folder + filename) == hash) {
  230. continue;
  231. } else {
  232. QFile::remove(target_folder + filename);
  233. }
  234. }
  235. Downloader video_downloader;
  236. video_downloader.setUrl(url);
  237. video_downloader.targetFile = new QFile(target_folder + filename);
  238. video_downloader.targetFile->open(QIODevice::ReadWrite);
  239. video_downloader.start();
  240. // TODO: Progress notification on video download!
  241. // connect(&video_downloader, &Downloader::progressChanged, this, &LotroDatManager::VideoDownloadProgressChanged);
  242. video_downloader.waitForDownloaded();
  243. video_downloader.targetFile->close();
  244. video_downloader.targetFile->deleteLater();
  245. if (FileSystem::fileHash(target_folder + filename) != hash) {
  246. emit caughtError("InstallVideos", {"IncorrectHash", hash, FileSystem::fileHash(target_folder + filename), target_folder, filename, url});
  247. }
  248. }
  249. db.CloseDatabase();
  250. emit processFinished("InstallVideos");
  251. }
  252. void LotroDatManager::InstallUpdates()
  253. {
  254. // TODO
  255. }
  256. void LotroDatManager::InstallMicroPatch()
  257. {
  258. // TODO
  259. }
  260. void LotroDatManager::CreateBackup()
  261. {
  262. emit processStarted("CreateBackup");
  263. QString locale_prefix = app_settings->value("General/original_locale", "English").toString();
  264. client_local_file.GetBackupManager().CreateBackup((QApplication::applicationDirPath() + "/backup/client_local_" + locale_prefix + ".dat").toStdString());
  265. client_general_file.GetBackupManager().CreateBackup((QApplication::applicationDirPath() + "/backup/client_general.dat").toStdString());
  266. emit processFinished("CreateBackup");
  267. }
  268. void LotroDatManager::RestoreFromBackup()
  269. {
  270. emit processStarted("CreateBackup");
  271. QString locale_prefix = app_settings->value("General/original_locale", "English").toString();
  272. client_local_file.GetBackupManager().RestoreFromBackup((QApplication::applicationDirPath() + "/backup/client_local_" + locale_prefix + ".dat").toStdString());
  273. client_general_file.GetBackupManager().RestoreFromBackup((QApplication::applicationDirPath() + "/backup/client_general.dat").toStdString());
  274. emit processFinished("CreateBackup");
  275. }
  276. void LotroDatManager::RemoveBackup()
  277. {
  278. emit processStarted("CreateBackup");
  279. QString locale_prefix = app_settings->value("General/original_locale", "English").toString();
  280. client_local_file.GetBackupManager().RemoveBackup((QApplication::applicationDirPath() + "/backup/client_local_" + locale_prefix + ".dat").toStdString());
  281. client_general_file.GetBackupManager().RemoveBackup((QApplication::applicationDirPath() + "/backup/client_general.dat").toStdString());
  282. emit processFinished("CreateBackup");
  283. }
  284. void LotroDatManager::ApplyTexts()
  285. {
  286. if (app_settings->value("patch_options/texts_general", "Disabled").toString() == "Enabled") {
  287. client_local_file.GetLocaleManager().EnableCategory(100);
  288. } else {
  289. client_local_file.GetLocaleManager().DisableCategory(100);
  290. }
  291. if (app_settings->value("patch_options/texts_emotes", "Disabled").toString() == "Enabled") {
  292. client_local_file.GetLocaleManager().EnableCategory(101);
  293. } else {
  294. client_local_file.GetLocaleManager().DisableCategory(101);
  295. }
  296. if (app_settings->value("patch_options/texts_items", "Disabled").toString() == "Enabled") {
  297. client_local_file.GetLocaleManager().EnableCategory(102);
  298. } else {
  299. client_local_file.GetLocaleManager().DisableCategory(102);
  300. }
  301. }
  302. void LotroDatManager::ApplyImages() {
  303. if (app_settings->value("patch_options/maps", "Disabled").toString() == "Enabled") {
  304. client_local_file.GetLocaleManager().EnableCategory(200);
  305. } else {
  306. client_local_file.GetLocaleManager().DisableCategory(200);
  307. }
  308. }
  309. void LotroDatManager::ApplySounds() {
  310. emit processStarted("ApplySounds");
  311. if (app_settings->value("patch_options/sounds", "Disabled").toString() == "Enabled") {
  312. client_local_file.GetLocaleManager().EnableCategory(300);
  313. } else {
  314. client_local_file.GetLocaleManager().DisableCategory(300);
  315. }
  316. if (app_settings->value("patch_options/video", "Disabled").toString() == "Enabled") {
  317. client_local_file.GetLocaleManager().EnableCategory(103);
  318. } else {
  319. client_local_file.GetLocaleManager().DisableCategory(103);
  320. }
  321. emit processFinished("ApplySounds");
  322. }
  323. bool LotroDatManager::startLotroLauncherWithParameters(LOTRO_DAT::DatLocaleManager::LOCALE locale)
  324. {
  325. QStringList args;
  326. args << "-skiprawdownload";
  327. if (locale == LOTRO_DAT::DatLocaleManager::PATCHED)
  328. args << "gamelaunch" << "-disablePatch";
  329. client_general_file.Deinitialize();
  330. client_local_file.Deinitialize();
  331. if(FileSystem::fileExists(QApplication::applicationDirPath() + "/user.ini")){
  332. QSettings login(QApplication::applicationDirPath() + "/user.ini", QSettings::IniFormat);
  333. login.beginGroup("Account");
  334. QString username = login.value("username", "").toString();
  335. QString password = login.value("password", "").toString();
  336. login.endGroup();
  337. args << "-username" << username << "-password" << password;
  338. }
  339. qDebug() << "Запускаем игру со следующими аргументами: " << args;
  340. QFile f(app_settings->value("General/game_folder_path", "none").toString() + "/LotroLauncher.exe");
  341. QProcess process;
  342. if (FileSystem::fileExists(f.fileName())) {
  343. if(f.fileName().contains(" ")) f.setFileName("\"" + f.fileName() + "\"");
  344. process.startDetached(f.fileName(), args);
  345. process.waitForFinished(-1);
  346. QApplication::quit();
  347. return true;
  348. } else {
  349. emit caughtError("startLotroLauncherWithParameters", {"LotroLauncherNotFound"});
  350. return false;
  351. }
  352. }