Skip to main content
Frostbite games organize content into three primary asset types: EBX (entity data), RES (resources), and Chunks (binary data). These assets are packaged into bundles and managed by the AssetManager.

Asset Types

EBX

Entity/Object definitions

RES

Resources (textures, meshes, etc.)

Chunks

Raw binary data

EBX Assets (Entity Data)

EBX files contain structured entity and object data using Frostbite’s reflection system. EbxAssetEntry Structure:
public class EbxAssetEntry : AssetEntry
{
    public Guid Guid;                      // Unique asset identifier
    public List<Guid> DependentAssets;     // Dependencies
    public override string AssetType => "ebx";
    
    public bool ContainsDependency(Guid guid)
    {
        return HasModifiedData 
            ? ModifiedEntry.DependentAssets.Contains(guid) 
            : DependentAssets.Contains(guid);
    }
}
From AssetManager.cs:353.

EBX File Format

EBX files use a binary format with reflection metadata:

EBX Field Types

public enum EbxFieldType : byte
{
    DbObject = 0x01,        // Complex object
    Struct = 0x02,          // Value type struct
    Pointer = 0x03,         // Reference to another object
    Array = 0x04,           // Array of elements
    String = 0x06,          // Wide string
    CString = 0x07,         // Character string
    Enum = 0x08,            // Enumeration
    FileRef = 0x09,         // Reference to file
    Boolean = 0x0A,         // Boolean value
    Int8 = 0x0B,            // Signed 8-bit
    UInt8 = 0x0C,           // Unsigned 8-bit
    Int16 = 0x0D,           // Signed 16-bit
    UInt16 = 0x0E,          // Unsigned 16-bit
    Int32 = 0x0F,           // Signed 32-bit
    UInt32 = 0x10,          // Unsigned 32-bit
    Int64 = 0x12,           // Signed 64-bit
    UInt64 = 0x11,          // Unsigned 64-bit
    Float32 = 0x13,         // 32-bit float
    Float64 = 0x14,         // 64-bit float
    Guid = 0x15,            // GUID
    Sha1 = 0x16,            // SHA1 hash
    ResourceRef = 0x17,     // Resource reference
    TypeRef = 0x19,         // Type reference
    BoxedValueRef = 0x1A    // Boxed value
}
From EbxReader.cs:18.

Reading EBX Assets

public EbxAsset GetEbx(EbxAssetEntry entry)
{
    using (EbxReader reader = EbxReader.CreateReader(GetEbxStream(entry)))
    {
        return reader.ReadAsset();
    }
}

// Example EBX structure
public class BlueprintBundle : DataBusData
{
    public List<Blueprint> Blueprints { get; set; }
    public CString Name { get; set; }
    // Additional fields...
}
EBX uses a sophisticated reflection system that allows runtime type discovery and manipulation without compile-time knowledge of game-specific types.

RES Assets (Resources)

RES assets are typed binary resources like textures, meshes, and audio. ResAssetEntry Structure:
public class ResAssetEntry : AssetEntry
{
    public override string Type => ((ResourceType)ResType).ToString();
    public override string AssetType => "res";
    
    public ulong ResRid;        // Resource ID (unique)
    public uint ResType;        // Resource type hash
    public byte[] ResMeta;      // Resource metadata
}
From AssetManager.cs:379.

Resource Types

public enum ResourceType : uint
{
    Texture = 0x6BDE20BA,
    MeshSet = 0x49B156D4,
    AtlasTexture = 0x957C32B1,
    ShaderProgramDatabase = 0x10F0E5A1,
    SwfMovie = 0x2D47A5FF,
    LocalizedStringResource = 0x5E862E05,
    HavokPhysicsData = 0x91043F65,
    SvgImage = 0x89983F10,
    RawFileData = 0x3568E2B7,
    // ... many more types
    Invalid = 0xFFFFFFFF
}
From AssetManager.cs:13. Each resource type has specific handling logic.

Resource Metadata

RES assets have type-specific metadata:
// Texture resource metadata contains:
// - Width, height
// - Pixel format (DXT1, DXT5, BC7, etc.)
// - Mip count
// - Texture type (2D, Cube, 3D)
// - Chunk GUID for pixel data
// MeshSet metadata includes:
// - Vertex buffer layout
// - Index buffer format
// - LOD levels
// - Bounding boxes
// - Chunk GUIDs for geometry data
// Audio metadata contains:
// - Sample rate
// - Channel count
// - Codec information
// - Duration
// - Chunk GUID for audio data

