Skip to main content

Overview

The ChunkAssetEntry class represents chunk assets in the Frostbite engine. Chunks are binary data blocks used for large resources like texture mipmaps, mesh LODs, and streaming data.

Class Definition

public class ChunkAssetEntry : AssetEntry
{
    public override string Name => Id.ToString();
    public override string Type => "Chunk";
    public override string AssetType => "chunk";
    
    public Guid Id;
    public uint BundledSize;
    public uint LogicalOffset;
    public uint LogicalSize;
    public uint RangeStart;
    public uint RangeEnd;
    public int H32;
    public int FirstMip;
    public bool IsTocChunk;
    public bool TocChunkSpecialHack;
}
Location: FrostySdk/Managers/AssetManager.cs:394

Properties

Id
Guid
Unique identifier for the chunk. Used as the chunk’s name.
BundledSize
uint
Size of the chunk data when stored in a bundle (may differ from actual size).
LogicalOffset
uint
Logical offset within the parent resource (for texture mips or mesh sections).
LogicalSize
uint
Logical size of the chunk data after decompression.
RangeStart
uint
Start offset in the range of data covered by this chunk.
RangeEnd
uint
End offset in the range of data covered by this chunk.
H32
int
32-bit hash of the parent resource name (FNV-1 hash). Links chunk to its owner.
FirstMip
int
For texture chunks, indicates the first mipmap level. -1 if not applicable.
IsTocChunk
bool
True if this chunk is stored in a Table of Contents chunk bundle.
TocChunkSpecialHack
bool
Internal flag for special TOC chunk handling.
Name
string
Returns the chunk GUID as a string (since chunks are identified by GUID).
Type
string
Always returns "Chunk".
AssetType
string
Returns "chunk" to identify this as a chunk asset entry.

Inherited Properties

See EbxAssetEntry for complete list of base properties including:
  • Sha1, Size, OriginalSize
  • IsModified, IsDirty, IsAdded
  • Bundles, LinkedAssets
  • Location, IsInline

Methods

AddToBundle (Override)

public override bool AddToBundle(int bid)
Adds the chunk to a bundle. Overridden to prevent adding orphaned chunks.
bid
int
required
Bundle index to add the chunk to
return
bool
True if successfully added. Returns false if chunk has no bundles and is not a new chunk.
Chunks cannot be added to bundles unless they already belong to at least one bundle or were explicitly created via AddChunk().

Inherited Methods

Chunk entries inherit methods from AssetEntry:
  • AddToBundles(IEnumerable<int>) - Add to multiple bundles
  • IsInBundle(int bid) - Check bundle membership
  • EnumerateBundles(bool addedOnly) - Iterate bundles
  • LinkAsset(AssetEntry) - Link to parent assets
See EbxAssetEntry for detailed method documentation.

Usage Examples

Reading a Chunk

Guid chunkId = /* ... chunk GUID ... */;
ChunkAssetEntry entry = assetManager.GetChunkEntry(chunkId);

if (entry != null)
{
    Console.WriteLine($"Chunk ID: {entry.Id}");
    Console.WriteLine($"Logical Size: {entry.LogicalSize} bytes");
    Console.WriteLine($"First Mip: {entry.FirstMip}");
    Console.WriteLine($"Is TOC Chunk: {entry.IsTocChunk}");
}

Loading Chunk Data

ChunkAssetEntry chunk = assetManager.GetChunkEntry(chunkId);
using (Stream stream = assetManager.GetChunk(chunk))
{
    byte[] chunkData = new byte[chunk.LogicalSize];
    stream.Read(chunkData, 0, (int)chunk.LogicalSize);
    
    // Process chunk data
}

Modifying a Chunk

Guid chunkId = /* ... */;
byte[] newData = /* ... modified chunk data ... */;

// For regular chunks
assetManager.ModifyChunk(chunkId, newData);

// For texture chunks (preserves mip information)
Texture texture = /* ... */;
assetManager.ModifyChunk(chunkId, newData, texture);

Creating a New Chunk

byte[] chunkData = /* ... your chunk data ... */;
int[] bundles = { bundleId };

// Create with auto-generated GUID
Guid newChunkId = assetManager.AddChunk(chunkData, bundles: bundles);

// Create with specific GUID
Guid customGuid = Guid.NewGuid();
Guid chunkId = assetManager.AddChunk(
    chunkData, 
    overrideGuid: customGuid,
    bundles: bundles
);

Console.WriteLine($"Created chunk: {chunkId}");

Creating a Texture Chunk

Texture texture = /* ... texture resource ... */;
byte[] mipData = /* ... mipmap level data ... */;
int[] bundles = { bundleId };

// Create chunk with texture information
Guid chunkId = assetManager.AddChunk(
    mipData,
    texture: texture,
    bundles: bundles
);

