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
|
# Asset Extraction
## What are Objects
Similar to overlays, due to the N64's small amount of memory graphical assets need to be loaded and unloaded depending on what is currently happening in the game. This is accomplished using objects, which are bundles of data with no header or other identifying information.
They consist of various things such as:
- Vertices: 3D coordinates used to assemble a 3d mesh.
- Textures: A 2D image that gets mapped to the triangles of a mesh.
- Palettes: A list of colors used as a look up table for palette textures.
- Display Lists: Graphical commands that get sent to the N64's Reality Co-Processer to render the object.
- c_keyframe Data: Used for skeletal animations.
- evw_anime Data: Used for texture animations.
Objects can be loaded into an arbitrary spot in ram. They are referenced with something called a segment address, which is a feature of the N64's RSP. There are are 16 segments an object can use, with the first byte indicating which segment. Most objects use segment 6, or address that look like 0x06XXXXXX
## Setting Up the Script
The data inside objects needs to be defined in multiple places in the repo. To make things less tedious, I wrote a script to automate a lot of it.
Download script.py from here: https://github.com/emilybrooks/af_asset_script
First you need to edit the `projectDir` variable to where your `af` folder is. You also need to make `input.csv` in the same folder as `script.py`. This is where we will record all the information about the object's data.
## Filling out input.csv
The first row of the csv file has:
- ROM start address
- ROM end address
- Segment number
- Object name
- Directory where files will be extracted to
- (Optional) Sub folder, for objects that contain sub objects.
For this tutorial I will be extracting tol_keitai_1. It's ROM address is 0x1127000, and the ROM end address can be found in assets.yaml

The first line of input.csv should look like this:
```csv
0x1127000, 0x1127A40, 6, tol_keitai_1, objects/tol_keitai_1
```
Note: The directory actually refers to two places. Code files will use `af/src` as the start, and assets will use `af/assets/jp` as the start. So the .c and .h files will be placed in `af/src/objects/tol_keitai_1`, and extracted assets will be placed in `af/assets/jp/objects/tol_keitai_1`
The next step of extracting objects is to document exactly what data it contains. One important tool we will use is the linker map from DnM+, which lists out the names of all the pieces of data.
Searching for `tol_keitai` brings up these lines:
```
005a8120 000003 005a8120 4 cKF_ckcb_r_tol_keitai_1_keitai_off1_tbl dataobject.obj
005a8124 000012 005a8124 4 cKF_kn_tol_keitai_1_keitai_off1_tbl dataobject.obj
005a8138 000006 005a8138 4 cKF_c_tol_keitai_1_keitai_off1_tbl dataobject.obj
005a8140 000084 005a8140 4 cKF_ds_tol_keitai_1_keitai_off1_tbl dataobject.obj
005a81c4 000014 005a81c4 4 cKF_ba_r_tol_keitai_1_keitai_off1 dataobject.obj
005a81d8 000088 005a81d8 1 .data dataobject.obj
005a81d8 000000 005a81d8 ...data.0 (entry of .data) dataobject.obj
005a81d8 000003 005a81d8 4 cKF_ckcb_r_tol_keitai_1_keitai_on1_tbl dataobject.obj
005a81dc 000002 005a81dc 4 cKF_kn_tol_keitai_1_keitai_on1_tbl dataobject.obj
005a81e0 000016 005a81e0 4 cKF_c_tol_keitai_1_keitai_on1_tbl dataobject.obj
005a81f8 000054 005a81f8 4 cKF_ds_tol_keitai_1_keitai_on1_tbl dataobject.obj
005a824c 000014 005a824c 4 cKF_ba_r_tol_keitai_1_keitai_on1 dataobject.obj
005a8260 000740 005a8260 1 .data dataobject.obj
005a8260 000000 005a8260 ...data.0 (entry of .data) dataobject.obj
005a8260 000020 005a8260 32 tol_keitai_1_pal dataobject.obj
005a8280 000100 005a8280 32 tol_keitai_1_ueura1_tex_txt dataobject.obj
005a8380 000100 005a8380 32 tol_keitai_1_ueomote1_tex_txt dataobject.obj
005a8480 000100 005a8480 32 tol_keitai_1_shitaura1_tex_txt dataobject.obj
005a8580 000100 005a8580 32 tol_keitai_1_shitaomote1_tex_txt dataobject.obj
005a8680 0001d0 005a8680 8 tol_keitai_1_v dataobject.obj
005a8850 000088 005a8850 8 main1_keitai1_model dataobject.obj
005a88d8 000088 005a88d8 8 main2_keitai1_model dataobject.obj
005a8960 000024 005a8960 4 cKF_je_r_tol_keitai_1_tbl dataobject.obj
005a8984 000008 005a8984 4 cKF_bs_r_tol_keitai_1 dataobject.obj
```
We will also use a program called Z64Utils. Currently it doesn't have full support for Animal Forest yet, but a modified build with partial functionality is pinned in the `#af_decomp` channel of our discord.
First load a ROM by going to ROM > Open. `af/baserom-jp.z64` or `af/baserom-decompressed-jp.z64` are fine.
In the filter field at the top put the object's rom start address (1127000), and click the entry that shows up. For the segment id, enter 6 and click OK.