Adding Resources

public ResAssetEntry AddRes(
    string name, 
    ResourceType resType, 
    byte[] resMeta, 
    byte[] buffer, 
    params int[] bundles)
{
    ResAssetEntry entry = new ResAssetEntry
    {
        Name = name,
        ResRid = Utils.GenerateResourceId(),
        ResType = (uint)resType,
        ResMeta = resMeta,
        IsAdded = true,
        IsDirty = true
    };
    
    entry.ModifiedEntry = new ModifiedAssetEntry
    {
        Data = Utils.CompressFile(buffer),
        OriginalSize = buffer.Length,
        ResMeta = entry.ResMeta
    };
    
    entry.ModifiedEntry.Sha1 = GenerateSha1(entry.ModifiedEntry.Data);
    entry.AddedBundles.AddRange(bundles);
    
    resList.Add(entry.Name, entry);
    resRidList.Add(entry.ResRid, entry);
    
    return entry;
}
From AssetManager.cs:1049.

Chunks (Binary Data)

Chunks store large binary blobs referenced by resources. ChunkAssetEntry Structure:
public class ChunkAssetEntry : AssetEntry
{
    public override string Name => Id.ToString();
    public override string Type => "Chunk";
    public override string AssetType => "chunk";
    
    public Guid Id;                 // Chunk identifier
    public uint BundledSize;        // Compressed size in bundle
    public uint LogicalOffset;      // Offset for streaming
    public uint LogicalSize;        // Logical size
    public uint RangeStart;         // Range start (textures)
    public uint RangeEnd;           // Range end (textures)
    public int H32;                 // FNV1 hash of parent
    public int FirstMip;            // First mipmap level
    public bool IsTocChunk;         // Is in TOC chunk list
}
From AssetManager.cs:394.

Chunk Usage

Chunks are primarily used for:

Texture Data

Pixel data for all mip levels

Mesh Data

Vertex and index buffers

Audio Data

Compressed audio samples

Physics Data

Havok physics meshes

Adding Chunks

public Guid AddChunk(
    byte[] buffer, 
    Guid? overrideGuid = null, 
    Texture texture = null, 
    params int[] bundles)
{
    ChunkAssetEntry entry = new ChunkAssetEntry 
    { 
        IsAdded = true, 
        IsDirty = true 
    };
    
    // Compress with appropriate algorithm
    CompressionType compressType = 
        (ProfilesLibrary.DataVersion == (int)ProfileVersion.Fifa18) 
            ? CompressionType.Oodle 
            : CompressionType.Default;
    
    entry.ModifiedEntry = new ModifiedAssetEntry
    {
        Data = (texture != null) 
            ? Utils.CompressTexture(buffer, texture, compressType)
            : Utils.CompressFile(buffer, compressionOverride: compressType),
        LogicalSize = (uint)buffer.Length,
        FirstMip = -1
    };
    
    if (texture != null)
    {
        entry.ModifiedEntry.LogicalOffset = texture.LogicalOffset;
        entry.ModifiedEntry.RangeStart = texture.RangeStart;
        entry.ModifiedEntry.RangeEnd = texture.RangeEnd;
        entry.ModifiedEntry.FirstMip = texture.FirstMip;
    }
    
    // Generate GUID
    byte[] guidBuf = Guid.NewGuid().ToByteArray();
    guidBuf[15] |= 1;  // Mark as chunk GUID
    entry.Id = overrideGuid ?? new Guid(guidBuf);
    
    chunkList.Add(entry.Id, entry);
    return entry.Id;
}
From AssetManager.cs:1089.
Chunk GUIDs have specific bit patterns - the LSB of the last byte is set to 1 for chunks. Don’t generate random GUIDs without this marker.

Bundles

Bundles group related assets together. BundleEntry Structure:
public class BundleEntry
{
    public string Name;                 // Bundle name
    public int SuperBundleId;           // Parent superbundle
    public EbxAssetEntry Blueprint;     // Blueprint asset (if any)
    public BundleType Type;             // Bundle type
    public bool Added;                  // User-added bundle
}

