Black Desert Online Modding Tools (2 Viewers)

Flipsticker

Potential Patron
Joined
Jun 27, 2017
Hi, I'm very new to this but I'm very interested in modding this awesome game. However, I'm not seeing this PAZ folder in my Black Desert folder. Is there something I'm missing? Thank you for your time
 

BlackFireBR

Content Creator
Joined
Sep 2, 2013
Hi, I'm very new to this but I'm very interested in modding this awesome game. However, I'm not seeing this PAZ folder in my Black Desert folder. Is there something I'm missing? Thank you for your time
What do you have in your Black Desert folder? Is it the steam version? Post a screenshot of your folder so we can help
 

Flipsticker

Potential Patron
Joined
Jun 27, 2017
What do you have in your Black Desert folder? Is it the steam version? Post a screenshot of your folder so we can help
Yes! I did download it from Steam. Should I uninstall and get it from elsewhere?
 

Attachments

  • Capture.PNG
    Capture.PNG
    44.9 KB · Views: 172

Flipsticker

Potential Patron
Joined
Jun 27, 2017
Okay, so now I have it working, and everything looks great. But I'd like to see my normal outfit that everyone else sees so I can change that, however, using resorepless.exe, I've set all the customization to "keep all," but my character is still showing up as nude. I've restarted the game a couple times. Any suggestions? Thanks in advance
 

BlackFireBR

Content Creator
Joined
Sep 2, 2013
Okay, so now I have it working, and everything looks great. But I'd like to see my normal outfit that everyone else sees so I can change that, however, using resorepless.exe, I've set all the customization to "keep all," but my character is still showing up as nude. I've restarted the game a couple times. Any suggestions? Thanks in advance
Try running resorepless as administrator.
If that doesn't work, use the restore backup option and apply the settings again
 

BlackFireBR

Content Creator
Joined
Sep 2, 2013
I updated the first page with a commented version from the quickbms script with the modifications provided by Garkin .
I also changed the order of stuff a little bit and updated the stuff about the "unreadable 256000 bytes" problem we used to have before.
 

Garkin

Avid Affiliate
Joined
Dec 28, 2016
As for my modified quickbms script - I was reminded that my code is testing just one byte and it is not enough to properly determine if decrypted file has valid header or not.

In order to make code a bit more safe, I have changed script to test also decompressed file size:
Code:
# Black Desert (script 0.2.4a) 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"
comtype blackdesert
set BDO_ICE_KEY binary "\x51\xF3\x0F\x11\x04\x24\x6A\x00"
encryption ice BDO_ICE_KEY

get EXT extension

