Actorizer actor creation - isghj5/mm-rando GitHub Wiki
Making an injected actor for actorizer is not that easy. You need to know C programming, you need to have a working mm decomp build, and then you need to do some jank to get it into actorizer.
We can only modify actors that are enemies or actors that the itemizer does not modify using this method: this method completely overwrites actors with our new code, which means we need to maintain all changes made by itemizer in our decomp actor, which is not always easy as they can be options in the randomizer and not always applied, and reverse engineering randomizer patch changes can be painful, so in generally we do not use this method on any actor itemizer needs to modify.
Decomp is used to generate the actors. MMRA files are binary replacement actor overlays ripped from a working decomp ROM. You need to install and get decomp working, and understand how to build and clean decomp, and ideally understand basic git control like branching and branch switching to make multiple actors, as this will allow you to save your changes and come back to them later if needed, as you do not want to make multiple actors in the same one decomp session they can mess with each other, git branching makes this easy, as each branch gets one actor.
Once you get git and decomp working, you need to find which actor you want to modify by its name. The actors code file will be in mm-decomp/src/overlay/actors/<actor_name>/<z_actorname.c>
. The header file will be in the same folder.
Once you make the changes you want to make to the actor, you need to rebuild decomp and test the actor in the ROM. This sometimes means moving the actor somewhere in-game where you can easily find them for debugging/testing of the changes you made. To do this easily, you should modify the scene files to spawn the actor in a better location. The scene files are extracted from the ROM to a C based data which we can modify in decomp, located at mm-decomp/extracted/n64-us/assets/scenes/Z2_<scenename>/
, where the actors are usually found in the room data not the scene data directly.
Example: If you wanted to place a different actor in the clocktower, replacing happy mask sales man, you would open mm-decomp/extracted/n64-us/assets/scenes/Z2_INSIDETOWER_room00.c
.
Inside of each room file exists at least one ActorEntry
array, which includes all of the actor spawn data, and then scroll to ACTOR_EN_OSN
which is the happy mask sales man, and replace his actor ID to change the actor spawn. All of the actor data for spawning an actor is here in this array of actor spawns, where every spawn has the Actor ID, position data, rotation data(and flags) and params data, and that will be the last element of the array, which you will likely need to change to match a value your new actor accepts.
Lastly, most actors need to use an "object" which contains the assets the actor uses, this object has to be in the object list for this room or the actor will fail to spawn, so you need to add the object to the list or remove, in this case OBJECT_OSN
is not needed anymore that we removed happy mask sales man. Be advised: the game does not safely check if all of the objects can fit in a scene when running, if the objects overflow this can crash or bug-out the game, so for testing it makes sense to delete some objects for actors we don't need if the list is large.
Once you have tested the actor and want to put it into actorizer, you need to rip the actor from the decomp ROM. We can use objdump for this:
mips-linux-gnu-objcopy --dump-section ..$OVERLAY_NAME=$OVERLAY_NAME.bin $BUILD_FILE
Where, OVERLAY_NAME is the full decomp name of the actor, and build file is the location of the build decompressed ROM decomp makes.
Example: If you made a change to the Cucco, the full name is ovl_En_Niw
, and the build location for the ROM is in mm-decomp/build/n64-us/mm-n64-us.z64
. This will output a file to the main decomp directory called ovl_En_Niw.bin which is our entire actorizer overlay file.
We now need to make a MMRA (MMR actor file) for this. You now need to make a matching .meta file that will live inside of our MMRA (which is just a renamed zip file) with our overlay bin. I honestly recommend taking an existing meta file from an actorizer actor, and ripping the meta file from that and reading it and updating it for your actor. You will need to update several values: The Actor ID, object ID, and File ID all have to match your original actor. The rest of the values are more complicated.
You will also need to update your actor init data location, this is data that is loaded by the game that tells the game what your actor needs to have when it's created, every actor has one, but the location of the data is dependent on the ROM build process; it's generally in its location in sequential .data order. We need this data to be passed to rando because it lives in the actor overlay list, and needs to be updated there separately.
This value can be calculated if you have a hex editor: its always in the .data overlay section of our .bin, and the overlay has a offset table that tells us where in the overlay every section is. The very last data at the end of the file, the last four bytes, is a number value of the offet of the section size table that we need, so if you have an actor with size 0x1000, and the final bytes say 0x40, then your size table is at location "0x1000-0x40" There, you will find the four sizes for the four overlay sections, .text
(which is our code), .data
, .rodata
and .bss
. Every one of those sections starts after the end of the previous, so data starts right after text, which is our code and .text
starts at the very first byte, which means .data
starts right after, and that will be at the location which is the same as the size of the text section.
Example: If you see your four sections of data are size 0x600, 0x100, 0x100, 0x0
then .text
is size 0x600, which is also the location of the start of the data section.
From there you want to visually scan through the data for our actor init data, you can do this by eye because actor init data always has the same pattern: its 0x20 bytes, where the first 2 bytes are the actor id (which you just found to add to the .meta file) and on that same 0x10 line should be the object id for the same actor. 0x10 after the actor id should be 2-4 memory pointers that will look like 0x801XXXXX
for the actor life stage pointers.
If you have trouble visually scanning through the data section, you can also just move the actor init data to the top of the actor file, as it's location in .data is sequential with the rest of .data values, if its at the top of the data section of the file, it will at the front of the .data section in the compiled bin.
Alternatively, instead of finding this actor init data offset by hand/eye, you can look up the actor init value in the decomp build map, which should be in mm-decomp/build/n64-us/mm-n64-us.map
, and calculate the difference in memory value between the actor init values and the start of the actor values.
This could be faster because you just need to find two values and enter them into a hex calculator and get the difference, although I find this slower and more annoying just because now I have to find both values and the map is a mess visually to find data.
Where, the two values you want are the vram location of the start of the actor, which is usually _<actor_name>SegmentTextStart
IE: _ovl_En_NiwSegmentTextStart
, and the location of the init data which is named to match your actors init values, which decomp now calls "Profile data" IE: En_Niw_Profile
. Take both of those two numbers, which in this example are 0x0000000080891060
and 0x0000000080893464
and put them into a hexadecimal calculator to get the offset value we need for the meta.
The meta data also contains some spawn data that might not exist already in randomizer, which you will want to update if needed, like which params are valid, if they have limits, and if the actor is considered kill-able (enemy) or not.
After updating the meta file, you just zip both the bin and meta file into the same file, and rename the filetype from .zip
to .mmra
. Move this file to the mmra/actors
folder and it will automatically get picked up by the actorizer code and update the actor in-game.