This will open a new window with the object data.

The very first section of data is marked as Unknown. Referencing the linker map, this object has two animations, `keitai_off1` and `keitai_on1`. This is animation data, which Z64Utils currently doesn't support yet. But we can still read the hexadecimal data and figure it out ourselves. For these, you want to find the BaseAnimationR data, which will have pointers to all the other pieces of data. It will be four segment addresses (06XXXXXX) in a row.

In this case, `cKF_ba_r_tol_keitai_1_keitai_off1` is at 0x060000A4, and has pointers to 0x06000000, 0x06000020, 0x06000004, and 0x06000018. You can reference the BaseAnimationR struct in c_keyframe.h and see that these are pointers to the ckcb, ds, kn, and c files respectively.
Let's add this to `input.csv`. For each item you put the segment address, the filename, and the splat segment type. c_keyframe animation uses `ckf_ckcb`, `ckf_ds`, `ckf_kn`, `ckf_c`, and `ckf_ba` types.
```csv
0x1127000, 0x1127A40, 6, tol_keitai_1, objects/tol_keitai_1
0x06000000, cKF_ckcb_r_tol_keitai_1_keitai_off1_tbl, ckf_ckcb
0x06000004, cKF_kn_tol_keitai_1_keitai_off1_tbl, ckf_kn
0x06000018, cKF_c_tol_keitai_1_keitai_off1_tbl, ckf_c
0x06000020, cKF_ds_tol_keitai_1_keitai_off1_tbl, ckf_ds
0x060000A4, cKF_ba_r_tol_keitai_1_keitai_off1, ckf_ba
```
The steps to add the second animation, `keitai_on1`, are the same.
The next piece of data is the vertices. Note that there are multiple groups of vertices in Z64Utils. When a display list references a specific set of vertices, Z64Utils will make that into it's own entry. However, These should only be a single array of vertices, `tol_keitai_1_v`. So grab the first Vertex section's address, which for this object is 0x06000150. These use the `vtx` type.
The next two sections are display lists, which Z64Utils was correctly able to identify. They are at 0x06000320 and 0x06000480. The order of these match the linker map's order, so 0x06000320 is `main1_keitai1_model` and 0x06000480 is `main2_keitai1_model`. These use the `af_gfx` type.
The next few items are textures. This object uses a palette, which shows up as `tlut_000005E8`. This uses the `af_palette` type.
For the other textures, we need to identify what type they are. Because of how they are used in the display list, Z64Utils figured this out automatically. You can click the texture in question, and above the preview window is a line of text with the dimensions and texture format.

For this object, all the textures are CI4. These use the `ci4` type. Other types include `i4`, `i8`, `ia4`, `ia8`, `ia16`, `ci8`, `rgba16`, or `rgba32`.
At the bottom is one last unknown section. This is the model's skeleton. It's composed of a JointElemR and BaseSkeletonR. You can find the addresses for these by starting at the bottom until you find a segment address, which is a pointer to `cKF_je_r_tol_keitai_1_tbl`. BaseSkeletonR is 8 bytes long, so count 8 bytes from the end of that address to get 0x06000A2C, which is the start of `cKF_bs_r_tol_keitai_1`. These use custom splat extensions `ckf_je` and `ckf_bs` respectively.