if EXT == "meta"
    putarray 0 0x4000 ""
    putarray 1 0x2000 ""
    putarray 2 0x80000 ""

    get VERSION long
    get pPAZCount long

    for i = 0 < pPAZCount
        get PAZ_NUM long
        get HASH long
        get PAZ_SIZE long

        string PAZ_NAME p= "PAD%05d.PAZ" PAZ_NUM
        putarray 0 PAZ_NUM PAZ_NAME
    next i

    get FILES_COUNT long
    savepos FILE_BLOCKS_START
    xmath FILE_BLOCKS_END "FILE_BLOCKS_START + (FILES_COUNT * 7 * 4)"
    goto FILE_BLOCKS_END

    get FOLDER_NAMES_TOTAL_LENGTH long
    savepos FOLDER_NAMES_START

    log MEMORY_FILE FOLDER_NAMES_START FOLDER_NAMES_TOTAL_LENGTH

    xmath FOLDER_NAMES_END "FOLDER_NAMES_START + FOLDER_NAMES_TOTAL_LENGTH"
    goto FOLDER_NAMES_END

    get FILE_NAMES_TOTAL_LENGTH long
    savepos FILE_NAMES_START

    log MEMORY_FILE2 FILE_NAMES_START FILE_NAMES_TOTAL_LENGTH

    math FOLDER_NAMES_TOTAL_LENGTH -= 8

    math i = 0
    for TMP = 0 < FOLDER_NAMES_TOTAL_LENGTH
        get INDEX_NUM long MEMORY_FILE
        get SUB_FOLDERS long MEMORY_FILE
        get FOLDER_NAME string MEMORY_FILE

        if FOLDER_NAME == ""
            break
        endif

        putarray 1 i FOLDER_NAME
        savepos TMP MEMORY_FILE
    next i

    math i = 0
    for TMP = 0 < FILE_NAMES_TOTAL_LENGTH
        get FILE_NAME string MEMORY_FILE2

        if FILE_NAME == ""
            break
        endif

        putarray 2 i FILE_NAME
        savepos TMP MEMORY_FILE2
    next i

    goto FILE_BLOCKS_START
    for i = 0 < FILES_COUNT
        get HASH long
        get FOLDER_NUM long
        get FILE_NUM long
        get PAZ_NUM long
        get OFFSET long
        get ZSIZE long
        get SIZE long

        getarray PAZ_NAME 0 PAZ_NUM
        getarray FOLDER_NAME 1 FOLDER_NUM
        getarray FILE_NAME 2 FILE_NUM
        string FILE_PATH = FOLDER_NAME
        string FILE_PATH += FILE_NAME

        open FDSE PAZ_NAME 1

        if ZSIZE == 0
            log FILE_PATH 0 0
        else
            log MEMORY_FILE3 OFFSET ZSIZE 1

            set SIZE2 long 0
            get FLAGS byte MEMORY_FILE3
            if (FLAGS == 0x6E || FLAGS == 0x6F) && ZSIZE > 9
                get DUMMY long MEMORY_FILE3
                get SIZE2 long MEMORY_FILE3
            endif

            encryption "" ""
            if SIZE == SIZE2
                clog FILE_PATH 0 ZSIZE SIZE MEMORY_FILE3
            else
                log FILE_PATH 0 SIZE MEMORY_FILE3
            endif
            encryption ice BDO_ICE_KEY
        endif

    next i


else if EXT == "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 ZSIZE == 0
            log FILE_PATH 0 0
        else
            log MEMORY_FILE2 OFFSET ZSIZE

            set SIZE2 long 0
            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

Files in .paz archives are stored in 3 different ways:
- uncompressed without header
- uncompressed with header
- compressed with header

Data header:
- ID (byte)
This value is always 0110 11?? (0x6C - 0x6F), last two bits are used as flags
- If the last bit is set (0110 11?1) (0x6D or 0x6F), data are compressed. If bit is not set, decompress function just removes header and copies data to output.
- If 2nd last bit is set (0110 111?) (0x6E or 0x6F), size in data header is stored as long otherwise is size stored as byte.​
- Compressed size (long or byte)
Compressed size in header can be different from what is in .paz/.meta file. Size in .paz/.meta must be multiple of 8 because of used encryption, size in data header is a real data size.​
- Decompressed size (long or byte)
Decompressed size must be the same as size in .paz/.meta file.​

Decompression function can handle any data with valid header, data without header will cause an error.

Here is commented part of the code where I'm testing if data have valid header:
Code:
if ZSIZE == 0                       #size in .paz file is 0, obviously no header here
    log FILE_PATH 0 0               #create 0 size file of specified name
else
    log MEMORY_FILE3 OFFSET ZSIZE 1 #decrypt data to memory

    set SIZE2 long 0                #declare variable SIZE2 (decompressed size in header) and inicialize it with value 0
    get FLAGS byte MEMORY_FILE3     #read 1st byte from data which should be ID

    #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
 
Last edited:

Garkin

Avid Affiliate
Joined
Dec 28, 2016
Do you think it's possible to find a way to compress it back to the game's format? I tried a lot of things in the past, and none of them work. The "reverse-decompression" method from quick bms doesn't apply for the compression method 85 (blackdesert).
Anyway you and me or someone else could work on trying to figure it out how to compress it? It would be amazing if we succeeded.
I was able to modify .paz archive and successfuly load modified file from this .paz archive. It could be useful if you want to load modified .lua script or any other file which can't be replaced using Meta Injector.

