This repository has been archived by the owner on Nov 20, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tdbin.hexpat
681 lines (681 loc) · 14.6 KB
/
tdbin.hexpat
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
#pragma endian little
#include <std/mem.pat>
#include <std/io.pat>
#include <std/sys.pat>
#pragma pattern_limit 500000
u24 tdbin_version = 0;
struct vec_t {
float x;
float y;
float z;
} [[static, format("vec_str")]];
fn vec_str(vec_t vec) {
return std::format("Vec({:.3g}, {:.3g}, {:.3g})", vec.x, vec.y, vec.z);
};
struct quat_t {
float x;
float y;
float z;
float w;
} [[static, format("quat_str")]];
fn quat_str(quat_t quat) {
return std::format("Quat({:.3g}, {:.3g}, {:.3g}, {:.3g})", quat.x, quat.y, quat.z, quat.w);
};
struct transform_t {
vec_t pos;
quat_t rot;
} [[static, format("transform_str")]];
fn transform_str(transform_t transform) {
return std::format("Transform({:s}, {:s})", vec_str(transform.pos), quat_str(transform.rot));
};
using entity_handle_t = u32;
using postprocessing_t;
using player_t;
using environment_t;
using boundary_t;
using fire_t;
using palette_t;
using pair_t;
using entity_t;
struct tdbin_t {
if (std::mem::read_string($, 5) == "TDBIN") {
char magic[5];
be u24 version;
tdbin_version = version;
if (tdbin_version >= 0x000501) {
char level[];
}
entity_handle_t driven_vehicle;
} else {
tdbin_version = 0x000300; // 0.3.0 (perftest)
float unknown_4; // could this be driven_vehicle?
}
std::print("TDBIN {:d}.{:d}.{:d}", (tdbin_version & 0xff0000) >> 16, (tdbin_version & 0xff00) >> 8, tdbin_version & 0xff);
vec_t shadow_volume;
transform_t spawnpoint;
if (tdbin_version >= 0x000501) {
entity_handle_t world_body;
entity_handle_t flashlight;
}
if (tdbin_version >= 0x000700) {
entity_handle_t explosion_script;
}
if (tdbin_version >= 0x010100) {
entity_handle_t achievement_script;
}
if (tdbin_version >= 0x000700) {
postprocessing_t postprocessing;
}
player_t player;
environment_t environment;
boundary_t boundary;
u32 fire_count;
fire_t fires[fire_count];
u32 palette_count;
palette_t palettes[palette_count];
u32 pair_count;
pair_t registry[pair_count];
u32 entity_count;
entity_t entities[entity_count];
if (tdbin_version >= 0x000500) {
u32 unknown_22;
u8 unknown_23[4];
if (tdbin_version >= 0x000702) {
u8 unknown_24[5];
}
}
std::assert($ == std::mem::size(), "bad tdbin");
};
struct postprocessing_t {
float brightness;
float colorbalance_r;
float colorbalance_g;
float colorbalance_b;
float colorbalance_a;
float saturation;
float gamma;
if (tdbin_version >= 0x000800) {
float bloom;
}
};
struct player_t {
transform_t transform;
float yaw;
float pitch;
vec_t velocity;
float health;
float unknown_1;
float bluetide; // this variable predates bluetide tho
if (tdbin_version >= 0x000900) {
float unknown_2;
float unknown_3;
}
};
struct environment_t {
char skybox[];
float skybox_tint_r;
float skybox_tint_g;
float skybox_tint_b;
float skybox_tint_a;
if (tdbin_version >= 0x000800) {
float brightness;
}
float skybox_rot;
float sun_tint_brightness_r;
float sun_tint_brightness_g;
float sun_tint_brightness_b;
float sun_color_tint_r;
float sun_color_tint_g;
float sun_color_tint_b;
float sun_color_tint_a;
vec_t sun_dir;
float sun_brightness;
if (tdbin_version <= 0x000300) {
u8 unknown_5;
}
float sun_spread;
float sun_length;
float sun_fog_scale;
float sun_glare;
if (tdbin_version > 0x000300) {
u8 unknown_6;
}
if (tdbin_version >= 0x000700) {
float constant_r;
float constant_g;
float constant_b;
float constant_a;
}
float ambient;
if (tdbin_version >= 0x000700) {
float ambient_exponent;
}
float exposure_min;
float exposure_max;
float brightness;
if (tdbin_version > 0x000300) {
float fog_color_r;
float fog_color_g;
float fog_color_b;
float fog_color_a;
}
float fog_start;
float fog_distance;
float fog_amount;
float fog_exponent;
float water_wetness;
float water_puddleamount;
float water_puddlesize;
float water_rain;
u8 nightlight;
char ambience_path[];
float ambience_volume;
if (tdbin_version >= 0x000505) {
float slippery;
}
if (tdbin_version >= 0x000700) {
float fog_scale;
}
if (tdbin_version >= 0x000900) {
vec_t snow_dir;
float snow_spread;
float snow_amount;
float snow_speed;
u8 snow_ground;
vec_t wind;
float water_hurt;
}
if (tdbin_version >= 0x000701 && tdbin_version < 0x000900) {
u32 unknown_7[8];
u8 unknown_8;
}
};
using vertex_t;
struct boundary_t {
u32 vertex_count;
vertex_t vertices[vertex_count];
if (tdbin_version >= 0x000900) {
float pad_left;
float pad_top;
float pad_right;
float pad_bottom;
}
};
struct vertex_t {
float x;
float z;
} [[static, format("vertex_str")]];
fn vertex_str(vertex_t vertex) {
return std::format("{:.3g} {:.3g}", vertex.x, vertex.z);
};
struct fire_t {
entity_handle_t entity;
vec_t pos;
float max_time;
float time;
u8 unknown_9[6];
} [[static]];
using palette_material_t;
struct palette_t {
palette_material_t materials[256];
u8 unknown_10;
u8 tint_black[4*256];
u8 tint_yellow[4*256];
} [[static]];
struct palette_material_t {
u8 kind;
float r;
float g;
float b;
float a;
float reflectivity;
float shininess;
float metalness;
float emissive;
u8 replaceable;
} [[static]];
struct pair_t {
char key[];
char value[];
} [[format("pair_str")]];
fn pair_str(pair_t node) {
return std::format("[\"{:s}\"]=\"{:s}\",", node.key, node.value);
};
enum entity_type_t : u8 {
body = 0x01,
shape,
light,
location,
water,
enemy,
joint,
vehicle,
wheel,
screen,
trigger,
script,
};
using entity_body_t;
using entity_shape_t;
using entity_light_t;
using entity_location_t;
using entity_water_t;
using entity_enemy_t;
using entity_joint_t;
using entity_vehicle_t;
using entity_wheel_t;
using entity_screen_t;
using entity_trigger_t;
using entity_script_t;
struct entity_t {
u8 type_raw;
u8 type = type_raw;
if (tdbin_version >= 0x000906 && type >= entity_type_t::enemy) {
type += 1;
}
entity_handle_t handle;
u8 tag_count;
pair_t tags[tag_count];
char description[];
match (type) {
(entity_type_t::body): entity_body_t entity;
(entity_type_t::shape): entity_shape_t entity;
(entity_type_t::light): entity_light_t entity;
(entity_type_t::location): entity_location_t entity;
(entity_type_t::water): entity_water_t entity;
(entity_type_t::enemy): entity_enemy_t entity;
(entity_type_t::joint): entity_joint_t entity;
(entity_type_t::vehicle): entity_vehicle_t entity;
(entity_type_t::wheel): entity_wheel_t entity;
(entity_type_t::screen): entity_screen_t entity;
(entity_type_t::trigger): entity_trigger_t entity;
(entity_type_t::script): entity_script_t entity;
}
u32 child_count;
entity_t children[child_count];
u32 pad;
std::assert(pad == 0xbeefbeef, "bad entity pad");
} [[format("entity_str")]];
fn entity_str(entity_t entity) {
str type_str;
u8 type = entity.type_raw;
if (tdbin_version >= 0x000906 && type >= entity_type_t::enemy) {
type += 1;
}
match (type) {
(entity_type_t::body): type_str = "body";
(entity_type_t::shape): type_str = "shape";
(entity_type_t::light): type_str = "light";
(entity_type_t::location): type_str = "location";
(entity_type_t::water): type_str = "water";
(entity_type_t::enemy): type_str = "enemy";
(entity_type_t::joint): type_str = "joint";
(entity_type_t::vehicle): type_str = "vehicle";
(entity_type_t::wheel): type_str = "wheel";
(entity_type_t::screen): type_str = "screen";
(entity_type_t::trigger): type_str = "trigger";
(entity_type_t::script): type_str = "script";
}
return std::format("{:d} [{:s}]", entity.handle, type_str);
};
using entity_flags_t;
struct entity_body_t {
entity_flags_t flags;
transform_t transform;
vec_t velocity;
float angular_velocity[3];
u8 dynamic;
if (tdbin_version < 0x000900) {
u8 unknown_11;
}
u8 body_flags;
};
struct entity_shape_t {
entity_flags_t flags;
transform_t transform;
u16 shape_flags;
u8 collision_layer;
u8 collision_mask;
float density;
float strength;
if (tdbin_version >= 0x000900) {
u16 texture_tile;
u16 blendtexture_tile;
float texture_weight;
float blendtexture_weight;
vec_t starting_world_position; // ?
} else {
u32 texture_tile;
vec_t starting_world_position; // ?
float texture_weight;
}
float unknown_12;
u8 unknown_13;
u8 unknown_14;
u32 sx;
u32 sy;
u32 sz;
if (sx*sy*sz > 0) {
u32 length;
std::assert(length%2 == 0, "bad shape length");
$ += length;
}
u32 palette;
float scale;
u32 unknown_15[2];
if (tdbin_version >= 0x000700) {
u8 unknown_16;
}
};
enum entity_light_type_t : u8 {
sphere = 0x01,
capsule,
cone,
area,
};
struct entity_light_t {
u8 enabled;
u8 type_raw;
u8 type = type_raw;
if (tdbin_version < 0x000700 && type >= entity_light_type_t::capsule) {
type += 1;
}
transform_t transform;
float color_r;
float color_g;
float color_b;
float color_a;
if (tdbin_version >= 0x000500) {
float scale;
}
float reach;
float size;
float unshadowed;
float angle;
float penumbra;
float fog_iter;
float fog_scale;
float area_size_x;
float area_size_z;
if (tdbin_version >= 0x000700) {
float capsule_size;
}
u8 unknown_20[13];
float unknown_21;
char sound_path[];
float sound_volume;
float glare;
};
struct entity_location_t {
entity_flags_t flags;
transform_t transform;
};
struct entity_water_t {
entity_flags_t flags;
transform_t transform;
float depth;
float wave;
float ripple;
float motion;
float foam;
if (tdbin_version >= 0x000900) {
float color_r;
float color_g;
float color_b;
float color_a;
}
if (tdbin_version >= 0x010400) {
float visibility;
}
u32 vertex_count;
vertex_t vertices[vertex_count];
};
struct entity_enemy_t {
std::error("entity type enemy not implemented");
};
enum entity_joint_type_t : u32 {
ball = 0x01,
hinge,
prismatic,
rope,
};
using entity_joint_knot_t;
struct entity_joint_t {
u32 type_raw;
u32 type = type_raw;
entity_handle_t entities[2] [[static]];
vec_t positions[2] [[static]];
vec_t axes[2] [[static]]; // what are these?
u8 connected;
u8 collide;
float strength;
float spring;
quat_t rotation;
float limit_min;
float limit_max;
float unknown_25;
float unknown_26;
float size;
if (tdbin_version >= 0x000900) {
u8 sound;
}
if (tdbin_version >= 0x000905) {
u8 autodisable; // ?
}
if (tdbin_version >= 0x000900) {
u32 unknown_27;
u32 unknown_28;
}
if (type == entity_joint_type_t::rope) {
float red;
float green;
float blue;
float alpha;
float unknown_29;
float rope_strength;
float max_stretch;
float slack;
float unknown_30;
u8 unknown_31;
u32 knot_count;
entity_joint_knot_t knots[knot_count];
}
};
struct entity_joint_knot_t { // wtf is this?
vec_t from;
vec_t to;
} [[static]];
using entity_vehicle_exhaust_t;
using entity_vehicle_vital_t;
struct entity_vehicle_t {
entity_flags_t flags;
entity_handle_t body;
transform_t transform;
vec_t velocity;
vec_t angular_velocity; // TODO: euler angles type
float unknown_32;
u32 wheel_count;
entity_handle_t wheels[wheel_count] [[static]];
float top_speed;
float unknown_33;
float spring;
float damping;
float acceleration;
float strength;
float friction;
float unknown_34;
u8 handbrake;
float antispin;
float steerassist;
float unknown_35;
float antiroll;
char sound[];
float pitch;
vec_t camera;
vec_t player;
vec_t exit;
vec_t propeller;
float difflock;
float boat_sink;
u32 voxel_count;
if (tdbin_version > 0x000300) {
u8 unknown_36;
float drivable;
}
u32 ref_count; // wtf is this?
u32 refs[ref_count] [[static]];
u32 exhaust_count;
entity_vehicle_exhaust_t exhausts[exhaust_count] [[static]];
u32 vital_count;
entity_vehicle_vital_t vitals[vital_count] [[static]];
float unknown_38;
if (tdbin_version >= 0x000900) {
u8 unknown_39;
float broken_threshold;
}
};
struct entity_vehicle_exhaust_t {
transform_t transform;
if (tdbin_version >= 0x000700) {
float strength;
}
} [[static]];
struct entity_vehicle_vital_t {
u32 body;
vec_t pos;
float unknown_37;
u32 shape;
} [[static]];
struct entity_wheel_t {
entity_flags_t flags;
entity_handle_t vehicle;
entity_handle_t vehicle_body;
entity_handle_t body;
entity_handle_t shape;
if (tdbin_version >= 0x010300) {
u8 unknown_40[17] [[static]];
}
transform_t transform;
transform_t empty_transform; // ?
float steer;
float drive;
float travel_min;
float travel_max;
float radius;
float width;
float angular_speed;
float unknown_41;
float unknown_42;
};
struct entity_screen_t {
entity_flags_t flags;
transform_t transform;
float size_x;
float size_y;
float bulge;
u32 resolution_x;
u32 resolution_y;
char path[];
u8 enabled;
u8 interactive;
float emissive;
float fxraster;
float fxca;
float fxnoise;
float fxglitch;
};
enum entity_trigger_type_t : u32 {
sphere = 1,
box,
polygon,
};
struct entity_trigger_t {
entity_flags_t flags;
transform_t transform;
entity_trigger_type_t type;
float sphere_size;
vec_t box_size;
float polygon_size;
u32 vertex_count;
vertex_t vertices[vertex_count] [[static]];
char sound[];
float sound_ramp;
u8 unknown_43;
float volume;
};
using entity_script_table_t;
using entity_script_sound_t;
using entity_script_transition_t;
struct entity_script_t {
entity_flags_t flags;
char path[];
u32 parameter_count;
pair_t parameters[parameter_count];
float last_update;
float time;
u32 unknown_17;
entity_script_table_t environment;
if (tdbin_version < 0x000500) {
u32 unknown_18_count;
u32 unknown_18[unknown_18_count];
}
u32 handle_count;
entity_handle_t handles[handle_count];
u32 sound_count;
entity_script_sound_t sounds[sound_count];
if (tdbin_version >= 0x000704) {
u32 transition_count;
entity_script_transition_t transitions[transition_count];
}
};
enum entity_script_value_type_t : u32 {
nil,
boolean,
number = 3,
string,
table,
reference = 0xfffffffb,
};
using entity_script_pair_t;
struct entity_script_table_t {
entity_script_pair_t table[while (
std::mem::read_unsigned($, 4) != entity_script_value_type_t::nil
)];
entity_script_value_type_t end_of_table_marker;
};
using entity_script_value_t;
struct entity_script_pair_t {
entity_script_value_t key;
entity_script_value_t value;
};
struct entity_script_value_t {
entity_script_value_type_t type;
match (type) {
(entity_script_value_type_t::nil): padding[0];
(entity_script_value_type_t::boolean): u8 value;
(entity_script_value_type_t::number): double value;
(entity_script_value_type_t::string): char value[];
(entity_script_value_type_t::table): entity_script_table_t value;
(entity_script_value_type_t::reference): u32 value;
(_): std::error(std::format("bad type {} at 0x{:x}", type, $));
}
} [[inline]];
struct entity_script_sound_t {
u32 type;
char path[];
};
struct entity_script_transition_t {
char key[];
u8 type;
float transition_time; // ?
double time; // ?
u8 unknown_19[4];
};
struct entity_flags_t {
if (tdbin_version >= 0x000902) {
u16 flags;
} else {
u8 flags;
}
} [[inline]];
tdbin_t tdbin @ 0;