Przeglądaj źródła

Ver 3.0.0. Added support for using categories. Should be fixed

Ivan Arkhipov 6 lat temu
rodzic
commit
d686108b01

+ 3 - 0
CHANGELOG

@@ -14,6 +14,9 @@ Version 2.0.0
 Version 2.1.0
     * Changed structure of project in order to use it as library. Added basic API functions for easier library management
 ----------------------------------------------------------------------
+Version 3.0.0
+    * Added support for dividing files into categories and activating/deactivating them in DatFile
+----------------------------------------------------------------------
 
 
     

+ 1 - 1
CMakeLists.txt

@@ -5,7 +5,7 @@ set(CMAKE_CXX_STANDARD 11)
 set(PROJECT_BINARY_DIR bin)
 set(PROJECT_VERSION 0.1.0)
 
-SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS} -O2 -Wall -Wextra" )
+SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS} -O3 -Wall -Wextra" )
 SET(CMAKE_EXE_LINKER_FLAGS  "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
 
 if (MSVS)

+ 6 - 0
include/DatFile.h

@@ -145,6 +145,11 @@ namespace LOTRO_DAT {
 
         LOCALE current_locale();
 
+        void EnableCategory(int category);
+
+        void DisableCategory(int category);
+
+        const std::unordered_set<long long>& GetInactiveCategoriesList();
     private:
         std::unordered_map<long long, Subfile*>* GetLocaleDictReference(LOCALE locale);
 
@@ -156,6 +161,7 @@ namespace LOTRO_DAT {
         std::unordered_map<long long, Subfile*> orig_dict_;
         std::unordered_map<long long, Subfile*> patch_dict_;
         std::unordered_map<long long, Subfile*> pending_patch_;
+        std::unordered_set<long long> inactive_categories;
 
     private:
         FILE *file_handler_;

+ 3 - 1
include/Subfile.h

@@ -50,6 +50,8 @@ namespace LOTRO_DAT
         long long version() const;
         long long block_size() const;
 
+        long long category;
+
 	protected:
 		DatFile *dat_;
         long long dictionary_offset_;
@@ -62,7 +64,7 @@ namespace LOTRO_DAT
         long long timestamp_;
         long long version_;
         long long block_size_;
-    };
+	};
 }
 };
 

BIN
lib/libLotroDat.dll.a


BIN
lib/libLotroDat_static.a


+ 120 - 12
src/DatFile.cpp

