reverse engineering substance designer file format

So I spent a bit of time using 010 Editor and breaking down the .sbsar file format used by Substance Designer. It was like trying to solve a jigsaw puzzle. Snapping those first few pieces together was addictive. Unfortunately, I did not document my experiences and a lot of interpretation is now forgotten.  I was able to breakdown simple “hello world” .sbsar files. Identifying a handful of nodes and their properties. Here is the .bt script and a screenshot of applying the script:

//—————–

——————————-
//— 010 Editor v7.0.2 Binary Template
//
// File:
// Authors:
// Version:
// Purpose:
// Category:
// File Mask:
// ID Bytes:
// History:
//————————————————

local int numOutputNodes = 2;

struct SBSAR {

struct HEADER{
char signature[4];
int UNKNOWN_contentFlag;
int cookerBuild;
uint asmUid;
int fileLength;
int UNKNOWN_1cJump;
int UNKNOWN_zeroPadding_1;
int fileLengthFromJump;
ushort versionMajor;
ushort versionMinor;
int UKNOWN_zeroPadding_2;
int UNKNOWN_headerEndFlag;
} header <bgcolor=cLtGray>;

local int numNodes = ReadInt(header.fileLength-16);

struct DELTAJUMPS (int numNodes, int numOutputNodes) {
int zeroDelta;
int UNKNOWN_constant;
int UNKNOWN_zeroPadding_3;
int deltas[numNodes];
int lastIndexes[numOutputNodes*2] <bgcolor=cGray>;

} deltaJumps(numNodes, numOutputNodes) <bgcolor=cPurple, open=true>;

local int nodeByteSizes[numNodes];
local int i;
for(i = 0; i < numNodes – 1; i++) {
nodeByteSizes[i] = deltaJumps.deltas[i+1] – deltaJumps.deltas[i];
}
nodeByteSizes[i] = deltaJumps.zeroDelta – deltaJumps.deltas[numNodes-1];
for(i = 0; i < numNodes; i++) {
Printf(“node[%i] = %i\n”, i, nodeByteSizes[i]);
}
local int j;
for(i = 0; i < numNodes; i++) {
if(i % 2 == 0) {
for(j = 0; j < nodeByteSizes[i]/4; j++) {
int n <bgcolor=cAqua>;
}
}
else {
for(j = 0; j < nodeByteSizes[i]/4; j++) {
int n <bgcolor=cLtBlue>;
}
}
}

// could use jump delta[0] as first 32
// – node[0] size
// 40 = 64
// 32 – node[1] size
// 60 = 96
// 20 – node[2] size
// 74 = 116
// 32 – node[3] size
// 94 = 148
// 20 – node[4] size – not including format 0,8,8
// A8 = 168

struct NODEINFO () {
ushort numOutputNodes <bgcolor=cDkAqua>;
ushort numInputNodes <bgcolor=cDkGreen>;
int outputNodes[numOutputNodes] <bgcolor=cDkAqua>;
if(numInputNodes > 0) {
int inputNodes[numInputNodes*2] <bgcolor=cDkGreen>;
}
int numNodes <bgcolor=cRed>;
int numNodesLowDiff <bgcolor=cLtGray>;
int numNodesHighDiff <bgcolor=cLtGray>;
int offsetToInputType <bgcolor=cSilver>;

} nodeinfo;

} sbsar <open=true>;

 

ue4 content folder naming convention

I prefer a flat file structure. I have one level of folders, with each folder corresponding directly to the name of the asset type (Blueprints, StaticMeshes, Textures, etc) and that’s it. No sub-folders beyond that. I don’t bother thinking about how to organize and nest folders into hierarchies like Content/Environment/Buildings or Content/Player/Gun.

flatcontent

I also don’t prefix my assets with BP_ or SM_. If you change the Content Browser view option to list mode, you can clearly see Blueprint or Static Mesh written below the name. Instead, I have a clear name like PlayerHmd (head-mounted display). The blueprint is called PlayerHmd, the static mesh is called PlayerHmd, the material is called PlayerHmd. Although the PlayerHmd assets are distributed across different folders, finding all the PlayerHmd assets is simple using the Content Browser filter (or the super handy Ctrl+P for quick open).

content_search

A flat file structure works if you keep a consistent name across asset types and leverage the search/filter tools. It also avoids duplicate assets.

Why flat? I’ve seen as many as 4 people stand around for over an hour debating where assets should go in the hierarchy – it’s crazy. Eventually, they all come to a fragile consensus (from exhaustion talking about it). A week later someone commits assets that don’t conform to the hierarchy and the debate continues…