# Technique writeups *Shard of mgsv-modding-pack — generated 2026-08-11. 8 files. Provenance is on every entry as `source:path`.* Long-form explanations of how to actually achieve specific results, written by people who did it. Closer to the findings shard than to format reference: these are worked solutions, not specifications. ## BobDoleOwndU documentation — format notes and technique writeups - `bdo_docs:mgsv/documentation/index.html` — no description - `bdo_docs:mgsv/mods.html` — no description ### `bdo_docs:mgsv/documentation/customtexturenames.html` Custom Texture Names - Back to Documentation... (index.html) ##### Getting FMDLs to Load Custom Texture Names To get an .fmdl to load a custom texture, this is what you need to do. I'll be using plparts_battledress as an example. Let's say you want to edit the diffuse map. First, you need to get the hashed name of the diffuse map. If you only have the real name for a texture, you can use QuickHash (https://github.com/BobDoleOwndU/QuickHash/releases), a small tool I wrote to generate the hashed name. The real name for the Battle Dress' diffuse map is sna5_main0_def_bsm.ftex. You need to include its path, without the extension in QuickHash to get its hashed name. You would enter the following for the correct hash to be generated: /Assets/tpp/chara/sna/Pictures/sna5_main0_def_bsm The result should be: 19bba3a3168b8 Ok, now you have the hashed name! Now, let's say I want to replace it with a custom texture called sna5_custom_def_bsm.ftex. I'll need to use QuickHash to generate the hash for this custom texture. I would enter: /Assets/tpp/chara/sna/Pictures/sna5_custom_def_bsm The result is: 1735ea6590c5c Ok, you now have the original hash, and the hash you are going to replace it with. Now you need to open up the .fmdl in a hex editor such as HxD. The .fmdl format is little-endian, which essentially means that the bytes are written backwards. So we need to reverse the bytes of our hashed names, starting from the end first. Start with the hash: 19bba3a3168b8 - Separate the bytes, starting with the end first: 1 9b ba 3a 31 68 b8 - Reverse the order: b8 68 31 3a ba 9b 1 - Replace the singular digit, No singular digit = 68, 1 = 69, 2 = 6A, 3 = 6B: b8 68 31 3a ba 9b 69 Repeat these steps for your custom texture's hash as well. Now search for the reversed version of the original hash in your hex editor (using hex as the search type). Now, replace the bytes you found with the reversed version of your custom texture's hash. Following the example I gave earlier, I would be replacing b8 68 31 3a ba 9b 69 with 5c 0c 59 a6 5e 73 69. And that's it! The .fmdl will now search for your custom texture's name instead of the original. Just add the custom named texture to the .pftxs file and it should work! ### `bdo_docs:mgsv/documentation/equipdevelopflowsetting.html` EquipDevelopFlowSetting Info - Back to Documentation... (index.html) ##### EquipDevelopFlowSetting.lua Information Location (original): data0.dat/Assets/tpp/motherbase/script EquipDevelopFlowSetting.lua is a major script used to control the flow of item and weapon development. It controls the GMP, resources, time, and levels required to develop items. The script has been minified, but I have discovered most of the minified variables meanings: p50 = id - p51 = ??? - p52 = Equipment Grade - p53 = Development Cost GMP - p54 = Deployment Cost GMP - p55 = R&D Level Requirement - p56 = Second Team Identifier - p57 = Second Team Level Requirement - p58 = Resource 1 Type - p59 = Resource 1 Development Cost - p60 = Resource 2 Type - p61 = Resource 2 Development Cost - p62 = ??? - p63 = ??? - p64 = ??? - p65 = Resource 1 Type - p66 = Resource 1 Deployment Cost - p67 = Resource 2 Type - p68 = Resource 2 Deployment Cost - p69 = ??? - p70 = ??? - p71 = Time to Develop - p72 = Offline (0) or Online (1) - p73 = Buddy Bond Requirement p74 = ??? It is possible to develop online items offline by setting p72 to 0, but upon reconnecting to MGSV's servers, they will return to their online state and will not remain developed if they were developed offline. ### `bdo_docs:mgsv/documentation/fsminfo.html` FSM Format Info - Back to Documentation... (index.html) ##### Fsm Format Information First SND Header 0x0 - 0x3 (32): Signature - 0x4 - 0x7 (32): File size - 0x5 - 0xF (64): Double, Time to begin playing (Always 0x0 for first SND) - 0x10 - 0x13 (32): Complete Wem file length - 0x14 - 0x1F: Unknown Other Sub File Header - 0x0 - 0x3 (32): Signature - 0x4 - 0x7 (32): File size - 0x5 - 0xF (64): Double, Time to beging playing Calculating the Double DEMO chunk order, ignoring SND chunks, (i.e. 3) * 1.001000004645 with the last digit rounded (i.e. 3.003000013935 becomes 3.00300001394) No preset size for SND chunks. Must be calculated from the play size of the chunk after being cut. There is no known way to do this currently. If a way to do this is found, it would allow cutscene audio to be replaced. Examples - 3F F0 04 18 94 B3 FF 2F = 1.00100000465 - 40 00 04 18 94 B3 FF 2F = 2.00200000929 - 40 08 06 24 DF 0D FE C6 = 3.00300001394 - 40 10 04 18 94 B3 FF 2F = 4.00400001858 - 40 14 05 1E B9 E0 FE FB = 5.00500002323 ### `bdo_docs:mgsv/documentation/mtarinfo.html` Mtar Format Info - Back to Documentation... (index.html) ##### Mtar Format Information Mtar (Motion Archive) is an archive file which contains MGSV's animation files (.gani). There appears to be two slightly differing formats for .mtar files. The first format is very easy to read and extract files from. For example, TppPlayer2Facial.mtar is an Mtar Type 1. The second format is much more confusing with scattered animation chunks and .ganis that do not have headers. For example, player2_resident is an Mtar Type 2. The only way to see which type of Mtar a file is, is to open it in a hex editor. If the file list in the beginning has two lines for each file, it is a Type 2. If it only has one per file, it is a Type 1. Both formats are Little-Endian. ###### Mtar Type 1 Format (i.e. TppPlayer2Facial.mtar) Mtar Type 1 Header 0x0 - 0x3 (32): Signature? 9C A8 FF 0B = Gzs, 72 2B 01 0C = Tpp - 0x4 - 0x7 (32): Number of files. Each line starting at 0x20 seems to indicate a file. - 0x8 - 0xB (32): Bone Group 1. - 0xC - 0xF (32): Bone Group 2. - 0x10 - 0x1F: Padding. File declaring/listing begins at 0x20. All files in the list follow this format - 0x20 - 0x27 (64): Hashed name of file. I.e. 63 0C 20 DA FA AF 53 FC = 3affada200c63.gani - 0x28 - 0x2B (32): File location offset. - 0x2C - 0x2F (32): File length. Gani Type 1 File Format - 0x0 - 0x3 (32): Signature (D2 A2 FC 0B). - 0x4 - 0x7 (32): Unknown. - 0x8 - 0xB (32): File length. - 0xC - 0xF (32): Padding. ###### Mtar Type 2 Format (i.e. player2_resident.mtar) Mtar Type 2 Header - 0x0 - 0x3 (32): Signature? 72 2B 01 0C = Tpp - 0x4 - 0x7 (32): Number of files. Each 2 lines starting at 0x20 to indicates a file. - 0x8 - 0xB (32): Bone Group 1. - 0xC - 0xF (32): Padding. - 0x10 - 0x13 (32): Bone Group 2. - 0x14 - 0x17 (32): Offset for main animation tracks' description. Signature (EF AA BD 4F). - 0x18 - 0x1F (80): Padding. A chunk with an unknown purpose will follow the main animation tracks' description. Known signatures can be 4B 53 E4 91 or 84 77 9A 3B. More possibilities for this signature may exist. File declaring/listing begins at 0x20. All files in the list follow this format - 0x20 - 0x27 (64): Hashed name of file. I.e. 63 0C 20 DA FA AF 53 FC = 3affada200c63.gani - 0x28 - 0x2B (32): File location offset. - 0x2C - 0x2D (16): File length divided by 10 (multiply by 10 to get the length). - 0x2E - 0x2F (16): File length may appear here as well. If it does, the .gani file has an extra chunk (.exchnk) of animation. - 0x30 - 0x31 (16): If the file has an .exchunk, its length will appear here. .exchunk data immediately follow the .gani file data. - 0x32 - 0x37 (48): Padding. - 0x38 - 0x3B (32): Offset for another chunk of animation data, tied to the .gani, at the end of the .mtar (.enchnk). - 0x3C - 0x3F (32): Padding. ### `bdo_docs:mgsv/documentation/perfectfirstperson.html` Perfect First-Person - Back to Documentation... (index.html) ##### Perfect First-Person with Any Model This tutorial is NOT recommended for beginners. If you don't have a decent understanding of how model swapping works and at least some understanding of reading hex, you will likely have trouble following this tutorial! Images are larger than they appear. To see their full size, right-click them and click open in new tab. What you'll need: A hex editor such as HxD (https://mh-nexus.de/en/downloads.php?product=HxD). - 3DS Max (http://www.autodesk.com/products/3ds-max/overview). - The MaxScript from here (https://github.com/Jayveerk/FMDL) to import TPP's models. - Knowledge of how to extract and import TPP's models. To get started, grab the model you want to convert to have perfect first-person. If you don't know how to do this, this isn't the tutorial for you. Start with something more basic. Once you've found the model you want to modify, open it with your hex editor. The section information area starts at 0x40. There are a total of 22 sections (0x16). Each hex section follows this pattern: - 0x0-0x1 (16): Section ID - 0x2-0x3 (16): Number of Entries - 0x4-0x7 (32): Offset For our purpose, we care about the sections with ID 0x1, 0x2, and 0x16. 0x1 is the mesh group definition section. 0x2 defines the objects contained within the mesh groups. 0x16 is a list of names for bones, mesh groups, materials, and possibly other things. ###### Getting the Mesh Group Names If you don't already know, most of MGSV's files are Little-Endian. What does that mean? It means that the files' bytes are written backwards. This means that if a file has an integer (integers are 4 bytes) written in the file as 50 C2 0A 00, they should actually be read as 00 0A C2 50 (hex 0xAC250, decimal 705104). You might also have noticed that I'm writing some numbers with a 0x prefix. What does this prefix mean? It just means that this is a hexadecimal number. What is a hexadecimal number? A hexadecimal number is a base-16 number. As humans, we normally use a base-10 number system, aka the decimal system. "Base-10 and Base-16? What the hell do those mean?" In simple terms, the base is the number of numbers you can place before adding a new digit to the number. The decimal system has 10 numbers you can place before you need to add a new digit. 0, 1, 2, 3, 4, 5, 6, 7, 8, and 9. Hexadecimal has 16 numbers you can place before you need to add a new digit. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, and F. "Why do I need to know this?" It's to let you know that hexadecimal numbers and decimal numbers are different. So when you are doing math with hex numbers, you need to know the difference. 0x10 is not decimal 10. 0x10 is decimal 16. 0x20 is decimal 32, and so on. Now, we're going to put your understanding of hex to use. In the section information area, look at the information for the section with id 0x1. Take note of the number of entries. In the image I provided above, there are 0xA entries. From converting hex to decimal, you can figure out that 0xA is decimal 10. This means that there are 10 mesh groups in this model. "I'm bad at converting hex to decimal. Is there an easy way to do it?" Yes, there is. Windows has you covered. The calculator that comes with Windows has a programmer mode. Programmer mode includes support for hex numbers, so you can use it to do all of the math and conversions related to hex. Click on the three lines by the mode name (probably standard or scientific) and select programmer. After that, click on hex, and you can now do all of your math in hex. It also will display the decimal number under the hex number, so it'll handle all conversions for you as well. Ok, make sure you remember or note down the number of mesh groups. We're going to need it shortly. Now, take a look at the offset for section 0x1 (0x1980 in the example image). This offset is where the mesh groups are actually defined. If we were to go to offset 0x1980 in the file, we wouldn't get the information we need though. Why? Because the listed offset is the offset from the end of the header. The header's size is listed at offset 0x28-0x2B. So to find the offset, we need to add that number to the section's listed offset. This is pretty easy though, as the header's size is always 0x100. So using the example from the image, I would add 0x100 to 0x1980 to get 0x1A80. If you're using HxD, press ctrl + g to bring up the goto tool and enter the offset you calculated there. There will be a number of entries for mesh groups listed here equal to the number we got earlier. Each mesh group definition follows this pattern: - 0x0-0x1 (16): Name's Position in List at Section 0x16 - 0x2 (8): Invisibility Flag - 0x3 (8): Unknown - 0x4-0x7 (32): Unknown -- Always FF FF FF FF for MESH_ROOT Right now, we only need one thing from this section. The position of the first mesh group's name in the list at 0x16. In the example image above, this number is 0x89. Now that we've got that, let's go back to the section information area. Now we need to find the mesh group names in the list at section 0x16. How can we find them? With a little bit of math! First multiply the number we got from the mesh group defintion section by 0x8. Why? Each name in the list is 8 bytes, so this will give us the offset in the list for the mesh group names. Now add section 0x16's offset to this number. Lastly, add 0x100 for the header length. You should now have the offset for the mesh group names! (In the example from the images, the equation would be 0x89 * 0x8 + 0x4EB0 + 0x100. So the calculated offset would be 0x53F8.) Now, go to the offset you calculated. Once you're at the offset you calculated, It's time to check if you did your math right. If the first 8 bytes you see at the offset are 35D648F974580000, congratulations! You did it right! If they are anything else, you did something wrong. Go back and retry the previous steps. Why is it wrong if the bytes aren't 35D648F974580000? Because those are the hashed bytes of the MESH_ROOT name. Every model begins with MESH_ROOT, so if it's not the first thing listed, you know you've done something wrong. Now, we're going to need the number of mesh groups we noted down earlier. Using the example in the images, the number was 0xA, so the first 10 names from the offset, including MESH_ROOT (35D648F974580000), are the names for the example model. Write down all of the mesh group names for your model somewhere. In the example in the image above, the mesh group names would be: 35D648F974580000, 1503CAB7A9900000, B4001240D58D0000, D9E70D5771AD0000, 787529D678980000, CDB116645B430000, 72F1B480B0F10000, 76C372DA97650000, 37AFAD1DDA860000, and 22FDA10B97B50000. Now, onto the last step before we can actually start fixing the first person; we need to import the model into 3DS Max. Use the MaxScript linked to at the top of this page to import your model into Max. Once the model is finished importing, I recommend maximizing the perspective viewport and zooming in so you can see the model clearly. On the left side of Max, there will be a list of objects that are named Object###. We need to figure out which mesh group each of these objects belong to. Go back to the section information area of the model in your hex editor. Go to the offset (+ 0x100) listed at section id 0x2. This is the section that defines which objects belong to each mesh group. The entries for object assigning (to mesh groups) follow this pattern: - 0x0-0x3 (32): Padding - 0x4-0x5 (16): Mesh Group ID - 0x6-0x7 (16): Number of Objects - 0x8-0x9 (16): Number of Preceding Objects - 0xA-0xB (16): Entry Number - 0xC-0xF (32): Padding - 0x10-0x11 (16): Material ID? (Doesn't seem to have an impact on the model if changed) - 0x12-0x1F (112): Padding So now we can start naming the objects in Max by their mesh group! (Note: Object sort order in Max should be set to descending age.) How do we know what an object should be named? Using the information from the object assigning section, we can figure out which mesh groups they're in! In the example in the image, the first 0xE (14) objects belong to mesh group 0. Remember the list of mesh group names we wrote down earlier? We're going to need it now. Each of those mesh group names were in order of id. So 35D648F974580000 is mesh group 0. Using the other entries from the example in the images, 1503CAB7A9900000 would be mesh group 1, B4001240D58D0000 would be mesh group 2 and so on. Using the example from the images, in Max, I would name the first 14 objects 35D648F974580000. The next entry in the object assigning list says the next 5 objects belong to mesh group 1. So I would name Object015-Object019 1503CAB7A9900000. Repeat this until all of the objects are named. When you're finished, your mesh group names should look something like the ones in this image: Yay! We've finally figured out which objects belong to each mesh group! I'd recommend saving the Max file with the named objects somewhere. We're about to undo all of the work we did naming them, and a backup will save you a lot of time if you make a mistake. ###### Editing the Mesh Groups At long last, it's time to start fixing first-person! How can we do it? TPP's first-person all works through naming mesh-groups specific names. "Wait; so you're telling me that if KojiPro had've named the mesh groups in every model the same thing, we would already have perfect first-person for every model?" Yep! But they didn't. So we have to do it ourselves now. There are four important mesh group names for our purposes: - MESH_ROOT: 35D648F974580000 - MESH_head: 0185E8A919060000 - MESH_body: 346B161A13FF0000 - MESH_arm: 8CFD744E57920000 "Why are these mesh groups important?" They are important for different reasons. MESH_ROOT, is exactly what it sounds like. All meshes connect to it, and it is never invisible. We do not want any objects inside MESH_ROOT. MESH_head, is again pretty obvious. Head objects go inside of it. Any objects in MESH_head will disappear both when in first-person and when using the int-scope. MESH_body disappears when using the int-scope (and possibly while in first-person). MESH_head and MESH_arm seem to be attached to MESH_body, so it is a good idea to have it. MESH_arm disappears when using the int-scope, but not when in first-person. Obviously, we want arm objects in this group. Before we get started moving the mesh groups, we need to decide if there are any mesh groups we should keep from the original model. Obviously we want to keep MESH_ROOT, but are there any other, less obvious ones? For example, the model I've been using in the images has an internal body that doesn't need to be visible. It also has a tiny square mesh in its own mesh group that doesn't need to be visible. I'm going to leave these two mesh groups as I want objects in them to be invisible. Once you've decided which mesh groups you want to keep (if any) we can come up with a list of all of the mesh groups we are going to be using. The list I've come up with for the model in the example images is the following: - MESH_ROOT: 35D648F974580000 - MESH_head: 0185E8A919060000 - MESH_body: 346B161A13FF0000 - MESH_arm: 8CFD744E57920000 - Internal Body: 37AFAD1DDA860000 - Square Mesh: 22FDA10B97B50000 Your list will likely look a bit different. But at minimum, the first four mesh groups should be the same. Now, it's time to rename the objects in 3DS Max to match our new mesh groups. However, I personally find it easier to name them with a number rather than a hash. The number we name each object will reference which mesh group we are going to place it in. For example, the first 14 objects in the model in the example images are all part of the head. So they will all be named 1. As in my list, MESH_head is mesh group 1 (MESH_ROOT is mesh group 0). Here's some tips for which mesh group an object should belong to. The eyelashes, eyes, mouth, neck, hair, and the low-poly head objects all should be placed in MESH_head. If an object contains part of the body and part of an arm, put it in MESH_arm. It will not negatively impact first person. If an object doesn't fall into the arm, head, or the additional mesh groups you've left included, it belongs in MESH_body. When you're finished, the object names should look something like the ones in this image: Alright, we're finally onto the hard part. It's time to hex edit the model! Go to the mesh group definition section (section id 0x1). The main thing we need to do is change the invisibility flag to represent our new mesh group list. In the example from the images, I want the first four groups to be visible and the rest to be invisible. "I don't need all of these groups. Can I delete the extra ones?" Yes, you can. But it would create more work for us, and the amount it would reduce the filesize by is negligible. In other words, it's not worth it. "My list is bigger than the original number of mesh groups! Can I add more?" Yes you can. Cases like this are very rare, but to fix first-person on some models (Quiet's Sniper Wolf model for example), it is necessary to add an additional mesh group. ###### Adding a new Mesh Group You likely won't need to do this, but if you do, it's best to do it now. We need to note down two things. The number of mesh group entries, and the size of the section. In the image above, you can see that there are 10 (0xA) mesh groups. Each entry is 8 bytes. So we can calculate that the section is 80 (0x50) bytes. Write the numbers for your model down somewhere. Now we need to actually add the new entry. First, you'll need to add some bytes. Click at the end of the last entry, then go to Edit > Insert bytes.... You'll need to add 8 bytes for the new entry. The first two bytes are the id for the position in the name list at 0x16. You might be thinking "The first two bytes should be the number following the previous entry's first two bytes!" Well, if you were thinking that, you're wrong. Why? While you could technically use the next id, you'd have to bump up every following reference to the list's value by one. This would take hours to do manually. Keep in mind that every single value in the name list is already referenced somewhere in the model, and we do not want to have to have to adjust those references. "So what do I put there then?" We'll be adding a new entry to the list at 0x16. So get the number of entries for the list at 0x16 (refer to this image (assets/images/section-pointers.png) for an example). Using the model from the images, these bytes would be FD 00. "Shouldn't it be the number following those bytes since we're adding a new entry?" No. The first name in the list is referenced by 0, so while there are 0xFD (decimal 253) values in the list, 0xFC (decimal 252) is actually the last id that is currently being used. The next byte determines if the mesh group is visible or not. If you want it to be visible it should be 00. If not, it should be 01. The next five bytes will always be 00 00 00 FF FF. With that, your entry should be complete! (Note: if you only added one entry, you may also want to add 8 empty bytes (00) of padding to keep the line-end consistent. When you're finished, the editied section should look something like this: We now need to write down the new number of entries and the new size. In the example above, the new number of entries is 11 (0xB) and the new size is 96 (0x60) (padding should be included in the size). We're going to need these numbers later. For each entry, in the mesh definition section, edit the third byte to be 00 if you want the mesh group to be visible, or 01 if you want the mesh group to be invisible. ###### Fixing First-Person Now it's time to move on to editing the object assigning section (section id 0x2). The object assigning section begins immediately after the mesh group definition section, so you can just go to the end of the mesh group defintion section to be at the right place. We need to get the number of entries and the size of the section. In the example above, you can see that there are 10 (0xA) entries. Each entry is 32 bytes, making the section 320 (0x140) bytes. Write the numbers for your model down somewhere. (If you already wrote down numbers from adding a new mesh group, it may be a good idea to write these numbers in the same place.) Got those numbers written down? Good! Now delete the entire object assigning section. "What?! Why?!" We're going to be changing the entire section, so we don't need any of the original data. Once you've deleted it, insert 0x20 bytes where it used to be. (Go to Edit > Insert bytes....) The first 4 bytes will always be 00 00 00 00. The next two bytes will represent the mesh group the objects will be in. Reference the model in Max here. Make sure the object list in Max is set to sort by descending age. Whatever the name of the first object is should be what these two bytes will be. For example, the first object in the model from the images is named 1. This means that the two bytes will be 01 00. The next two bytes are the number of objects that should be placed in this mesh group. This is basically the number of objects in Max that have the same name in a row. Using the model from the images as an example again, the first 14 objects are all named 1. So these bytes should be 0E 00. The next two bytes are the number of preceding objects. This will always be 00 00 for the first entry. For the other entries, just add the previous entry's number of objects, to the previous entry's number of preceding objects. For example, if the previous entry had 0x5 objects, and 0x15 preceding objects, you would add those together to get 0x1A as the number of preceding objects for your new entry. The next two bytes are just the entry number. The first entry will be 01 00, the second entry will be 02 00 and so on. The next four bytes are always 00 00 00 00. Now we're onto the second line (assuming your hex editor is set to have 16 byte lines [0x0 - 0xF]). The entire next 16 bytes will all be 00. The first two bytes of the line reportedly represent the material id, but changing the value doesn't seem to have an impact on the model. And if it doesn't have an impact on the model, there's no point in setting a value. The next 14 bytes are all padding. With that, you've completed your first entry! Now, repeat these steps to add entries until all of your objects have been been added. When you're done, the section will look something like this: Now, write down the new number of entries and size of the section. In the image above, the section now has 8 entries and is 256 (0x100) bytes. With this, we're almost done! Head back to the section information area at the beginning of the file. We need to edit the section information to match the changes we made. In the model from the images, the object assigning section (section id 0x2) no longer has 0xA entries. It now has 0x8 entries. We need to edit the information here to match that. We also changed the size of the section, so every offset that follows the information we changed needs to account for the size change. The model from the image's object assigning section is now 0x40 bytes smaller than it originally was. So every offset after section id 0x2 needs to be decreased by 0x40. Note: If you added another mesh group to the mesh group defintion section, you will need to change section id 0x2's offset as well. You will also need to account for that additional size change in all of the other following section offsets. You will also need to increase the number of entries for section 0x16 to account for the additional name(s) you will be adding. Compare the following two images to see the changes I made to the model used in the images: With the offsets adjusted, we can move onto editing the mesh group names. It'll be the same equation as we used before to get to the mesh group names, but you'll have to use section id 0x16's new offset this time. (For the model in the images, the equation is now 0x89 * 0x8 + 0x4E70 + 0x100, which equates to 0x53B8.) You'll want to replace the name hashes with the ones in the list we made earlier. So the first four hashes should now be 35D648F974580000, 0185E8A919060000, 346B161A13FF0000, 8CFD744E57920000, followed by any mesh groups that you decided to keep (if you decided to keep any). Any of the unused mesh group names can be nulled (replaced with 00 bytes). See the following two images for an example of what the edited mesh group names might look like: ###### Adding a new name to the list If you did add a new mesh group, you'll need to add its name to the end of the name list. To find the end of the name list, multiply the original number of entries for section id 0x16 by 8, and add section id 0x16's offset + 0x100. (The equation for the model in the images would be 0xFD * 0x8 + 0x4E70 + 0x100, which equates to 0x5758.) There may be 8 bytes of padding after the last entry. If there is, you can just overwrite those 8 bytes with the name for your entry without impacting the file size any more than we already did. If there isn't any padding, or you added more than one entry, you'll need to remember how much you changed the file size by. (+0x8 bytes for every entry you add.) See the following images for an example of a name added to the end of the list: There's one last thing we need to do. There are two offsets at the top of the file that reference the model data that we need to adjust. These offsets are located at offset 0x2C and 0x30. The same changes we made to the offsets for the sections following section id 0x2, have to made to these pointers. If you changed the size of section id 0x16 by adding new names, you will need to account for that file size change when adjusting these offsets as well. in the model from the images, I have to decrease both of these pointers by 0x40. Here's a before and after image: With that, congratulations! We're done! Your model should now have perfect first-person. Swap it in game, and test it out! ### `bdo_docs:mgsv/documentation/soundswapping.html` Sound Swapping and the Wwise Format - Back to Documentation... (index.html) ##### Sound Swapping and the Wwise Format What you need before sound swapping: The latest QAR dictionary.txt (https://github.com/secaproject/MGSV-QAR-Dictionary-Project) - GzsTool (https://github.com/Atvaark/GzsTool/releases) - Ravioli Game Tools (http://www.scampers.org/steve/sms/other.htm#ravioli_download) - HxD (https://mh-nexus.de/en/downloads.php?product=HxD) - Audacity (Optional) (http://www.audacityteam.org/download/) - Wwise (Optional) (https://www.audiokinetic.com/download/)--IMPORTANT: Newer versions of Wwise may not work! The .wem format seems to have changed in v2016.1.1. Download v2015.1.9 to be safe! - A method to get your modified soundbank back into the game (either the QAR Tool or SnakeBite) This tutorial is specifically for voice swapping. It can be used for some other audio files as well, but may not work for all audio files. First thing’s first. Update your GzsTool’s qar_dictionary.txt with the updated one you downloaded. Now you’re ready to unpack the chunk.dat files (with GzsTool) and find the soundbanks you want. If you’re looking to swap a character’s voice, Snake’s soundbank is in chunk0, and all of the playable staff members’ are in chunk1. Inside either folder, go to “Assets\tpp\sound\asset” and you’ll find the respective soundbanks. All soundbanks have the .sbp extension. Now, that you’ve found your soundbank, we can start getting sounds out of it! If you are planning on modifying this soundbank, there’s an extra step first. Drag the .sbp file onto GzsTool. GzsTool will unpack it and inside will be a .bnk, .sab and .stp file. The .bnk is a wwise audio container. The other two file formats seem to be related to 3D animation, but the .stp also contains wwise audio files. The file we care about right now is the .bnk. Run Ravioli’s RScanner. Click “New Scan…”. Navigate to the folder that GzsTool unpacked the contents of the .sbp into and select the .bnk file. The contents of the .bnk will show up in RScanner’s window. Scroll to the bottom and look for the last file listed. There may be a file called Unkn####.dat after this file, but we can ignore it. We only care about the last file named File####.wwise_x (note that “x” can be any letter). In example, the last file in Snake’s voice’s .bnk is File0075.wwise_v. We need to remember the number of the file, this is important later. Following my example, I would need to remember 75. Now, we can close RScanner and delete the folder and xml file that GzsTool extracted from the .sbp file. We don’t need the files inside the folder or the xml file anymore. All we needed was the number we found on the last file. Next, we need to get all of the audio files in an audible format. Create a new folder that will hold the audible versions of your files. Change the extension on the .sbp file you’ve been working with to “.bnk”. Now, start RExtractor. Under “Input file(s)” select the .sbp file you just changed the extension on. Under “Output directory” select the new folder you created. Under options, select “Convert sounds to: Wave” and “Allow scanning of unknown files”. After that, click “Start” and allow it to finish. It may say some files failed to convert. Ignore and delete these files. They are likely not voice files anyway. Hooray! You now have the files in an audible format! You can now close RExtractor. Now, we need to get the files in their original format. Create another new folder, which will hold the files in their original format. Change the extension of the .sbp you changed back to “.sbp”. Start RScanner again. Once again, click “New scan…”. Choose your .sbp file. This time, click “Extract All…” and select the newly created folder. Now we have the files both in an audible format and their original format! Now, you’ll need to repeat the whole process up to this point on a second .sbp to get the files you want to swap in. However, you can skip the part where we opened the .sbp with GzsTool and opened the .bnk file with RScanner to see what the last file’s number was. We do not need this number since we aren’t editing this file. Once you’ve got the files you want to swap in, we can get started on the fun part (by fun I mean very long and tedious). The first thing to do is to listen to all of the audio you extracted, so you know exactly what each file contains. It’s a good idea to note what every file is in a text editor and then reference your notes later. Once you’ve got your notes down, we can begin. Remember the number we got earlier? This is where it’s going to come in handy. That number tells you which files came from the .bnk and which files came from the .stp. Using my Snake example, the number was 75. This means that File0001 - File0075 came from the .bnk. All of the others came from the .stp. Why is it important to know this? It’s much easier to swap over files from the .stp! You can just rename the file you want to swap in and replace the old one! This is NOT the case with .bnk files though. They require some manual hex editing to work correctly. When swapping in files, be weary of their file size. The size of the sound you’re swapping in must be smaller than or equal to the file size of the original. If a file is slightly too big to fit in, we can fix it with Audacity and Wwise (I’ll cover this later). If it’s much too big, it will not work. Find another file. So now that you know the limitations of sound swapping, you can begin! Start by replacing all of the wwise files that came from the .stp. Again, you can do this by renaming the file you want to swap in to the original file’s name and then overwriting it. Once you’re done that, we can talk about how to replace files from the .bnk. For each of these files, you’re going to need to edit them in HxD. (Note: size restrictions still apply with hex editing files.) Don’t understand what the hex says? No problem! All of the work has been done for you already: - 0x00 - 0x03: (32) "RIFF" name - 0x04 - 0x07: (32) Riff size - 0x08 - 0x0A: (32) "WAVE" name - 0x0B - 0x0F: (32) Chunk type: "fmt " - 0x10 - 0x13: (32) Chunk size - 0x14 - 0x15: (16) 0xFFFF (audio format) 0xFFFF means experimental - 0x16 - 0x17: (16) Num of channels - 0x18 - 0x1B: (32) Sample rate in Hz (stored backwards) ex: 44 AC 00 00 = 44100Hz - 0x1C - 0x1F: (32) Avg bytes per second - 0x20 - 0x21: (16) 0x0000 (block align) - 0x22 - 0x23: (16) 0x0000 bits per sample (expected 0bps) - 0x24 - 0x25: (16) Chunk size - 0x26 - 0x27: (16) Extra fmt? (1 = yes) - 0x28 - 0x2B: (32) Subtype (4 = 1 channel, no seek table) - 0x2C - 0x2F: (32) Num of samples (num of bit per sample) - 0x30 - 0x33: (32) Mod signal - 0x34 - 0x35: (16) Data size (go to 0x5A - 0x5D) - 0x36 - 0x39: (32) Setup packet offset - 0x3A - 0x3D: (32) First audio packet offset - 0x3E - 0x3F: Unknown - 0x40 - 0x43: (32) Mod signal - 0x44 - 0x47: Unknown - 0x48 - 0x4D: Unknown relation to subtype - 0x4E - 0x4F: (16) Padding(?) - 0x50 - 0x53: (32) Uid - 0x54: _blocksize_0_pow - 0x55: _blocksize_1_pow This is the layout for the wwise format’s header. It’s not necessary to understand what most of it means for what we’re doing. But if you’re getting into more advanced sound modding, this information is important. Open up both the file you’re replacing and the file you want to replace it with in HxD. You’ll want to overwrite the following sections on the file you’re replacing by copying the same section from the file you’re replacing it with: - 0x16 - 0x17 (very rarely necessary, but if it does differ, this needs to be overwritten) - 0x18-0x1B - 0x28-0x2B (again, very rarely necessary, but if it does differ, this needs to be overwritten) - 0x48-0x4D (also rarely necessary, but if it differs, overwrite it) - 0x50-0x53 That covers the header. Now to get the actual data in. On the file you’re replacing the original with, look for a string of text that says “data”. In most of MGSV’s wwise files there are two of these strings. We want the second one. (The first one is usually followed by a bunch of periods and then LIST. If you see this one, ignore it. If you find a wwise file that only has one data string, like custom built ones, follow the same process, but use the single data string.) After the four bytes following the string is the actual data. You’re going to want to highlight from this point all the way to the bottom of the file and copy it. You’re going to want to highlight this same section in the original file and paste over it. Example: If I see “dataø...É” I want to start highlighting at the É since it is the fifth byte after the data string. Once you’ve done that, you’re done editing the file! HxD will have created a .bak file of the file you edited. Delete the .bak file. We do not need it. Repeat this process for every file that came from the .bnk. Done editing all of your files? Good! We can put the .sbp back together now. Start RScanner. Click “New scan…” and choose the .sbp. This time, click “Combine…”. Now choose the folder that contains the edited/replaced wwise files. It will probably tell you that it needs to add padding to the files to make them the correct size. Just keep clicking ok (or hold enter) until it’s done. Once it’s finished, you can either save the edited soundbank in a new place, or just overwright the old one. With that, you’re done! Just put the edited soundbank in the game and you should hear your changes. ##### Shrinking Audio Files Now, let’s talk about getting sounds that are slightly too big over a smaller sound. We can do this with Wwise and Audacity. Start Wwise and create a new project. Make note of where the project is located. We’re going to need to go to this location later to get our file. Under “Platforms”, we only need Windows and under “Import assets to project” select none. Go to Project > Project Settings. Click the Source Settings tab. Click the ellipsis under “Default Conversion Settings”. Open Factory Conversion Settings > Vorbis and choose Vorbis Quality Low. Then click “Ok” to close both windows. Now, go to Project > Import Audio Files. Click “Add Files” and choose the .wav version of the file that you want to swap into the game. Now click “Import”. Once you’ve imported your sound(s) go to Project > Convert All Audio Files…. In the window that pops up, only select Windows. Click “Ok”. Navigate to your Wwise project’s location. Inside its folder will be a “.cache” folder. Navigate to “.cache\Windows\SFX”. Inside here, will be the wwise version of the .wav you imported. (The extension will be .wem.) This file should have a smaller size than the original file, and may be able to fit over the smaller wwise file you were trying to replace! If it still doesn’t, you’re not out of luck yet, this is where Audacity comes in. Start Audacity. Go to File > Import > Audio and select the .wav version of the sound you want to swap in. Choose “Make a copy of the files before editing” if a window pops up. In the bottom left corner, there will be a value that says “Project Rate (Hz)” which influences the bitrate of the sound you’re working with. Decrease this value. You can drop it down to 32000, and any difference will not be noticeable to the human ear. Once you’ve done that, go to File > Export Audio…. Under “Save as type” choose “WAV (Microsoft) signed 16-bit PCM”. Save it as a new file; don’t overwrite the original. Now, go back to Wwise. On a panel on the left you should see a folder icon with “Actor-Mixer Hierarchy” beside it and under that, you should see “Default Work Unit”. Click the + beside “Default Work Unit”. In there you will see the original file you imported. Delete it. Now go to Project > Clear Audio File Cache…. In the window that pops up, select “All converted files” and click “Ok”. Now, go to Project > Import Audio Files… and choose the .wav you created with Audacity. After that, just click "Import". If it says there's a conflict, click "Import" again. It will overwrite the old file. Then, go to Project > Convert All Audio Files… and again only select Windows. Go back to your project’s location and then to “.cache\Windows\SFX”. Your wwise (.wem) file will be there and it should be an even smaller file size. If it is small enough, you can now swap it in!