Texture Modding in Custom Forges - Kamzik123/AnvilToolkit-Resources GitHub Wiki

This tutorial shows you how to put a texture mod into your own custom patch forge for Assassin's Creed Shadows or Black Flag Resynced (BFR), without repacking the game's huge original forges.

Two things trip people up here, and this page covers both:

  1. Mip dependencies (RawAssets). In Shadows and BFR, the largest mips of a texture are not stored in the TextureMap. They sit in separate .RawAsset files in the forge. If you don't remove those dependencies, you'd have to copy the RawAssets into your custom forge too. Part 1 shows how to get rid of them.
  2. Prefetch data. If you put a .data with a prefetch entry into your custom forge (a Material, TextureSet, Mesh, etc.), you need to copy that entry into your forge's PrefetchingFileInfos file. Part 2 shows how. A .data that holds only a TextureMap never has an entry, so a pure texture swap skips this step.

Before you start: You need a custom patch forge. If you don't have one yet, follow Creating a New Patch Forge for Assassin's Creed Shadows or later first. With AnvilToolkit 1.3.7+ it's a single click (Game Explorer → right-click → New → Patch Forge).

This page doesn't cover image editing itself (replacing the image, pixel formats, etc.). For that, see the Texture Viewer page.


Table of Contents


How Shadows/BFR textures are stored

A texture is made up of mips: the full-resolution image plus a chain of smaller and smaller copies (half size, quarter size, and so on). In older games the whole chain sits inside the TextureMap file. In Shadows and BFR it's split in two:

Part Where it lives What it holds
TextureMap Inside a .data file, e.g. RED_GEN_Bamboo_Blinds_01_DiffuseMap.data The smaller mips, plus links (by ID) to the RawAssets below
RawAsset(s) Loose files in the forge itself, not in any .data, e.g. 878D995BF6300000.RawAsset The largest mips (up to 4), the ones that actually make the texture look sharp

When you unpack a forge you'll see thousands of them next to the .data files (DataPC_boot_patch_02.forge alone has over 6,000):

DataPC_boot_patch_02.forge/
    1005_-_RED_GEN_Bamboo_Blinds_01_DiffuseMap.data
    1094_-_RED_GEN_LUT_DIFF_Paint_Red_02_DiffuseMap.data
    ...
    26632_-_81A406BA37400000.RawAsset
    26633_-_878D995BF5F00000.RawAsset
    26634_-_878D995BF6300000.RawAsset
    ...

This is why the custom forge gets confusing. If you edit and save a texture normally, AnvilToolkit writes your new high-resolution mips back into those RawAsset files. Your custom forge would then need the edited RawAssets as well as the .data. That's more files to track, they're named only by a hex ID, and they're easy to forget. Leave them out and the game uses the original RawAssets, so your texture shows the old image up close or looks broken.

Removing the mip dependencies avoids all of that. It turns the texture into a standard, self-contained TextureMap with every mip stored inside it, so the .data is the only thing your custom forge needs.


Overview of the workflow

1. Copy the texture's .data from the original forge into your custom forge, then unpack it
2. Open the TextureMap → load its RawAssets → Tools → Remove CompiledMip dependencies
3. Edit/replace the image → Save
4. Repack the .data
5. For any non-TextureMap .data in your forge (Material, TextureSet, Mesh, ...), copy its prefetch
   entry from the original forge's PrefetchingFileInfos into your custom forge's PrefetchingFileInfos
6. Repack your custom forge → test in game

Part 1: Remove the mip dependencies

Step 1: Find the texture and copy its .data into your custom forge

  1. Unpack the original forge that contains the texture you want to mod (right-click the .forge → Unpack).
  2. Find the .data that contains the TextureMap. Texture data files are usually named after the texture, e.g. RED_GEN_Bamboo_Blinds_01_DiffuseMap.data.
  3. Copy that .data into your custom forge's folder (for example DataPC_boot_patch_03.forge).
  4. In your custom forge, right-click the copied .data → Unpack.