@@ -24,11 +24,15 @@ namespace LOTRO_DAT {
 
     bool DatFile::InitDatFile(const std::string &filename, int dat_id) {
         try {
-            if (dat_state_ != CLOSED)
+            if (dat_state_ != CLOSED && filename == filename_)
+                return true;
+
+            if (dat_state_ != CLOSED && filename != filename_)
                 CloseDatFile();
 
             dat_id_ = dat_id;
             dat_state_ = CLOSED;
+            current_locale_ = ORIGINAL;
             root_directory_ = nullptr;
             file_handler_ = nullptr;
 
@@ -243,9 +247,14 @@ namespace LOTRO_DAT {
             return false;
         }
 
+        if (data.options["cat"].IsDefined())
+            file->category = data.options["cat"].as<long long>();
+        else
+            fprintf(stderr, "WARNING DatFile::PatchFile() - category option 'cat' was not set in patch subfile with id = %lld\n", file_id);
+
         BinaryData old_data = GetFileData(file);
         BinaryData patch_data = file->MakeForImport(old_data, data);
-        ApplyFilePatch(dictionary_[file_id], patch_data, rewrite_original);
+        ApplyFilePatch(file, patch_data, rewrite_original);
         return true;
     }
 
@@ -458,7 +467,6 @@ namespace LOTRO_DAT {
 
     /// Special functions used by patch process.
     /// Shouldn't be used by any external class.
-
     void DatFile::ApplyFilePatch(Subfile *file, const BinaryData &data, bool rewrite_original) {
         if (patched_list.count(file->file_id()) != 0) {
             fprintf(stderr, "Warning: DatFile::ApplyFilePatch - found 2 files in patch with the same file_id = %lld. Passing last...\n", file->file_id());
@@ -471,7 +479,7 @@ namespace LOTRO_DAT {
         dat_state_ = UPDATED;
 
         if (orig_dict_.count(file->file_id()) == 0 && !rewrite_original) {
-            orig_dict_[file->file_id()] = new Subfile(this, dictionary_[file->file_id()]->MakeHeaderData());
+            orig_dict_[file->file_id()] = new Subfile(this, file->MakeHeaderData());
         }
 
         auto journal = GetFragmentationJournal();
@@ -512,6 +520,20 @@ namespace LOTRO_DAT {
             patch_dict_[file_id] = new Subfile(this, file->MakeHeaderData()); // Создали новое значение
         }
 
+        // If category is forbidden, then return file header data to original state
+        if (inactive_categories.count(file->category) != 0) {
+            dictionary_[file_id]->file_offset_ = orig_dict_[file_id]->file_offset_;
+            dictionary_[file_id]->file_size_ = orig_dict_[file_id]->file_size_;
+            dictionary_[file_id]->block_size_ = orig_dict_[file_id]->block_size_;
+            dictionary_[file_id]->timestamp_ = orig_dict_[file_id]->timestamp_;
+            dictionary_[file_id]->version_ = orig_dict_[file_id]->version_;
+        }
+
+        if (orig_dict_.count(file_id) != 0)
+            orig_dict_[file_id]->category = file->category;
+        if (patch_dict_.count(file_id) != 0)
+            patch_dict_[file_id]->category = file->category;
+
         UpdateFragmentationJournal(journal);
     }
 
@@ -655,9 +677,11 @@ namespace LOTRO_DAT {
         // 15 bytes for "Hi from Gi1dor"
         // 4 bytes for LOCALE
         // 4 bytes for orig_dict.size()
-        // 32 * orig_dict.size() bytes for orig_dict data
+        // (32 + 4) * orig_dict.size() bytes for orig_dict data
         // 4 bytes for patch_dict.size()
-        // 32 * patch_dict.size() bytes for patch_dict data
+        // (32 + 4) * patch_dict.size() bytes for patch_dict data
+        // 4 bytes for inactive_categories dict
+        // 4 * inactive_categories.size() bytes for inactive_categories data
 
         size_t orig_dict_size = size_t(dicts_data.CutData(offset, offset + 4).ToNumber<4>(0));
         offset += 4;
@@ -665,8 +689,12 @@ namespace LOTRO_DAT {
             auto file = new Subfile(this, dicts_data.CutData(offset, offset + 32));
             orig_dict_[file->file_id()] = file;
             offset += 32;
-        }
+            orig_dict_[file->file_id()]->category = dicts_data.ToNumber<4>(offset);
+            offset += 4;
 
+            if (orig_dict_[file->file_id()]->category == 0)
+                fprintf(stderr, "WARNING DatFile::InitLocales() - file category is undefined (0)!\n");
+        }
 
         size_t patch_dict_size = size_t(dicts_data.CutData(offset, offset + 4).ToNumber<4>(0));
         offset += 4;
@@ -674,10 +702,26 @@ namespace LOTRO_DAT {
             auto file = new Subfile(this, dicts_data.CutData(offset, offset + 32));
             patch_dict_[file->file_id()] = file;
             offset += 32;
+            patch_dict_[file->file_id()]->category = dicts_data.ToNumber<4>(offset);
+            offset += 4;
+            if (patch_dict_[file->file_id()]->category == 0)
+                fprintf(stderr, "WARNING DatFile::InitLocales() - file category is undefined (0)!\n");
+
+        }
+
+        size_t active_patches_dict_size = size_t(dicts_data.CutData(offset, offset + 4).ToNumber<4>(0));
+        offset += 4;
+        for (size_t i = 0; i < active_patches_dict_size; i++) {
+            inactive_categories.insert(dicts_data.ToNumber<4>(offset));
+            offset += 4;
         }
 
         std::cout << "There are " << patch_dict_.size() << " files in patch locale dictionary" << std::endl;
         std::cout << "There are " << orig_dict_.size() << " files in original locale dictionary" << std::endl;
+        std::cout << "Unactive patches now: ";
+        for (auto i : inactive_categories)
+            std:: cout << i;
+        std::cout << std::endl;
     }
 
     std::unordered_map<long long, Subfile *> *DatFile::GetLocaleDictReference(LOCALE locale) {
@@ -711,7 +755,7 @@ namespace LOTRO_DAT {
                     continue;
                 }
                 if (dictionary_[file.first]->MakeHeaderData().CutData(8, 16) ==
-                    file.second->MakeHeaderData().CutData(8, 16))
+                    file.second->MakeHeaderData().CutData(8, 16) || inactive_categories.count(orig_dict_[file.first]->category) != 0)
                     continue;
 
                 long long file_id = file.first;
@@ -756,7 +800,7 @@ namespace LOTRO_DAT {
     }
 
     void DatFile::CommitLocales() {
-        std::cout << "Commiting locales..." << std::endl;
+        std::cout << "Committing locales..." << std::endl;
         SubfileData data = dictionary_[2013266257]->PrepareForExport(GetFileData(dictionary_[2013266257]));
         data.options["fid"] = "2013266257";
         data.options["ext"] = ".unknown";
@@ -767,11 +811,16 @@ namespace LOTRO_DAT {
         // 15 bytes for "Hi from Gi1dor"
         // 4 bytes for LOCALE
         // 4 bytes for orig_dict.size()
-        // 32 * orig_dict.size() bytes for orig_dict data
+        // (32 + 4) * orig_dict.size() bytes for orig_dict data
         // 4 bytes for patch_dict.size()
-        // 32 * patch_dict.size() bytes for patch_dict data
+        // (32 + 4) * patch_dict.size() bytes for patch_dict data
+        // 4 bytes for inactive_categories list
+        // 4 * inactive_categories.size() bytes for inactive_categories data
 
-        data.binary_data = BinaryData(14 + 15 + 4 + 4 + orig_dict_.size() * 32 + 4 + patch_dict_.size() * 32);
+        data.binary_data = BinaryData(14 + 15 + 4
+                                      + 4 + (32 + 4) * orig_dict_.size()
+                                      + 4 + (32 + 4) * patch_dict_.size()
+                                      + 4 + 4 * inactive_categories.size());
 
         size_t current_size = 0;
         data.binary_data.Append(GetFileData(dictionary_[2013266257u]).CutData(0, 14), current_size);
@@ -789,6 +838,8 @@ namespace LOTRO_DAT {
         for (auto file : orig_dict_) {
             data.binary_data.Append(file.second->MakeHeaderData(), current_size);
             current_size += 32;
+            data.binary_data.Append(BinaryData::FromNumber<4>(file.second->category), current_size);
+            current_size += 4;
         }
 
         data.binary_data.Append(BinaryData::FromNumber<4>(patch_dict_.size()), current_size);
@@ -797,10 +848,67 @@ namespace LOTRO_DAT {
         for (auto file : patch_dict_) {
             data.binary_data.Append(file.second->MakeHeaderData(), current_size);
             current_size += 32;
+            data.binary_data.Append(BinaryData::FromNumber<4>(file.second->category), current_size);
+            current_size += 4;
+        }
+
+        data.binary_data.Append(BinaryData::FromNumber<4>(inactive_categories.size()), current_size);
+        current_size += 4;
+        for (auto patch_id : inactive_categories) {
+            data.binary_data.Append(BinaryData::FromNumber<4>(patch_id), current_size);
+            current_size += 4;
         }
 
         PatchFile(data, true);
         std::cout << "Done!" << std::endl;
     }
+
+    void DatFile::EnableCategory(int category) {
+        std::cout << "Disabling category " << category << std::endl;
+        if (inactive_categories.count(category) == 0)
+            return;
+        inactive_categories.erase(category);
+
+        for (auto file : dictionary_) {
+            auto file_id = file.first;
+            if (patch_dict_.count(file_id) > 0 && patch_dict_[file_id]->category == category) {
+                dat_state_ = UPDATED;
+
+                file.second->file_offset_ = patch_dict_[file_id]->file_offset_;
+                file.second->file_size_ = patch_dict_[file_id]->file_size_;
+                file.second->block_size_ = patch_dict_[file_id]->block_size_;
+                file.second->timestamp_ = patch_dict_[file_id]->timestamp_;
+                file.second->version_ = patch_dict_[file_id]->version_;
+                patched_list.insert(file_id);
+            }
+        }
+    }
+
+    void DatFile::DisableCategory(int category) {
+        std::cout << "Disabling category " << category << std::endl;
+        if (inactive_categories.count(category) != 0)
+            return;
+        inactive_categories.insert(category);
+
+        for (auto file : dictionary_) {
+            auto file_id = file.first;
+
+            if (orig_dict_.count(file_id) && orig_dict_[file_id]->category == category) {
+                dat_state_ = UPDATED;
+
+                file.second->file_offset_ = orig_dict_[file_id]->file_offset_;
+                file.second->file_size_ = orig_dict_[file_id]->file_size_;
+                file.second->block_size_ = orig_dict_[file_id]->block_size_;
+                file.second->timestamp_ = orig_dict_[file_id]->timestamp_;
+                file.second->version_ = orig_dict_[file_id]->version_;
+                patched_list.insert(file_id);
+            }
+        }
+    }
+
+    const std::unordered_set<long long>& DatFile::GetInactiveCategoriesList() {
+        return inactive_categories;
+    }
+
 }
 }

+ 28 - 5
src/Examples/patcher_example.cpp

@@ -16,13 +16,13 @@ using namespace LOTRO_DAT;
 using namespace std;
 
 int main() {
-    std::cout << "Gi1dor's LotRO .dat patcher ver. 2.1.0" << std::endl;
+    std::cout << "Gi1dor's LotRO .dat patcher ver. 3.0.0" << std::endl;
     freopen("errors.log", "w", stderr);
 
-   // setbuf(stdout, NULL);
+    setbuf(stdout, NULL);
     setbuf(stderr, NULL);
 
-   // setvbuf (stdout, NULL, _IONBF, BUFSIZ);
+    setvbuf (stdout, NULL, _IONBF, BUFSIZ);
     setvbuf (stderr, NULL, _IONBF, BUFSIZ);
 
     std::cout << "Hello! I'm a basic shell version of .dat file patcher.\n";
@@ -63,9 +63,11 @@ int main() {
 
     while (true) {
         std::cout << "Please, choose, what should I do. I can patch datfile from database to .dat file (enter 1), "
-                "change locale (enter 2), print current locale (enter 3) or exit (enter -1)\n";
+                "change locale (enter 2), print current locale (enter 3), enable category (enter 4), disable category (enter 5), "
+                "print disabled categories (enter 6) or exit (enter -1)\n";
+
         int cmd = 0;
-        std::cout << "Enter number of command (1-4): ";
+        std::cout << "Enter number of command (1-6): ";
         std::cin >> cmd;
 
         std::string tmp;
@@ -143,7 +145,28 @@ int main() {
         }
 
         if (cmd == 4) {
+            int category_id = 0;
+            std::cout << "Enter category id: ";
+            std::cin >> category_id;
+            file.EnableCategory(category_id);
+            std::cout << "Category successfully enabled!" << std::endl;
+            file.CommitChanges();
+        }
+
+        if (cmd == 5) {
+            int category_id = 0;
+            std::cout << "Enter category id: ";
+            std::cin >> category_id;
+            file.DisableCategory(category_id);
+            std::cout << "Category successfully disabled!" << std::endl;
+            file.CommitChanges();
+        }
 
+        if (cmd == 6) {
+            std::cout << "Disabled categories: ";
+            for (auto i : file.GetInactiveCategoriesList())
+                std::cout << i << " ";
+            std::cout << endl;
         }
     }
     file.CloseDatFile();

+ 2 - 1
src/Subfile.cpp

@@ -29,6 +29,7 @@ namespace LOTRO_DAT {
         timestamp_ = header.ToNumber<4>(20); // timestamp
         version_ = header.ToNumber<4>(24); // version
         block_size_ = header.ToNumber<4>(28); // block_size
+        category = 0;
     }
 
     Subfile::Subfile(DatFile *dat, long long dictionary_offset, long long fragments_count, long long unknown1, long long file_id,
@@ -36,7 +37,7 @@ namespace LOTRO_DAT {
                                 long long file_size, long long timestamp, long long version, long long block_size) :
             dat_(dat), dictionary_offset_(dictionary_offset), fragments_count_(fragments_count), unknown1_(unknown1), file_id_(file_id),
             file_offset_(file_offset),
-            file_size_(file_size), timestamp_(timestamp), version_(version), block_size_(block_size) {
+            file_size_(file_size), timestamp_(timestamp), version_(version), block_size_(block_size), category(0) {
 
         if (file_size_ > MAXSIZE)
             throw DatException("Bad Subfile::Subfile() - File size is too much... Maybe it's incorrect..?",