-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathfstb.bt
152 lines (116 loc) · 4.23 KB
/
fstb.bt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
LittleEndian();
#include "common/common.bt"
string GetOffsetString(uint offset)
{
return offset == 0 ? "null" : ReadString(offset);
}
struct
{
// The signature is FSTB in TPP, FSTBwin in GZ
char FSTBSignature[4] <hidden = true>;
union
{
ubyte IsBigEndian;
char WinSignature[3];
} BigEndianAndWinSignature <hidden = true>;
if (BigEndianAndWinSignature.WinSignature != "win" && (BigEndianAndWinSignature.IsBigEndian & 1))
BigEndian();
byte Type; // 2 for OMBS; 3 for GNTN; 4 for MBQF; 5 for AFGH/MAFR
Assert(Type == 4 || Type == 5, "Only FSTB files versions 4 and 5 (TPP, MGO, SSD) supported.");
uint BlockLevelCount <hidden = true>;
uint BlockLevelsOffsetsOffset <hidden = true>;
uint PackCommonFpkCount <hidden = true>;
uint PackCommonFpkOffset[PackCommonFpkCount] <read = GetOffsetString>;
} Header <bgcolor=0xFCFCFC>;
typedef struct
{
ushort x;
ushort z;
} SmallBlockDefinition <read = Str("(%d, %d)", x, z)>;
struct LargeLodBlockDefinition
{
SmallBlockDefinition SmallBlockBoundCorner; // This block is (always?) outside the block's range.
ushort SmallBlockBoundRangeX;
ushort SmallBlockBoundRangeZ;
// Row-major; index = (x - SmallBlockBoundCorner.x) + SmallBlockBoundRangeZ * (z - SmallBlockBoundCorner.z)
if (SmallBlockBoundRangeX != 0 && SmallBlockBoundRangeZ != 0)
{
struct
{
local uint llod_Z;
local uint llod_X;
for (llod_Z = 0; llod_Z < SmallBlockBoundRangeZ; llod_Z++)
for (llod_X = 0; llod_X < SmallBlockBoundRangeX; llod_X++)
byte Mask : 1;
} BitMask;
}
// Align to next 32-bit boundary
if (FTell() % 4 != 0)
{
local uint paddingCount = 4 - (FTell() % 4);
byte Padding[paddingCount] <hidden = true>;
local uint pdIdx;
for (pdIdx = 0; pdIdx < paddingCount; pdIdx++)
Assert(Padding[pdIdx] == 0);
}
};
struct BlockDefinition
{
StrCode32 NameHash; // For example, "afgh_bridge"
uint FpkCount <hidden = true>; Assert(FpkCount == 1);
uint LargeLodFpkCount <hidden = true>;
uint SuperLowLodFmdlPathOffset <read = GetOffsetString>;
uint LargeLodBlockDefinitionsCount <hidden = true>; Assert (LargeLodBlockDefinitionsCount == LargeLodFpkCount);
uint LargeLodBlockDefinitionOffset <hidden = true>;
uint SmallBlockDefinitionsOffset <hidden = true>;
uint SmallBlockDefinitionCount <hidden = true>;
SmallBlockDefinition blockStart; // Min values in the smallBlocks
SmallBlockDefinition blockEnd; // Max values in the smallBlocks
uint FpkPathOffsets[FpkCount] <read = GetOffsetString>;
if (LargeLodFpkCount != 0)
uint LargeLodFpkPathOffsets[LargeLodFpkCount] <read = GetOffsetString>;
FSeek(LargeLodBlockDefinitionOffset);
if (LargeLodBlockDefinitionsCount != 0)
{
struct
{
uint Offsets[LargeLodBlockDefinitionsCount] <hidden = true>;
local uint lblkIdx;
for (lblkIdx = 0; lblkIdx < LargeLodBlockDefinitionsCount; lblkIdx++)
{
FSeek(Offsets[lblkIdx]);
LargeLodBlockDefinition LargeLodBlock <optimize = false>;
}
} LargeLodBlocks;
}
FSeek(SmallBlockDefinitionsOffset);
struct
{
SmallBlockDefinition SmallBlock[SmallBlockDefinitionCount] <optimize=false>;
} SmallBlocks;
};
typedef struct
{
uint EntryCount <hidden = true, bgcolor = 0x2A2B04, fgcolor=0xFCFCFC>;
if (EntryCount != 0)
{
uint Offsets[EntryCount] <hidden = true, bgcolor = 0x2A2B04, fgcolor=0xFCFCFC>;
local uint blkIdx;
for (blkIdx = 0; blkIdx < EntryCount; blkIdx++)
{
FSeek(Offsets[blkIdx]);
BlockDefinition Definition <bgcolor = 0xF2F254>;
}
}
} BlockDefinitions;
if (Header.BlockLevelCount != 0)
{
FSeek(Header.BlockLevelsOffsetsOffset);
uint Offsets[Header.BlockLevelCount] <hidden = true>;
local uint defIdx;
for (defIdx = 0; defIdx < Header.BlockLevelCount; defIdx++)
{
FSeek(Offsets[defIdx]);
BlockDefinitions Definitions; // Pack large, Pack extraLarge
}
}