1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Black Desert Online Modding Tools

Discussion in 'Tools & Guides' started by BlackFireBR, Jul 7, 2016.

  1. BlackFireBR

    BlackFireBR Content Creator

    Joined:
    Sep 2, 2013
    Messages:
    1,320
    Likes Received:
    867
    META INJECTOR
    This tool allows you to put modified files inside the game.​

    What does it do exactly:
    It makes the game look for the files in the Black Desert root folder instead of looking inside the compressed PADxxxxx.PAZ files, so you can use modified files.
    [​IMG]
    Download Link: Meta Injector

    Source Code : Included in the .zip file, under "source_codes"
    The only files you need to understand what they do (and not all of it), are these ones:
    • main.c : Handles the menus
    • file_operations.c : Handles things like open files, count files, copy files, check files existence, etc.
    • patcher.c : Does all the magic.
    • meta_explorer.c : Reads the pad00000.meta files and retrieves/decrypt the information of this index file and stores all the information in memory.

    Let's start with the file main.c:

    main.c : It is responsible only for the user interface (menus), it doesn't do anything but to give the user the options to install or restore a backup. If the user chooses the "Install" option, it calls te "runPatcher()" function, located in the "patcher.c" file.

    patcher.c : It's the Meta Injector code itself. If reads the files from the "files_to_patch" folder, and patches the pad00000.meta file and then copies the files to their right location.

    void runPatcher():
    The most important function in the patcher.c file.
    The first thing it does is to call the function:
    Code:
    getAllFiles(char* pathToFiles, char* extFilter, long* filesCount)
    
    This is located in the file "file_operations.c" and what it does is: It opens the folder specified in "pathToFiles" and if it's a file, it stores the file names and the path to that file into a variable that I called "FileBlock* fileNames",
    If it's not a file, it goes inside that folder by calling the same function recursively, but with the "pathToFiles" changed to that folder.

    Warning: It's is important that you save the path to each file into the "fileNames[ i ].originalPath" variable because we are going to use this information to copy the files to their right location later.

    ------------------------------------------------------------------------------------------------------------------------

    Going back to the "runPatcher()" function again, now we have to get information from the pad00000.meta file. For that we call those two functions, located in the "meta_explorer.c" file:
    Code:
    metaFileInfo = getMetaFileInfo(getLatestBackup());
    fileBlocks = fillFileBlocks(metaFileInfo);
    
    getLatestBackup() : returns you lastest pad00000[xxxx-xx-xx].meta.backup file name(Implementation located in "utilities.c"). We have to use the backup because we need a clean meta file to retrieve the right information.
    If no backup exists, it simply uses the "pad00000.meta" file.

    MetaFileInfo* getMetaFileInfo(char* metaFileName)
    First, take a look on how the pad00000.meta file is structured:
    [​IMG]

    Now, look at the beginning of the .meta file:
    [​IMG]
    The first 4 bytes are just the client version, so we skip it by doing :
    Code:
    fseek(metaFile,sizeof(long),SEEK_SET);
    The next 4 bytes, are how many .PAZ file the game has right now, I store this info in "metaFileInfo->pazCount"

    Next, I skip this whole part that are just the PAZ_NUM,PAZ_HASH,PAZ_SIZE by doing:
    Code:
    fseek(metaFile,(metaFileInfo->pazCount * (3 * sizeof(long))),SEEK_CUR);
    (3 * sizeof(long)) skips one "line"

    So now, if you read the next 4 bytes, it gives you how many of the "File Blocks" you are going to have next.

    File Blocks are the most important thing in the program, they are this:
    [​IMG]

    But we are not going to mess with it in this function yet, we just need to know how many of them there are, so we just store the read value in the "metaFileInfo->filesCount" variable.

    Now, the file pointer should be right at the beginning of the "File Blocks" part,
    so we just save that location under "metaFileInfo->fileBlocksStart" so we can jump right into that point later.
    We do that by doing:
    Code:
    metaFileInfo->originalFileBlocksStart = ftell(metaFile);
    I also calculated where the "File Blocks" should stop, by doing this simple calculation:
    Code:
    File Blocks End =  File Blocks Start + (Files Count * (size of one registry))
    Since each "line" (registry) of the file blocks has 7 fields and each fields is has 4 bytes, and 7*4 = 28, I did:
    Code:
    #define ONE_REGISTRY 28
    That's the end of the getMetaFileInfo function.
    ------------------------------------------------------------------------------------------------------------------------
    FileBlock* fillFileBlocks(MetaFileInfo* metaFileInfo)
    This will read that "File Blocks" section from the .meta file, and also, decrypt the File Names and Folder Names, and store all that in the "fileBlocks" variable:
    [​IMG]

    Now for this part, I'm going to simplify things a little.
    The way I did in my code, was because there were some versions of the game that I couldn't read the first 256000 bytes from the "File Blocks" part, but now this is fixed. But the code works either way.

    So all the part from:
    Code:
    printf("\nSearching for hash: %ld\n", multiplemodeldesc_hash);
    to
    Code:
    printf("FILE_BLOCKS_COUNT: %ld (%ld missing files)\n", metaFileInfo->fileBlocksCount,metaFileInfo->filesCount -  metaFileInfo->fileBlocksCount);
    You can delete it and use this code instead:
    Code:
        // Allocates the memory for the File Blocks
        fileBlocks = (FileBlock*)calloc(metaFileInfo->filesCount + 1, sizeof(FileBlock));
    
        // Initialized the variable that counts how many file blocks we have
        metaFileInfo->fileBlocksCount = 0;
    
        // This will open you last pad00000.meta.backup file,
        // just in case your current pad00000.meta file is already modified.
        FILE* metaFile = openFile(getLatestBackup(),"rb");
    
        // Go to where the file blocks start
        fseek(metaFile,metaFileInfo->originalFileBlocksStart,SEEK_SET);
    
       // Fill the File Blocks
       for (i = 0; i < metaFileInfo->filesCount; i++)
       {
            // Saves the exact byte where this registry begins (VERY IMPORTANT)
            fileBlocks[i].metaOffset = ftell(metaFile);
    
            // Reads the next 28 bytes of the meta file and stores it
            fread(&fileBlocks[i].hash,sizeof(long),1,metaFile);
            fread(&fileBlocks[i].folderNum,sizeof(long),1,metaFile);
            fread(&fileBlocks[i].fileNum,sizeof(long),1,metaFile);
            fread(&fileBlocks[i].pazNum,sizeof(long),1,metaFile);
            fread(&fileBlocks[i].fileOffset,sizeof(long),1,metaFile);
            fread(&fileBlocks[i].zsize,sizeof(long),1,metaFile);
            fread(&fileBlocks[i].size,sizeof(long),1,metaFile);
    
            metaFileInfo->fileBlocksCount++;
       }
    
    All we did, was reading this:
    [​IMG]

    Now we are going to decrypt and read the folder names (relative paths to the files if they were extracted from the .PAZ file)
    [​IMG]
    Code:
         // Seek to file blocks end (optional)
        fseek(metaFile,metaFileInfo->fileBlocksEnd,SEEK_SET);
    
        // Reads how many folder names we will be reading
        long folders_part_length = 0;
        fread(&folders_part_length, sizeof(long),1,metaFile);
    
    For the next part bellow:
    Code:
    /// ******************* FOLDER NAMES DECRYPTION **********************
    I simply used the code posted here:
    https://www.undertow.club/posts/138739

    What you have to know about it is that it reads the meta file all the encrypted bytes from the "Folder names" part and stores them in the "ctext" variable. After that it reads this "ctext" variable, 8 bytes at the time, and it decrypts these 8 bytes, storing the decrypted data into the "ptext" variable.

    After everything is done, this moves the "ptext" pointer back to the beginning to the memory region where you have the decrypted folder names.
    Code:
    ptext -= folders_part_length;
    At this point, if we read the ptext variable, we are going to have this:
    Code:
    [FOLDER_NUM (4bytes) ][SUBFOLDERS_NUM (4bytes) ]character/'\0'[FOLDER_NUM (4bytes) ][SUBFOLDERS_NUM (4bytes) ] character/texture/'\0' ....
    And we actually want:
    Code:
    folderNames[0] = "character/";
    folderNames[1] = "character/texture/";
    ...
    
    So, for the next part
    Code:
    /// FOLDER NAMES FILLING
    We are basically puting each "folder name" into each position of the array "folderNamesArray".

    Like, we are skipping the first 2 numbers:
    [FOLDER_NUM (4bytes) ][SUBFOLDERS_NUM (4bytes) ]
    Code:
    for (j = (2 * sizeof(long)) /* Skips the first 2 numbers */; j < folders_part_length; j++)
    {
         ...
         j += (2 * sizeof(long)); /* Skips the first 2 numbers */
    }
    
    Reading the string until we find a '\0', and storing it into the folderNamesArray:
    Code:
    character/'\0'
    Code:
            // If it's not a \0
            if (ptext[j] != 0)
            {
                folderNameLength++;
            }
            else // If the \0 is found
            {
                    // Store the folder name
             }
    
    ---------------------------------------------------------------------------------------
    Bellow this comment:
    Code:
     // Assigns the right File Name from the fileNameArray to the right File Block, based on the File Num
    We basically copy the content of each "folderNamesArray", to the "fileBlocks" structure
    (We have to do this because the order from "folderNamesArray" is different from what we read in the "File Blocks" section)
    [​IMG]

    The next thing:
    Code:
    /// ******************* FILE NAMES DECRYPTION **********************
    and
    Code:
    /// FILE NAMES FILLING
    It's the same thing. The only difference is that the "File Names" section doesn't have the "FOLDER_NUM" and "SUBFOLDERS_COUNT" numbers in front of each file, so we don't have to skip them every time.

    In the end I do this:
    Code:
    qsort(fileBlocks,metaFileInfo->fileBlocksCount,sizeof(FileBlock),compare);
    But it's just to make searching in this fileBlocks faster, it's not really necessary.

    This is the end of the fillFileBlocks() function
    -----------------------------------------------------------------------------------------------------------------------------------------

    Going back to the "runPatcher()" again:
    After you have your MetaFileInfo and your FileBlocks filled, it's time to do what Meta Injector actually does.

    What we are going to do now, is to look for each file name we discovered in the "files_to_patch" folder, into our "FileBlock* fileBlocks" structure, and if we have a matching name, we are going to copy some information from that "fileBlock[ i ]" that we don't have in out "filesToPatch[ j ]" that is going to be relevant in the future. And also set the variable "needPatch" from that file in the "filesToPatch" array, to 1.

    This "needPatch" flag will be used to check if we need to patch this file block in the meta file or not.

    Just like before, the current code in the source code, is a little more complicated than it needs to be for your application, so from the lines bellow:
    Code:
     printf("\nSearching for files in the meta file...");
    to
    Code:
     /// COPYING FILES
    Delete the code in between and use this code instead:
    Code:
       // Searches for the files from the "files_to_patch" folder in the "fileBlocks"
        for (j = 0; j < filesToPatchCount; j++)  // For each file from the "filesToPatch" array
        {
           // Sequential search through all File Blocks
            for (i = 0; i < metaFileInfo->fileBlocksCount; i++)
            {
                // If they have the same file name
                if (strcmpi(fileBlocks[i].fileName,filesToPatch[j].fileName) == 0)
                {
                    // Time to get some relevant information from the matched file block:
     
                    // This will be used to patch the meta file
                    filesToPatch[j].metaOffset = fileBlocks[i].metaOffset;
     
                    // This will be used to copy the files to where they are suposed to go
                    filesToPatch[j].folderName = fileBlocks[i].folderName;
                    filesToPatch[j].originalPath = fileBlocks[i].originalPath;
    
                    // Indicates this file block will need to be patched in the meta file
                    filesToPatch[j].needPatch = 1;
    
                    // Breaks from the for loop that goes though the file blocks,
                    // since we've already found a match for this fileToPatch[j]
                    break;
                }
            }
        }
    
    Next thing, we call:
    Code:
    copyFilesBack(filesToPatch, filesToPatchCount);
    Again, you don't need to do what I did in my code, there is a simple way to do what this function does, and I'm going to teach you right now:

    You have to copy the files from the "files_to_patch" folder, in wherever subfolder they are (remember this information was stored in the "originalPath" variable), to the path the game will look from them,
    which consist in "Black Desert Installation Folder" + filesToPatch[ i ].folderName

    So for example. Let's say you installed your game into:
    "C:\Program Files (x86)\Black Desert Online\"

    (In my code, I get the current working dir, which gives me the path to the meta_injector.exe, and I remove the "\Paz" at the end of the path, which gives me the exact game path.)

    and let's say you have this in your filesToPatch[0]:
    fileName = "phw_00_uw_0001.dds"
    folderName = "character/texture/"
    originalPath = "files_to_patch\"

    What you are going to do is to make a way to copy "phw_00_uw_0001.dds" from ""C:\Program Files (x86)\Black Desert Online\Paz\files_to_patch\" to ""C:\Program Files (x86)\Black Desert Online\character\texture\"

    In a sort of code way, you would have to do this:
    Code:
    void copyFilesBack(FileBlock* filesToPatch, int filesToPatchCount)
    {
        char* bdoRootFolder = "C:/Program Files (x86)/Black Desert Online/";
        int i = 0;
        for (i = 0; i < filesToPatchCount; i++)
        {
            if (filesToPatch[i].needPatch)
            {
                copy filesToPatch[i].fileName from filesToPatch[i].originalPath to bdoRootFolder + filesToPatch[i].folderName
            }
        }
    }
    
    After that we call:
    Code:
     patchMetaFile(filesToPatch, filesToPatchCount, menu1ChosenOption);
    Again, here's a simplified version of it:
    Code:
    void patchMetaFile(FileBlock* filesToPatch, int filesToPatchCount)
    {
        int i = 0;
    
        // This is going to be used to "break" the index file
        long random_folder_num = 1;
        long random_file_num = 60556;
    
        // Opens the meta file
        FILE* metaFile = fopen("pad00000.meta","rb+");
    
        // For each file to patch
        for (i = 0; i < filesToPatchCount; i++)
        {
            // Check if it's marked to patch
            if(filesToPatch[i].needPatch)
            {
                // Goes to the right where the file block starts, and skips the first number (the hash)
                fseek(metaFile,filesToPatch[i].metaOffset + sizeof(long), SEEK_SET);
     
                // Overrites the folder num and file num written there, to random values
                fwrite(&random_folder_num, sizeof(long),1,metaFile);
                fwrite(&random_file_num, sizeof(long),1,metaFile);
            }
        }
        fclose(metaFile);
    }
    
    Let me explain what we just did. The game, when it's loading a file, it goes to the pad00000.meta file and it reads the "File Blocks" part and all the other things we did for the "meta_explorer.c" part. To find a file, the game looks for a combination of "file number" and "folder number" so it can know in which position of the arrays "folderNames" and "filesNames" it need to look into. (just like we did in the meta explorer).

    If you put some absurd values in there, the game will not be able to tell in which "PAD0xxxx.PAZ" the file it needs is located, so it searches for the file, in the game's root folder (That's why we copied the files there before).

    So for the random values, we chose 1 for the "folder num" and "60556" for the file num. It could be anything, really, as long as you are sure that there is no combination of folderNames[random_folder_num] and fileNames[random_file_num], that when it reads it, it gives the right folder name and file name for the file you are looking for.
    (If fact, if you simply increased one of the original numbers by one, it would already do the trick, because it wouldn't find a match for the file)
    -------------------------------------------------------------------------------------------------------------------------------
    And there you go!

    This is all that my program does, step by step. Only the important parts.

    Send me a PM if you need any further explanation on anything.
    Older versions: Click here

    Instructions:
    1 - Extract the zip file to your "PAZ\" folder, which is located inside your installation folder.
    (Note: For steam users it's usually under: "C:\Program Files (x86)\Steam\steamapps\common\Black Desert Online\").
    2 - Put all your modified files in the "files_to_patch" folder.
    3 - Run "meta_injector.exe"
    4 - Follow the screen instructions.

    Do this every time a game update is released:
    - Restore you last backup using the tool, before you update the game, otherwise you will get a "corrupted files" message from the launcher.
    If that happens, close the launcher, use the "Restore a backup" option, and open the launcher again.

    Uninstall:
    Run meta_injector.exe and select the "Restore backup" option.
    The latest ones are the most up to date.
     

    Attached Files:

    Last edited: Sep 15, 2017
    TehPenguin, aliraja, comsci and 5 others like this.
  2. BlackFireBR

    BlackFireBR Content Creator

    Joined:
    Sep 2, 2013
    Messages:
    1,320
    Likes Received:
    867
    PAZ Browser
    With this tool, you can browse ALL the folders and extract ALL the files from the game you can't normally access.

    The game has those files compressed, inside the files named "PAD0xxxx.PAZ", located in your "Paz\" folder.
    This tool allows you to view what's inside them and extract what you want.

    It also has a 3D Model Viewer so you can preview all the game's 3D models.

    (You can only view them, to edit them, see
    Black Desert Online 3D Model Export / Import Tool down bellow in this post)
    [​IMG]
    Download Link: PAZ Browser

    (Source code inside the .zip file, under the folder "source_codes")

    Installation:

    1 - Extract the zip file to your "PAZ\" folder, which is located inside your installation folder.
    (Note: For steam users it's usually under: "C:\Program Files (x86)\Steam\steamapps\common\Black Desert Online\").
    2 - Run "paz_browser.exe" inside that folder.



    Features
    Browse ALL the folders and ALL the files of the game and choose exactly the files you want to extract:
    [​IMG]

    Search

    [​IMG]
    You can find a specific file you want to extract without having to go through all the folders to find it.
    The search allows you to search multiple files at once, as well, search by extension, and even search all the files that has a certain pattern.

    Here's some of the features of the search:
    Code:
    For multiple files, separate them by commas.
        phw_00_ub_0004.pac,multiplemodeldesc.xml,pew_00_lb_0053_dec.dds
    
    If you want to list all the files from from an extension, do it like this:
        *.xml,*dds,*pac - Will give you all the files with the extension .xml or .dds or .pac
    
    If you want to list only the files that are in a specific folder, do this:
         character/*.xml  This will give you all the files .xml located in the folder "character/"
    
    You can search for parts of the file name, doing this:
         *_00_ub_0001.pac  This will give you all the files that ends with "_00_ub_0001.pac"
    
    You can also do this to find all the armor parts:
         phw_00_*_0001.pac  This will give you: phw_00_ub_0001.pac,phw_00_lb_0001.pac,phw_00_hand_0001.pac
         (Basically the character * makes the program ignore what's between the words it separates)
    
    Extract the whole game

    [​IMG]
    • It extracts 100% of the game files.
    • It displays how many files were already extracted, and what percentage of the extraction is already completed.
    Real Outfit and Armor Names Listing
    [​IMG]
    Press "N" to toggle between the "Real Names" and the "File Names" when browsing armor files.

    This feature uses a .txt file located in "Paz\patcher_resources\" and it's called "real_names.txt":

    [​IMG]

    • The left side accepts the same things as the "search" in this tool.
    • You can add more into this file, obeying the same pattern and the tool will automatically recognize it the next time you launch it.
    • # is interpreted as a comment and the entire line is ignored
    I didn't check if all the file names are correct. If you find any mistake, feel free to post them here and I can fix it in a future release.

    Also feel free to post here, updated versions of this file made by you.
    -----------------------------------------------------------------------------------------------------------------------------------------------------
    As it is written in the program, here's what each color represents:
    When not browsing the Outfit and Armors:

    • Green: It's a folder
    • White: It's a file

    When browsing the Outfit and Armors:
    • Magenta: Cash-shop Item
    • Blue: Non-Cash-Shop Item
    • Green: Class-Exclusive Item

    Yellow: If you have at least 2 backups in your Paz folder, the tool compares the files that are present in your previous backup, with the ones that are present in your game right now. The new files that were added in the newest update, are shown as Yellow:
    [​IMG]


    File Extraction to Folder with Meaningful Names

    [​IMG]
    Now every time you extract a file that has a "Real Name", the folder it's extracted uses that name, as long as which class it belongs. (See picture above for more details)


    Change the order the files are displayed

    [​IMG]
    Now to make it easier to find the files you want, you can sort them by:

    • File Name
    • Real Name
    • Most Recent
    • Extension
    And choose if you want them sorted in a "ascendant" order, or a "descendant" order.

    Sorting by "Most Recent" simply sorts them by "File Number" (The order they were added in the game by the developers, at least in theory). So using "Most Recent - Descendant" will give you better chances to find the file from the newest outfit for example.

    Multiple File Selection Made it Easy

    [​IMG]
    Do you want to select multiple files like you are holding "Shift" if you were using a File Explorer? You can do that now by using the key "S" to select both the current file the cursor is pointing and the file bellow.
    If you selected more that you wanted by any chance, you can undo that selection by pressing "W".

    Extract All The Outfit Parts At Once

    [​IMG]
    Have you ever wanted to extract all the parts of the armor at once (Upperbody, Lowerbody, Shoulder, etc)?
    Well, now you can.
    Every time you are in the "9_upperbody" folder of any class, when you try to extract one or more files, after prompting where do you want to extract the files to, it asks you if you want to do just that.
    If you press 'y' or 'Y' it will extract not only the _ub_ file, but also all the other that are from the same outfit your selected, and then, when it's done, it will open the folder where extracted everything.

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    Black Desert Online 3D Model Export / Import Tool

    Thanks to IndigoDesert now it's possible to export .pac files open them on any 3D Editor like blender, edit them, and then re-import them back to the game.

    The process is very simple, and I'm going to try to make the explanation as simple as possible with a lot of images to guide you through the process.

    Here we go:
    1. Download Paz Browser and extract ALL THE FILES from the .zip file to: "Black Desert Online\Paz\"
    2. Open your "Paz" folder and run "paz_browser.exe"
    3. Find the .pac file you want to edit and press ENTER to extract and preview the file (Don't close the window that open with the extracted files)
      [​IMG]
      For the nude body models, using the menus, go to "Your class->Body Mesh":

      Here's the list of the nude body models files of each class:
      • Sorceress : phw_00_nude_0001_noalpha.pac
      • Ranger : pew_00_nude_0001_noalpha.pac
      • Tamer : pbw_00_nude_0001.pac
      • Valkyrie : pvw_00_nude_0001.pac
      • Valkyrie : pvw_00_nude_0001.pac
      • Witch : pww_00_nude_0001.pac
      • Kunoichi : pnw_00_nude_0001.pac
      • Dark Knight : pdw_00_nude_0001.pac
      • Plum(Maehwa) : pkww_00_nude_0002.pac
      • Warrior : phm_00_nude_0001.pac
      • Berserker : pgm_00_nude_0001.pac
      • Blader(Musa) : pkm_00_nude_0001.pac
      • Wizard : pwm_00_nude_0001.pac
      • Ninja : pnm_00_nude_0001.pac
    4. Download PAC_to_DAE_Converter_v3.zip and extract all the content to the same folder that contains the .pac file (The folder the program opened after extracting the .pac file)
      4---extract.gif
    5. Right click "pac_to_dae.bat" and then click "Edit"
      5---edit.gif
    6. Replace "PAC_FILE_NAME.pac" with the name of the .pac file you are trying to extract. Also, replace "CLASSPREFIX" with the first 3 letters of the pac file you are converting:
      E.g: If the pac file name is: phw_00_nude_0001_noalpha.pac, replace "CLASSPREFIX_01.pab" with "phw_01.pab"
      [​IMG]
    7. Save the file and run "pac_to_dae.bat". 3 new files will be created in this folder:
      - Each .pac file has 3 "Level of Detail" (LOD) files.
      - When you convert it to .dae, it separates it in 3 different files:
      • lod0 is the one with more details
      • lod3 is the one with less details.
      [​IMG]
    8. Open up Blender or any other 3D Editing software, and go to "File->Import->Collada (default) (.dae)" and find your .dae files.
      [​IMG]
    9. When you are done editing, go to "File->Export->Collada (default) (.dae)" and replace the original file.
      [​IMG]
      WARNING: I've been told that Blender doesn't export DAE files properly. You must use a program like Maya or 3DSmax.
      If you use blender, it is possible you get the error: "Missing arrays!"
    10. Now go back to your folder, right click "dae_to_pac.bat" and click on "Edit".
      edit2.gif
    11. Do the same thing you did before, but replace "DAE_FILE_NAME.dae" with the ".dae" file name you just edited and exported, "PAC_FILE_NAME.pac" with the original .pac file name, and "CLASSPREFIX" again with the first 3 letters of the .pac
      edit3.gif
      Note: If you want all the "Level of Detail" to use the same mesh that you just edited, add "-replaceAllLOD" before the "-r"
    12. Run "dae_to_pac.bat"
    13. Now download Meta Injector and extract all the files to: "Black Desert Online\Paz\"
    14. Place the .pac file you just created into "Black Desert Online\Paz\files_to_patch\"
    15. Run "meta_injector.exe"
    16. Choose "Run Injector" and "Let the program decide where they should go."
    If you make new modifications, you have to go through the whole process again, including injecting it with the Meta Injector.

    OLD STUFF:

    Here you are going to find old things that were posted in this thread. All of them were already incorporated in one of my tools' latest versions, but if by any chance, you want to download some of the old stuff, here they are.
    You are going to find here stuff like the "Black Desert Online File Extractor" , "Hashes Generator for Meta Injector" and Ray Wings's "resorep_hasher"
    Black Desert Online File Extractor
    View attachment 56142
    A tool that uses quickbms to extract all files from your game

    Download Link:


    Source Code: https://www.undertow.club/attachments/src-file-extractor-v1-1-zip.56139/

    Instructions:

    1 - Extract this zip file to your PAZ folder.
    2 - Run "File Extractor.exe"
    3 - Use the options on the screen to do what you want.
    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    How to find the texture from an armor
    - Download: Black Desert Resorepless Mod
    - Extract into your "PAZ" folder.
    - Run "resorepless.exe"
    - Choose option "Tools-> Get Textures from a file"
    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    Hashes Generator for Meta Injector
    Sometimes the tool won't find the new armor just released for the game, to fix that, you need to generate the file "hashes.txt" again.

    Download the Hashes Generator for Meta Injector, and follow the instructions inside the .zip.
    ---------------------------------------------------------------------------------------------------------------------------------
    Files "Not Found"
    There are around 2% of game files (8000 files) that can't be patched with this tool.
    If you get this message in the end of the program:
    View attachment 55448
    If it's a new armor you are trying to patch, try using the Hashes Generator. Otherwise unfortunately there is nothing it can be done for those files and they will not be recognized by the game.
    ---------------------------------------------------------------------------------------------------------------------------------
    All files must have their original name.
    This means that if you use Resorep texture names like: 472539502.dds won't work.You need to use the original name of the texture like : pbw_00_ub_0001.dds.To do that, use this tool created by Ray Wing:
    ---------------------------------------------------------------------------------------------------------------------------------
    Note1: If you are going to manually move the files, make sure the files are inside their original folders
    For example: pew_00_ub_0034.dds file should be under​
    so when you move or copy, it should go to this path:
    (This doesn't matter if you chose options 1 or 2 of the program though, the program does that for you)
    ----------------------------------------------------------------------------------------------------------------------------------
    PAZ Files Browser
    With this tool, you can preview 3D files from the game without having to open or extract the whole game.
    This way you can easily find the corresponding file name for an armor that you want to mod, using my other tools.

    Notice: This tool only allows you to view the file.
    3D Model Exporting and Importing is found further down bellow this page.

    [​IMG]
    The tool uses quickbms to extract the files and 3D Object Coverter to open them.
    Source code here: src-paz_browser_v1.2.zip

    Download: Black Desert Online - Paz Files Browser


    Instructions:
    - Extract ALL files to your "PAZ" folder
    - Run "paz_browser.exe"
    - Use the arrow keys and the ENTER key to navigate through the menu

    [​IMG]

    Important: To visualize the model with textures, click on this icon:

    [​IMG]

    Known issues:
    -If you encounter this message:

    [​IMG]
    - Download this: 3d_object_converter_v6.50.zip and extract all the files to "Black Desert Online\Paz\patcher_resources\3d_converter\"

    Observations:
    - Every file your preview is extracted, both .pac file and texture files under "Black Desert Online\Paz\patcher_resources\extracted_files\".
    ------------------------------------------------------------------------------------------------------------------------------------------------------

    meta5.jpg
    PAZ_FILE.jpg
    6---Rename.gif 7---run.gif
     

    Attached Files:

    Last edited: Jul 21, 2017
  3. BlackFireBR

    BlackFireBR Content Creator

    Joined:
    Sep 2, 2013
    Messages:
    1,320
    Likes Received:
    867
    Modders Stuff
    This section is reserved to gather all the information I was able to discover so far about the files my tools uses from the game, as well some useful small programs that I made.

    The META File
    The pad00000.meta file, located in your PAZ folder, it's an index file. It tells the game how many .PAZ files there are, which files are in which .PAZ, and their offset, size, etc. When the game needs to load any file, this is where it looks it up to find out where it is.

    The file names and folder names in this files are encrypted using a ICE encryption key (can be found way down below), and the actual files, inside the .PAZ are compressed with a specific algorithm for Black Desert (in quickbms it's the compression algorithm 85) and it's also encrypted with the same ICE key.

    The rest are basically only integer numbers, and you can read their value by reading blocks of 4 bytes at the time, they are not encrypted or anything.

    This is how the pad00000.meta file file is structured:
    Notice: The numbers displayed in this image have changed a lot, but the structure of the file is still the same
    pad00000-layout-new.jpg
    The most important thing you should focus, is the structure I called "File Blocks", this is what tells most of the information about the files. It has these fields:
    HASH| FOLDER_NUM | FILE_NUM | PAZ_NUM | OFFSET | ZSIZE | SIZE |​

    HASH: A Unique number that identifies the file, each file has it's own hash number and you will NEVER find the same number in this file twice. (Unique)

    FOLDER_NUM: Each folder of the game is assigned a number to it, this is used if you have an array of folder names for example, and you use this number to find the right position in the array, corresponding to the folder we are looking for.

    FILE_NUM: Same thing as the folder num. Each file has a number, starting from 0 and ending at the number you read in the PAZ_COUNT variable in the beginning of the meta file.

    PAZ_NUM: The number of the .PAZ this file is located. For example, if this number is 1, the file is located in your file PAD00001.PAZ.

    OFFSET: First byte in the .PAZ which the file is stored

    ZSIZE: The size of the file when it's still compressed, it's how many bytes you have to read in the .PAZ file in order to extract the full compressed file.

    SIZE: The size the file will have, once uncompressed.

    This is how the pad00000.meta file looks like if you open it with a hex edit program:
    [​IMG]


    This is a simplified version of a meta file, with only 3 .PAZ files, 3 folders and 4 files. This is the basic structure of the meta file. The official meta file follows the same pattern, it just has more files in it ( a lot more).

    Before we proceed, this is a few things we need to clarify:
    - Each BIG Block represents 4 bytes.
    - Each small block represents one byte.
    - Red blocks with white background means this is encrypted and they will not appear like this, unless you decrypt those bytes.
    - DUMMY is the client version

    This is the same file as the first image, but with all the numbers converted from hex to dec:
    [​IMG]

    Now let's understand how the game knows which file to load:

    Let's pick the first FILE_HASH: 631490897:

    - We can see it belongs to a file, which folder num is 2
    - When we search for folder num = 2 in the "folders_part" of the file, we find that the name of the folder is "character/" ,so the file is in the "character" folder".
    - next, we know the file number is 0, so the game will look in the "file names part" and when it finds the first '\0', if will know that it's the end of the file name we are looking for. (If file num was == 2, we would have to count 2 '\0', and everything that is between the 2nd and the 3rd '\0' is the file name)

    So we discovered that the file with the hash 631490897 is "multiplemodeldesc.xml" and it's located in "character/"

    One thing you should be aware of, when converting from hex to dec.
    For example, the FILE_HASH we just used: 631490897
    When you convert it to hex, you get this:
    [​IMG]

    But when you look at the meta file, you are not going to find 25 A3 C9 51, instead you need to find 51 C9 A3 25
    [​IMG]


    So everytime you convert to hex, remember to change the order in blocks of 2.

    Warning, don't do this mistake:
    25 A3 C9 51 -> 15 9C 3A 52
    it's:
    25 A3 C9 51 - > 51 C9 A3 25


    PAZ File
    The .PAZ files are all named like this: PAD0xxxx.PAZ and they contain the actual files of the game, also compressed and encrypted, as usual.

    This is how a .PAZ file is structured:
    [​IMG]

    - Light-red colored means encrypted.


    ----------------------------------------------------------------------------------------------------------------------------------------------

    Bonus: ICE Decryption for Black Desert Online in C:
    (Credits to Miau Lightouch)

    Code:
    // ice cipher source: http://www.darkside.com.au/ice/index.html
    #include "ice.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    
    int main (){
    
        FILE *fp, *fout;
    
        int count = 7730712; // copy from folder/file name size
        int count2 = 0;
        fp = fopen("filename.dat","rb"); // encrypted filename block (I dump to a file for test.)
        fout = fopen("output.dat", "wb"); // the file to write out the decrypted text to file.
        uint8_t *ctext = (uint8_t *) malloc(count); // alloc to meet our need.
        uint8_t *ptext = (uint8_t *) malloc(count);
    
    
        if (fp==NULL) {
            perror ("Error opening file");
        }
        else {
            // count2 is the real bytes count that program read out, but should be same as "count".
            count2 = fread(ctext, 1, count, fp);
        printf ("Total number of bytes read: %d\n", count2);
    
        const uint8_t *s = "\x51\xF3\x0F\x11\x04\x24\x6A\x00"; // it's a magic, you know.
    
        ICE_KEY *ik = ice_key_create(0); // init the key
        ice_key_set(ik, s); // set the key
    
        long cuts = count2/8;
        while (cuts--){
            ice_key_decrypt(ik, ctext, ptext); // key, in (encrypted text), out (decrypted text)
            ctext +=8;
            ptext +=8;
        }
    
        ptext -= count2; // reset the pointer back to the begining.
    
        fwrite(ptext, 1, count, fout);
        fclose(fout);
        fclose(fp);
    }
    
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    Quickbms Script Updated and Commented
    This is a modified version of the original script found at http://aluigi.altervista.org/bms/blackdesert.bms
    The problem with that old script is that sometimes it produced some corrupted files, when extracted.
    Thanks to Garkin whith this script modification, we can extract all files and not having then corrupted.

    I commented the script line by line so you can understand better what's going on.

    Remember, if you have any doubt on why we are doing this, please refer to this image:
    pad00000-layout-new.jpg
    Code:
    # Black Desert (script 0.2.4) modified by Garkin
    #
    #  My modifications are based on BlackFire's modified script:
    #  https://www.undertow.club/posts/129096
    #
    #  Original script:
    #  http://aluigi.altervista.org/bms/blackdesert.bms
    #
    # If you are using Notepad++, change the Language to "Visual Basic" to get a nice color code
    
    quickbmsver "0.7.4"
    
    # Defines the compression type that will be used, when extracting a file
    comtype blackdesert
    
    # Sets the encryption key we are going to use later
    set BDO_ICE_KEY binary "\x51\xF3\x0F\x11\x04\x24\x6A\x00"
    encryption ice BDO_ICE_KEY
    
    # gets the extension of the opened file
    get EXT extension
    
    #If the file extension is .meta
    if EXT == "meta"
    # pre-allocation, improves speed (doesn't matter if the values are bigger)
       putarray 0 0x4000 ""   # Array that is going to store the PAZs names
       putarray 1 0x2000 ""   # Array that is going to store the folder names
       putarray 2 0x80000 ""  # Array that is going to store the file names
    
       # Reads the first 4 bytes (long) of the meta file and stores it in the variable VERSION. (In C: fread(&version,sizeof(long),1,metaFile);)
       get VERSION long
     
       # Reads how many PAZ files your game has. (In C: fread(&pPAZCount,sizeof(long),1,metaFile);)
       get pPAZCount long
    
       # Paz files informations
       for i = 0 < pPAZCount
           get PAZ_NUM long
           get HASH long
           get PAZ_SIZE long
    
          # Using the number stored in PAZ_NUM with 5 digits,creates a string that will hold the complete .PAZ file name (E.g.:PAD00001.PAZ) (In C: sprintf(paz_name,"PAD%.5d.PAZ",paz_num);)
           string PAZ_NAME p= "PAD%05d.PAZ" PAZ_NUM
     
          # Stores in the array 0 in the position [PAZ_NUM], the string we just created (In C: array0[paz_num] = paz_name;)
           putarray 0 PAZ_NUM PAZ_NAME
       next i
    
       # Reads how many files your game has. (In C: fread(&files_count,sizeof(long),1,metaFile)
       get FILES_COUNT long
     
       # Saves the current position in the file in a variable. This position is the beginning of the blocks that have the following format: HASH|FOLDER_NUM|FILE_NUM|PAZ_NUM|OFFSET|ZSIZE|SIZE # (In C: long file_blocks_start = ftell(metafile);)
       savepos FILE_BLOCKS_START
     
       # Calculates the position which is where the file blocks ended (each file block has 28 bytes (7 * sizeof(long)) (In C: long file_blocks_end = (current pos - 7 * sizeof(long));)
       xmath FILE_BLOCKS_END "FILE_BLOCKS_START + (FILES_COUNT * 7 * 4)"
     
       # Moves the file pointer to the end of the File Blocks, skipping the whole File Blocks section for now
       goto FILE_BLOCKS_END
    
       # Gets the total length of the strings that are comming next, that are the folder names strings (In C: fread(&folder_names_total_length,sizeof(long),1,metaFile);)
       get FOLDER_NAMES_TOTAL_LENGTH long
     
       # Saves the position where the folder names strings start (In C: long folder_names_start = ftell(fp);)
       savepos FOLDER_NAMES_START
     
       # Saves all the next "FOLDER_NAMES_TOTAL_LENGTH" bytes, starting from the offset "FOLDER_NAMES_START" in a temporary memory called MEMORY_FILE (In C: fread(memory_file,1,folder_names_total_length,metaFile);)
       log MEMORY_FILE FOLDER_NAMES_START FOLDER_NAMES_TOTAL_LENGTH
    
       # Calculates which byte the folder names strings end (In C: long folder_names_end = folder_names_start + folders_name_total_length;)
       xmath FOLDER_NAMES_END "FOLDER_NAMES_START + FOLDER_NAMES_TOTAL_LENGTH"
     
       # Goes to that position (In C: fseek(metaFile,folder_names_end,SEEK_SET);)
       goto FOLDER_NAMES_END
    
       # Gets the total length of the strings that are comming next, that are the file names strings (In C: fread(&file_names_total_length,sizeof(long),1,metaFile);)
       get FILE_NAMES_TOTAL_LENGTH long
     
       # Saves the position where the file names strings start (In C: long file_names_start = ftell(fp);)
       savepos FILE_NAMES_START
    
       # Saves all the next "FILE_NAMES_TOTAL_LENGTH" bytes, starting from the offset "FILE_NAMES_START" in a temporary memory called MEMORY_FILE2 (In C: fread(memory_file2,1,file_names_total_length,metaFile);)
       log MEMORY_FILE2 FILE_NAMES_START FILE_NAMES_TOTAL_LENGTH
    
       # Don't know why, but it ignores the last 8 bytes of the folder names string (2 irrelevent longs, maybe?)
       math FOLDER_NAMES_TOTAL_LENGTH -= 8
    
       # Reads the string which has all the folder names, assigning each folder name to a different position in the array 1 (folders array)
       math i = 0
       for TMP = 0 < FOLDER_NAMES_TOTAL_LENGTH
           get INDEX_NUM long MEMORY_FILE        # Reads from the MEMORY_FILE the the index number of the current folder
           get SUB_FOLDERS long MEMORY_FILE        # Reads from the MEMORY_FILE the number of subfolder of the current folder
           get FOLDER_NAME string MEMORY_FILE    # Reads from the MEMORY_FILE a folder name, as string, until a '\0' is found. E.g: "character/"
    
          # If no name was read, means that we reached the end of the folder names
           if FOLDER_NAME == ""
               break
           endif
    
          # Stores the folder name, in the position i of the array 1 (folders array) (In C: array1[i] = folder_name;)
           putarray 1 i FOLDER_NAME
     
          # Updates TMP with the current position we are going to read now in MEMORY_FILE, this is just so the "for" condition stops when we reach "FOLDER_NAMES_TOTAL_LENGTH"
           savepos TMP MEMORY_FILE
       next i
    
       math i = 0
       # Reads the string which has all the file names, assigning each file name to a different position in the array 2 (files array)
       for TMP = 0 < FILE_NAMES_TOTAL_LENGTH
          # Reads from the MEMORY_FILE a file name, as string, until a '\0' is found.
           get FILE_NAME string MEMORY_FILE2
     
          # If no name was read, means that we reached the end of the file names
           if FILE_NAME == ""
               break
           endif
     
          # Stores the folder name, in the position i of the array 1 (folders array) (In C: array1[i] = file_name;)
           putarray 2 i FILE_NAME
     
          # Updates TMP with the current position we are going to read now in MEMORY_FILE
           savepos TMP MEMORY_FILE2
       next i
     
       # Now we are going to extract the files, combining the information we find in the file blocks, with the arrays filled with the file and folder names
    
       # Goes back to the beginning of the file blocks
       goto FILE_BLOCKS_START
     
     
       # For each File Block
       for i = 0 < FILES_COUNT
           get HASH long        # Gets the unique indentifier of this file
           get FOLDER_NUM long  # Gets the index in the array 1 (folders array) which has the folder name from this file
           get FILE_NUM long    # Gets the index in the array 2 (files array) which has the file name from this file
           get PAZ_NUM long        # Gets the number of the .PAZ file that the file is located
           get OFFSET long        # Gets the offset inside the .PAZ file specified which the file starts
           get ZSIZE long        # Gets the compressed size of the file
           get SIZE long        # Gets the uncompressed size of the file
    
          # Gets the PAZ name at the position [PAZ_NUM] of the array 0 (PAZ names array) and stores is in the PAZ_NAME variable (In C: paz_name     = array0[paz_num])
           getarray PAZ_NAME 0 PAZ_NUM
     
          # Gets the folder name at the position [FOLDER_NUM] of the array 1 (folders array) and stores is in the FOLDER_NAME variable (In C: folder_name = array1[paz_num];)
           getarray FOLDER_NAME 1 FOLDER_NUM
     
          # Gets the file name at the position [FILE_NUM] of the array 1 (folders array) and stores is in the FILE_NAME variable (In C: file_name     = array2[paz_num];)
           getarray FILE_NAME 2 FILE_NUM
     
          # Creates a string and concatenates folder name with the file name strings, so we get the full path to the file. Eg: "character/multiplemodeldesc.xml"
           string FILE_PATH = FOLDER_NAME
           string FILE_PATH += FILE_NAME
    
          # Opens the .PAZ file specified in the PAZ_NAME variable
           open FDSE PAZ_NAME 1
    
          # If uncompressed size is greater than compressed size, it means that the file is compressed, so we use "clog" which uncompresses and extracts the file
           if SIZE > ZSIZE
              clog FILE_PATH OFFSET ZSIZE SIZE 1
              # FILE_PATH: The path with the file name in the end, where the file will be extracted. Example: character/multiplemodeldesc.xml
              # OFFSET   : The byte in this .PAZ file which the compressed encrypted file starts
              # ZSIZE    : The size of the file should be when still compressed
              # SIZE     : The the file should be, when decompressed
               # 1        : Number of the file associated to the archive
         
          # If the uncompressed size is 0 (Yes there are files with 0 size)
           elseif SIZE == 0
              # Extract the file without decompressing it, and it will have 0 bytes
               log FILE_PATH 0 0
         
          # If uncompressed smaller than the compressed size
           else
              # Extracts the file temporaryly in memory so we can do a check first, without decompressing it
               log MEMORY_FILE3 OFFSET ZSIZE 1
         
              # Gets the first byte from the extracted file to do a check
               get FLAGS byte MEMORY_FILE3
         
                  #Even if decompression algorithm supports header where is size stored as byte, this method is not used in .paz files,
                #so it is safe to omit this method. Valid IDs for method where size is stored as long are 0x6E for uncompressed data
                #and 0x6F for compressed data. Also we have to make sure that data contains at least whole header (9 bytes)
                if (FLAGS == 0x6E || FLAGS == 0x6F) && ZSIZE > 9
                    get DUMMY long MEMORY_FILE3 #read compressed data size, I have called variable DUMMY because we don't use it
                    get SIZE2 long MEMORY_FILE3 #read decompressed data size
                endif
         
              encryption "" ""                 #turn off encryption because data in MEMORY_FILE3 are already decrypted
                if SIZE == SIZE2                #if decompressed size from .paz/.meta file is the same as decompressed size from data header,
                                                #we will consider data header as valid and data can be sent to decompression function                                   
                    clog FILE_PATH 0 ZSIZE SIZE MEMORY_FILE3    #send file to decompression function and store result to specified file
                else                            #if data header is not valid, data are uncompressed without header
                    log FILE_PATH 0 SIZE MEMORY_FILE3           #store data with length SIZE to specified file
                endif
                encryption ice BDO_ICE_KEY      #turn encryption back on
           endif
       next i
    
    # Same thing as the .meta extension, but if you open a .PAZ file to extract
    else if EXT == "PAZ"  #If the file extension is .PAZ
       get DUMMY long
       get TOTAL_FILES long
       get FILE_PATHS_TOTAL_LENGTH long
    
       savepos FILE_BLOCKS_START
       xmath FILE_BLOCKS_END "FILE_BLOCKS_START + (TOTAL_FILES * 4 * 6)"
       log MEMORY_FILE FILE_BLOCKS_END FILE_PATHS_TOTAL_LENGTH
    
       math i = 0
       for TMP = 0 < FILE_PATHS_TOTAL_LENGTH
           get FILE_PATH string MEMORY_FILE
    
           if FILE_PATH == ""
               break
           endif
    
           putarray 0 i FILE_PATH
           savepos TMP MEMORY_FILE
       next i
    
       for i = 0 < TOTAL_FILES
           get HASH long
           get FOLDER_NUM long
           get FILE_NUM long
           get OFFSET long
           get ZSIZE long
           get SIZE long
    
           getarray FOLDER_NAME 0 FOLDER_NUM
           getarray FILE_NAME 0 FILE_NUM
           string FILE_PATH = FOLDER_NAME
           string FILE_PATH += FILE_NAME
    
           if SIZE > ZSIZE
               clog FILE_PATH OFFSET ZSIZE SIZE
           elseif SIZE == 0
               log FILE_PATH 0 0
           else
               log MEMORY_FILE2 OFFSET ZSIZE
               get FLAGS byte MEMORY_FILE2
         
                if (FLAGS == 0x6E || FLAGS == 0x6F) && ZSIZE > 9
                    get DUMMY long MEMORY_FILE2
                    get SIZE2 long MEMORY_FILE2
                endif
         
               encryption "" ""
                  if SIZE == SIZE2                                      
                    clog FILE_PATH 0 ZSIZE SIZE MEMORY_FILE2
                else                
                    log FILE_PATH 0 SIZE MEMORY_FILE2      
                endif
                encryption ice BDO_ICE_KEY
           endif
       next i
    
    endif
    
    You can download this code here:
    blackdesert_script_0.2.5.zip

    If you need help understanding quickbms scripts, please refer to http://aluigi.altervista.org/papers/quickbms.txt, everything you need is there.
    --------------------------------------------------------------------------------------------------------------------------------------------
    The 256000 unreadable bytes:
    In some older version of the game, there was a section in the meta file, which was exactly 256000 bytes long, and it contained 8000 file blocks that I simply couldn't read, because if I read them as integers (4 bytes at the time), it only gave me huge or negative numbers.
    So far I don't know how to read them, but I discovered that all the 8000 missing files that are there, have something in common:
    All of their hashes uses only 7 hexadecimal letters to represent it, instead of 8. Let me explain:
    Let's compare the hashes from "multiplemodeldesc.xml" to the "pew_00_ub_0031_dec_n.dds" (One of the missing files)

    multiplemodeldesc.xml hash:
    DECIMAL: 631490897
    HEX (Big Endian): 25 A3 C9 51
    HEX (Little Endian): 51 C9 A3 25

    pew_00_ub_0031_dec_n.dds hash:
    DECIMAL: 25743895
    HEX (Big Endian): 188D217 (or 01 88 D2 17)
    HEX (Little Endian): 17 D2 88 01

    The complete list of all missing files and their hashes and file/folder numbers can be found here:
    missing_files.txt

    As you can see, when it's one of those files, it when you convert the number from dec to hex, you always get only 7 letters, because the 8th one is always 0

    So what I'm thinking is that, when they made the .meta file, they simply decided not to store this extra "0" to save some space, and since we are always reading 4bytes, it actually reads the seven letters + 1 more of the next field, giving us just nonsense.

    This is no longer a problem and nowadays we can read the file blocks like we used to, except for the TW version, but I don't know if that has changed as well.

    QUICKBMS Script that skips those 256kb

    Back when we had this problem of the unreadable 256kb, you would get this error, when you try to extract game's files using pad00000.meta
    Code:
    Error: incomplete input file 0: C:\Program Files (x86)\Black Desert Online\Paz\PAD00000.meta
           Can't read 525213419 bytes from offset 00ffa5c8.
           Anyway don't worry, it's possible that the BMS script has been written
           to exit in this way if it's reached the end of the archive so check it
           or contact its author or verify that all the files have been extracted.
           Please check the following coverage information to know if it's ok.
    
      coverage file 0    45%   7539936    16754120
    
    Last script line before the error or that produced the error:
      50  log MEMORY_FILE2 TMP NAMES_SIZE
    Here is a modified version of the original script, that solves that problem:
    blackdesert_script_skip_256.zip

    This is just like the original script, but with the only difference is that I skip 256000 bytes after we read all the information about the PAZ files, and also, to discover the new "FILE_BLOCKS_START" and "FILE_BLOCKS_END", this is the algorithm I used:

    - Search for the hash: 631490897 (from multiplemodeldesc.xml)
    - Go back 28 bytes (7 * 4) (nFields(hash,folderNum,fileNum,pazNum,offset,zsize,size) * sizeof(int))
    - Read hash,folderNum,fileNum,pazNum,offset,zsize,size
    - If pazNum >= 1 or <= TOTAL_PAZ_COUNT
    - Go back 28 bytes
    - repeat.

    Here's the code in C that does that:
    metaexplorer.c

    So my goal was to find which byte starts the first hash from the "file blocks" section.
    Here is the full list of the file blocks, in the order they appear in the pad000.meta file.
    script-meta-output.txt
    The order is: HASH|FOLDER_NUM|FILE_NUM|PAZ_NUM|FOLDER_NAME|FILE_NAME

    I also made a program that sorts this file by fileNum, and outputs the numbers of the files that are missing and how many of them are missing:
    filesort.zip
    Also, the sorted file is this:
    sorted_file.zip

    I've also made a version of the blackdesert.bms file that prints FILE_HASH | FOLDER_NUM | FOLE_NUM | FOLDER_NAME | FILE_NAME reading all from the .meta file (also skips the 256000 bytes, so you might want to delete those lines of code if you want it to work in the newest versions)
    quick_bms_script_print.zip
     

    Attached Files:

    Last edited: Jul 16, 2017
    adolf102 likes this.
  4. Hanabikimchi

    Hanabikimchi Potential Patron

    Joined:
    Jan 25, 2013
    Messages:
    8
    Likes Received:
    0
    looks super interesting, I'm looking forward what you can do with that
     
  5. alcaster4242

    alcaster4242 Avid Affiliate

    Joined:
    Mar 12, 2016
    Messages:
    202
    Likes Received:
    46
    Is the png icons working?
    I couldn't get it to work, unless it's a special png file?
     
  6. Kenith

    Kenith Avid Affiliate

    Joined:
    Mar 7, 2016
    Messages:
    70
    Likes Received:
    116
    Thanx
     
    Last edited: Jul 14, 2016
  7. Kenith

    Kenith Avid Affiliate

    Joined:
    Mar 7, 2016
    Messages:
    70
    Likes Received:
    116
    I wanna change 'Black garter belt' and find the file of it

    dxt1
    pew_99_ub_0004_02.dds
    pew_99_ub_0004_dec_sp.dds
    dxt5
    pew_99_ub_0004_dec.dds
    pew_99_ub_0004_dec_m.dds
    ( It's used in 'resorep mod')

    but when I run 'meta injector'
    It failed to find 'pew_99_ub_0004_dec.dds' ( maybe main part of 'Bra and Panties' )
     
  8. Jensen

    Jensen Potential Patron

    Joined:
    Jun 4, 2016
    Messages:
    11
    Likes Received:
    0
    hey, this looks really good, but ive been trying to get something but i cant find how, and if its possible
    basically i want Le Vladian underware, i want to remove the underware, just leave the stockings and waist/leg chains

    is this possible ? it used to be before the last patches (EU), then i moved to resorepless and i couldnt do it any more
    any info is appreciated, thanks
     
  9. latuel

    latuel Potential Patron

    Joined:
    Mar 24, 2016
    Messages:
    11
    Likes Received:
    1
    I wanna change Valkyrie's New Clothes texture.
    PVW_00_Ub_076.PAC
    Textures in PAD04089.PAZ(pvw_00_ub_0076.dds, pvw_00_ub_0076_hair.dds)
    How can i do it?
     
  10. BlackFireBR

    BlackFireBR Content Creator

    Joined:
    Sep 2, 2013
    Messages:
    1,320
    Likes Received:
    867
    Are you using the original names for those files?
    Does it at least succeed in the "Running Meta Injector" part?
     
  11. BlackFireBR

    BlackFireBR Content Creator

    Joined:
    Sep 2, 2013
    Messages:
    1,320
    Likes Received:
    867
    Yeah, I tried to patch that file too, unfortunately it doesn't work.
    I'm trying to see if I can find an alternative for those cases, but I need to study the pad00000.meta file a little more to see if I can do something about it.

    Download this:
    Le Vladian underware textures removed.zip
    - Extract to the "files_to_patch" folder.
    - Run "Meta Injector Reloaded.exe"
    - After done patching, move the folder inside the "files_to_patch" folder to your Black Desert Online root folder.
    Eg:
    If you were in
    "C:\Program Files (x86)\Black Desert Online\PAZ\files_to_patch\"
    you should move the "character" folder to
    "C:\Program Files (x86)\Black Desert Online\"

    Aparently this file doesn't exist in the NA version yet. I just extracted the whole have and I haven't found it.
    You will have to extract it yourself using quickbms and then just follow the instructions from the Meta Injector Reloaded normally.
    Let me know if you need help when extracting the files.
     

    Attached Files:

    Jensen likes this.
  12. Kera

    Kera Vivacious Visitor

    Joined:
    Mar 29, 2016
    Messages:
    28
    Likes Received:
    4
    In the interest of removing a step, would it hurt to just make the final step in your patcher copy the files from files_to_patch into the root folder?

    Maybe make it optional. One of the reasons I do not like moving the files (and would prefer a copy) is that way files_to_patch files just overwrites whatever was in the target directory and keeps it up to date. If you want to tinker, you do it inside of files_to_patch, then just re-run the patcher and it places everything nicely. It also handles deletes - delete from files_to_patch, re-run patcher, and those entries are unpatched so the files can remain where they are without causing issues.
     
  13. Jensen

    Jensen Potential Patron

    Joined:
    Jun 4, 2016
    Messages:
    11
    Likes Received:
    0
    thanks a bunch man, works almost perfectly
    first pic is with transparent resorepless installed, and it works fine
    second pic is the same, but after i press show underware
    2016-07-09_1239850503.jpg
    maybe you know how to fix it ? or maybe i did something wrong
    again, thanks a bunch
     
  14. BlackFireBR

    BlackFireBR Content Creator

    Joined:
    Sep 2, 2013
    Messages:
    1,320
    Likes Received:
    867
    Download the Le Vladian underwear textures removed in the post above and follow the instructions I mentioned above.
    This should fix your problem (Assuming you don't want to see the Le Vladian underwear
     
  15. BlackFireBR

    BlackFireBR Content Creator

    Joined:
    Sep 2, 2013
    Messages:
    1,320
    Likes Received:
    867
    Black Desert Online Texture Extractor
    [​IMG]
    A tool that uses quickbms to extract only the texture files from your .PAZ files.

    Download Link:

    Source Code: Source Code - Texture Extractor.zip
    Instructions:
    1 - Extract this zip file to your PAZ folder.

    2 - Run "Texture Extractor.exe"

    3 - Press 1 if you want to create a folder called "extracted_textures" in your "PAZ" folder and extract all the textures there.

    4 - Press 2 if you want to specify another folder to extract the textures.

    Note: After the textures are extracted, a file called "log-textures.txt" will be created in your PAZ folder which contains the relation between all .PAZ files number and texture names, this can be useful if you want to extract only a specific file in the future without having to extract all .PAZ files again
     
    alcaster4242 likes this.
  16. alcaster4242

    alcaster4242 Avid Affiliate

    Joined:
    Mar 12, 2016
    Messages:
    202
    Likes Received:
    46
    Nice, been looking for this.
     
  17. BlackFireBR

    BlackFireBR Content Creator

    Joined:
    Sep 2, 2013
    Messages:
    1,320
    Likes Received:
    867
    META INJECTOR RELOADED V1.1
    performance-meta-reloaded.jpg
    The program now runs almost twice as fast due to the new copy technique and now in "Part 2" the meta file is loaded in memory instead of accessing the file directly and after all the changes are done, a new file is created and filled with the modified content of the memory.​

    - Added options about what to do with the files in the "files_to_patch" folder after the patch is done:
    NEW-OPTIONS-META-INJECTOR-RELOADED.jpg

    - Added a header to the program showing the version.
    - File count and detection is now made before the first menu shows up
    - The "Running Meta Injector" was renamed to "Part (1/2)"
    - The "Running Meta Patcher" was renamed to "Part (2/2)"
    - Part 1 slightly faster than before.
    - Part 2 insanely faster than before.
    - Now it shows which meta file is chosen in the beginning after the user input in the first menu.
    - Fixed a bug where the same file could result in "not found" or "Success!" in "Part 2" depending on which order of the meta files were used.
     
    Last edited: Jul 9, 2016
    alcaster4242 likes this.
  18. latuel

    latuel Potential Patron

    Joined:
    Mar 24, 2016
    Messages:
    11
    Likes Received:
    1
    [​IMG]

    i'm KR Server.
    Not Found result.

     

    Attached Files:

  19. BlackFireBR

    BlackFireBR Content Creator

    Joined:
    Sep 2, 2013
    Messages:
    1,320
    Likes Received:
    867
    Yeah, unfortunately those new files will not be able to be patched. Sorry =/
     
    Last edited: Jul 9, 2016
  20. Chronix

    Chronix Potential Patron

    Joined:
    Apr 24, 2016
    Messages:
    23
    Likes Received:
    1
    Since I started using the metainjector I stopped crashing to desktop in heidel.

    But I found a new problem. It's been a few times now but I get these strange graphical glitches when a valkyrie is wearing Acher Guard armor, atleast the 2 times I saw it it was a valkyrie. I'll try to screenshot it next time.

    Oh yah I don't seem to get the gltich when it is my own valkyrie wearing the armor. (armor swap and pearl shop, dont know if it would be the same if I bought it for real)