1+ //------------------------------------------------
2+ //--- 010 Editor v9.0.2 Binary Template
3+ //
4+ // File: AIWAYP.bt
5+ // Authors: shadowcookie
6+ // Version: 0.1
7+ // Purpose:
8+ // Category: RE Engine
9+ // File Mask: *.aiwayp.*|*.aiwaypmgr.*|*.ainvm.*|*.aimap.*
10+ // ID Bytes: 41 49 4D 50
11+ // History:
12+ //------------------------------------------------
13+
14+ local int version = Atoi(SubStr(FileNameGetExtension(GetFileName()), 1));
15+ local int isManager = Strstr(GetFileName(), ".aiwaypmgr.") != -1;
16+ local int isMap = Strstr(GetFileName(), ".aimap.") != -1;
17+ local int isNavmesh = Strstr(GetFileName(), ".ainvm.") != -1;
18+ local int isWaypoint = !isManager && !isNavmesh && !isMap;
19+
20+ local int format3 = (isMap && version == 28); // dmc5
21+ local int format4 = (isMap && version == 41); // re2 rt
22+ local int format5 = (isWaypoint && version == 5); // re4
23+ // dd2, wilds
24+ local int format9 = (isWaypoint && version > 6 || isManager && version >= 8 || isNavmesh && version >= 30);
25+
26+ void align(int n) {
27+ if (FTell()%n == 0) return;
28+ FSkip(n - FTell()%n);
29+ }
30+
31+ typedef struct FixedWString {
32+ uint32 len;
33+ if (len > 0) {
34+ wchar_t str[len];
35+ }
36+ align(4);
37+ };
38+
39+ uint magic;
40+ FixedWString name <read=(len > 0 ? str : "<empty>")>;
41+
42+ if (!format3 && !format4) {
43+ FixedWString hash <read=(len > 0 ? str : "<empty>")>;
44+ }
45+
46+ uint32 num; // likely flags
47+
48+ if (format3 || format4 || format5) {
49+ GUID guid;
50+ int ukn;
51+ } else if (format9) {
52+ uint ukn;
53+ uint32 hash1;
54+ uint32 hash2;
55+ uint ukn2;
56+ }
57+
58+ uint64 layersOffset;
59+ uint64 rszOffset;
60+
61+ uint64 lastSectionOffset;
62+ if (format4) {
63+ uint64 contentGroup1Offset;
64+ } else {
65+ uint64 count;
66+ }
67+
68+ uint64 nodeParentTblOffset;
69+
70+ uint64 secondContentGroupOffset, secondNodeTableOffset;
71+
72+ typedef struct intOrFloat {
73+ int32 num;
74+ FSkip(-4);
75+ float flt;
76+ };
77+
78+ string readIntOrFloat(intOrFloat &vec) {
79+ string str = "";
80+ SPrintf(str, "%d / %f", vec.num, vec.flt);
81+ return str;
82+ }
83+
84+ typedef struct vec3 {
85+ float x;
86+ float y;
87+ float z;
88+ };
89+
90+
91+ // TODO ContentGroupTriangle, ContentGroupPolygon
92+ struct ContentGroupMapPoint {
93+ uint32 nodeCount;
94+
95+ struct { // via.navigation.map.NodeInfo - position and normals?
96+ vec3 pos;
97+ vec3 normal;
98+ } nodes[nodeCount];
99+
100+ uint32 a, b;
101+ uint connectionCount, maxConnectionId;
102+ struct {
103+ uint32 id, n2, n3, n4, n5, n6, n7, n8;
104+ } connections[connectionCount] <read=(Str("%d %d %d %d %d %d %d %d", id, n2, n3, n4, n5, n6, n7, n8))>;
105+
106+ uint32 newcount;
107+
108+ typedef uint32 UknownId;
109+ local uint64 count = 0;
110+
111+ struct {
112+ uint id, connectionId, n3, n4, n5, n6, n7;
113+ } connectionInfo[newcount] <read=(Str("%d %d %d %d %d %d %d", id, connectionId, n3, n4, n5, n6, n7))>;
114+
115+ if (ReadFloat() != 1) {
116+ uint32 padding;
117+ }
118+
119+ struct
120+ {
121+ float val1;
122+ float val2;
123+ float min_X;
124+ float min_Y;
125+ float min_Z;
126+ FSkip(4);
127+ float max_X;
128+ float max_Y;
129+ float max_Z;
130+ FSkip(4);
131+ } bounds;
132+
133+ uint32 typesCount1, typesCount2, typesCount3, typesCount4;
134+ if (typesCount1 > 0) uint32 type1[typesCount1];
135+ if (typesCount2 > 0) uint32 type2[typesCount2];
136+ if (typesCount3 > 0) uint32 type3[typesCount3];
137+ if (typesCount4 > 0) uint32 type4[typesCount4];
138+
139+ if (exists(nodeParentTblOffset)) {
140+ FSeek(nodeParentTblOffset);
141+ }
142+
143+ uint32 nodeParentTbl[connectionCount];
144+ };
145+
146+ struct ContentGroupTriangles {
147+ uint32 nodeCount;
148+
149+ struct {
150+ uint32 ind[3];
151+ ubyte flags[4];
152+ vec3 pos <read=(Str("%f %f %f",x, y, z))>;
153+ } TriangleNode[nodeCount] <read=(Str("%d %d %d : %f %f %f", ind[0], ind[1], ind[2], pos.x, pos.y, pos.z))>;
154+
155+ uint32 something;
156+ uint32 positionCount;
157+ struct {
158+ vec3 vec <read=(Str("%f %f %f",x, y, z))>;
159+ uint32 padding;
160+ } Positions[positionCount] <read=(Str("%f %f %f", vec.x, vec.y, vec.z))>; // ends at 196
161+
162+ uint32 countAgain, lastIndex;
163+ align(16);
164+
165+ struct TriangleInfo {
166+ uint32 n7;
167+ // TODO dmc5: index2count is in n2 instead
168+ uint32 id, n1, n2, n3, n4, index2count, n6;
169+ } Triangles[nodeCount] <read=(Str("%d", id))>;
170+
171+ local int triCount = 0;
172+ struct {
173+ local int i = 0;
174+ for (i = 0; i < nodeCount; i++) {
175+ struct {
176+ triCount += Triangles[i].index2count;
177+ struct {
178+ uint32 id, triangleIndex, n3, n4, n5, n6, n7;
179+ } faces[Triangles[i].index2count] <read=(Str("%d %d %d %d %d %d %d", triangleIndex, id, n3, n4, n5, n6, n7))>;
180+ } TriangleFaces <read=(faces[0].triangleIndex)>;
181+ }
182+ } Faces;
183+
184+ float d, e;
185+ vec3 v1 <read=(Str("%f %f %f",x, y, z))>;
186+ FSkip(4);
187+ vec3 v2 <read=(Str("%f %f %f",x, y, z))>;
188+ FSkip(4);
189+ vec3 v3 <read=(Str("%f %f %f",x, y, z))>;
190+ };
191+
192+ struct ContentGroupPolygon {
193+ uint32 nodeCount;
194+ // todo
195+ };
196+
197+
198+
199+
200+ struct ContentGroup {
201+ uint32 contentCount;
202+ // TODO: handle contentCount > 1 (e.g. wilds Npc_NPC.ainvm)
203+ // structure looks like classname1, node_count1, nodes1, classname2, node_count2, nodes2, node_data, ...
204+ FixedWString classname <read=str>;
205+ if (WStringToString(classname.str) == "via.navigation.map.ContentGroupMapPoint") {
206+ ContentGroupMapPoint points;
207+ } else if (WStringToString(classname.str) == "via.navigation.map.ContentGroupTriangle") {
208+ ContentGroupTriangles triangles;
209+ } else if (WStringToString(classname.str) == "via.navigation.map.ContentGroupPolygon") {
210+ ContentGroupPolygon polygons <read="TODO">;
211+ }
212+ // TODO via.navigation.map.ContentGroupMapBoundary
213+ };
214+
215+ if (exists(contentGroup1Offset) && contentGroup1Offset > 0) {
216+ FSeek(contentGroup1Offset);
217+ ContentGroup ContentGroup1 <read=classname.str>;
218+ } else if (exists(nodeParentTblOffset) && nodeParentTblOffset > 0) {
219+ ContentGroup ContentGroup1 <read=classname.str>;
220+ }
221+
222+ if (secondContentGroupOffset > 0 && secondNodeTableOffset) {
223+ FSeek(secondContentGroupOffset);
224+ ContentGroup ContentGroup2 <read=classname.str>;
225+ }
226+
227+
228+ if (exists(layersOffset)) {
229+ FSeek(layersOffset);
230+ if (format3) {
231+ struct {
232+ uint32 nameHash;
233+ uint32 flags <format=binary>;
234+ } layers[64] <optimize=false, read=(nameHash)>;
235+ } else {
236+ struct {
237+ FixedWString name;
238+ uint32 flags <format=binary>;
239+ } layers[64] <optimize=false, read=(name.str)>;
240+ }
241+ }
242+
243+ if (exists(rszOffset)) {
244+ FSeek(rszOffset);
245+ struct {
246+ uint magic;
247+ } RSZ;
248+ }
249+
250+
251+ string mapToUknownIdsData(uint32 val) {
252+ local uint index = val;
253+ local string result;
254+ SPrintf(result, "%u", index);
255+ if (index <= nodeParentCount) {
256+ local uint oldPos = FTell();
257+ FSeek(nodeParentTblOffset + index * 4);
258+ local uint exVal = ReadUInt();
259+ FSeek(oldPos);
260+ SPrintf(result, "%u => Parent[%u] = %u", index, index, exVal);
261+ }
262+ return result;
263+ }
264+
265+ FSeek(lastSectionOffset);
266+ struct {
267+ uint32 ukn1, ukn2;
268+ uint32 count;
269+ // very TODO
270+
271+ if (count > 0) {
272+ struct {
273+ uint32 hash1, hash2;
274+ uint32 idk[5];
275+ uint32 flags1[3] <format=binary>;
276+ uint32 idk2;
277+ uint32 flags2[3] <format=binary>;
278+ uint32 idk3[4];
279+
280+ uint32 count1, count2, count3;
281+ struct {
282+ uint32 idMaybe;
283+ uint32 numbers[6];
284+ } yetMoreData[4];
285+ uint64 offset1, offset2;
286+
287+ uint32 flags3[3] <format=binary>;
288+ uint32 idk5;
289+ uint32 flags4[3] <format=binary>;
290+ uint32 idk6[4];
291+ FixedWString hashString <read=(str)>;
292+
293+ } moreData[count] <optimize=false>;
294+ }
295+
296+ } endsection;
0 commit comments