That's all the data in this object! input.csv should look like this:
```csv
0x1127000, 0x1127A40, 6, tol_keitai_1, objects/tol_keitai_1
0x06000000, cKF_ckcb_r_tol_keitai_1_keitai_off1_tbl, ckf_ckcb
0x06000004, cKF_kn_tol_keitai_1_keitai_off1_tbl, ckf_kn
0x06000018, cKF_c_tol_keitai_1_keitai_off1_tbl, ckf_c
0x06000020, cKF_ds_tol_keitai_1_keitai_off1_tbl, ckf_ds
0x060000A4, cKF_ba_r_tol_keitai_1_keitai_off1, ckf_ba
0x060000C0, cKF_ckcb_r_tol_keitai_1_keitai_on1_tbl, ckf_ckcb
0x060000C4, cKF_kn_tol_keitai_1_keitai_on1_tbl, ckf_kn
0x060000C8, cKF_c_tol_keitai_1_keitai_on1_tbl, ckf_c
0x060000E0, cKF_ds_tol_keitai_1_keitai_on1_tbl, ckf_ds
0x06000134, cKF_ba_r_tol_keitai_1_keitai_on1, ckf_ba
0x06000150, tol_keitai_1_v, vtx
0x06000320, main1_keitai1_model, af_gfx
0x06000480, main2_keitai1_model, af_gfx
0x060005E8, tol_keitai_1_pal, af_palette
0x06000608, tol_keitai_1_ueura1_tex_txt, ci4
0x06000708, tol_keitai_1_ueomote1_tex_txt, ci4
0x06000808, tol_keitai_1_shitaura1_tex_txt, ci4
0x06000908, tol_keitai_1_shitaomote1_tex_txt, ci4
0x06000A08, cKF_je_r_tol_keitai_1_tbl, ckf_je
0x06000A2C, cKF_bs_r_tol_keitai_1, ckf_bs
```
## Adjusting the Code
Now that `input.csv` is setup we can run the script:
```bash
python3 script.py
```
Note: If you're on windows you want to run this script in wsl, so that the files it generates will use LF line endings.
This will do three things. `output.txt` will be created in the same directory as `script.py`. `af/src/objects/tol_keitai_1/tol_keitai_1.c` and `af/src/objects/tol_keitai_1/tol_keitai_1.h` will also be created.
The .c file contains include statements for all the data splat will extract from the rom. This file will be compiled and linked when make is run.
The .h file has an extern statement for all of the object's data. You can include this header in your actor's .c file, and use these names in code.
`output.txt` contains the symbol name definitions for all the data. This should be pasted into `symbol_addrs_assets.txt`. You should place it so the rom addresses are in order with the rest of the file.
One important thing to point out is `tol_keitai_1_v`. It has an extra option for it's size. This is necessary for vertices so that extracted display lists can properly reference it as an array.
`output.txt` also contains the splat segment definitions. This should be pasted into `assets.yaml`, replacing the old auto generated one.
### Textures
Textures require a width and height argument in order to extract them. This can be found in Z64Utils in the text above the texture preview, similar to how we found the texture's format.
An example from a separate object file:
```yaml
- [0xD66A58, i4, obj_e_count01/obj_e_count01_spot_tex_sgi_i4, 16, 16]
```
### Palette Textures
Palette textures require the palette name as a third argument. In this case, we know the palette is `tol_keitai_1_pal`.
```yaml
- [0x1127608, ci4, tol_keitai_1_ueura1_tex_txt, 16, 32, tol_keitai_1_pal]
- [0x1127708, ci4, tol_keitai_1_ueomote1_tex_txt, 16, 32, tol_keitai_1_pal]
- [0x1127808, ci4, tol_keitai_1_shitaura1_tex_txt, 16, 32, tol_keitai_1_pal]
- [0x1127908, ci4, tol_keitai_1_shitaomote1_tex_txt, 16, 32, tol_keitai_1_pal]
```
This object only has one palette and it's included in the object. However some objects use external palettes. In order to use a palette from a different object, it needs to define a `global_id`. This can only be set when the segment is in dictionary format.
Here's `obj_s_house1` as an example:
```yaml
- { start: 0xD5B008, type: af_palette, name: obj_s_house1_a_pal, global_id: obj_s_house1_a_pal }
- { start: 0xD5B028, type: af_palette, name: obj_s_house1_b_pal, global_id: obj_s_house1_b_pal }
- { start: 0xD5B048, type: af_palette, name: obj_s_house1_c_pal, global_id: obj_s_house1_c_pal }
- { start: 0xD5B068, type: af_palette, name: obj_s_house1_d_pal, global_id: obj_s_house1_d_pal }
- { start: 0xD5B088, type: af_palette, name: obj_s_house1_e_pal, global_id: obj_s_house1_e_pal }
```
`obj_s_house1` has 5 palettes, so for the palette argument you would put a list of each of them, like this:
```yaml
- start: 0xD83058
type: ci4
name: obj_house/obj_s_house1_t3_tex_txt
width: 128
height: 32
palettes: [obj_s_house1_a_pal, obj_s_house1_b_pal, obj_s_house1_c_pal, obj_s_house1_d_pal, obj_s_house1_e_pal]
```
Finally, these textures will be extracted as `<filename>_<palette_name>.ci4.png`. Our script generated an include statement for `<filename>.ci4.png`, so you need to update this to `obj_s_house1_t3_tex_txt_obj_s_house1_a_pal.ci4.inc.c`
### Adjusting code
Because we renamed the segment, we also need to adjust the DMA table and the object table, which specify where files are in the ROM.
In `dmadata_table_jp.h`, rename object_01127A40 to tol_keitai_1:
```
DEFINE_DMA_ENTRY(tol_keitai_1, "tol_keitai_1")
```
In `object_table.h` rename object_01127A40 and the object enum:
```
/* 0x02D */ DEFINE_OBJECT(tol_keitai_1, OBJECT_TOL_KEITAI_1)
```
We also need to adjust the .c code itself. In this case, tol_keitai_1 is part of ac_tools.c, so the object table defined there needs the renamed enum. In your actor file you would include `tol_keitai_1.h` and delete any extern statements you made before extracting this data.
## Splitting Files
At this point its possible to extract and build, however doing so will produce this error:
```bash
Error: ckf_ba segment cKF_ba_r_tol_keitai_1_keitai_off1 length (28) is not 20 bytes!
```
This is because there are padding bytes between `cKF_ba_r_tol_keitai_1_keitai_off1` and the next segment. Whats happening is that keitai_off1, keitai_on1, and the rest of the data are in 3 separate files. This can be seen in the linker map, where `...data.0 (entry of .data) dataobject.obj` lines appear between files. The IDO compiler aligns new files to the next 0x10 increment, which in this case results in 8 padding bytes.
To replicate this, we're going to make seperate .c files for this object. First let's edit assets.yaml to include a c file and data section for each section:
```yaml
- [auto, c, keitai_off1]
- start: 0x1127000
type: .data
name: keitai_off1
subsegments:
- [0x1127000, ckf_ckcb, cKF_ckcb_r_tol_keitai_1_keitai_off1_tbl]
- [0x1127004, ckf_kn, cKF_kn_tol_keitai_1_keitai_off1_tbl]
- [0x1127018, ckf_c, cKF_c_tol_keitai_1_keitai_off1_tbl]
- [0x1127020, ckf_ds, cKF_ds_tol_keitai_1_keitai_off1_tbl]
- [0x11270A4, ckf_ba, cKF_ba_r_tol_keitai_1_keitai_off1]
- [0x11270B8]
- [auto, c, keitai_on1]
- start: 0x11270C0
type: .data
name: keitai_on1
subsegments:
- [0x11270C0, ckf_ckcb, cKF_ckcb_r_tol_keitai_1_keitai_on1_tbl]
- [0x11270C4, ckf_kn, cKF_kn_tol_keitai_1_keitai_on1_tbl]
- [0x11270C8, ckf_c, cKF_c_tol_keitai_1_keitai_on1_tbl]
- [0x11270E0, ckf_ds, cKF_ds_tol_keitai_1_keitai_on1_tbl]
- [0x1127134, ckf_ba, cKF_ba_r_tol_keitai_1_keitai_on1]
- [0x1127148]
- [auto, c, tol_keitai_1]
- start: 0x1127150
type: .data
name: tol_keitai_1
subsegments:
- [0x1127150, vtx, tol_keitai_1_v]
- [0x1127320, af_gfx, main1_keitai1_model]
- [0x1127480, af_gfx, main2_keitai1_model]
- [0x11275E8, af_palette, tol_keitai_1_pal]
- [0x1127608, ci4, tol_keitai_1_ueura1_tex_txt, 16, 32, tol_keitai_1_pal]
- [0x1127708, ci4, tol_keitai_1_ueomote1_tex_txt, 16, 32, tol_keitai_1_pal]
- [0x1127808, ci4, tol_keitai_1_shitaura1_tex_txt, 16, 32, tol_keitai_1_pal]
- [0x1127908, ci4, tol_keitai_1_shitaomote1_tex_txt, 16, 32, tol_keitai_1_pal]
- [0x1127A08, ckf_je, cKF_je_r_tol_keitai_1_tbl]
- [0x1127A2C, ckf_bs, cKF_bs_r_tol_keitai_1]
- [0x1127A34]
```
Next we need to create these .c files. Copy `tol_keitai_1.c` and rename it to `keitai_on1.c`. Then delete all the include statements after `cKF_ba_r_tol_keitai_1_keitai_off1`. Repeat this for `keitai_on1.c`, and then in `tol_keitai_1.c` delete the include states that were moved to the other files.
# Building
Everything should be set up. Run `make extract` and then `make` to see if the ROM builds correctly.
Note: sometimes you'll get a compile error in one of the extracted display lists. This is because of segmented addresses. Something else in code generated a symbol for that segmented address, eg `D_6000180`, and the display list extracting script will use that symbol instead of the vertex symbol in the object. This can be resolved by adding that symbol to `ignored_addresses.txt`. As an example:
```
D_6000180 = 0x06000180; // ignore:true
```
|