public enum BundleType
{
    None = -1,
    SubLevel,               // Contains level data
    BlueprintBundle,        // Contains blueprint definitions
    SharedBundle            // Shared resources
}
From AssetManager.cs:100 and 114.

Bundle Organization

Assets maintain bundle membership:
public class AssetEntry
{
    public List<int> Bundles = new List<int>();         // Original bundles
    public List<int> AddedBundles = new List<int>();    // User-added
    public List<int> RemBundles = new List<int>();      // Removed bundles
    
    public bool IsInBundle(int bid) => 
        Bundles.Contains(bid) || AddedBundles.Contains(bid);
    
    public IEnumerable<int> EnumerateBundles(bool addedOnly = false)
    {
        if (!addedOnly)
        {
            for (int i = 0; i < Bundles.Count; i++)
            {
                if (!RemBundles.Contains(Bundles[i]))
                    yield return Bundles[i];
            }
        }
        
        for (int i = 0; i < AddedBundles.Count; i++)
            yield return AddedBundles[i];
    }
}
From AssetManager.cs:168.

Asset Linking

Assets can be linked to track dependencies:
public void LinkAsset(AssetEntry assetToLink)
{
    if (!LinkedAssets.Contains(assetToLink))
        LinkedAssets.Add(assetToLink);
    
    // Store parent reference in chunk
    if (assetToLink is ChunkAssetEntry entry)
    {
        if (entry.HasModifiedData)
        {
            entry.ModifiedEntry.H32 = Fnv1.HashString(Name.ToLower());
        }
        else
        {
            entry.H32 = Fnv1.HashString(Name.ToLower());
        }
    }
}
From AssetManager.cs:244. Common Linking Patterns:
1

Texture → Chunk

TextureAsset (RES) links to texture data chunk
2

Mesh → Multiple Chunks

MeshSet (RES) links to vertex buffer, index buffer, and optional LOD chunks
3

Blueprint → EBX

BlueprintBundle (EBX) references contained blueprint assets

Asset Data Locations

public enum AssetDataLocation
{
    Cas,            // In catalog CAS archive
    SuperBundle,    // In binary superbundle
    Cache,          // In Frosty cache (patched data)
    CasNonIndexed   // In CAS but via manifest
}

public class AssetExtraData
{
    public Sha1 BaseSha1;           // Base asset hash
    public Sha1 DeltaSha1;          // Delta hash (patches)
    public long DataOffset;         // Offset in file
    public int SuperBundleId;       // Superbundle reference
    public bool IsPatch;            // Is patched data
    public string CasPath;          // Path to CAS file
}
From AssetManager.cs:92 and 125.

Modification Workflow

1

Load Asset

EbxAssetEntry entry = App.AssetManager.GetEbxEntry("path/to/asset");
EbxAsset asset = App.AssetManager.GetEbx(entry);
2

Modify Data

dynamic rootObject = asset.RootObject;
rootObject.SomeProperty = newValue;
asset.Update();  // Update internal dependencies
3

Save Changes

App.AssetManager.ModifyEbx(entry.Name, asset);
entry.IsDirty = true;
4

Persist to Project

FrostyProject project = new FrostyProject();
project.Save("MyMod.fbproject");

Enumeration and Filtering

// Get all textures
foreach (ResAssetEntry entry in App.AssetManager.EnumerateRes())
{
    if (entry.ResType == (uint)ResourceType.Texture)
    {
        // Process texture...
    }
}

// Get modified EBX of specific type
foreach (EbxAssetEntry entry in 
    App.AssetManager.EnumerateEbx("MeshAsset", modifiedOnly: true))
{
    // Process modified meshes...
}

// Get assets in specific bundle
BundleEntry bundle = App.AssetManager.GetBundle(bundleId);
foreach (EbxAssetEntry entry in App.AssetManager.EnumerateEbx(bundle))
{
    // Process bundle assets...
}

Performance Considerations

Best Practices:
  • Use GUID lookups for EBX assets (O(1) vs O(n) for name search)
  • Cache frequently accessed assets
  • Batch modifications before saving
  • Use modifiedOnly flags when enumerating to reduce iteration
  • Link chunks to parent assets for proper dependency tracking

Next Steps

Architecture

Understand how AssetManager fits in the overall architecture

Plugin System

Create plugins to handle custom asset types

Build docs developers (and LLMs) love