Which forge do I copy from? If the same .data exists in more than one forge of the chain (e.g. in both DataPC_boot.forge and DataPC_boot_patch_01.forge), always take it from the highest-numbered patch. That's the version the game currently uses.

Step 2: Open the texture and load its RawAssets

  1. Double-click the .TextureMap inside the unpacked .data. The Texture Viewer opens.
  2. The viewer needs the RawAssets to rebuild the full-resolution texture. It looks for them automatically in the current folder and the two folders above it. Your custom forge doesn't contain them, so it will ask you to select them.
  3. In the file dialog, browse to the original forge's unpacked folder (the one you copied the .data from). The dialog's title lists the RawAsset IDs it needs, and the file-name box is already filled in with a matching filter. Select the requested .RawAsset file(s) and confirm.

Tip: Do this every time. If you cancel the dialog, the texture can't be loaded. Don't just copy the RawAssets into your custom forge to make the prompt go away. The point of this tutorial is that they don't need to be there.

Step 3: Remove the CompiledMip dependencies

  1. Click the Tools button in the Texture Viewer.
  2. Choose Remove CompiledMip dependencies.

Because you loaded the RawAssets in Step 2, the viewer already holds the full mip chain, including the large mips that came from the RawAssets. This command drops the links to the RawAssets, so on the next save the whole chain goes into the TextureMap itself. Nothing gets written to any RawAsset.

Note: The .data will get bigger than the original, because it now carries the high-resolution mips that used to sit in the RawAssets. That's expected.

Step 4: Edit the image and save

  1. Replace or edit the image as usual (Replace button, drag & drop, flip, etc.). See the Texture Viewer page for details. You can also do this before Step 3, the order doesn't matter as long as you remove the dependencies before you save.
  2. Click Save.

Repeat Steps 2-4 for every TextureMap in this .data you want to change.

Step 5: Repack the .data

Go back up to your custom forge folder, right-click the .data → Repack.

At this point your custom forge contains the edited .data and no RawAssets, which is exactly what you want.


Part 2: Copy the prefetch data into your custom forge

What is prefetch data?

Before the game loads a .data file, it checks a list of other files that .data depends on and loads those first. This is the prefetch data. In Shadows and BFR, the lists for all the .data files in a forge are stored together in one meta file in that forge, PrefetchingFileInfos:

DataPC_boot_patch_03.forge/
    0_-_Body_Torso_Naoe.data                         ← your modded .data
    1_-_PrefetchingManifest.PrefetchingManifest
    2_-_DeletedFilesManifest.DeletedFilesManifest
    3_-_PrefetchInfoOverrides.PrefetchInfoOverrides
    4_-_PrefetchingFileInfos.PrefetchInfo            ← the file you edit here
    5_-_GlobalMetaFile.MetaFile

A new patch forge starts with an empty PrefetchingFileInfos. When you add a .data to it, the original prefetch entry for that .data is still in the original forge's PrefetchingFileInfos, and the game doesn't look there for your copy. You need to copy the entry over yourself. If you don't, the files your .data depends on aren't preloaded, and things can fail to load or crash.

What an entry looks like

Each .data that has prefetch data gets one PrefetchFileInfoObject. The Path on it is the .data's root file, so it contains the .data's name. Inside is the list of files to preload. A real example from DataPC_boot.forge, for Body_Torso_Naoe.data:

<PrefetchFileInfoObject ID="2159653212301" Path="DataPC_boot\Body_Torso_Naoe\Body_Torso_Naoe.Material">
    <List Name="FilterTables" />
    <List Name="PrefetchFileInfos">
        <PrefetchInfo ID="2116211603279" Path="DataPC_boot\Skin_SssProfile_ACF\Skin_SssProfile_ACF.SssProfile">
            <List Name="DataLayerFilterIndices" />
        </PrefetchInfo>
        <PrefetchInfo ID="2134380624537" Path="DataPC_boot\Head_Template_NormalMap\Head_Template_NormalMap.TextureMap">
            <List Name="DataLayerFilterIndices" />
        </PrefetchInfo>
        <!-- ... more dependencies ... -->
    </List>
</PrefetchFileInfoObject>