It seem that game client doesn't check if hash is valid for .paz archives nor stored files, so it was easier then I thought. How to do it:
  1. add data header to modified file. Header is 9 bytes long and contains:
    - (byte) 0x6E: ID which tells decompression function that data after header are uncompressed
    - (long) data size: data size = modified file size + header size (9)
    - (long) modified file size
    (More info about header is in spoiler in my previous post.)
  2. encrypt data using ICE.
    Input to ICE encrypt function must have size which is multiple of 8 (add 0x00 to the end), new size = modified file size + header size + 8 - ((modified file size + header size) % 8).
    Encryption works exactly the same as decryption, just use function ice_key_encrypt() instead of ice_key_decrypt().
  3. append encrypted data to the end of .paz archive where file was originally stored.
    Appending is easiest way, if you put file to the original location, you will have to change offsets for all files stored in .paz archive after that modified file.
  4. write new offset, compressed size and decompressed size to both .meta file and .paz archive.
    In .meta and .paz files find entry for original file and change (I will use variable names from .bms script):
    - OFFSET: offset where is new file (end of the original .paz archive)
    - ZSIZE: ZSIZE = SIZE + 9 + 8 - ((SIZE + 9) % 8)
    - SIZE: modified file size
Note: "Data size" in data header is not the same as ZSIZE. Size in data header is size of your modified file + 9 (header). ZSIZE has to be multiple of 8, so it will be up to 7 bytes bigger then size in data header.
 
Last edited:

BlackFireBR

Content Creator
Joined
Sep 2, 2013
I was able to modify .paz archive and successfuly load modified file from this .paz archive. It could be useful if you want to load modified .lua script or any other file which can't be replaced using Meta Injector.

It seem that game client doesn't check if hash is valid for .paz archives nor stored files, so it was easier then I thought. How to do it:
  1. add data header to modified file. Header is 9 bytes long and contains:
    - (byte) 0x6E: ID which tells decompression function that data after header are uncompressed
    - (long) data size: data size = modified file size + header size (9)
    - (long) modified file size
    (More info about header is in spoiler in my previous post.)
  2. encrypt data using ICE.
    Input to ICE encrypt function must have size which is multiple of 8 (add 0x00 to the end), new size = modified file size + header size + 8 - ((modified file size + header size) % 8).
    Encryption works exactly the same as decryption, just use function ice_key_encrypt() instead of ice_key_decrypt().
  3. append encrypted data to the end of .paz archive where file was originally stored.
    Appending is easiest way, if you put file to the original location, you will have to change offsets for all files stored in .paz archive after that modified file.
  4. write new offset, compressed size and decompressed size to both .meta file and .paz archive.
    In .meta and .paz files find entry for original file and change (I will use variable names from .bms script):
    - OFFSET: offset where is new file (end of the original .paz archive)
    - ZSIZE: ZSIZE = SIZE + 9 + 8 - ((SIZE + 9) % 8)
    - SIZE: modified file size
Note: "Data size" in data header is not the same as ZSIZE. Size in data header is size of your modified file + 9 (header). ZSIZE has to be multiple of 8, so it will be up to 7 bytes bigger then size in data header.
Man, you are a genius. Amazing finding. Thank you so much for sharing this with us.
I'm going to give it a try and make a program that does exactly that, for any file we want.
Thanks a lot for the help, I would've never figured that out on my own.
 

superlativo

Vivacious Visitor
Joined
Mar 9, 2016
BlackFireBR BlackFireBR hello, i have follow the guide for extract dae files, editing with blender, export the result, but i get an error when i use PACtool for "dae_to_pac"
what to do?
Py8vhms.png
 

Kitty Ears

Swell Supporter
Joined
Apr 13, 2016
BlackFireBR BlackFireBR hello, i have follow the guide for extract dae files, editing with blender, export the result, but i get an error when i use PACtool for "dae_to_pac"
what to do?
View attachment 63514

Did you pick replace? That's what I had to do to avoid the errors. Merge never worked for me. Sorry I am still in the process of learning myself. I can get the models in there, but they have errors. Suzu might be able to assist better. Try replace in the meantime.

EDIT: I just saw your post in Suzu's thread. Blender does not export the DAE properly. You must use a program like Maya or 3DSmax.
 