ChunkAssetEntry chunk = assetManager.GetChunkEntry(chunkId);
Console.WriteLine($"Mip level: {chunk.FirstMip}");
Console.WriteLine($"Range: {chunk.RangeStart} - {chunk.RangeEnd}");

Linking Chunks to Resources

ResAssetEntry res = assetManager.GetResEntry("textures/character/diffuse");
ChunkAssetEntry chunk = assetManager.GetChunkEntry(chunkId);

// Link chunk to resource
res.LinkAsset(chunk);

// The chunk now has H32 set to the resource's name hash
Console.WriteLine($"Parent hash: 0x{chunk.H32:X8}");

Finding Parent Resource

ChunkAssetEntry chunk = assetManager.GetChunkEntry(chunkId);

// H32 contains FNV-1 hash of parent resource name
int parentHash = chunk.H32;

// Search for parent resource by hash
foreach (ResAssetEntry res in assetManager.EnumerateRes())
{
    int resHash = Fnv1.HashString(res.Name.ToLower());
    if (resHash == parentHash)
    {
        Console.WriteLine($"Parent resource: {res.Name}");
        break;
    }
}

Enumerating Texture Mipmaps

ResAssetEntry texRes = assetManager.GetResEntry("textures/ui/icon");

// Enumerate linked chunks (mipmaps)
foreach (AssetEntry linked in texRes.LinkedAssets)
{
    if (linked is ChunkAssetEntry chunk)
    {
        Console.WriteLine($"Mip {chunk.FirstMip}: " +
            $"{chunk.LogicalSize} bytes, " +
            $"range {chunk.RangeStart}-{chunk.RangeEnd}");
    }
}

Working with Modified Chunks

ChunkAssetEntry chunk = assetManager.GetChunkEntry(chunkId);

if (chunk.HasModifiedData)
{
    ModifiedAssetEntry mod = chunk.ModifiedEntry;
    
    Console.WriteLine($"Modified Size: {mod.Data.Length}");
    Console.WriteLine($"Logical Size: {mod.LogicalSize}");
    Console.WriteLine($"First Mip: {mod.FirstMip}");
    Console.WriteLine($"Range: {mod.RangeStart} - {mod.RangeEnd}");
    
    // Modified chunks may have H32 set
    if (mod.H32 != 0)
    {
        Console.WriteLine($"Parent: 0x{mod.H32:X8}");
    }
}

Checking Chunk Bundle Membership

ChunkAssetEntry chunk = assetManager.GetChunkEntry(chunkId);

Console.WriteLine($"In {chunk.Bundles.Count} bundles:");
foreach (int bundleId in chunk.EnumerateBundles())
{
    BundleEntry bundle = assetManager.GetBundleEntry(bundleId);
    Console.WriteLine($"  - {bundle.Name}");
}

// Check if chunk is in specific bundle
if (chunk.IsInBundle(targetBundleId))
{
    Console.WriteLine("Chunk is in target bundle");
}

Chunk Compression

Chunks are compressed based on the game profile:
// Compression is handled automatically by AssetManager
// FIFA 18/20 use Oodle compression
if (ProfilesLibrary.DataVersion == (int)ProfileVersion.Fifa18 ||
    ProfilesLibrary.DataVersion == (int)ProfileVersion.Fifa20)
{
    // Uses Oodle compression
}
else
{
    // Uses default compression (ZLib or ZStd)
}

Modified Chunk Entry

When a chunk is modified, additional data is stored:
public class ModifiedAssetEntry
{
    public byte[] Data;              // Compressed chunk data
    public Sha1 Sha1;               // SHA-1 hash
    public long OriginalSize;        // Original size
    
    // Chunk-specific fields
    public uint LogicalOffset;
    public uint LogicalSize;
    public uint RangeStart;
    public uint RangeEnd;
    public int FirstMip;
    public int H32;                  // Parent resource hash
    
    public bool AddToChunkBundle;    // Add to chunk bundle?
    public bool IsInline;            // Inline in bundle?
}

Special Chunk Types

TOC Chunks

Table of Contents chunks store chunk bundles:
if (chunk.IsTocChunk)
{
    Console.WriteLine("This is a TOC chunk");
    // TOC chunks have special handling for bundle storage
}

Texture Chunks

Texture mipmaps are stored as chunks:
if (chunk.FirstMip >= 0)
{
    Console.WriteLine($"Texture mip level {chunk.FirstMip}");
    Console.WriteLine($"Mip range: {chunk.RangeStart} to {chunk.RangeEnd}");
}

Mesh Chunks

Mesh sections may be stored as chunks for streaming:
ChunkAssetEntry meshChunk = /* ... */;
Console.WriteLine($"Mesh section size: {meshChunk.LogicalSize}");

Build docs developers (and LLMs) love