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+ struct
116+ {
117+ float v_X;
118+ float v_Y;
119+ float v_Z;
120+ float min_X;
121+ float min_Y;
122+ float min_Z;
123+ FSkip(4);
124+ float max_X;
125+ float max_Y;
126+ float max_Z;
127+ FSkip(4);
128+ } bounds;
129+
130+ uint32 typesCount1, typesCount2, typesCount3, typesCount4;
131+ uint32 type1[typesCount1];
132+ uint32 type2[typesCount2];
133+ uint32 type3[typesCount3];
134+ uint32 type4[typesCount4];
135+
136+ if (exists(nodeParentTblOffset)) {
137+ FSeek(nodeParentTblOffset);
138+ }
139+
140+ uint32 nodeParentTbl[connectionCount];
141+ };
142+
143+ struct ContentGroupTriangles {
144+ uint32 nodeCount;
145+
146+ struct {
147+ uint32 ind[3];
148+ ubyte flags[4];
149+ vec3 pos <read=(Str("%f %f %f",x, y, z))>;
150+ } TriangleNode[nodeCount] <read=(Str("%d %d %d : %f %f %f", ind[0], ind[1], ind[2], pos.x, pos.y, pos.z))>;
151+
152+ uint32 something;
153+ uint32 positionCount;
154+ struct {
155+ vec3 vec <read=(Str("%f %f %f",x, y, z))>;
156+ uint32 padding;
157+ } Positions[positionCount] <read=(Str("%f %f %f", vec.x, vec.y, vec.z))>; // ends at 196
158+
159+ uint32 countAgain, lastIndex;
160+ align(16);
161+
162+ struct TriangleInfo {
163+ uint32 n7;
164+ // TODO dmc5: index2count is in n2 instead
165+ uint32 id, n1, n2, n3, n4, index2count, n6;
166+ } Triangles[nodeCount] <read=(Str("%d", id))>;
167+
168+ local int triCount = 0;
169+ struct {
170+ local int i = 0;
171+ for (i = 0; i < nodeCount; i++) {
172+ struct {
173+ triCount += Triangles[i].index2count;
174+ struct {
175+ uint32 id, triangleIndex, n3, n4, n5, n6, n7;
176+ } faces[Triangles[i].index2count] <read=(Str("%d %d %d %d %d %d %d", triangleIndex, id, n3, n4, n5, n6, n7))>;
177+ } TriangleFaces <read=(faces[0].triangleIndex)>;
178+ }
179+ } Faces;
180+
181+ float d, e;
182+ vec3 v1 <read=(Str("%f %f %f",x, y, z))>;
183+ FSkip(4);
184+ vec3 v2 <read=(Str("%f %f %f",x, y, z))>;
185+ FSkip(4);
186+ vec3 v3 <read=(Str("%f %f %f",x, y, z))>;
187+ };
188+
189+ struct ContentGroupPolygon {
190+ uint32 nodeCount;
191+ // todo
192+ };
193+
194+
195+
196+
197+ struct ContentGroup {
198+ uint32 contentCount;
199+ // TODO: handle contentCount > 1 (e.g. wilds Npc_NPC.ainvm)
200+ // structure looks like classname1, node_count1, nodes1, classname2, node_count2, nodes2, node_data, ...
201+ FixedWString classname <read=str>;
202+ if (WStringToString(classname.str) == "via.navigation.map.ContentGroupMapPoint") {
203+ ContentGroupMapPoint points;
204+ } else if (WStringToString(classname.str) == "via.navigation.map.ContentGroupTriangle") {
205+ ContentGroupTriangles triangles;
206+ } else if (WStringToString(classname.str) == "via.navigation.map.ContentGroupPolygon") {
207+ ContentGroupPolygon polygons <read="TODO">;
208+ }
209+ // TODO via.navigation.map.ContentGroupMapBoundary
210+ };
211+
212+ if (exists(contentGroup1Offset) && contentGroup1Offset > 0) {
213+ FSeek(contentGroup1Offset);
214+ ContentGroup ContentGroup1 <read=classname.str>;
215+ } else if (exists(nodeParentTblOffset) && nodeParentTblOffset > 0) {
216+ ContentGroup ContentGroup1 <read=classname.str>;
217+ }
218+
219+ if (secondContentGroupOffset > 0 && secondNodeTableOffset) {
220+ FSeek(secondContentGroupOffset);
221+ ContentGroup ContentGroup2 <read=classname.str>;
222+ }
223+
224+
225+ if (exists(layersOffset)) {
226+ FSeek(layersOffset);
227+ if (format3) {
228+ struct {
229+ uint32 nameHash;
230+ uint32 flags <format=binary>;
231+ } layers[64] <optimize=false, read=(nameHash)>;
232+ } else {
233+ struct {
234+ FixedWString name;
235+ uint32 flags <format=binary>;
236+ } layers[64] <optimize=false, read=(name.str)>;
237+ }
238+ }
239+
240+ if (exists(rszOffset)) {
241+ FSeek(rszOffset);
242+ struct {
243+ uint magic;
244+ } RSZ;
245+ }
246+
247+
248+ string mapToUknownIdsData(uint32 val) {
249+ local uint index = val;
250+ local string result;
251+ SPrintf(result, "%u", index);
252+ if (index <= nodeParentCount) {
253+ local uint oldPos = FTell();
254+ FSeek(nodeParentTblOffset + index * 4);
255+ local uint exVal = ReadUInt();
256+ FSeek(oldPos);
257+ SPrintf(result, "%u => Parent[%u] = %u", index, index, exVal);
258+ }
259+ return result;
260+ }
261+
262+ FSeek(lastSectionOffset);
263+ struct {
264+ uint32 ukn1, ukn2;
265+ uint32 count;
266+ // very TODO
267+
268+ if (count > 0) {
269+ struct {
270+ uint32 hash1, hash2;
271+ uint32 idk[5];
272+ uint32 flags1[3] <format=binary>;
273+ uint32 idk2;
274+ uint32 flags2[3] <format=binary>;
275+ uint32 idk3[4];
276+
277+ uint32 count1, count2, count3;
278+ struct {
279+ uint32 idMaybe;
280+ uint32 numbers[6];
281+ } yetMoreData[4];
282+ uint64 offset1, offset2;
283+
284+ uint32 flags3[3] <format=binary>;
285+ uint32 idk5;
286+ uint32 flags4[3] <format=binary>;
287+ uint32 idk6[4];
288+ FixedWString hashString <read=(str)>;
289+
290+ } moreData[count] <optimize=false>;
291+ }
292+
293+ } endsection;
0 commit comments