TextureMaps never have an entry. A .data that holds only a TextureMap (like ..._DiffuseMap.data) doesn't depend on anything, so it has no prefetch entry and there is nothing to copy. If your custom forge contains only TextureMap .data files, skip straight to Part 3.

You need this part when your mod also includes other .data files, for example a Material or TextureSet you edited to point at a new texture, or a Mesh. Those usually do have entries.

Step 1: Export your custom forge's PrefetchInfoOverrides

  1. In your custom forge, export PrefetchInfoOverrides.PrefetchInfoOverrides to XML (double-click it, or right-click → Export).
  2. Open the XML in a text editor. It can be very large (tens of MB), so use an editor that handles big files (Notepad++, VS Code, etc.).

Step 2: Find and copy the entry for your .data

  1. Search the XML for the name of your .data, e.g. Body_Torso_Naoe. You want the <PrefetchFileInfoObject line whose Path contains that name, not a <PrefetchInfo line. A <PrefetchInfo line only means some other .data depends on yours.
  2. Select the whole block, from <PrefetchFileInfoObject ...> down to its matching </PrefetchFileInfoObject>, and copy it.

Searching by ID instead: The ID on the object is the ID of the .data's root file. If a name search finds several similar results, search for the exact ID instead (e.g. ID="2159653212301").

Step 3: Paste it into your custom forge's PrefetchingFileInfos

  1. In your custom forge, export PrefetchingFileInfos.PrefetchInfo to XML the same way.

  2. For a fresh patch forge, the list will be empty:

    <PrefetchingFileInfos>
        <List Name="Objects" />
    </PrefetchingFileInfos>
  3. Turn the empty list into an open/close pair and paste your copied block(s) inside:

    <PrefetchingFileInfos>
        <List Name="Objects">
            <PrefetchFileInfoObject ID="2159653212301" Path="DataPC_boot\Body_Torso_Naoe\Body_Torso_Naoe.Material">
                <List Name="FilterTables" />
                <List Name="PrefetchFileInfos">
                    <!-- ... copied exactly as-is ... -->
                </List>
            </PrefetchFileInfoObject>
        </List>
    </PrefetchingFileInfos>

    If the list already has entries (from earlier mods), just paste the new block next to them inside <List Name="Objects">.

  4. Save the XML, then import it back into the PrefetchingFileInfos.PrefetchInfo file (right-click → Import, and select your edited XML).

Repeat Steps 2-3 for every non-TextureMap .data you put in your custom forge.

Only edit PrefetchingFileInfos. Don't edit your custom forge's PrefetchInfoOverrides. It describes the forges below yours in the chain and must stay exactly as the New → Patch Forge command created it.


Part 3: Repack and test

  1. Go up to the folder containing your custom forge and right-click it → Repack.
  2. Wait until the AnvilToolkit Console says the forge was written successfully.
  3. Launch the game and check your texture, both up close (where the large mips are used) and from a distance.

Common mistakes

Mistake Result
Saved without removing the mip dependencies The new large mips went into the RawAsset files, not the TextureMap. Your custom forge doesn't contain those RawAssets, so the game uses the originals and the texture looks unchanged (or wrong) up close. Re-open the texture, remove the dependencies, and save again.
Cancelled the RawAsset prompt The texture can't be loaded. Point the dialog at the original forge's folder, where the RawAssets are.
Copied RawAssets into the custom forge "to be safe" Not needed once the dependencies are removed. They just bloat your mod.
Didn't copy the prefetch entry for a non-TextureMap .data The files that .data depends on aren't preloaded. Things may fail to load or crash.
Added your entries to PrefetchInfoOverrides too Not needed and shouldn't be done. Only PrefetchingFileInfos gets your entries.
Copied a <PrefetchInfo> line instead of the <PrefetchFileInfoObject> block You copied a reference to your .data from someone else's entry, not your .data's own entry. Search again for the <PrefetchFileInfoObject line.
Copied the .data or its prefetch entry from an older forge in the chain You could revert changes Ubisoft made in a later patch. Always take both from the highest-numbered patch that contains the .data.
⚠️ **GitHub.com Fallback** ⚠️