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