superlativo

Vivacious Visitor
Joined
Mar 9, 2016
Did you pick replace? That's what I had to do to avoid the errors. Merge never worked for me. Sorry I am still in the process of learning myself. I can get the models in there, but they have errors. Suzu might be able to assist better. Try replace in the meantime.

EDIT: I just saw your post in Suzu's thread. Blender does not export the DAE properly. You must use a program like Maya or 3DSmax.
rip :( but thanks
 
W

willyarchez

BlackFireBR BlackFireBR Woah man.
This is some impressive stuff you're sharing with us.
You are even sharing open-source? Woah, you sir won 100% of my respect.

Continue the good work man, I will follow closely.
Peace :)
 

Jamie12

Potential Patron
Joined
Jul 8, 2017
BlackFireBR BlackFireBR First off i'd like to say you do wonderful work and everything you do interests me not only for the content but the time and effort you put in to this. I used the old method that was out about a year ago where you went into the notepad file and swapped the Correct lines with armor you wanted to have on and so forth. I use to add the underwear mod as armor, and when i removed it it would be nude under that. I had he entire system then figured out. But having issues with this new system although im maneuvering through it quite well and believe i'm on the right track.

Here is what i do....

I Use Paz Browser. follow the guide to char/ranger and i get to the upper body selection...i pull the one i want and use the feature to pull the rest of the set. after its extracted i copy and paste it into the Files to patch folder.
I run meta Injector option 1 to install...
then i run resorepless.
When i log on. I still have the very same outfit on but the nude mod does work. I'm sorry for the menial question but i cant seem to find a walk through on applying to the game.
 

Garkin

Avid Affiliate
Joined
Dec 28, 2016
If anyone interested, attached is alternative program for extracting files from .meta/.paz archves.
On my computer it's a lot faster then using QuickBMS.
Code:
Garkin's UnPAZ v1.1 - tool for extracting Black Desert Online archives.

UnPAZ <input file> <commands>

<input file>:  name of .meta or .paz file (default: pad00000.meta)
<commands>:
  -f <mask>:  Filter, this argument must be followed by mask. Mask supports wildcards * and ?.
  -o <path>:  Output folder, this argument must be followed by path.
  -h:  Print this help text
  -l:  List file names without extracting them
  -n:  No folder structure, extract files directly to output folder.
  -y:  Yes to all questions (creating folders, overwritting files).
  -q:  Quiet (limit printed messages to file names)

Examples:
  UnPAZ pad00001.paz -f *.luac
  UnPAZ pad00000.meta -y -f *languagedata_??.txt -o Extracted
  UnPAZ D:\Games\BlackDesert\live\Paz\pad00000.meta -l


EDIT:
Change log:
1.0a:
- it now asks if you want to create path for extracted files.
(It helps if you accidentaly run executable in Paz folder without any arguments, so you can stop it before it will extract all files... :wink:)
1.0b:
- another bug smashed, fixed option "overwrite (a)ll" for files.
1.1:
- added command -n (don't keep internal folder structure)
- fixed possible bugs when source/target path does't exist

EDIT 2: Recompiled executable file so it should not ask for additional libraries (libboost_filesystem-mt.dll, libboost_system-mt.dll, libwinpthread-1.dll).
 

Attachments

UnPAZ_v1.1.zip
743.8 KB · Views: 248

Last edited:

BlackFireBR

Content Creator
Joined
Sep 2, 2013
Garkin, can you make an extra parameter for your UnPAZ tool which allows me to extract the files, and not keep the folder structure?
For example, the way it is right now, if I say to extract the file "phw_00_ub_0001.pac" to "C:\Extracted\", the file will be located at:
"C:\Extracted\character\model\1_pc\2_phw\armor\9_upperbody\phw_00_ub_0001.pac" after it's extracted, but I actually wanted only "C:\Extracted\phw_00_ub_0001.pac"
Also, could you include the source code with those changes for me? Please?
 
Last edited:

Users who are viewing this thread

Top


Are you 18 or older?

This website requires you to be 18 years of age or older. Please verify your age to view the content, or click Exit to leave.