• Welcome to Smashboards, the world's largest Super Smash Brothers community! Over 250,000 Smash Bros. fans from around the world have come to discuss these great games in over 19 million posts!

    You are currently viewing our boards as a visitor. Click here to sign up right now and start on your path in the Smash community!

Melee dat format...

Tcll

Smash Lord
Joined
Jul 10, 2010
Messages
1,780
Location
The Gates of Darkness
NNID
Tcll5850
R revel8n : if you haven't already, please update my wiki page :)

I was hoping others would do the same, but apparently my page didn't fly for very long, and didn't get as popular as expected...
(Alot of people still don't know about it)
 

zankyou

Smash Lord
Joined
Sep 12, 2014
Messages
1,055
Looking at rootnodes right now. quake_model_set has a structure that looks extremely close to my notes on animation files.
Z zankyou R revel8n Tcll Tcll
I forget if I've posted this before, but

grGroundParam
0x4C = word, Fixed Camera BOOL (1 = Enable, 0 = Disable = Regular Camera)

Stages like PokeFloats & Icicle Mountain have this enabled.
Regular Camera Pokefloats neutral stage hack when.
 

Achilles1515

Smash Master
Joined
Jun 18, 2007
Messages
3,211
Location
Cincinnati / Columbus OH
Pixel Processing
- Previously referred to as the "blend structure" or something of the sort.

Code:
struct Material {
    ...
    0x14    PixelProc pointer     /* sizeof(PixelProc) = 0xC */
}
Code:
/* each entry below is a single byte */

struct PixelProc {
    0x0    bitflags
                   (01):  GXBool update_enable [GXSetColorUpdate]
                   (02):  GXBool update_enable [GXSetAlphaUpdate]
                   (04):  GXBool enable [GXSetDstAlpha]        /* "constant alpha" */
                   (08):  GXBool before_tex [GXSetZCompLoc]
                   (10):  GXBool compare_enable [GXSetZMode]
                   (20):  GXBool update_enable [GXSetZMode]
                   (40):  GXBool dither [GXSetDither]
    0x1    u8 ref0 [GXSetAlphaCompare]
    0x2    u8 ref1 [GXSetAlphaCompare]
    0x3    u8 alpha [GXSetDstAlpha]
    0x4    GXBlendMode type [GXSetBlendMode]
    0x5    GXBlendFactor src_factor [GXSetBlendMode]
    0x6    GXBlendFactor dst_factor [GXSetBlendMode]
    0x7    GXLogicOp op [GXSetBlendMode]
    0x8    GXCompare func [GXSetZMode]
    0x9    GXCompare comp0 [GXSetAlphaCompare]
    0xA    GXAlphaOp op [GXSetAlphaCompare]
    0xB    GXCompare comp1 [GXSetAlphaCompare]
}
Enumerations
Code:
/********************************/

typedef u8 GXBool;

#define GX_TRUE        ((GXBool)1)
#define GX_FALSE       ((GXBool)0)
#define GX_ENABLE      ((GXBool)1)
#define GX_DISABLE     ((GXBool)0)

/********************************/

typedef enum _GXAlphaOp
{
    GX_AOP_AND,
    GX_AOP_OR,
    GX_AOP_XOR,
    GX_AOP_XNOR,
    GX_MAX_ALPHAOP

} GXAlphaOp;

/********************************/

typedef enum _GXBlendMode
{
    GX_BM_NONE,
    GX_BM_BLEND,
    GX_BM_LOGIC,
    GX_BM_SUBTRACT,
    GX_MAX_BLENDMODE

} GXBlendMode;

/********************************/

typedef enum _GXBlendFactor
{
    GX_BL_ZERO,
    GX_BL_ONE,
    GX_BL_SRCCLR,
    GX_BL_INVSRCCLR,
    GX_BL_SRCALPHA,
    GX_BL_INVSRCALPHA,
    GX_BL_DSTALPHA,
    GX_BL_INVDSTALPHA,

    GX_BL_DSTCLR = GX_BL_SRCCLR,
    GX_BL_INVDSTCLR = GX_BL_INVSRCCLR

} GXBlendFactor;

/********************************/

typedef enum _GXCompare
{
    GX_NEVER,
    GX_LESS,
    GX_EQUAL,
    GX_LEQUAL,
    GX_GREATER,
    GX_NEQUAL,
    GX_GEQUAL,
    GX_ALWAYS

} GXCompare;

/********************************/

typedef enum _GXLogicOp
{
    GX_LO_CLEAR,
    GX_LO_AND,
    GX_LO_REVAND,
    GX_LO_COPY,
    GX_LO_INVAND,
    GX_LO_NOOP,
    GX_LO_XOR,
    GX_LO_OR,
    GX_LO_NOR,
    GX_LO_EQUIV,
    GX_LO_INV,
    GX_LO_REVOR,
    GX_LO_INVCOPY,
    GX_LO_INVOR,
    GX_LO_NAND,
    GX_LO_SET

} GXLogicOp;

/********************************/
Z zankyou Tcll Tcll DRGN DRGN Punkline Punkline R revel8n
 
Last edited:

DRGN

Technowizard
Moderator
Joined
Aug 20, 2005
Messages
2,178
Location
Sacramento, CA
"The length and width of these textures should not exceed 1024x1024, and each value must be a power of 2."
- GameCube SDK Version 1.0, Character Pipeline for Artists, page 14
Hm. Although there are certainly textures in Melee with a width and/or height that's not a power of 2, like 48x48 or 96x96 (e.g. both in PlSkWh.dat). Pretty sure I've never seen a texture exceed those max dimensions though. From zankyou's image, apparently they must be a multiple of 2 at least though.

At first I thought I'd have DTW disallow texture imports with dimensions larger than that, or that aren't a multiple of 2. But maybe it should allow them but give a warning message instead? I'm leaning toward the former because it would be simpler and prevent problems. Also, do you think a visual indication in the DAT Texture Tree tab (i.e. reading from files) would then be necessary, since it shouldn't be possible for them to be in there?
 

Achilles1515

Smash Master
Joined
Jun 18, 2007
Messages
3,211
Location
Cincinnati / Columbus OH
Hm. Although there are certainly textures in Melee with a width and/or height that's not a power of 2, like 48x48 or 96x96 (e.g. both in PlSkWh.dat). Pretty sure I've never seen a texture exceed those max dimensions though. From zankyou's image, apparently they must be a multiple of 2 at least though.

At first I thought I'd have DTW disallow texture imports with dimensions larger than that, or that aren't a multiple of 2. But maybe it should allow them but give a warning message instead? I'm leaning toward the former because it would be simpler and prevent problems. Also, do you think a visual indication in the DAT Texture Tree tab (i.e. reading from files) would then be necessary, since it shouldn't be possible for them to be in there?
I've sat here thinking about the answer to this question for too long. I'm simply not sure, mostly because I haven't done any testing with odd-dimensioned images. Since we don't have solid determinations for what does and doesn't work, I would allow everything. It wouldn't be a bad idea to have a message of some sort appear. It might be such a rare occurrence that an obstructive (Yes/No) would be okay, but a warning in the status label might just do.
 

TGE

Smash Rookie
Joined
May 10, 2014
Messages
20
Location
Netherlands
Sorry for my long time absence (I simply couldn't find time, and it was also just a pain to work with) but I might have made a great discovery.

I found the (partial) source code of the sysdolphin library in the killer7 leaked source code.

https://mega.nz/#!ox5zBTga!APJrFboCHoJEUnRaw6VqQ5IcKbRiwVp41-atieqBMps

While not entirely complete, you could possibly infer other parts of the library by using the code that uses it. Not to mention that there is a Maya exporter that exports to an intermediary text format, which pack.exe can then compile into a .dat model file.

Hopefully people with more time and motivation can use this to finally create a full fledged model editor for Melee.
 
Last edited:

Achilles1515

Smash Master
Joined
Jun 18, 2007
Messages
3,211
Location
Cincinnati / Columbus OH

Tcll

Smash Lord
Joined
Jul 10, 2010
Messages
1,780
Location
The Gates of Darkness
NNID
Tcll5850
Sorry for my long time absence (I simply couldn't find time, and it was also just a pain to work with) but I might have made a great discovery.

I found the (partial) source code of the sysdolphin library in the killer7 leaked source code.

https://mega.nz/#!ox5zBTga!APJrFboCHoJEUnRaw6VqQ5IcKbRiwVp41-atieqBMps

While not entirely complete, you could possibly infer other parts of the library by using the code that uses it. Not to mention that there is a Maya exporter that exports to an intermediary text format, which pack.exe can then compile into a .dat model file.

Hopefully people with more time and motivation can use this to finally create a full fledged model editor for Melee.
nice :)

things would be moving alot faster for me if I wasn't in such poverty...
but yes, I am at least working on what you want ;)

not very many hackers have the motivation to even begin modeling, and I somewhat have to agree with it...
documentation sucks and there's not many good examples to learn from. (NeHe is beyond outdated, and not a good thing to start with)
modern OpenGL isn't hard to learn, but nobody explains it in a way a noob can understand...

it's really just a bunch of arrays sent to the GPU with shaders to manage the data from...
and no, it's not just triangles only, but most static GL primitives.

I also have to blame the stuck-up attitudes of some developers for the reason modelling in general isn't easy.
(nobody tries to make things easy)
 

DRGN

Technowizard
Moderator
Joined
Aug 20, 2005
Messages
2,178
Location
Sacramento, CA
I've sat here thinking about the answer to this question for too long. I'm simply not sure, mostly because I haven't done any testing with odd-dimensioned images. Since we don't have solid determinations for what does and doesn't work, I would allow everything. It wouldn't be a bad idea to have a message of some sort appear. It might be such a rare occurrence that an obstructive (Yes/No) would be okay, but a warning in the status label might just do.
Yeah, when I went back to this, I agree with all of this. I added a pop-up warning for texture imports with dimensions that aren't a multiple of 2 (not the power of 2 rule, since that is so commonly ignored) or are greater than 1024, but it will still allow the import. Also, textures that match this criteria in the D AT Texture Tree are highlighted in a light red (similar to the light blue mipmap highlighting).

Because of this, I inadvertently found a custom costume with multiple custom textures that were given invalid dimensions (widths and/or heights that are odd). But the costume works on both Dolphin and console (Wii). I've even found several examples of vanilla textures with invalid dimensions. It's pretty weird that there are such clear contradictions to the SDK's statement.

I'm wondering if I should just disable these "invalid" texture warnings. I was going to just leave it in, now that it's there. But what do you think? They don't do much harm in being there, but they don't really have any useful function either. It's something more for users to understand; i.e. making the program less intuitive. And it's a slight conflict with the mipmap highlighting, since a texture can't be highlighted with both light blue and light red if it happens to also have "invalid" properties.

Also, what's the largest texture you guys have successfully used for stage background images?
 

revel8n

Smash Cadet
Joined
Dec 1, 2009
Messages
51
Because of this, I inadvertently found a custom costume with multiple custom textures that were given invalid dimensions (widths and/or heights that are odd). But the costume works on both Dolphin and console (Wii). I've even found several examples of vanilla textures with invalid dimensions. It's pretty weird that there are such clear contradictions to the SDK's statement.
Images and textures are technically 2 separate concepts. Images are simply raw bitmap data, textures just raw buffers of data and, although often associated with storing images for use on graphics hardware, do not need to have a direct correlation with images.

You can store a 48x48 image, or any other odd size in between, in a 64x64 texture, the size of which can be determined when the texture is actually created (next power of 2, etc.). Or even take multiple different sizes of images and store them in one texture large enough to contain them all.

Since they can be treated differently, you do not have to assume an image is limited by anything other than max texture size and memory constraints, unless there is something specific that shows images have the same constraints as textures, which in melee, "even" and "power of 2" do not appear to be limits for the image definitions, even if it may be necessary for the final texture they are stored in for use by the hardware.
 
Last edited:

Tcll

Smash Lord
Joined
Jul 10, 2010
Messages
1,780
Location
The Gates of Darkness
NNID
Tcll5850
in some interfaces, textures can actually mix multiple images together for materials, which of course mix multiple textures together.

I don't have my computer up to look atm but I think blender supports this, such as mixing a diffuse map with a light map or specular map in a single texture.

EDIT: btw R revel8n it's documented in the Nintendo manuals (I forget where honestly) that the image should be fitted to the tlut size, which is either 4x4, 8x4, or 8x8 depending on the format.
other than that, there's really no precise limitations to the texture size.

OpenGL may throw errors otherwise if configured incorrectly (applies to the code used), which is likely where the power of 2 issue originated from, but this is not the case with GX.
 
Last edited:

Achilles1515

Smash Master
Joined
Jun 18, 2007
Messages
3,211
Location
Cincinnati / Columbus OH
The mesh flags & 0xC000 are the cull modes i believe, i cannot remember which is which at the moment.

The mesh flags & 0x3000 is the type, and determines what type of data the offset at 0x14 points to.
  1. 0x2000 is envelope/weighted, so 0x14 points to the joint weight structures.
  2. 0x1000 are "shape sets", so 0x14 points to a different type of structure (have not finished investigating these, just using the terminology from the asm)).
  3. 0x0000 still need to verify.
So you cannot change those bits without making other data changes.

Planning on debugging through a lot of the structure handling soon, so hopefully i can fill out more of the data structures for different areas in order to get closer to completing the file format handling.
Code:
0x2000 = POBJ_ENVELOPE
0x1000 = POBJ_SHAPEANIM (0x24 in size)
0x0000 = POBJ_SKIN

#define HSD_DEFAULT_MAX_SHAPE_VERTICES 2000
#define HSD_DEFAULT_MAX_SHAPE_NORMALS 2000


ShapeSet
0x00    half    flags
                (0001) = SHAPESET_AVERAGE
                (0002) = SHAPESET_ADDITIVE
0x02    half    nb_shape
0x04    word    nb_vertex_index
0x08    point    vertex_desc
0x0C    point    vertex_idx_list    /* array */
0x10    word    nb_normal_index
0x14    point    normal_desc
0x18    point    normal_idx_list /* array */
0x1C    point    blend.bp /* array of floats of size (nb_shape * sizeof(float)) */
0x20    float    blend.bl
 
Last edited:

DRGN

Technowizard
Moderator
Joined
Aug 20, 2005
Messages
2,178
Location
Sacramento, CA
I've merged this thread with the "DAT File Research" thread to consolidate important information. There's no need for multiple threads on the subject. Due to the time differences between new and old posts between these threads, this didn't pose any continuity issues regarding conversations within them. I've left a permanent redirect for the old DAT File Research thread for those that might come looking for it later. revel8n seemed to like this merger idea, and zankyou is, well, still MIA....


On another note, I do have something DAT related to share. I wrote something for use at work to visualize debug workflows, and I realized it would be really interesting and useful to apply it to file structures. So I wrote a script to unravel DAT files and graph them. And I created this out of Y.Link's Blue costume file (PlClBu.dat):

PlClBu.dat_no_labels.png

Pretty cool.

Here's an svg of this, where you can zoom in and view structure offsets (similar to below). Blue nodes are structures that point to multiple other structures, yellow are those that are just an in-between, pointing to only one structure, and red are the branch ends of the file tree, which have no child structs.
PlClBu.dat_graph_example.png


They can also be output with more information per-node, like in this svg, but it's less pretty and much more difficult to read.

These can also be made into project files, where you can open up the graph and more easily view and color specific branches:
PlClBu.dat_graph_example2.png


Unfortunately, there are so many file structures that adding labels to them all makes everything unreadable. I only have a few more minutes at the moment, but I'll try to be back soon to post up some more files, scripts, workflows, and some practical applications.

Hopefully this reveals some interesting new structures or patterns when looking at other files like stages.
 

DRGN

Technowizard
Moderator
Joined
Aug 20, 2005
Messages
2,178
Location
Sacramento, CA
Finally had some more time to play with this. Instructions on how to generate these for more files are at the bottom half of this post.

I've just barely started, but so far using these as a roadmap for following data structures in a hex editor is pretty nice.

Here are renders of GrHe.dat (Rest Area Stage) and GrSt.dat (Yoshi's Story):
GrHe.dat (Rest Area, no labels).png GrSt.dat (Yoshi's Story, no labels).png

I added some more color indicators; gray are Root/Reference Tables and their nodes; orange/gold are structures larger than 0x100 bytes (usually textures). I'll need to change the latter though, as it's too close to yellow.

Anyone who's looked at stage dat files has probably already noticed the huge root/reference node tables they have. You can see those here as the gray nodes; they sprawl out and touch all sorts of things to identify them. I never looked at these too closely before, but I always assumed that the root nodes were the only entry points to various structures or branches in the file; apparently there are multiple such entry points, and it looks like many are only supplemental, for naming/description purposes. Makes more sense now. I figure they're left out of character DAT files to save space, since there are so many. But if the game doesn't use them for anything, why are they left in any file?


And here's an effects file (EfFxData.dat; Fox/Falco's Effects file):

EfFxData.dat (Fox & Falco Effects).png


A much more horizontal tree (many branches which aren't very deep). I've long since thought that all of the Ef__Data files contained more textures, but hadn't investigated beyond EfCoData. And the above graph shows 13 structures (again, the orage/gold nodes) that are good candidates for textures, while DTW currently only shows 5 textures for this file. Confirming those and getting DTW to recognize them in any file is a matter of understanding the structures directly above those nodes. Following in line with EfCoData, I think that some of these will be chunks of several textures end-to-end, in order to create texture animations (in a frame-by-frame manner), which explains why they wouldn't have the usual image data headers. Stratocaster Stratocaster What files are the structures that you mentioned here found in?


I encourage anyone to start checking out different files and structures yourself for any Melee technology/aspects (be it animations/stages/etc.) that you'd like to see advanced. Multiple sets of eyes or minds on the matter to look for patterns should help speed things up.

Here are some different files that I've already created graphs for: Test Files and Renderings. There are images and SVGs already generated in there, so you don't need anything but a browser to check most of them out.


To open the .gephi project files in the download above and view the graphs in the way you see in the screenshots above, you'll want to download Gephi. And for creating the layouts in the way I've been doing, you'll need to download and install the Network Splitter 3D plugin.


To start generating graphs and looking at new DATs yourself, you'll need python installed, and this script: DAT_Visualizer.py You'll also need the graphviz module to run this. If you have trouble installing it from the download there, you could try just downloading this graphviz package, and put the graphviz folder in the same directory as the DAT_Visualizer script. (To change node coloring for the 'larger than 0x100 bytes' structs, look for and comment-out or edit the line "if structLength >= 0x100: nodeColor = 'orange'".)

Pass the visualizer script a DAT file (one that has a relocation table), and it should create two basic graph-type files: a "___graph.gv" file and a "___graph.gv.svg" file. The SVG file can be opened in a browser, and you'll see structures and info on each one. You'll need to do a good amount of zooming out and/or scrolling, as the presentation there is a little unwieldy. The .gv file can be imported into Gephi, to beautify it and make it easier to work with. Instructions on how to do that are below. However, these are just recommendations from someone who has just started with this; it might very well be worth trying different layouts and arrangements to find different patterns. You could even experiment with totally different plug-ins for Gephi, found here.

1 ]-[ Importing ]

Upon importing the .gv file, there are a few options you can configure. I've been using these:

- Graph Type: Directed
- Auto-scale and Self-loops checked; Create missing nodes unchecked
- Edges merge strategy: Average or Do Not Merge​


2 ]-[ Graph Configuration (optional, but useful) ]

- Look for a light-bulb icon in the bottom-left of the Graph panel; use that to set a dark background color so you can better see the graph.
- To the right of that, look for a button to toggle "Edges have source node color" (I may later change the visualizer script so this isn't needed)
- Set node sizes to be based on number of child structures:
= In the Appearance panel in the top-left, click on Nodes.
= To the right of the tabs there, you'll see some buttons, click on the one that says Size when hovered over.
= Click on the Ranking tab (still in the Appearance panel).
= From the dropdown, choose "Out-Degree"
= Set Min size to ~22, and Max size to ~60
= Hit Apply at the bottom​


3 ]-[ Data Table adjustment ]

If you want to use the Network Splitter 3D layout, you need to add a new type of data to the nodes; a z-order attribute needs to be added. To do this, click on the Data Laboratory tab at the top of the program. Then, at the bottom of the program look for a big button that says "Duplicate column"; click on that, select "hierarchydepth" from the dropdown, and then in the window that pops up, add "[Z]" to the end of the title (it should now say "hierarchydepth_copy[Z]") and click OK. This will create an attribute on each node that tells the layout manager how to prioritize certain nodes on another dimension.

Now go back to the Overview tab, and look for the Statistics panel (should be on the right). At the top you should see "Average Degree". Click the Run button the right of that. This will calculate a few things and open a window, on which you can just hit close. This is also necessary before the Network Splitter 3D layout will work. I recommend saving your current work as a .gephi project file at this point.


4 ]-[ Node Arrangement ]

The graph will initially be loaded into a small square pattern; unlike screenshots I've shown. To move these points into new patterns, you'll want to apply some layouts (you'll see a panel in the bottom-left of the program where you can apply these). The choice on these is arbitrary, and just depends on how you think you might like to see the data. This is how I've been expanding some of mine, and what created some of the screenshots here:

- First, you might want to zoom out a little bit from the graph
- Run the "Yifan Hu" layout (at the bottom of the layout dropdown). Default values should be fine.
- [Optional] Run the Network Splitter 3D layout, with a Z-Maximum Level of 0. (Doing this before the next step seems to help alleviate crashes.)
- Run the Network Splitter 3D layout. Here are some values you might try starting with:
= Z-Maximum Level: 30-90
= Z-Distance Factor: 1 (essentially, this factors into the height of the graph)
= Z-Scale / Alfa: [Default]​

If you can't enter values for the Network Splitter 3D layout, Re-run the Average Degree Overview. Or, the program may have had an error; restart it. I'm not sure yet what causes a crash here, but I would just try different Z-Maximum levels; a successful render should only take a second or so.


5 ]-[ Graph Flip ]

You'll probably notice the file header and initial structures are at the bottom. While that might be more akin to an actual tree, I feel it makes a little more sense to look at the file top-down. You can flip the graph upside down by going to the layouts, and choose Rotate, input 180, and hit Run.



Once you've got the graph as you like, you can zoom in or manipulate it in the Graph tab, or go to the Preview tab at the very top, which allows you to set up how the graph will render if you want to export it as a PNG/SVG/PDF.

I'm interested to see what others generate and infer.
 
Last edited:

SinsOfApathy

Smash Journeyman
Joined
Feb 24, 2015
Messages
474
NNID
Psion312
Since the MObj and the associated is in need of some love and Killer7's source code has the header file for HSD formats. Unfortunately, the dump I have doesn't have the jobj.h, there's references to it in the other headers. I basically had to copy the headers for sysdolphin between us/jp/eu source code, because 1 header always seemed to be missing from each one of them.

It's possible I have a bad dump, but I doubt it.

Code:
struct MOBJ_DATA
{
// 0x00
uint32 class_name; //technically char*, always 0
uint32 rendermode;
uint32 tobjOffset <format = hex>; // tobj structure
uint32 materialOffset <format = hex>; // material colors?
// 0x10
uint32 renderdescOffset <format = hex>; // The original source code says, "付いていても無視" or "Ignore even if it's attached"
uint32 pedescOffset <format = hex>;
};

The comments below have 用, meaning for that function usage.

各種フラグ just means "Various flags"

Code:
struct PEDesc {
  u8    flags;           /*+ 各種フラグ */
  u8    ref0;          /*+ GXSetAlphaCompare()用 */
  u8    ref1;          /*+ GXSetAlphaCompare()用 */
  u8    dst_alpha;     /*+ GXSetDstAlpha()用 */
  u8      type;          /*+ GXSetBlendMode()用 */
  u8    src_factor;    /*+ GXSetBlendMode()用 */
  u8    dst_factor;    /*+ GXSetBlendMode()用 */
  u8    logic_op;      /*+ GXSetBlendMode()用 */
  u8    z_comp;        /*+ GXSetZMode()用 */
  u8    alpha_comp0;   /*+ GXSetAlphaCompare()用 */
  u8    alpha_op;      /*+ GXSetAlphaCompare()用 */
  u8    alpha_comp1;   /*+ GXSetAlphaCompare()用 */
}

Code:
struct MATERIAL_COLORS
{
// 0x00
uint32 ambient <format = hex>;
uint32 diffuse <format = hex>;
uint32 specular <format = hex>;
float alpha;
// 0x10
float shininess;
};

The IMAGE_HEADER differs in that sysdolphin has:
u32 mipmap;
f32 minLOD;
f32 maxLOD;

I'm pasting the contents of the TObj, since it's the main one that doesn't match up do to a sheer lack of information.

Code:
struct _HSD_TObj {
  HSD_Obj        object;     /*+ Object構造体*/
          
  struct _HSD_TObj  *next;      /*+ リンク*/
  GXTexMapID        id;         /*+ テクスチャID */
  GXTexGenSrc       src;        /*+ テクスチャ座標のソース*/
  u32            mtxid;      /*+ マトリクスID */
  Quaternion        rotate;     /*+ テクスチャ回転値 */
  Vec               scale;      /*+ テクスチャスケール値 */
  Vec               translate;  /*+ テクスチャリピート値 */
  GXTexWrapMode     wrap_s;     /*+ s方向ラップモード */
  GXTexWrapMode     wrap_t;     /*+ t方向ラップモード */
  u8                repeat_s;   /*+ s方向リピート値 */
  u8                repeat_t;   /*+ t方向リピート値 */
  u16            anim_id;    /*+ tobjdesc->id */

  u32               flag;    /*+ マッピングタイプ */
  /* Tex coord の生成タイプ */
# define TEX_COORD_UV           0  /*+ UVマッピング */
# define TEX_COORD_REFLECTION   1  /*+ リフレクションマッピング */
# define TEX_COORD_HILIGHT      2  /*+ ハイライトマッピング */
# define TEX_COORD_SHADOW       3  /*+ シャドウマッピング */
# define TEX_COORD_TOON     4  /*+ Toon */
  //FUJITA(グラデーション用に新設)
# define TEX_COORD_GRADATION    5
# define TEX_COORD_BACKLIGHT    6
# define TEX_COORD_MASK     (0x0f) /* マスク値 */
# define tobj_coord(T) ((T)->flag & TEX_COORD_MASK) /* マクロ*/

  /* tev の合成タイプ */
# define TEX_LIGHTMAP_DIFFUSE    (0x1<<4) /*+ diffuseマップ */
# define TEX_LIGHTMAP_SPECULAR    (0x1<<5) /*+ specularマップ */
# define TEX_LIGHTMAP_AMBIENT    (0x1<<6) /*+ ambientマップ */
# define TEX_LIGHTMAP_EXT    (0x1<<7) /*+ Reflection/Hilight 等 */
# define TEX_LIGHTMAP_SHADOW    (0x1<<8) /*+ shadowマップ */
# define TEX_LIGHTMAP_MASK \
  (TEX_LIGHTMAP_DIFFUSE \
   |TEX_LIGHTMAP_SPECULAR \
   |TEX_LIGHTMAP_AMBIENT \
   |TEX_LIGHTMAP_EXT \
   |TEX_LIGHTMAP_SHADOW) /* マスク値 */
# define tobj_lightmap(T) ((T)->flag & TEX_LIGHTMAP_MASK) /* マクロ*/

# define TEX_COLORMAP_NONE        (0<<16) /*+ カラーマップなし */
# define TEX_COLORMAP_ALPHA_MASK    (1<<16) /*+ アルファマスク */
# define TEX_COLORMAP_RGB_MASK        (2<<16) /*+ RGBマスク */
# define TEX_COLORMAP_BLEND        (3<<16) /*+ ブレンド */
# define TEX_COLORMAP_MODULATE        (4<<16) /*+ モジュレイト */
# define TEX_COLORMAP_REPLACE        (5<<16) /*+ リプレイス */
# define TEX_COLORMAP_PASS        (6<<16) /*+ パス */
# define TEX_COLORMAP_ADD        (7<<16) /*+ 加算 */
# define TEX_COLORMAP_SUB        (8<<16) /*+ 減算 */
# define TEX_COLORMAP_MASK        (0x0f<<16) /* マスク値 */
# define tobj_colormap(T) ((T)->flag & TEX_COLORMAP_MASK) /* マクロ*/

# define TEX_ALPHAMAP_NONE        (0<<20) /*+ アルファマップなし */
# define TEX_ALPHAMAP_ALPHA_MASK    (1<<20) /*+ アルファマスク */
# define TEX_ALPHAMAP_BLEND        (2<<20) /*+ ブレンド */
# define TEX_ALPHAMAP_MODULATE        (3<<20) /*+ モジュレイト */
# define TEX_ALPHAMAP_REPLACE        (4<<20) /*+ リプレイス */
# define TEX_ALPHAMAP_PASS        (5<<20) /*+ パス */
# define TEX_ALPHAMAP_ADD        (6<<20) /*+ 加算 */
# define TEX_ALPHAMAP_SUB        (7<<20) /*+ 減算 */
# define TEX_ALPHAMAP_MASK        (0x0f<<20) /* マスク値 */
# define tobj_alphamap(T) ((T)->flag & TEX_ALPHAMAP_MASK) /* マクロ*/

# define TEX_BUMP            (0x1<<24) /*+ bumpマップ */
# define tobj_bump(T) ((T)->flag & TEX_BUMP) /* マクロ */
# define TEX_MTX_DIRTY            (1<<31) /* internal use only */
  float             blending;   /*+ blend 値 */
  GXTexFilter        magFilt;    /*+ texel/pixel > 1.0の時に用いられる
                  テクスチャフィルタータイプ */
  HSD_ImageDesc        *imagedesc; /*+ ImageDescへのポインタ */
  HSD_Tlut          *tlut;      /*+ Tlutへのポインタ */
  HSD_TexLODDesc    *lod;    /*+ LODDescへのポインタ */
  struct _HSD_AObj  *aobj;      /*+ AObjへのポインタ */
  HSD_ImageDesc        **imagetbl; /*+ テクスチャスイッチ用イメージテーブル */
  HSD_Tlut        **tluttbl;    /*+ TLUTスイッチ用テーブル */
  u8            tlut_no;    /*+ パレットアニメーションのカレントtlut番号。
                      (u8) -1 はカレントtlutがセットされていない
                    ことを表す。この場合はメンバ tlutが使用
                    される。 */
  Mtx             mtx;        /*+ テクスチャマトリクス */
  GXTexCoordID        coord;      /*+ テクスチャ座標出力先 */
  HSD_TObjTev       *tev;    /*+ 一段Tev設定 */
};

What we have defined as a PALLETE_HEADER is either wrong or was changed later in the library.

Code:
/*+
* HSD_Tlut 構造体はテクスチャのパレット情報を保持する構造体である。
*/
typedef struct _HSD_Tlut {
  void          *lut;        /*+ テクスチャルックアップテーブル */
  GXTlutFmt     fmt;        /*+ tlut フォーマット */
  u32           tlut_name;    /*+ tlut 名 (割り当て結果が格納される) */
  u16           n_entries;    /*+ パレット数 */
} HSD_Tlut;
 
Last edited:

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
DRGN DRGN your project is so awesome. Graphics like these really help illustrate the bounds of something too abstract to think of as a whole. I really admire stuff like what you’re doing.

I encourage anyone to start checking out different files and structures yourself for any Melee technology/aspects (be it animations/stages/etc.) that you'd like to see advanced. Multiple sets of eyes or minds on the matter to look for patterns should help speed things up.
I have a couple of short lectures saved that talk about various methods of visualizing strings of binary with little to no preconceptions about how it is structured. Either makes for a great watch during lunch or something:

-- https://www.youtube.com/watch?v=4bM3Gut1hIk -- Derbycon 2012 - Chris Domas demoing Cantor Dust
-- https://www.youtube.com/watch?v=T3qqeP4TdPA -- Blackhat 2010 - Greg Conti, Sergey Bratus

These go over various byte plotting methods, and ways of using tuple graphs to see patterns and relationships very quickly from unknown strings of binary.

---

Here are a couple of tools that use some of the concepts talked about in the above lectures. You can use them to explore any binary, like Melee files:

Binvis - www.binvis.io
This tool is useful for visualizing entropy in byte sequences, and can be useful for finding where different regions in a file are located

https://i.imgur.com/UgvW1fk.png - https://i.imgur.com/U9ufOYw.png

It’s particularly good at finding ascii. For instance, see DbCo.dat:
https://i.imgur.com/c56Zp7o.png
The blue curves are text, with the black sections representing null termination bytes.

---

Veles - https://codisec.com/veles/
Hex editor that includes some tools inspired by the Cantor Dust demo.

They go over most of the features and explain some concepts in this page

https://i.imgur.com/kkOfnRr.png -- https://i.imgur.com/2DFWNye.png
---

I've merged this thread with the "DAT File Research" thread to consolidate important information. There's no need for multiple threads on the subject.
I’ve been accumulating a lot of info that has mostly to do with RAM data, but is very closely tied to all of the file data objects mentioned in this thread.

I was considering starting a thread about HSD objects, but this is probably the best place to post it now. It’s a lot to go over though, so I’ll just make a followup post soon with a big info dump.

---

Since the MObj and the associated is in need of some love and Killer7's source code has the header file for HSD formats. Unfortunately, the dump I have doesn't have the jobj.h, there's references to it in the other headers. I basically had to copy the headers for sysdolphin between us/jp/eu source code, because 1 header always seemed to be missing from each one of them.

It's possible I have a bad dump, but I doubt it.

Code:
struct MOBJ_DATA
{
// 0x00
uint32 class_name; //technically char*, always 0
uint32 rendermode;
uint32 tobjOffset <format = hex>; // tobj structure
uint32 materialOffset <format = hex>; // material colors?
// 0x10
uint32 renderdescOffset <format = hex>; // The original source code says, "付いていても無視" or "Ignore even if it's attached"
uint32 pedescOffset <format = hex>;
};

The comments below have 用, meaning for that function usage.

各種フラグ just means "Various flags"

Code:
struct PEDesc {
  u8    flags;           /*+ 各種フラグ */
  u8    ref0;          /*+ GXSetAlphaCompare()用 */
  u8    ref1;          /*+ GXSetAlphaCompare()用 */
  u8    dst_alpha;     /*+ GXSetDstAlpha()用 */
  u8      type;          /*+ GXSetBlendMode()用 */
  u8    src_factor;    /*+ GXSetBlendMode()用 */
  u8    dst_factor;    /*+ GXSetBlendMode()用 */
  u8    logic_op;      /*+ GXSetBlendMode()用 */
  u8    z_comp;        /*+ GXSetZMode()用 */
  u8    alpha_comp0;   /*+ GXSetAlphaCompare()用 */
  u8    alpha_op;      /*+ GXSetAlphaCompare()用 */
  u8    alpha_comp1;   /*+ GXSetAlphaCompare()用 */
}

Code:
struct MATERIAL_COLORS
{
// 0x00
uint32 ambient <format = hex>;
uint32 diffuse <format = hex>;
uint32 specular <format = hex>;
float alpha;
// 0x10
float shininess;
};

The IMAGE_HEADER differs in that sysdolphin has:
u32 mipmap;
f32 minLOD;
f32 maxLOD;

I'm pasting the contents of the TObj, since it's the main one that doesn't match up do to a sheer lack of information.

Code:
struct _HSD_TObj {
  HSD_Obj        object;     /*+ Object構造体*/
     
  struct _HSD_TObj  *next;      /*+ リンク*/
  GXTexMapID        id;         /*+ テクスチャID */
  GXTexGenSrc       src;        /*+ テクスチャ座標のソース*/
  u32            mtxid;      /*+ マトリクスID */
  Quaternion        rotate;     /*+ テクスチャ回転値 */
  Vec               scale;      /*+ テクスチャスケール値 */
  Vec               translate;  /*+ テクスチャリピート値 */
  GXTexWrapMode     wrap_s;     /*+ s方向ラップモード */
  GXTexWrapMode     wrap_t;     /*+ t方向ラップモード */
  u8                repeat_s;   /*+ s方向リピート値 */
  u8                repeat_t;   /*+ t方向リピート値 */
  u16            anim_id;    /*+ tobjdesc->id */

  u32               flag;    /*+ マッピングタイプ */
  /* Tex coord の生成タイプ */
# define TEX_COORD_UV           0  /*+ UVマッピング */
# define TEX_COORD_REFLECTION   1  /*+ リフレクションマッピング */
# define TEX_COORD_HILIGHT      2  /*+ ハイライトマッピング */
# define TEX_COORD_SHADOW       3  /*+ シャドウマッピング */
# define TEX_COORD_TOON     4  /*+ Toon */
  //FUJITA(グラデーション用に新設)
# define TEX_COORD_GRADATION    5
# define TEX_COORD_BACKLIGHT    6
# define TEX_COORD_MASK     (0x0f) /* マスク値 */
# define tobj_coord(T) ((T)->flag & TEX_COORD_MASK) /* マクロ*/

  /* tev の合成タイプ */
# define TEX_LIGHTMAP_DIFFUSE    (0x1<<4) /*+ diffuseマップ */
# define TEX_LIGHTMAP_SPECULAR    (0x1<<5) /*+ specularマップ */
# define TEX_LIGHTMAP_AMBIENT    (0x1<<6) /*+ ambientマップ */
# define TEX_LIGHTMAP_EXT    (0x1<<7) /*+ Reflection/Hilight 等 */
# define TEX_LIGHTMAP_SHADOW    (0x1<<8) /*+ shadowマップ */
# define TEX_LIGHTMAP_MASK \
  (TEX_LIGHTMAP_DIFFUSE \
   |TEX_LIGHTMAP_SPECULAR \
   |TEX_LIGHTMAP_AMBIENT \
   |TEX_LIGHTMAP_EXT \
   |TEX_LIGHTMAP_SHADOW) /* マスク値 */
# define tobj_lightmap(T) ((T)->flag & TEX_LIGHTMAP_MASK) /* マクロ*/

# define TEX_COLORMAP_NONE        (0<<16) /*+ カラーマップなし */
# define TEX_COLORMAP_ALPHA_MASK    (1<<16) /*+ アルファマスク */
# define TEX_COLORMAP_RGB_MASK        (2<<16) /*+ RGBマスク */
# define TEX_COLORMAP_BLEND        (3<<16) /*+ ブレンド */
# define TEX_COLORMAP_MODULATE        (4<<16) /*+ モジュレイト */
# define TEX_COLORMAP_REPLACE        (5<<16) /*+ リプレイス */
# define TEX_COLORMAP_PASS        (6<<16) /*+ パス */
# define TEX_COLORMAP_ADD        (7<<16) /*+ 加算 */
# define TEX_COLORMAP_SUB        (8<<16) /*+ 減算 */
# define TEX_COLORMAP_MASK        (0x0f<<16) /* マスク値 */
# define tobj_colormap(T) ((T)->flag & TEX_COLORMAP_MASK) /* マクロ*/

# define TEX_ALPHAMAP_NONE        (0<<20) /*+ アルファマップなし */
# define TEX_ALPHAMAP_ALPHA_MASK    (1<<20) /*+ アルファマスク */
# define TEX_ALPHAMAP_BLEND        (2<<20) /*+ ブレンド */
# define TEX_ALPHAMAP_MODULATE        (3<<20) /*+ モジュレイト */
# define TEX_ALPHAMAP_REPLACE        (4<<20) /*+ リプレイス */
# define TEX_ALPHAMAP_PASS        (5<<20) /*+ パス */
# define TEX_ALPHAMAP_ADD        (6<<20) /*+ 加算 */
# define TEX_ALPHAMAP_SUB        (7<<20) /*+ 減算 */
# define TEX_ALPHAMAP_MASK        (0x0f<<20) /* マスク値 */
# define tobj_alphamap(T) ((T)->flag & TEX_ALPHAMAP_MASK) /* マクロ*/

# define TEX_BUMP            (0x1<<24) /*+ bumpマップ */
# define tobj_bump(T) ((T)->flag & TEX_BUMP) /* マクロ */
# define TEX_MTX_DIRTY            (1<<31) /* internal use only */
  float             blending;   /*+ blend 値 */
  GXTexFilter        magFilt;    /*+ texel/pixel > 1.0の時に用いられる
                  テクスチャフィルタータイプ */
  HSD_ImageDesc        *imagedesc; /*+ ImageDescへのポインタ */
  HSD_Tlut          *tlut;      /*+ Tlutへのポインタ */
  HSD_TexLODDesc    *lod;    /*+ LODDescへのポインタ */
  struct _HSD_AObj  *aobj;      /*+ AObjへのポインタ */
  HSD_ImageDesc        **imagetbl; /*+ テクスチャスイッチ用イメージテーブル */
  HSD_Tlut        **tluttbl;    /*+ TLUTスイッチ用テーブル */
  u8            tlut_no;    /*+ パレットアニメーションのカレントtlut番号。
                      (u8) -1 はカレントtlutがセットされていない
                    ことを表す。この場合はメンバ tlutが使用
                    される。 */
  Mtx             mtx;        /*+ テクスチャマトリクス */
  GXTexCoordID        coord;      /*+ テクスチャ座標出力先 */
  HSD_TObjTev       *tev;    /*+ 一段Tev設定 */
};

What we have defined as a PALLETE_HEADER is either wrong or was changed later in the library.

Code:
/*+
* HSD_Tlut 構造体はテクスチャのパレット情報を保持する構造体である。
*/
typedef struct _HSD_Tlut {
  void          *lut;        /*+ テクスチャルックアップテーブル */
  GXTlutFmt     fmt;        /*+ tlut フォーマット */
  u32           tlut_name;    /*+ tlut 名 (割り当て結果が格納される) */
  u16           n_entries;    /*+ パレット数 */
} HSD_Tlut;
These are great! Your notes about TObjs confirm something I’d like to go over in more detail about AObjs.

Basically, AObjs are "Animation" objects that connect multiple types of objects to FObj chains, or "Frame" data objects.

JObjs, TObjs, RObjs, and I think CObjs can use AObj structures to sort of plug into scripted animation data.

I'll go over this more in my followup post later. I haven't been looking at the leaked killer7 stuff for a lack of understanding how, but the CSM updates have helped me considerably in terms of understanding file and instance structure.

---

Stratocaster Stratocaster What files are the structures that you mentioned here found in?
They are in the character files like PlCa (for Captain Falcon). Hope that helps.

You guys talking about subaction events?

The [28] player event is pretty well understood at this point.

I have some notes on an old pen and paper scratchpad from years back that breaks down how the event data is just a string of compressed arguments passed as parameters to a more general function.

This parse function actually taught me how powerpc does float casting. My old chicken scratch suggests:
Code:
event [28]: Spawn GFX
Parse function scans 5 words for params in order to set up a call to function 80086960: GFX_EffectSpawn
r3 = player entity
r4 = GFX ID  - concatenated index of general and unique graphics?
r5 = JObj ID - player skeleton, 0-based
r6 = unk bool
r7 = unk bool
r8 = XYZ float array -- Origin; relative to JObj
r9 = XYZ float array -- scatter amount

As event string:
L = event Line 0-4 (word alignment for mask)
M = hexadecimal bitmask containing x-bit integer
L MMMMMMMM -  X-BIT -- DESCRIPTION

0 FC000000 -  6-bit -- (opcode int - 0xA) = player event index
0 03FC0000 -  8-bit -- JObj ID = r5
0 00020000 -  1-bit -- bool = r6
0 00010000 -  1-bit -- bool = r7
0 0000FFFF -  -- unused bits
1 FFFF0000 - 16-bit -- GFX ID = r4
1 0000FFFF - 16-bit -- unknown signed float = f1
2 FFFF0000 - 16-bit -- X Origin = 0x0(r8)
2 0000FFFF - 16-bit -- Y Origin = 0x4(r8)
3 FFFF0000 - 16-bit -- Z Origin = 0x8(r8)
3 0000FFFF - 16-bit -- X Scatter = 0x0(r9)
4 FFFF0000 - 16-bit -- Y Scatter = 0x4(r9)
4 0000FFFF - 16-bit -- Z Scatter = 0x8(r9)

r8 floats are cast as signed fixed points:
0xFF.FF - 8 bit UINT + 8-bit mantissa

r9 floats are cast as unsigned fixed points:
0xFF.FF - 8-bit SINT + 8-bit mantissa
IIRC, one of those unk bools makes the graphic unattached from the JObj after spawning; but I haven’t checked it out in awhile.

I also have a post in Itaru’s moveset data thread with function addresses of every event callback I could find. Of the 5 parser functions, one is dedicated to executing player events, and another is dedicated to executing projectile events.

80071028 - parses Player GFX events -- some IDs of which are tied to the loaded player character files.

80278F2C - parses Projectile GFX events

Other player events, such as “body auras” will assign graphics; and there are also macro events that combine a GFX ID with a SFX ID to shorten the existing GFX and SFX syntaxes for the sake of making footstep effects, or landing effects.
 
Last edited:

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
If you'll pardon the double-post, I thought it appropriate since I go over quite a bit here:
  • Persistent Objects
    • understanding the difference between Live Objects vs File Object Descriptions
  • HSD Info Tables
    • How some objects use HSD Info Tables to function with some amount of automation
  • Melee HSD Info Samples
    • HSD Info Table samples - includes WObj, CObj, Fog Object, and LObj
  • DAT Allocations
    • DAT File allocation references in RAM
  • Player HUD structure
    • An example of a simple skeleton structure using IfAll.dat
  • JObj Kings and Entity Emperors
    • How JObjs wrapped with data make class types like "players" and "items"
  • HSD_JObjAddAnim
    • How the player HUD structure loads AObjDescs to animate joints and textures
Edit: Clarify arguments for HSD_JObjAddAnimAll_Indexed

---

Several months ago, @Itaru asked for a code that added a 4th digit to the player damage HUD. My research into the matter has kept me busy because there’s a lot to learn regarding HSD objects.

Specifically -- things about how procedurally assigned AObjs may be used to animate (and sometimes initialize) JObjs and TObjs.

This applies to characters, menus, stages, and anything else that might be transformed as a joint or a texture.

---

Persistent Objects

In order to distinguish between live instances and their respective file data descriptions, my notes refer to file data objects by appending a “-Desc” suffix to their HSD object name. This is based on my observations of a few symbol names leaked from the killer7 csm renaissance.

A live JObj is different from what I’ll be calling a JObjDesc -- the latter being the structure you are all probably familiar with.

https://i.imgur.com/Z1BLztx.png


The following information about the structure of file data objects has mostly been obtained from DTW , Tcll Tcll 's wiki, and posts in this thread.

Edit 8/26/2018 - Filled in blanks thanks to SinsOfApathy SinsOfApathy 's Melee Reassembled project.

Compare the two types of each object listed here to get an idea of how the structures differ:
Code:
Data types:
P    = pointer address
B    = byte
S    = short (hword, 2-byte)
W    = word (4-byte)
F    = floating point (single)
D    = floating point (double)
##   = array of bytes
(##) = bitmask (byte)

JObjDesc = Joint Object File Description
Code:
JObjDesc - 0x40 bytes
0x00    W    Class Name
0x04    W    Flags
0x08    P    to JObjDesc Child
0x0C    P    to JObjDesc Sibling
0x10    P    to DObjDesc
0x14    F    X Rotation
0x18    F    Y Rotation
0x1C    F    Z Rotation
0x20    F    X Scale
0x24    F    Y Scale
0x28    F    Z Scale
0x2C    F    X Translation
0x30    F    Y Translation
0x34    F    Z Translation
0x38    P    to inverse transform matrix
0x3C    P    to RObjDesc -- not used for procedural RObj assignments?
                          -- which seems to be like, all of them?
JObj = Live Joint Object
Code:
JObj - 0x88 bytes
0x00    P    to HSD_Info table
0x04    W    Class Parent
0x08    P    to JObj Sibling
0x0C    P    to JObj Parent
0x10    P    to JObj Child
0x14    W    Flag word, 32 bits
0x18    P    to DObjDesc Link      -- assigns a Material and Polygon object to this joint. Note this is a live DObj, not a DObjDesc
                                - resulting display is heavily influenced by JOBj flags and transformation values
0x1C    F    Quaternion Rotation X
0x20    F    Quaternion Rotation Y
0x24    F    Quaternion Rotation Z
0x28    F    Quaternion Rotation W
0x2C    F    Local X Scale
0x30    F    Local Y Scale
0x34    F    Local Z Scale     -- Scale
0x38    F    Local X Translation
0x3C    F    Local Y Translation
0x40    F    Local Z Translation -- Translation
0x44    F    Absolute X matrix 0x0  - shear? -- rotation 1 1 (effects rotation, skew, and scale?)
0x48    F    Absolute X matrix 0x4  - ?      -- rotation 1 2
0x4C    F    Absolute X matrix 0xC  - ?      -- rotation 1 3
0x50    F    Absolute X matrix 0x10 - global translation -- Absolute X position
0x54    F    Absolute Y matrix 0x0  - shear? -- rotation 2 1
0x58    F    Absolute Y matrix 0x4  - ?      -- rotation 2 2
0x5C    F    Absolute Y matrix 0xC  - ?      -- rotation 2 3
0x60    F    Absolute Y matrix 0x10 - global translation -- Absolute Y position
0x64    F    Absolute Z matrix 0x0  - shear? -- rotation 3 1
0x68    F    Absolute Z matrix 0x4  - ?      -- rotation 3 2
0x6C    F    Absolute Z matrix 0xC  - ?      -- rotation 3 3
0x70    F    Absolute Z matrix 0x10 - global translation -- Absolute Z position
0x74    P    to "VEC"    --  used in calls to 8037A65C : HSD_VecFree
0x78    P    to "MTX"    -- instantiated copy of inverse transform matrix
0x7C    P    to AObj     -- AObj struct keeps track of timers, flags, and pointers related to animating JObjs.
0x80    P    to RObj     -- Some JObjs will reference another JObj from a different hierarchy through an RObj container
                          - For example, Fox's shine graphic has a bone that links to Fox using RObj links
0x84    P    to JObjDesc -- This points to the start of the source JObj definition in a file loaded from disk into RAM.
                          - These pointers are extremely useful for researching file data

DObjDesc = Display Object File Description
Code:
DObjDesc - 0x10 bytes
0x00    W    Class Name
0x04    P    to Sibling DObjDesc
0x08    P    to MObjDesc
0x0C    P    to PObjDesc
DObj = Live Display Object
Code:
DObj - 0x18 bytes
0x00    P    to HSD_Info table
0x04    P    to Sibling DObj   -- Multiple DObjs may be linked together
0x08    P    to MObj           -- Material Object Link - texture assets and params
0x0C    P    to PObj           -- Polygon Object Link  - mesh vertex and weight params
0x10    W    unknown
0x14    W    Flags             -- Flags can be seen being set on some DObj initializations


PObjDesc = Polygon Object File Description
Code:
PObjDesc - 0x18 bytes
0x00    W    Class Name
0x04    P    to Sibling PObjDesc
0x08    P    to Vertex Attributes Array
0x0C    S    Flags
0x0E    S    Display List Blocks
0x10    P    to Display List Data
0x14    P    to Influence Matrix Array
PObj = Live Polygon Object
Code:
PObj - 0x18 bytes
0x00    P    to HSD_Info table
0x04    P    to Sibling PObj
0x08    P    to Vertex Attributes Array
0x0C    S    Flags
0x0E    S    Display List Blocks
0x10    P    to Display List Data
0x14    P    to Influence Matrix Array


MObjDesc = Material Object File Description
Code:
MObjDesc - 0x18 bytes
0x00    W    Class Name
0x04    W    Flags? "Render Mode"
0x08    P    to TObjDesc
0x0C    P    to Material Color Instance
0x10    P    to Render Struct
0x14    P    to PEDesc (Pixel Processor Struct)
MObj = Live Material Object
Code:
MObj - 0x18 bytes
0x00    P    to HSD_Info table
0x04    W    Flags? "Render Mode"
0x08    P    to TObj -- Texture link
0x0C    P    to Material Color Instance -- Texture color properties
0x10    P    to Render Struct
0x14    P    to PEDesc (Pixel Processor Struct)


TObjDesc = Texture Object File Description
Code:
TObjDesc - 0x5C bytes
0x00    W    Class Name
0x04    P    to Sibling TObjDesc
0x08    W    GXTexMapID
0x0C    W    Coord Gen Source Args (GXTexGenSrc)
0x10    F    Rotation X
0x14    F    Rotation Y
0x18    F    Rotation Z
0x1C    F    Scale X
0x20    F    Scale Y
0x24    F    Scale Z
0x28    F    Translation X
0x2C    F    Translation Y
0x30    F    Translation Z
0x34    W    Wrap S (GXTexWrapMode)
0x38    W    Wrap T (GXTexWrapMode)
0x3C    b    Repeat S
0x3D    b    Repeat T
0x3E    s    (padding)
0x40    W    Flags
0x44    F    Blending
0x48    W    Mag Filter (GXTexFilter)
0x4C    P    to Image Header (ImageDesc)
0x50    P    to Palette Header (TlutDesc)
0x54    P    to LOD Structure (TexLODDesc)
0x58    P    to TEV Structure (TObjTevDesc)
TObj = Live Texture Object
Code:
TObj - 0xAC bytes
0x00    P    to HSD_Info table
0x04    W    Object
0x08    P    to next TObj
0x0C    W    GXTexMapID
0x10    W    Coord Gen Source Args (GXTexGenSrc)
0x14    W    MTX id
0x18    W    Quaternion Rotation X
0x1C    F    Quaternion Rotation Y
0x20    F    Quaternion Rotation Z
0x25    F    Quaternion Rotation W
0x28    F    Scale X
0x2C    F    Scale Y
0x30    F    Scale Z
0x34    F    Translation X
0x38    F    Translation Y
0x3C    F    Translation Z
0x40    W    Wrap S (GXTexWrapMode)
0x44    W    Wrap T (GXTexWrapMode)
0x48    B    Repeat S
0x49    B    Repeat T
0x4A    S    (padding)
0x4C    W    Texture Flags
0x50    F    Blending
0x54    W    Mag Filter (GXTexFilter)
0x58    P    to Image Header in file data (ImageDesc)
0x5C    P    to Palette Header Instance (TlutDesc)
0x60    P    to Level of Detail Struct in file data (TexLODDesc)
0x64    P    to AObj --  (see blinking)
0x68    P    to start of image index for animated textures (imagetbl)
0x6C    P    to start of image palette index for animate textures (tluttbl)
0x70    B    Tlut_no
0x71    3    (padding)
0x74    F    MTX 1, 1
0x78    F    MTX 1, 2
0x7C    F    MTX 1, 3
0x80    F    MTX 1, 4
0x85    F    MTX 2, 1
0x88    F    MTX 2, 2
0x8C    F    MTX 2, 3
0x90    F    MTX 2, 4
0x94    F    MTX 3, 1
0x98    F    MTX 3, 2
0x9C    F    MTX 3, 3
0xA0    F    MTX 3, 4
0xA4    F    GXTexCoordID
0xA8    P    to TEV Struct (TObjTevDesc)


AObjDesc = Animation Object File Description
Code:
AObjDesc - 0x10 bytes
0x00    W    unk
0x04    F    End Frame
0x08    P    to Root FObjDesc
0x0C    W    obj_id
AObj = Live Animation Object
Code:
AObj - 0x18 bytes
0x00    W    Flags
0x04    F    current animation frame
0x08    F    Rewind frame --  see 8036531C : HSD_AObjSetRewindFrame
0x0C    F    End frame    --  see 8036532C : HSD_AObjSetEndFrame
0x10    F    frame rate of animation
0x14    P    to FObj
0x18    P    to unk JObj (or possibly HSD_Obj)


FObjDesc = Frame Data Object File Description
Code:
FObjDesc - 0x14 bytes
0x00    P    to Next FObjDesc
0x04    W    Data String length -- bytes -- includes null termination byte
0x08    W    unk
0x0C    W    flags
0x10    P    to Data String
FObj = Live Frame Data Parse Object
Code:
FObj - 0x34 bytes
0x00    P    to next FObj     -- used for X, Y, and Z data, I believe
0x04    P    to current Parse -- Parses 1 byte of data at a time, stopping at keyframes
0x08    P    to Parse start   -- a body of data copied over to a buffer from FObjDesc ?
0x0C    W    length of data to parse
0x10        unk -- I believe these are temporary values used to operate on MTX
0x14        unk -- like JObjs and TObjs, these seem to mostly comprise of floats
0x18        unk -- like JObjs and TObjs, File Desc objects contain no such array
0x1C        unk
0x20        unk
0x24        unk
0x28        unk
0x2C        unk
0x30        unk


RObjDesc = Reference Object File Description
Code:
unknown
RObj = Live Reference Object
Code:
RObj - 0x1C bytes
0x00    P    unk - something to do with allocation
0x04    W    Flags
0x08    P    JObj Constraint
0x0C    W    unk
0x10    W    unk
0x14    W    unk
0x18    P    to AObj -- needs more research

---

HSD Info Tables

A handful of HSD objects make use of what’s called an “HSD Info table” when instantiating from file data. These include JObjs, DObjs, PObjs, MObjs, and TObjs from the definitions above -- but not AObjs, FObjs, or RObjs. In fact, most HSD structures don’t use them at all.

The objects that use info tables however rely on them to do basic things; like create instances:

https://i.imgur.com/MwYlOhB.png


HSD Info tables describe a list of callback routines for an object of a specific class type.

These callbacks are used to create default behaviors for all objects of said type. The first 5 callbacks in the list are standardized as follows:

slot 1 - 0x28 - Obj Alloc
slot 2 -
0x2C - Obj Init
slot 3 -
0x30 - Obj Release
slot 4 -
0x34 - Obj Destroy
slot 5 -
0x38 - Obj Amnesia
slot 6+ (unique)


Each info table links a function to these slots. Some object info tables will contain additional callbacks, which serve unique purposes specific to that object type.

---

Generic Info Table Structure:
Code:
Generic Info Table structure:

0x00 - Info table initialization callback
     -- when the first object of a type is used, this callback function
        activates the info table and initializes all of the following params

0x04 - Active status flag
     -- 1 == active, 0 == inactive

0x08 - lib name string
0x0C - class name string

0x10 - HWORD - size of object allocation
0x12 - HWORD - size of info table

0x14 - Parent class info table
0x18 - Sibling class info table
0x1C - Child class info table
     -- info tables inform functions about how classes are related
        order of siblings depends on order of info table activation

0x20 - Active object instances
0x24 - Total allocations available
     -- the total will rise to meet the needs of active object instances
     -- the “amnesia” callback appears to be responsible for wiping this to 0

0x28 - Object allocation callback
0x2C - Object initialization callback
0x30 - Object release callback
0x34 - Object destroy callback
0x38 - Object amnesia callback

0x3C+ specialized function callbacks

---

The function hsdNew works by passing one of these info table addresses as argument r3:
Code:
- if the given info table is inactive,
  -> callback event 0x00 = Info Table initialization callback

-> callback event 0x28 = Object allocation callback

- if returned allocation is null,
  <- return null object address

- zero out allocation space
- store info table address at 0x00(alloc)
- use returned allocation address as r3 arg
-> callback event 0x2C = Object initialization callback

- if returned object address is null,
  -> callback event 0x34 = Object destroy callback
  <- return null object
- else,
  <- return new HSD object address

The function is using the generic HSD callback slots in the info table to handle the work of creating a new HSD object; regardless of which type it is given.

https://i.imgur.com/ZIWCi1z.png


Info tables use child/sibling links to imply an inheritance tree structure. Some functions will refer to an info table’s parent structure for callbacks.

From these, we can even find a few object types that have yet to be explored:

LObj - 0xD4 object size -- Achilles says, “Light Object”
CObj - 0x8C object size -- Achilles says, “Camera Object”
WObj - 0x20 object size -- (world object? window object?)
Fog - 0x20 object size -- fog object


---

Melee HSD Info Table Samples
Screenshot from:

1.02
Melee: 4-player
stage: Venom
6 player entities
no item entities
Code:
80407590
hsdClass_info_head
       Info Init ->    0x00    803822C0
      Status flag :    0x04    00000001
    Library name ->    0x08    804076A4
      Class name ->    0x0C    804076BC
      Object Size :    0x10    0004
        Info Size :    0x12    003C
    Class Parent ->    0x14    00000000
   Class Sibling ->    0x18    00000000
     Class Child ->    0x1C    80406398
      Active Objs :    0x20    00000000
     Total Allocs :    0x24    00000000
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    80382224
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80382294


80406398
hsd_PObj_info
       Info Init ->    0x00    8036EB88
      Status flag :    0x04    00000001
    Library name ->    0x08    804066E4
      Class name ->    0x0C    804066FC
      Object Size :    0x10    0018
        Info Size :    0x12    0048
    Class Parent ->    0x14    80407590
   Class Sibling ->    0x18    80405E28
     Class Child ->    0x1C    803C0998
      Active Objs :    0x20    000001FE
     Total Allocs :    0x24    00000220
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    8036E9F0
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    8036EB14
       PObj Disp ->    0x3C    8036E8AC
       Setup MTX ->    0x40    8036E83C
       PObj Load ->    0x44    8036BDA0

803C0998
ft_PObj_info
       Info Init ->    0x00    800740E4
      Status flag :    0x04    00000001
    Library name ->    0x08    803C09E0
      Class name ->    0x0C    804D3A50
      Object Size :    0x10    0018
        Info Size :    0x12    0048
    Class Parent ->    0x14    80406398
   Class Sibling ->    0x18    00000000
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    00000257
     Total Allocs :    0x24    00000257
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    8036E9F0
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    8036EB14
       PObj Disp ->    0x3C    8036E8AC
       Setup MTX ->    0x40    80074048
       PObj Load ->    0x44    800226A8


80405E28
hsd_MObj_info
       Info Init ->    0x00    80363F28
      Status flag :    0x04    00000001
    Library name ->    0x08    80405F90
      Class name ->    0x0C    80405FA8
      Object Size :    0x10    0020
        Info Size :    0x12    0050
    Class Parent ->    0x14    80407590
   Class Sibling ->    0x18    80405450
     Class Child ->    0x1C    803C6980
      Active Objs :    0x20    000001FE
     Total Allocs :    0x24    00000218
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    80363E28
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80363EC4
      MObj Setup ->    0x3C    80363A24
       MObj Load ->    0x40    80363144
       Make TExp ->    0x44    80363284
  MObj Setup Tev ->    0x48    803639AC
      MObj Unset ->    0x4C    80363B68

803F1F90
it_MObj_info
       Info Init ->    0x00    80277D08
      Status flag :    0x04    00000000
    Library name ->    0x08    803F206C
      Class name ->    0x0C    804D51B0
      Object Size :    0x10    0020
        Info Size :    0x12    0050
    Class Parent ->    0x14    00000000
   Class Sibling ->    0x18    00000000
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    00000000
     Total Allocs :    0x24    00000000
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    80363E28
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80363EC4
      MObj Setup ->    0x3C    80277D8C
       MObj Load ->    0x40    80363144
       Make TExp ->    0x44    80363284
  MObj Setup Tev ->    0x48    803639AC
      MObj Unset ->    0x4C    80363B68

803C6980
ft_MObj_info
       Info Init ->    0x00    800BF260
      Status flag :    0x04    00000001
    Library name ->    0x08    803C6A5C
      Class name ->    0x0C    804D3C00
      Object Size :    0x10    0020
        Info Size :    0x12    0050
    Class Parent ->    0x14    80405E28
   Class Sibling ->    0x18    00000000
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    000001C5
     Total Allocs :    0x24    000001C5
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    80363E28
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80363EC4
      MObj Setup ->    0x3C    800BF2B8
       MObj Load ->    0x40    80363144
       Make TExp ->    0x44    80363284
  MObj Setup Tev ->    0x48    803639AC
      MObj Unset ->    0x4C    80363B68


80405450
hsd_DObj_info
       Info Init ->    0x00    8035E4E4
      Status flag :    0x04    00000001
    Library name ->    0x08    80405548
      Class name ->    0x0C    80405560
      Object Size :    0x10    0018
        Info Size :    0x12    0044
    Class Parent ->    0x14    80407590
   Class Sibling ->    0x18    804072A8
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    000003C3
     Total Allocs :    0x24    000003DD
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    8035E440
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    8035E49C
       DObj Disp ->    0x3C    8035E388
       DObj Load ->    0x40    8035E0A4

804072A8
hsd_Obj_info_head
       Info Init ->    0x00    8037E6C4
      Status flag :    0x04    00000001
    Library name ->    0x08    804072E4
      Class name ->    0x0C    804D5F68
      Object Size :    0x10    0008
        Info Size :    0x12    003C
    Class Parent ->    0x14    80407590
   Class Sibling ->    0x18    00000000
     Class Child ->    0x1C    80406708
      Active Objs :    0x20    00000000
     Total Allocs :    0x24    00000000
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    80382224
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80382294

80406708
hsd_JObj_info
       Info Init ->    0x00    803737F4
      Status flag :    0x04    00000001
    Library name ->    0x08    80406AA0
      Class name ->    0x0C    80406AB8
      Object Size :    0x10    0088
        Info Size :    0x12    0050
    Class Parent ->    0x14    804072A8
   Class Sibling ->    0x18    804060C0
     Class Child ->    0x1C    803C0948
      Active Objs :    0x20    00000300
     Total Allocs :    0x24    0000031C
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8037340C
     Obj Release ->    0x30    803736F8
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80373790
       JObj Load ->    0x3C    80370BEC
   JObj Make MTX ->    0x40    8036F1F8
mkRBillBoardMTX ->    0x44    803740E8
       JObj Disp ->    0x48    803743B8
   Release Child ->    0x4C    80373470

803C0948
ft_intp_JObj_info
       Info Init ->    0x00    800737D8
      Status flag :    0x04    00000001
    Library name ->    0x08    803C09E0
      Class name ->    0x0C    803C09F8
      Object Size :    0x10    0088
        Info Size :    0x12    0050
    Class Parent ->    0x14    80406708
   Class Sibling ->    0x18    803C08F8
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    000001DE
     Total Allocs :    0x24    000001DE
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8037340C
     Obj Release ->    0x30    803736F8
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80373790
        JObj ??? ->    0x3C    80073780
   JObj Make MTX ->    0x40    8036F1F8
mkRBillBoardMTX ->    0x44    803740E8
       JObj Disp ->    0x48    803743B8
   Release Child ->    0x4C    80373470


803C08F8
ft_JObj_info
       Info Init ->    0x00    80073700
      Status flag :    0x04    00000001
    Library name ->    0x08    803C09E0
      Class name ->    0x0C    804D3A40
      Object Size :    0x10    0088
        Info Size :    0x12    0050
    Class Parent ->    0x14    80406708
   Class Sibling ->    0x18    00000000
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    00000006
     Total Allocs :    0x24    00000006
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8037340C
     Obj Release ->    0x30    803736F8
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80373790
       JObj Load ->    0x3C    80370BEC
   JObj Make MTX ->    0x40    8036F1F8
        JObj ??? ->    0x44    800735BC
       JObj Disp ->    0x48    803743B8
   Release Child ->    0x4C    80373470


804060C0
hsd_LObj_info
       Info Init ->    0x00    80367688
      Status flag :    0x04    00000001
    Library name ->    0x08    804061F8
      Class name ->    0x0C    80406210
      Object Size :    0x10    00D4
        Info Size :    0x12    0040
    Class Parent ->    0x14    804072A8
   Class Sibling ->    0x18    80407078
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    00000010
     Total Allocs :    0x24    00000010
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    803674B4
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80367628
       LObj Load ->    0x3C    80366EA8

80407078
hsd_Fog_info
       Info Init ->    0x00    8037E120
      Status flag :    0x04    00000001
    Library name ->    0x08    80407164
      Class name ->    0x0C    804D5F30
      Object Size :    0x10    0020
        Info Size :    0x12    003C
    Class Parent ->    0x14    804072A8
   Class Sibling ->    0x18    80405570
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    00000001
     Total Allocs :    0x24    00000001
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    8037E04C
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80382294

80405570
hsd_TObj_info
       Info Init ->    0x00    80361548
      Status flag :    0x04    00000001
    Library name ->    0x08    80405A14
      Class name ->    0x0C    80405A2C
      Object Size :    0x10    00AC
        Info Size :    0x12    0048
    Class Parent ->    0x14    804072A8
   Class Sibling ->    0x18    80406FD0
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    00000489
     Total Allocs :    0x24    000004A9
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    8036142C
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    803614E8
  MakeTextureMtx ->    0x3C    8035EF38
       TObj Load ->    0x40    8035EC08
  TObj Make TExp ->    0x44    803600A0

80406FD0
hsd_WObj_info
       Info Init ->    0x00    8037D900
      Status flag :    0x04    00000001
    Library name ->    0x08    80407050
      Class name ->    0x0C    80407068
      Object Size :    0x10    0020
        Info Size :    0x12    0040
    Class Parent ->    0x14    804072A8
   Class Sibling ->    0x18    80406220
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    0000002A
     Total Allocs :    0x24    0000002A
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    8037D864
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    8037D8B8
       WObj Load ->    0x3C    8037D2E4

80406220
hsd_CObj_info
       Info Init ->    0x00    8036A8BC
      Status flag :    0x04    00000001
    Library name ->    0x08    80406328
      Class name ->    0x0C    80406340
      Object Size :    0x10    008C
        Info Size :    0x12    0040
    Class Parent ->    0x14    804072A8
   Class Sibling ->    0x18    00000000
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    0000000F
     Total Allocs :    0x24    0000000F
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8036A654
     Obj Release ->    0x30    8036A6C8
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    8036A85C
       CObj Load ->    0x3C    8036A2EC

The info table names I have given have been derived from corresponding string pointers.

Names prefixed with “ft_” and “it_” appear to be specialized versions of objects just for Melee.

For example, a “Fighter” or “ft_” seems to refer to a player entity. A player skeleton has a single “ft_JObj” as the root of its structure. It basically works like a container by wrapping the root of a regular “hsd_JObj” skeleton with a base “hsd_DObj” display group.

The other JObj type, “ft_intp_JObj” appears to be used to double up the joints in each “bone” of a player skeleton -- presumably for the purpose of animating “interpolated” transformations.

---

DAT allocations

There are a few global structures in RAM that keep track of allocations that appear to be updated from some hardware interrupts involving the disk.

Frankly, I don’t know much about it other than the fact that it can be used to derive information about what files are currently in memory. It’s very useful for this reason.


DAT Allocation Chains = index of links in grouped allocation chains
Code:
DAT allocation chains
@80432078 * ??
0x0    P    points to another allocation link in this chain
              uses 0 nulls at end of group alloc
0x4    P    pointer to start of this allocation
              consists largely of loaded DAT files, and their corresponding
              relocation info tables.
0x8    W    length of allocation for loaded file
              this is padded to account for a 0x20 byte alignment,
              and possibly some header info.
DAT Allocation Index = header objects for files in an allocation chain
Code:
DAT Allocation Index
@80432124 * 0x50

DAT Allocation Index Element

0x00    b    unk -- written to conditionally by using an immediate value
0x01    b    unk -- passed as argument r3 in calls to 80017740
0x02    b    unk -- passed as argument r5 (?)
0x03    b    unk
0x04    b    unk -- passed as argument r10 (?)
0x05    b    unk
0x06    s    DVD Entrynum of pathname string for file
0x08    s    status-- 9999 for ready(0x270F)
               used to represent some kind of a status for loading things
               from DVD.
0x0A    s    unk
0x0C    W    file size
0x10    P    to HSD Allocation Link for File follow link pointer to go
               directly to file allocation.
0x14    P    to HSD Allocation Link for Relocation Info or use the relocation
               info table to use pointers to various sections of the file.
0x18    ?    unk



80432078    0x000    unk, start of global index container
8043207C    0x004    unk index of "Old" interrupt elements this index of data
                       is overwritten with the "New" version of the index.
  ...
804320C0    0x048    unk index of "New" interrupt elements this data is copied
                       over to the "Old" index.
  ...
80432104    0x08C    unk data
  ...
80432124    0x0AC    HSD Allocation Index Element slot 1 game functions use
                       (base of DAT Alloc index) + 0xAC to access each slot,
                       incrementing the index by 0x1C.
80432140    0x0C8    HSD Allocation Index Element slot 2
8043215C    0x0E4    HSD Allocation Index Element slot 3
  ...
804329C8    0x950    HSD Allocation Index Element slot 80 there is a strict
                       limit of 80 slots.
DAT Relocation Info Table = special allocations at end of loaded file -- helps relocate file offsets
Code:
DAT Relocation Info Table
these are allocated alongside files dynamically,
but are accessed from the above static structures.

# first 0x20 bytes = string copied directly from the header of a DAT file
0x00    W    File Size
0x04    W    data block size
0x08    W    relocation table count
0x0C    W    root count
0x10    W    root count 2
0x14    W    unk
0x18    W    unk
0x1C    W    unk

0x20    P    to Reloc Base Address
               file start + 0x20
0x24    P    to Reloc
               pointer table in file relocation table
0x28    P    to root node index 1
0x2C    P    to root node index 2
0x30    P    to Symbol Strings
               used by functions to find data sections within data body.
0x34    ?    to unk1
0x38    ?    to unk2
0x3C    ?    to unk3

0x40    P    to File Data Start file header start
               (as opposed to relocation base address)


From these structures, it’s possible to derive information about where in a file certain objects have come from. I have a little more information about how to use it here.

---

Global player HUD structure

The player HUD structure uses a global array of 6 allocations (one for each player slot) dedicated to storing information used to sort of “puppet” the persistent matrix in the JObjs used by HUD digits.

HUD Index = array of 6 player HUD structures
Code:
@804a10c8 0x64 * 6
0x00    P    HUD_parent_entity -- unk class type E?
0x04    P    next HUD entity? -- unsure about this one
0x08    B    Player slot -- 0-5 ; representing players 1-6
0x0A    S    damage % (int) -- Updated damage
0x0C    S    old damage % (int) -- Unupdated damage -- used for update condition in new color calculation
0x0E    B    damage from last attack
0x0F    B    Frames of "shake" effect remaining after being hit -- will be set to 10 perpetually by flag (20)
0x10    W    Flags: -- flags byte:
0x10    (80)  Explode Animation flag? -- appears to trigger whether to animate death explosion (of digits)
0x10    (20)  force digits to shake -- untested as of 11/27 - observed behavior at 802f5af4
0x10    (10)  unk
0x10    (06)  2-bit ID -- appears to be related to some kind of animation status -- used to trigger heal animation
0x10    (02)  unk -- can be observed in all active players?
0x10    (08)  hide all digits -- can be observed in pause and "GO!" screen
0x14    F    X translation 100's digit -- These are manipulated in order to "shake" the digits upon taking damage
0x18    F    X translation 10's -- (they appear to reset back to default JObj definition)
0x1C    F    X translation 1's
0x20    F    X translation % sign
0x24    F    Y translation 100's digit
0x28    F    Y translation 10's
0x2C    F    Y translation 1's
0x30    F    Y translation % sign
0x34    F    X Velocity 100's -- Upon death, these values seem to be given random numbers to cause the digits to explode
0x38    F    Y Velocity 100's -- all digits appear to add Y velocity to create a "falling" gravity effect
0x3C    F    X Velocity 10's
0x40    F    Y Velocity 10's
0x44    F    X Velocity 1's
0x48    F    Y Velocity 1's
0x4C    F    X Velocity % sign
0x50    F    Y Velocity % sign
0x54    P    to 100's JObj -- These JObjs are siblings, and share a parent that can be modified to transform entire display
0x58    P    to 10's JObj -- each digit connects to an animated TObj in order to display the digit textures
0x5C    P    to 1's JObj
0x60    P    to % sign JObj


The end of the index contains a footer structure that has information used to instantiate assets referenced in the array:
Code:
@804a10c8
0x25C - JObjDesc Parent
0x260 - JAnim Selection (Joints)
0x264 - JAnim Selection (Textures)
0x268 - (null)
I didn’t go over this in much detail, but a function involved in retrieving this information used the “symbol” name “DmgNum_Scene_Models”

I recall an error message referring to what I think we commonly refer to here as an element of the “string table” as a “symbol” with

Code:
803BA5B0 : "Cannot find symbol %s"
I believe that it’s unique for the IfAll.dat relocation table to have a dedicated global pointer, but this is how the HUD initialization function reaches it

https://i.imgur.com/cXs1M0e.png


---

JObj Kings and Entity Emperors

There’s an interesting relationship between JObjs and what SSBM Data Sheet users call “Entities.”

Each entity in the game is given an ID that represents a type; such as players, items, and stage pieces.

Each can potentially contain 2 very valuable pointers in their structure:
0x28 - point to root JObj of skeleton (if applicable)
0x2C - point to start of unique data allocation for this instance, formatted by class type
# some entities don't use these data pointers, relying instead on global data allocations

JObjDescs like the one pointed to at 0x25C from the HUD index footer can be used to load instances.

Once a root JObj is loaded with HSD_JObjLoad, the entire skeleton and all of its assets will also become instantiated using the params described in a JObjDesc:

https://i.imgur.com/PDMmbOj.png


A live JObj will link back to its parent and JObjDesc in addition to its other defined parameters.

---

Entities wrap a JObj skeleton and a data allocation together. When calling functions related to players, the game passes around “player entities” like they were names. Achilles1515 Achilles1515 used to call these “external player data tables” in his notes.

Achilles also had some excellent notes about Entities in a post about a global structure that points to the root of several entity types. The structure can be reached using r13, which is a special register used to anchor a relative pointer for global read/write data.

lwz r4, -0x3e74(r13)
lwz r26, 0x24(r4)

If zero, no projectiles/items/articles or whatever on screen.

If not zero, it's a pointer to item #1 on screen and every subsequent item on screen is daisy chained to item #1 by

lwz r27,0x8(r26)

If zero, then you're at the last spawned item on screen.
-------------

Same basic thing for characters.


lwz r4, -0x3e74(r13)
lwz r26,0x20(r4)

r26 holds pointer to first spawned character. Follow the 0x8 daisy chain until this value equals zero an you're at the last spawned character.

This is powerful.
I have some additional notes using samples taken from various circumstances in the game while monitoring this table of his. Some offsets really required some provocation; like doing Fox's special taunt.

Each entity stores a class ID:
Code:
# Entity Select ----------------------------

lwz r3, -0x3e74(r13)
r3 = 804D782C (points to start of entity select index)

00    point    Class ID 000E (on start of scene?)
04    point    Class ID 000F (during multispawn load? Classic Team Battle)
08    point    Class ID 000E
0C    point    Class ID 000D
10    point    Class ID 0002
14    point    Class ID 0003 (Stage Entity?)
18    point    Class ID 0001
1C    point    Class ID 0005 (Possibly related to pending scene transitions)
20    point    Class ID 0004 -- First Player Entity on Stage
24    point    Class ID 0006 -- First Item/Projectile Entity on Stage
28    point    Class ID 0007
2C    point    Class ID 0008 -- First (?) GFX entity (dust clouds, shine GFX)
30    point    Class ID 0008 -- GFX entity?
34    point    Class ID 0009 (on STAGE CLEAR screen)
38    point    Class ID 000E
3C    point    Class ID 000E
40    point    Class ID 000E
44    point    Class ID 000F (on Master Hand Classic stage)
48    point    Class ID 0010
4C    point    Class ID 0011 (on Fox special taunt, screen overlay?)
50    point    Class ID 0013
54    point    Class ID 0013
58    point    Class ID 0014
5C    point    Class ID 0016
60    point    Class ID 0015
64+   null?    not sure if there are more
With all that, I can say only the following about entity class IDs:

03 = stage entity
04 = player entity
06 = item entity
08 = GFX entity
0E ~ used for HUD entity skeleton root; damage percentage display
0F ~ used during multispawn load (?)
10 = camera entity
11 ~ used for fox special taunt (?)
16 ~ unk -- highest witnessed class ID

---

To relate this back to the player HUD structure...

Each player HUD has an entity that uses type “0E” to identify itself. These entities don’t seem to use a data table, but offset 0x28 points to a root JObj instance as a part of initialization.

Each JObj in the skeleton points back to its JObjDesc, allowing us to navigate through all of the involved structure by starting with the global HUD index as a base:

https://i.imgur.com/8rIAytl.png


From the index of HUD structures, it’s possible to access all of these children bones for the sake of animating them with RNG. The joints are simply wiggled around in random directions to make the “shake” effect on hits, and are thrown in random directions to make the death “explosion” effect.

Other animations use scripted transformations, however.

---

HSD_JObjAddAnim

When a JObj needs to be animated with scripted information, it uses an AObj.

The AObj declares the time and rate of an animation.
From each AObj is a link to a root in a chain of FObjs.
Once instantiated, each FObj parses a data string.
These data strings describe frame-based transformations to the JObj matrix over time.

---

For example, when a player initializes, the HUD digits are under the visible screen area, and are animated to rise up into view each time a player spawns.

Without AObjs assigned to the digits' JObjs; the digits would start out of view and never move into place.

It’s not directly obvious how a JObjDesc connects to an AObjDesc, however. The two seem to be separated at birth -- only to be combined procedurally as separate arguments for a function call to HSD_JObjAddAnim.

---

I don’t know what these are officially called, so I’ve been just calling them by their object letter followed by the suffix “-Anim.”

JAnim Select (Joints) and JAnim Select (Textures) are used to call JObjAddAnim when used with a JObj. Each is just an index of pointers, connecting to different animations:

JAnim Selection = index of animations to select from
Code:
to JAnim 1
to JAnim 2
to JAnim 3
...

Format used for both joint and texture JAnim roots
A function (8000c07c) that I’ve been calling “HSD_JObjAddAnimAll_Indexed” uses the following arguments to select these animations for some "HUD"-like displays:
r3 = JObj
r4 = JAnim ID
r5 = JAnim Select (Joints)
r6 = JAnim Select (Textures)
r7 = JAnim Select (unk -- mesh flags?)

Each argument may be null, allowing for the assignments to be optional based on what’s linked to in each JAnim joint written in a file.

---

The JAnim structures mimic JObj relationships, and are used merely to walk the structure of joints in a skeleton. They are basically just complex containers used to deliver AObjs.

https://i.imgur.com/gFx3YsE.png


JAnim = Joint-level JObj -> AObj container for HSD_JObjAddAnim r4
Code:
0x00    P    to Child JAnim
0x04    P    to Sibling JAnim
0x08    P    to AobjDesc
0x0C    P    to RObj JAnim
0x10    W    flags for PObj (?)

A root JAnim structure can be used with the root JObj to call HSD_JObjAddAnimAll -- allowing a whole skeleton to be animated at once.

This is what the HSD_JObjAddAnimAll_Indexed function calls once it has selected a JAnim skeleton on the index provided. For player HUD digits, animation 0 is used to initialize digits. Animation 1 is used to stretch them out when healing from a heal item.

Individual JObjs can also be animated on their own with HSD_JObjAddAnim.

Each AObjDesc in the structure connects to a chain of FObjDescs that each instantiate their own parse of file data strings once turned into instances.

---

For JAnim (Texture) params, the structure continues even further.

https://i.imgur.com/UABQvva.png



T_JAnim = Joint-level TObj -> AObj assignment for HSD_JObjAddAnim r5
Code:
0x00    P    to Child T_JAnim
0x04    P    to Sibling T_JAnim
0x08    P    to DAnim param

Texture assignment to Joints seems to be optional -- but is useful because Joints have a broader scope in structure than textures do. A Joint can have multiple joints, each possibly having multiple Display objects, each possibly having multiple Textures from their associated Materials.

Because of this, the structures continue to mimic the relationships of each necessary object to create parameters for their own “-AddAnim” functions:

DAnim = HSD_DObjAddAnim r4
Code:
0x00    P    to unk
0x04    P    to Sibling DAnim?
0x08    P    to MAnim/TAnim param

MAnim/TAnim = HSD_MObjAddAnim r4 -- HSD_TObjAddAnim r4
Code:
same struct passed for both cases
0x00    P    to unk
0x04    P    to unk
0x08    P    to AObjDesc
0x0C    P    to ImageDesc Array for ID transformations

The ImageDesc Array for HUD texture animations is used to animate which decimal number shows for each digit.

---

So here’s my attempt to illustrate all of this at once:
https://i.imgur.com/aTUbFGB.png


- Dotted rectangles represent the scope of each of the 4 skeletons (as used by JObjAddAnim)
- Square nodes represent data inside of a file that's been loaded into RAM
- Octagonal nodes represent instantiated objects with their own dynamic allocations.
- Arrows represent pointers. Line color reflects skeleton type.
- Dashed lines represent procedural assignments through function calls.

---

A lot of the graphs here were partially based on the rough notes I scribbled all over this screenshot that I took. I was using Cheat Engine's memory view feature to get a better understanding of how the player HUD parse data gets from point A to point B.

https://i.imgur.com/vQ4eW8Q.png
 
Last edited:

DRGN

Technowizard
Moderator
Joined
Aug 20, 2005
Messages
2,178
Location
Sacramento, CA
R revel8n Do you have any plans to update the OP, or would you like me to edit it to add links to this new information above?

Since the MObj and the associated is in need of some love and Killer7's source code has the header file for HSD formats. Unfortunately, the dump I have doesn't have the jobj.h, there's references to it in the other headers. I basically had to copy the headers for sysdolphin between us/jp/eu source code, because 1 header always seemed to be missing from each one of them.

It's possible I have a bad dump, but I doubt it.

Code:
struct MOBJ_DATA
{
// 0x00
uint32 class_name; //technically char*, always 0
uint32 rendermode;
uint32 tobjOffset <format = hex>; // tobj structure
uint32 materialOffset <format = hex>; // material colors?
// 0x10
uint32 renderdescOffset <format = hex>; // The original source code says, "付いていても無視" or "Ignore even if it's attached"
uint32 pedescOffset <format = hex>;
};

The comments below have 用, meaning for that function usage.

各種フラグ just means "Various flags"

Code:
struct PEDesc {
  u8    flags;           /*+ 各種フラグ */
  u8    ref0;          /*+ GXSetAlphaCompare()用 */
  u8    ref1;          /*+ GXSetAlphaCompare()用 */
  u8    dst_alpha;     /*+ GXSetDstAlpha()用 */
  u8      type;          /*+ GXSetBlendMode()用 */
  u8    src_factor;    /*+ GXSetBlendMode()用 */
  u8    dst_factor;    /*+ GXSetBlendMode()用 */
  u8    logic_op;      /*+ GXSetBlendMode()用 */
  u8    z_comp;        /*+ GXSetZMode()用 */
  u8    alpha_comp0;   /*+ GXSetAlphaCompare()用 */
  u8    alpha_op;      /*+ GXSetAlphaCompare()用 */
  u8    alpha_comp1;   /*+ GXSetAlphaCompare()用 */
}

Code:
struct MATERIAL_COLORS
{
// 0x00
uint32 ambient <format = hex>;
uint32 diffuse <format = hex>;
uint32 specular <format = hex>;
float alpha;
// 0x10
float shininess;
};

The IMAGE_HEADER differs in that sysdolphin has:
u32 mipmap;
f32 minLOD;
f32 maxLOD;

I'm pasting the contents of the TObj, since it's the main one that doesn't match up do to a sheer lack of information.

Code:
struct _HSD_TObj {
  HSD_Obj        object;     /*+ Object構造体*/
        
  struct _HSD_TObj  *next;      /*+ リンク*/
  GXTexMapID        id;         /*+ テクスチャID */
  GXTexGenSrc       src;        /*+ テクスチャ座標のソース*/
  u32            mtxid;      /*+ マトリクスID */
  Quaternion        rotate;     /*+ テクスチャ回転値 */
  Vec               scale;      /*+ テクスチャスケール値 */
  Vec               translate;  /*+ テクスチャリピート値 */
  GXTexWrapMode     wrap_s;     /*+ s方向ラップモード */
  GXTexWrapMode     wrap_t;     /*+ t方向ラップモード */
  u8                repeat_s;   /*+ s方向リピート値 */
  u8                repeat_t;   /*+ t方向リピート値 */
  u16            anim_id;    /*+ tobjdesc->id */

  u32               flag;    /*+ マッピングタイプ */
  /* Tex coord の生成タイプ */
# define TEX_COORD_UV           0  /*+ UVマッピング */
# define TEX_COORD_REFLECTION   1  /*+ リフレクションマッピング */
# define TEX_COORD_HILIGHT      2  /*+ ハイライトマッピング */
# define TEX_COORD_SHADOW       3  /*+ シャドウマッピング */
# define TEX_COORD_TOON     4  /*+ Toon */
  //FUJITA(グラデーション用に新設)
# define TEX_COORD_GRADATION    5
# define TEX_COORD_BACKLIGHT    6
# define TEX_COORD_MASK     (0x0f) /* マスク値 */
# define tobj_coord(T) ((T)->flag & TEX_COORD_MASK) /* マクロ*/

  /* tev の合成タイプ */
# define TEX_LIGHTMAP_DIFFUSE    (0x1<<4) /*+ diffuseマップ */
# define TEX_LIGHTMAP_SPECULAR    (0x1<<5) /*+ specularマップ */
# define TEX_LIGHTMAP_AMBIENT    (0x1<<6) /*+ ambientマップ */
# define TEX_LIGHTMAP_EXT    (0x1<<7) /*+ Reflection/Hilight 等 */
# define TEX_LIGHTMAP_SHADOW    (0x1<<8) /*+ shadowマップ */
# define TEX_LIGHTMAP_MASK \
  (TEX_LIGHTMAP_DIFFUSE \
   |TEX_LIGHTMAP_SPECULAR \
   |TEX_LIGHTMAP_AMBIENT \
   |TEX_LIGHTMAP_EXT \
   |TEX_LIGHTMAP_SHADOW) /* マスク値 */
# define tobj_lightmap(T) ((T)->flag & TEX_LIGHTMAP_MASK) /* マクロ*/

# define TEX_COLORMAP_NONE        (0<<16) /*+ カラーマップなし */
# define TEX_COLORMAP_ALPHA_MASK    (1<<16) /*+ アルファマスク */
# define TEX_COLORMAP_RGB_MASK        (2<<16) /*+ RGBマスク */
# define TEX_COLORMAP_BLEND        (3<<16) /*+ ブレンド */
# define TEX_COLORMAP_MODULATE        (4<<16) /*+ モジュレイト */
# define TEX_COLORMAP_REPLACE        (5<<16) /*+ リプレイス */
# define TEX_COLORMAP_PASS        (6<<16) /*+ パス */
# define TEX_COLORMAP_ADD        (7<<16) /*+ 加算 */
# define TEX_COLORMAP_SUB        (8<<16) /*+ 減算 */
# define TEX_COLORMAP_MASK        (0x0f<<16) /* マスク値 */
# define tobj_colormap(T) ((T)->flag & TEX_COLORMAP_MASK) /* マクロ*/

# define TEX_ALPHAMAP_NONE        (0<<20) /*+ アルファマップなし */
# define TEX_ALPHAMAP_ALPHA_MASK    (1<<20) /*+ アルファマスク */
# define TEX_ALPHAMAP_BLEND        (2<<20) /*+ ブレンド */
# define TEX_ALPHAMAP_MODULATE        (3<<20) /*+ モジュレイト */
# define TEX_ALPHAMAP_REPLACE        (4<<20) /*+ リプレイス */
# define TEX_ALPHAMAP_PASS        (5<<20) /*+ パス */
# define TEX_ALPHAMAP_ADD        (6<<20) /*+ 加算 */
# define TEX_ALPHAMAP_SUB        (7<<20) /*+ 減算 */
# define TEX_ALPHAMAP_MASK        (0x0f<<20) /* マスク値 */
# define tobj_alphamap(T) ((T)->flag & TEX_ALPHAMAP_MASK) /* マクロ*/

# define TEX_BUMP            (0x1<<24) /*+ bumpマップ */
# define tobj_bump(T) ((T)->flag & TEX_BUMP) /* マクロ */
# define TEX_MTX_DIRTY            (1<<31) /* internal use only */
  float             blending;   /*+ blend 値 */
  GXTexFilter        magFilt;    /*+ texel/pixel > 1.0の時に用いられる
                  テクスチャフィルタータイプ */
  HSD_ImageDesc        *imagedesc; /*+ ImageDescへのポインタ */
  HSD_Tlut          *tlut;      /*+ Tlutへのポインタ */
  HSD_TexLODDesc    *lod;    /*+ LODDescへのポインタ */
  struct _HSD_AObj  *aobj;      /*+ AObjへのポインタ */
  HSD_ImageDesc        **imagetbl; /*+ テクスチャスイッチ用イメージテーブル */
  HSD_Tlut        **tluttbl;    /*+ TLUTスイッチ用テーブル */
  u8            tlut_no;    /*+ パレットアニメーションのカレントtlut番号。
                      (u8) -1 はカレントtlutがセットされていない
                    ことを表す。この場合はメンバ tlutが使用
                    される。 */
  Mtx             mtx;        /*+ テクスチャマトリクス */
  GXTexCoordID        coord;      /*+ テクスチャ座標出力先 */
  HSD_TObjTev       *tev;    /*+ 一段Tev設定 */
};

What we have defined as a PALLETE_HEADER is either wrong or was changed later in the library.

Code:
/*+
* HSD_Tlut 構造体はテクスチャのパレット情報を保持する構造体である。
*/
typedef struct _HSD_Tlut {
  void          *lut;        /*+ テクスチャルックアップテーブル */
  GXTlutFmt     fmt;        /*+ tlut フォーマット */
  u32           tlut_name;    /*+ tlut 名 (割り当て結果が格納される) */
  u16           n_entries;    /*+ パレット数 */
} HSD_Tlut;
Great info!

I had some of this thanks to Achilles and the GameCube SDK; I've been able to find a good amount of information on some structs in there, and figure out a few more. But you still have some new stuff too. What I have can currently be found in the Structural Analysis tab of DTW (there are a number of things I need to get around to properly documenting):
Untitled.png

Though that analysis is pretty rudimentary, as it's only designed to help work with character files (and a small part of stage files) at the moment. It won't even identify known structures in other files. I could certainly do something better if I put that rare commodity known as time into it.

Anyway, I notice a few discrepancies with what you and I have.

For the Material Struct, diffusion and ambiance are switched. And the float you have listed just before shininess is Transparency Control (which can adjust the transparency of a model part, though certain flags need to be set to enable this; more info here).

The last pointer in the Material Obj struct is named Pixel Processor Offset in Achilles and my notes. You have "PE" Desc in yours; do you know what PE stands for? Pixel Engine maybe?

I had most on the Texture Struct that you posted, but the information on animation ID and flags at 0x3E and 0x40 (following the repeat s/t bytes) is very interesting. Do you know what the animation ID refers or points to? Is it an index into some list? Since it's normally zeroes, it was previously thought to be padding.

In the palette header, what you have listed as 'void' is a pointer to the palette data. When you say that what we have defined for the palette header is wrong, are you referring to what's in revel8n's second post in this thread? Yours and his seem pretty close to one another, besides the aforementioned void, and the "unknown" he lists at 0x8 (described now as the "name"). Speaking of which, I'm not sure that's ever used in Melee. Have you ever seen it not zeroed out? If [in terms of considering the struct documentation to be wrong] you're mostly referring to the "unknown" two bytes at the end of the struct (at 0xE), I'm pretty sure that's just padding. So optionally that could just not be considered as part of the structure.

DRGN DRGN your project is so awesome. Graphics like these really help illustrate the bounds of something too abstract to think of as a whole. I really admire stuff like what you’re doing.



I have a couple of short lectures saved that talk about various methods of visualizing strings of binary with little to no preconceptions about how it is structured. Either makes for a great watch during lunch or something:

-- https://www.youtube.com/watch?v=4bM3Gut1hIk -- Derbycon 2012 - Chris Domas demoing Cantor Dust
-- https://www.youtube.com/watch?v=T3qqeP4TdPA -- Blackhat 2010 - Greg Conti, Sergey Bratus

These go over various byte plotting methods, and ways of using tuple graphs to see patterns and relationships very quickly from unknown strings of binary.

---

Here are a couple of tools that use some of the concepts talked about in the above lectures. You can use them to explore any binary, like Melee files:

Binvis - www.binvis.io
This tool is useful for visualizing entropy in byte sequences, and can be useful for finding where different regions in a file are located

https://i.imgur.com/UgvW1fk.png - https://i.imgur.com/U9ufOYw.png



It’s particularly good at finding ascii. For instance, see DbCo.dat:
https://i.imgur.com/c56Zp7o.png

The blue curves are text, with the black sections representing null termination bytes.

---

Veles - https://codisec.com/veles/
Hex editor that includes some tools inspired by the Cantor Dust demo.

They go over most of the features and explain some concepts in this page

https://i.imgur.com/kkOfnRr.png -- https://i.imgur.com/2DFWNye.png


---



I’ve been accumulating a lot of info that has mostly to do with RAM data, but is very closely tied to all of the file data objects mentioned in this thread.

I was considering starting a thread about HSD objects, but this is probably the best place to post it now. It’s a lot to go over though, so I’ll just make a followup post soon with a big info dump.

---



These are great! Your notes about TObjs confirm something I’d like to go over in more detail about AObjs.

Basically, AObjs are "Animation" objects that connect multiple types of objects to FObj chains, or "Frame" data objects.

JObjs, TObjs, RObjs, and I think CObjs can use AObj structures to sort of plug into scripted animation data.

I'll go over this more in my followup post later. I haven't been looking at the leaked killer7 stuff for a lack of understanding how, but the CSM updates have helped me considerably in terms of understanding file and instance structure.

---






You guys talking about subaction events?

The [28] player event is pretty well understood at this point.

I have some notes on an old pen and paper scratchpad from years back that breaks down how the event data is just a string of compressed arguments passed as parameters to a more general function.

This parse function actually taught me how powerpc does float casting. My old chicken scratch suggests:
Code:
event [28]: Spawn GFX
Parse function scans 5 words for params in order to set up a call to function 80086960: GFX_EffectSpawn
r3 = player entity
r4 = GFX ID  - concatenated index of general and unique graphics?
r5 = JObj ID - player skeleton, 0-based
r6 = unk bool
r7 = unk bool
r8 = XYZ float array -- Origin; relative to JObj
r9 = XYZ float array -- scatter amount

As event string:
L = event Line 0-4 (word alignment for mask)
M = hexadecimal bitmask containing x-bit integer
L MMMMMMMM -  X-BIT -- DESCRIPTION

0 FC000000 -  6-bit -- (opcode int - 0xA) = player event index
0 03FC0000 -  8-bit -- JObj ID = r5
0 00020000 -  1-bit -- bool = r6
0 00010000 -  1-bit -- bool = r7
0 0000FFFF -  -- unused bits
1 FFFF0000 - 16-bit -- GFX ID = r4
1 0000FFFF - 16-bit -- unknown signed float = f1
2 FFFF0000 - 16-bit -- X Origin = 0x0(r8)
2 0000FFFF - 16-bit -- Y Origin = 0x4(r8)
3 FFFF0000 - 16-bit -- Z Origin = 0x8(r8)
3 0000FFFF - 16-bit -- X Scatter = 0x0(r9)
4 FFFF0000 - 16-bit -- Y Scatter = 0x4(r9)
4 0000FFFF - 16-bit -- Z Scatter = 0x8(r9)

r8 floats are cast as signed fixed points:
0xFF.FF - 8 bit UINT + 8-bit mantissa

r9 floats are cast as unsigned fixed points:
0xFF.FF - 8-bit SINT + 8-bit mantissa
IIRC, one of those unk bools makes the graphic unattached from the JObj after spawning; but I haven’t checked it out in awhile.

I also have a post in Itaru’s moveset data thread with function addresses of every event callback I could find. Of the 5 parser functions, one is dedicated to executing player events, and another is dedicated to executing projectile events.

80071028 - parses Player GFX events -- some IDs of which are tied to the loaded player character files.

80278F2C - parses Projectile GFX events

Other player events, such as “body auras” will assign graphics; and there are also macro events that combine a GFX ID with a SFX ID to shorten the existing GFX and SFX syntaxes for the sake of making footstep effects, or landing effects.
Wow, interesting tools!

I haven't really looked at subactions or events, but I've been thinking that a new tool for subactions and animations sounds like one of the main things that the Melee community could use a new focus on. CrazyHand can do a lot, of course, but there's also so much it can't do; and the absence of the main developer and lack of good source code, and the limitations those incur (namely, not being able to update it with new events, or the addition of features) suggests we just need to start on something new.

If you'll pardon the double-post, I thought it appropriate since I go over quite a bit here:
  • Persistent Objects
    • understanding the difference between Live Objects vs File Object Descriptions
  • HSD Info Tables
    • How some objects use HSD Info Tables to function with some amount of automation
  • Melee HSD Info Samples
    • HSD Info Table samples - includes WObj, CObj, Fog Object, and LObj
  • DAT Allocations
    • DAT File allocation references in RAM
  • Player HUD structure
    • An example of a simple skeleton structure using IfAll.dat
  • JObj Kings and Entity Emperors
    • How JObjs wrapped with data make class types like "players" and "items"
  • HSD_JObjAddAnim
    • How the player HUD structure loads AObjDescs to animate joints and textures
Edit: Reformatted with spoilers, fixed typos, etc.

---

Several months ago, @Itaru asked for a code that added a 4th digit to the player damage HUD. My research into the matter has kept me busy because there’s a lot to learn regarding HSD objects.

Specifically -- things about how procedurally assigned AObjs may be used to animate (and sometimes initialize) JObjs and TObjs.

This applies to characters, menus, stages, and anything else that might be transformed as a joint or a texture.

---

Persistent Objects

In order to distinguish between live instances and their respective file data descriptions, my notes refer to file data objects by appending a “-Desc” suffix to their HSD object name. This is based on my observations of a few symbol names leaked from the killer7 csm renaissance.

A live JObj is different from what I’ll be calling a JObjDesc -- the latter being the structure you are all probably familiar with.

https://i.imgur.com/Z1BLztx.png


The following information about the structure of file data objects has mostly been obtained from DTW , Tcll Tcll 's wiki, and posts in this thread.

Information about instantiated structures are from my own accumulated research, so I would appreciate any feedback about mistakes or confirmations.

Compare the two types of each object listed here to get an idea of how the structures differ:
Code:
Data types:
P    = pointer address
B    = byte
S    = short (hword, 2-byte)
W    = word (4-byte)
F    = floating point (single)
D    = floating point (double)
##   = array of bytes
(##) = bitmask (byte)

JObjDesc = Joint Object File Description
Code:
JObjDesc - 0x40 bytes
0x00    W    "name"?
0x04    W    Flags
0x08    P    to JObj Child
0x0C    P    to JObj Sibling
0x10    P    to DObj
0x14    F    X Rotation
0x18    F    Y Rotation
0x1C    F    Z Rotation
0x20    F    X Scale
0x24    F    Y Scale
0x28    F    Z Scale
0x2C    F    X Translation
0x30    F    Y Translation
0x34    F    Z Translation
0x38    P    to inverse transform matrix
0x3C    P    to RObjDesc -- not used for procedural RObj assignments?
                          -- which seems to be like, all of them?
JObj = Live Joint Object
Code:
JObj - 0x88 bytes
0x00    P    to HSD_Info table
0x04    W    "name"?
0x08    P    to JObj Sibling
0x0C    P    to JObj Parent
0x10    P    to JObj Child
0x14    W    Flag word, 32 bits
0x18    P    to DObj Link      -- assigns a Material and Polygon object to this joint. Note this is a live DObj, not a DObjDesc
                                - resulting display is heavily influenced by JOBj flags and transformation values
0x1C    F    Local X Rotation  -- Begining of local transformation vars:
0x20    F    Local Y Rotation
0x24    F    Local Z Rotation  -- Rotation
0x28    F    unknown float...
0x2C    F    Local X Scale
0x30    F    Local Y Scale
0x34    F    Local Z Scale     -- Scale
0x38    F    Local X Translation
0x3C    F    Local Y Translation
0x40    F    Local Z Translation -- Translation
0x44    F    Absolute X matrix 0x0  - shear? -- rotation 1 1 (effects rotation, skew, and scale?)
0x48    F    Absolute X matrix 0x4  - ?      -- rotation 1 2
0x4C    F    Absolute X matrix 0xC  - ?      -- rotation 1 3
0x50    F    Absolute X matrix 0x10 - global translation -- Absolute X position
0x54    F    Absolute Y matrix 0x0  - shear? -- rotation 2 1
0x58    F    Absolute Y matrix 0x4  - ?      -- rotation 2 2
0x5C    F    Absolute Y matrix 0xC  - ?      -- rotation 2 3
0x60    F    Absolute Y matrix 0x10 - global translation -- Absolute Y position
0x64    F    Absolute Z matrix 0x0  - shear? -- rotation 3 1
0x68    F    Absolute Z matrix 0x4  - ?      -- rotation 3 2
0x6C    F    Absolute Z matrix 0xC  - ?      -- rotation 3 3
0x70    F    Absolute Z matrix 0x10 - global translation -- Absolute Z position
0x74    P    to "VEC"    --  used in calls to 8037A65C : HSD_VecFree
0x78    P    to "MTX"    -- instantiated copy of inverse transform matrix
0x7C    P    to AObj     -- AObj struct keeps track of timers, flags, and pointers related to animating JObjs.
0x80    P    to RObj     -- Some JObjs will reference another JObj from a different hierarchy through an RObj container
                          - For example, Fox's shine graphic has a bone that links to Fox using RObj links
0x84    P    to JObjDesc -- This points to the start of the source JObj definition in a file loaded from disk into RAM.
                          - These pointers are extremely useful for researching file data

DObjDesc = Display Object File Description
Code:
DObjDesc - 0x10 bytes
0x00    W    "name"?
0x04    P    to Sibling DObj
0x08    P    to MObj
0x0C    P    to PObj
DObj = Live Display Object
Code:
DObj - 0x18 bytes
0x00    P    to HSD_Info table
0x04    P    to Sibling DObj   -- Multiple DObjs may be linked together
0x08    P    to MObj           -- Material Object Link - texture assets and params
0x0C    P    to PObj           -- Polygon Object Link  - mesh vertex and weight params
0x10    W    unknown
0x14    W    Flags             -- Flags can be seen being set on some DObj initializations


PObjDesc = Polygon Object File Description
Code:
PObjDesc - 0x18 bytes
0x00    W    "name"?
0x04    P    to Sibling PObj
0x08    P    to Vertex Attributes Array
0x0C    S    Flags
0x0E    S    Display List Blocks
0x10    P    to Display List Data
0x14    P    to Influence Matrix Array
PObj = Live Polygon Object
Code:
PObj - 0x18 bytes
0x00    P    to HSD_Info table
0x04    P    to Sibling PObj
0x08    P    to Vertex Attributes Array
0x0C    S    Flags
0x0E    S    Display List Blocks
0x10    P    to Display List Data
0x14    P    to Influence Matrix Array


MObjDesc = Material Object File Description
Code:
MObjDesc - 0x18 bytes
0x00    W    "name"?
0x04    W    Flags? "Render Mode"
0x08    P    to TObj
0x0C    P    to Material Color Instance
0x10    P    to Render Struct
0x14    P    to PEDesc (Pixel Processor Struct)
MObj = Live Material Object
Code:
MObj - 0x18 bytes
0x00    P    to HSD_Info table
0x04    W    Flags? "Render Mode"
0x08    P    to TObj -- Texture link
0x0C    P    to Material Color Instance -- Texture color properties
0x10    P    to Render Struct
0x14    P    to PEDesc (Pixel Processor Struct)


TObjDesc = Texture Object File Description
Code:
TObjDesc - 0x5C bytes
0x00    W    "name"?
0x04    P    to Sibling TObjDesc
0x08    W    GXTexMapID
0x0C    W    Coord Gen Source Args (GXTexGenSrc)
0x10    F    Rotation X
0x14    F    Rotation Y
0x18    F    Rotation Z
0x1C    F    Scale X
0x20    F    Scale Y
0x24    F    Scale Z
0x28    F    Translation X
0x2C    F    Translation Y
0x30    F    Translation Z
0x34    W    Wrap S (GXTexWrapMode)
0x38    W    Wrap T (GXTexWrapMode)
0x3C    b    Repeat S
0x3D    b    Repeat T
0x3E    s    (padding)
0x40    W    Flags
0x44    F    Blending
0x48    W    Mag Filter (GXTexFilter)
0x4C    P    to Image Header (ImageDesc)
0x50    P    to Palette Header (TlutDesc)
0x54    P    to LOD Structure (TexLODDesc)
0x58    P    to TEV Structure (TObjTevDesc)
TObj = Live Texture Object
Code:
TObj - 0xAC bytes
0x00    P    to HSD_Info table
0x04    W    unk
0x08    P    to next TObj
0x0C    W    unk
0x10    W    Coord Gen Source Args (GXTexGenSrc)
0x14    W    unk
0x18    W    unk
0x1C    F    unk (rotation X?)
0x20    F    unk (rotation Y?)
0x25    F    unk (rotation Z?)
0x28    F    Scale X
0x2C    F    Scale Y
0x30    F    Scale Z
0x34    F    Translation X
0x38    F    Translation Y
0x3C    F    Translation Z
0x40    W    Wrap S (GXTexWrapMode)
0x44    W    Wrap T (GXTexWrapMode)
0x48    B    Repeat S
0x49    B    Repeat T
0x4A    S    (padding)
0x4C    W    Texture Flags
0x50    F    Blending
0x54    W    Mag Filter (GXTexFilter)
0x58    P    to Image Header in file data (ImageDesc)
0x5C    P    to Palette Header Instance (TlutDesc)
0x60    P    to Level of Detail Struct in file data (TexLODDesc)
0x64    P    to AObj --  (see blinking)
0x68    P    to start of image index for animated textures
0x6C    P    to start of image palette index for animate textures
0x70    B    Texture Animation State ID
0x71    3    unk (padding?)
0x74    F    unk
0x78    F    unk
0x7C    F    unk
0x80    F    unk
0x85    F    unk
0x88    F    unk
0x8C    F    unk
0x90    F    unk
0x94    F    unk
0x98    F    unk
0x9C    F    unk
0xA0    F    unk
0xA4    F    unk
0xA8    P    to TEV Struct (TObjTevDesc)


AObjDesc = Animation Object File Description
Code:
AObjDesc - 0x10 bytes
0x00    W    unk
0x04    F    End Frame
0x08    P    to Root FObjDesc
0x0C    W    unk
AObj = Live Animation Object
Code:
AObj - 0x18 bytes
0x00    W    Flags
0x04    F    current animation frame
0x08    F    Rewind frame --  see 8036531C : HSD_AObjSetRewindFrame
0x0C    F    End frame    --  see 8036532C : HSD_AObjSetEndFrame
0x10    F    frame rate of animation
0x14    P    to FObj


FObjDesc = Frame Data Object File Description
Code:
FObjDesc - 0x14 bytes
0x00    P    to Next FObjDesc
0x04    W    Data String length -- bytes -- includes null termination byte
0x08    W    unk
0x0C    W    flags
0x10    P    to Data String
FObj = Live Frame Data Parse Object
Code:
FObj - 0x34 bytes
0x00    P    to next FObj     -- used for X, Y, and Z data, I believe
0x04    P    to current Parse -- Parses 1 byte of data at a time, stopping at keyframes
0x08    P    to Parse start   -- a body of data copied over to a buffer from FObjDesc ?
0x0C    W    length of data to parse
0x10        unk -- I believe these are temporary values used to operate on MTX
0x14        unk -- like JObjs and TObjs, these seem to mostly comprise of floats
0x18        unk -- like JObjs and TObjs, File Desc objects contain no such array
0x1C        unk
0x20        unk
0x24        unk
0x28        unk
0x2C        unk
0x30        unk


RObjDesc = Reference Object File Description
Code:
unknown
RObj = Live Reference Object
Code:
RObj - 0x1C bytes
0x00    P    unk - something to do with allocation
0x04    W    Flags
0x08    P    JObj Constraint
0x0C    W    unk
0x10    W    unk
0x14    W    unk
0x18    P    to AObj -- needs more research

---

HSD Info Tables

A handful of HSD objects make use of what’s called an “HSD Info table” when instantiating from file data. These include JObjs, DObjs, PObjs, MObjs, and TObjs from the definitions above -- but not AObjs, FObjs, or RObjs. In fact, most HSD structures don’t use them at all.

The objects that use info tables however rely on them to do basic things; like create instances:

https://i.imgur.com/MwYlOhB.png


HSD Info tables describe a list of callback routines for an object of a specific class type.

These callbacks are used to create default behaviors for all objects of said type. The first 5 callbacks in the list are standardized as follows:

slot 1 - 0x28 - Obj Alloc
slot 2 -
0x2C - Obj Init
slot 3 -
0x30 - Obj Release
slot 4 -
0x34 - Obj Destroy
slot 5 -
0x38 - Obj Amnesia
slot 6+ (unique)


Each info table links a function to these slots. Some object info tables will contain additional callbacks, which serve unique purposes specific to that object type.

---

Generic Info Table Structure:
Code:
Generic Info Table structure:

0x00 - Info table initialization callback
     -- when the first object of a type is used, this callback function
     -- activates the info table and initializes all of the following params

0x04 - Active status flag
     -- 1 == active, 0 == inactive

0x08 - lib name string
0x0C - class name string

0x10 - HWORD - size of object allocation
0x12 - HWORD - size of info table

0x14 - Parent class info table
0x18 - Sibling class info table
0x1C - Child class info table
     -- info tables inform functions about how classes are related
     -- order of siblings depends on order of info table activation

0x20 - Active object instances
0x24 - Total allocations available
     -- the total will rise to meet the needs of active object instances
     -- the “amnesia” callback appears to be responsible for wiping this to 0

0x28 - Object allocation callback
0x2C - Object initialization callback
0x30 - Object release callback
0x34 - Object destroy callback
0x38 - Object amnesia callback

0x3C+ specialized function callbacks

---

The function hsdNew works by passing one of these info table addresses as argument r3:
Code:
- if the given info table is inactive,
  -> callback event 0x00 = Info Table initialization callback

-> callback event 0x28 = Object allocation callback

- if returned allocation is null,
  <- return null object address

- zero out allocation space
- store info table address at 0x00(alloc)
- use returned allocation address as r3 arg
-> callback event 0x2C = Object initialization callback

- if returned object address is null,
  -> callback event 0x34 = Object destroy callback
  <- return null object
- else,
  <- return new HSD object address

The function is using the generic HSD callback slots in the info table to handle the work of creating a new HSD object; regardless of which type it is given.

https://i.imgur.com/ZIWCi1z.png


Info tables use child/sibling links to imply an inheritance tree structure. Some functions will refer to an info table’s parent structure for callbacks.

From these, we can even find a few object types that have yet to be explored:

LObj - 0xD4 object size -- Achilles says, “Light Object”
CObj - 0x8C object size -- Achilles says, “Camera Object”
WObj - 0x20 object size -- (world object? window object?)
Fog - 0x20 object size -- fog object


---

Melee HSD Info Table Samples
Screenshot from:

1.02
Melee: 4-player
stage: Venom
6 player entities
no item entities
Code:
80407590 
hsdClass_info_head 
       Info Init ->    0x00    803822C0
      Status flag :    0x04    00000001
    Library name ->    0x08    804076A4
      Class name ->    0x0C    804076BC
      Object Size :    0x10    0004
        Info Size :    0x12    003C
    Class Parent ->    0x14    00000000
   Class Sibling ->    0x18    00000000
     Class Child ->    0x1C    80406398
      Active Objs :    0x20    00000000
     Total Allocs :    0x24    00000000
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    80382224
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80382294


80406398 
hsd_PObj_info 
       Info Init ->    0x00    8036EB88
      Status flag :    0x04    00000001
    Library name ->    0x08    804066E4
      Class name ->    0x0C    804066FC
      Object Size :    0x10    0018
        Info Size :    0x12    0048
    Class Parent ->    0x14    80407590
   Class Sibling ->    0x18    80405E28
     Class Child ->    0x1C    803C0998
      Active Objs :    0x20    000001FE
     Total Allocs :    0x24    00000220
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    8036E9F0
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    8036EB14
       PObj Disp ->    0x3C    8036E8AC
       Setup MTX ->    0x40    8036E83C
       PObj Load ->    0x44    8036BDA0

803C0998 
ft_PObj_info 
       Info Init ->    0x00    800740E4
      Status flag :    0x04    00000001
    Library name ->    0x08    803C09E0
      Class name ->    0x0C    804D3A50
      Object Size :    0x10    0018
        Info Size :    0x12    0048
    Class Parent ->    0x14    80406398
   Class Sibling ->    0x18    00000000
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    00000257
     Total Allocs :    0x24    00000257
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    8036E9F0
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    8036EB14
       PObj Disp ->    0x3C    8036E8AC
       Setup MTX ->    0x40    80074048
       PObj Load ->    0x44    800226A8
 
 
80405E28 
hsd_MObj_info 
       Info Init ->    0x00    80363F28
      Status flag :    0x04    00000001
    Library name ->    0x08    80405F90
      Class name ->    0x0C    80405FA8
      Object Size :    0x10    0020
        Info Size :    0x12    0050
    Class Parent ->    0x14    80407590
   Class Sibling ->    0x18    80405450
     Class Child ->    0x1C    803C6980
      Active Objs :    0x20    000001FE
     Total Allocs :    0x24    00000218
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    80363E28
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80363EC4
      MObj Setup ->    0x3C    80363A24
       MObj Load ->    0x40    80363144
       Make TExp ->    0x44    80363284
  MObj Setup Tev ->    0x48    803639AC
      MObj Unset ->    0x4C    80363B68

803F1F90 
it_MObj_info 
       Info Init ->    0x00    80277D08
      Status flag :    0x04    00000000
    Library name ->    0x08    803F206C
      Class name ->    0x0C    804D51B0
      Object Size :    0x10    0020
        Info Size :    0x12    0050
    Class Parent ->    0x14    00000000
   Class Sibling ->    0x18    00000000
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    00000000
     Total Allocs :    0x24    00000000
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    80363E28
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80363EC4
      MObj Setup ->    0x3C    80277D8C
       MObj Load ->    0x40    80363144
       Make TExp ->    0x44    80363284
  MObj Setup Tev ->    0x48    803639AC
      MObj Unset ->    0x4C    80363B68
 
803C6980 
ft_MObj_info 
       Info Init ->    0x00    800BF260
      Status flag :    0x04    00000001
    Library name ->    0x08    803C6A5C
      Class name ->    0x0C    804D3C00
      Object Size :    0x10    0020
        Info Size :    0x12    0050
    Class Parent ->    0x14    80405E28
   Class Sibling ->    0x18    00000000
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    000001C5
     Total Allocs :    0x24    000001C5
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    80363E28
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80363EC4
      MObj Setup ->    0x3C    800BF2B8
       MObj Load ->    0x40    80363144
       Make TExp ->    0x44    80363284
  MObj Setup Tev ->    0x48    803639AC
      MObj Unset ->    0x4C    80363B68
 
 
80405450 
hsd_DObj_info 
       Info Init ->    0x00    8035E4E4
      Status flag :    0x04    00000001
    Library name ->    0x08    80405548
      Class name ->    0x0C    80405560
      Object Size :    0x10    0018
        Info Size :    0x12    0044
    Class Parent ->    0x14    80407590
   Class Sibling ->    0x18    804072A8
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    000003C3
     Total Allocs :    0x24    000003DD
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    8035E440
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    8035E49C
       DObj Disp ->    0x3C    8035E388
       DObj Load ->    0x40    8035E0A4
 
804072A8 
hsd_Obj_info_head 
       Info Init ->    0x00    8037E6C4
      Status flag :    0x04    00000001
    Library name ->    0x08    804072E4
      Class name ->    0x0C    804D5F68
      Object Size :    0x10    0008
        Info Size :    0x12    003C
    Class Parent ->    0x14    80407590
   Class Sibling ->    0x18    00000000
     Class Child ->    0x1C    80406708
      Active Objs :    0x20    00000000
     Total Allocs :    0x24    00000000
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    80382224
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80382294
 
80406708 
hsd_JObj_info 
       Info Init ->    0x00    803737F4
      Status flag :    0x04    00000001
    Library name ->    0x08    80406AA0
      Class name ->    0x0C    80406AB8
      Object Size :    0x10    0088
        Info Size :    0x12    0050
    Class Parent ->    0x14    804072A8
   Class Sibling ->    0x18    804060C0
     Class Child ->    0x1C    803C0948
      Active Objs :    0x20    00000300
     Total Allocs :    0x24    0000031C
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8037340C
     Obj Release ->    0x30    803736F8
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80373790
       JObj Load ->    0x3C    80370BEC
   JObj Make MTX ->    0x40    8036F1F8
mkRBillBoardMTX ->    0x44    803740E8
       JObj Disp ->    0x48    803743B8
   Release Child ->    0x4C    80373470
 
803C0948 
ft_intp_JObj_info 
       Info Init ->    0x00    800737D8
      Status flag :    0x04    00000001
    Library name ->    0x08    803C09E0
      Class name ->    0x0C    803C09F8
      Object Size :    0x10    0088
        Info Size :    0x12    0050
    Class Parent ->    0x14    80406708
   Class Sibling ->    0x18    803C08F8
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    000001DE
     Total Allocs :    0x24    000001DE
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8037340C
     Obj Release ->    0x30    803736F8
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80373790
        JObj ??? ->    0x3C    80073780
   JObj Make MTX ->    0x40    8036F1F8
mkRBillBoardMTX ->    0x44    803740E8
       JObj Disp ->    0x48    803743B8
   Release Child ->    0x4C    80373470
 

803C08F8 
ft_JObj_info 
       Info Init ->    0x00    80073700
      Status flag :    0x04    00000001
    Library name ->    0x08    803C09E0
      Class name ->    0x0C    804D3A40
      Object Size :    0x10    0088
        Info Size :    0x12    0050
    Class Parent ->    0x14    80406708
   Class Sibling ->    0x18    00000000
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    00000006
     Total Allocs :    0x24    00000006
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8037340C
     Obj Release ->    0x30    803736F8
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80373790
       JObj Load ->    0x3C    80370BEC
   JObj Make MTX ->    0x40    8036F1F8
        JObj ??? ->    0x44    800735BC
       JObj Disp ->    0x48    803743B8
   Release Child ->    0x4C    80373470
 

804060C0 
hsd_LObj_info 
       Info Init ->    0x00    80367688
      Status flag :    0x04    00000001
    Library name ->    0x08    804061F8
      Class name ->    0x0C    80406210
      Object Size :    0x10    00D4
        Info Size :    0x12    0040
    Class Parent ->    0x14    804072A8
   Class Sibling ->    0x18    80407078
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    00000010
     Total Allocs :    0x24    00000010
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    803674B4
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80367628
       LObj Load ->    0x3C    80366EA8
 
80407078 
hsd_Fog_info 
       Info Init ->    0x00    8037E120
      Status flag :    0x04    00000001
    Library name ->    0x08    80407164
      Class name ->    0x0C    804D5F30
      Object Size :    0x10    0020
        Info Size :    0x12    003C
    Class Parent ->    0x14    804072A8
   Class Sibling ->    0x18    80405570
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    00000001
     Total Allocs :    0x24    00000001
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    8037E04C
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    80382294
 
80405570 
hsd_TObj_info 
       Info Init ->    0x00    80361548
      Status flag :    0x04    00000001
    Library name ->    0x08    80405A14
      Class name ->    0x0C    80405A2C
      Object Size :    0x10    00AC
        Info Size :    0x12    0048
    Class Parent ->    0x14    804072A8
   Class Sibling ->    0x18    80406FD0
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    00000489
     Total Allocs :    0x24    000004A9
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    8036142C
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    803614E8
  MakeTextureMtx ->    0x3C    8035EF38
       TObj Load ->    0x40    8035EC08
  TObj Make TExp ->    0x44    803600A0
 
80406FD0 
hsd_WObj_info 
       Info Init ->    0x00    8037D900
      Status flag :    0x04    00000001
    Library name ->    0x08    80407050
      Class name ->    0x0C    80407068
      Object Size :    0x10    0020
        Info Size :    0x12    0040
    Class Parent ->    0x14    804072A8
   Class Sibling ->    0x18    80406220
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    0000002A
     Total Allocs :    0x24    0000002A
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8038221C
     Obj Release ->    0x30    8037D864
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    8037D8B8
       WObj Load ->    0x3C    8037D2E4
 
80406220 
hsd_CObj_info 
       Info Init ->    0x00    8036A8BC
      Status flag :    0x04    00000001
    Library name ->    0x08    80406328
      Class name ->    0x0C    80406340
      Object Size :    0x10    008C
        Info Size :    0x12    0040
    Class Parent ->    0x14    804072A8
   Class Sibling ->    0x18    00000000
     Class Child ->    0x1C    00000000
      Active Objs :    0x20    0000000F
     Total Allocs :    0x24    0000000F
       Obj Alloc ->    0x28    803821C4
        Obj Init ->    0x2C    8036A654
     Obj Release ->    0x30    8036A6C8
     Obj Destroy ->    0x34    80382228
     Obj Amnesia ->    0x38    8036A85C
       CObj Load ->    0x3C    8036A2EC

The info table names I have given have been derived from corresponding string pointers.

Names prefixed with “ft_” and “it_” appear to be specialized versions of objects just for Melee.

For example, a “Fighter” or “ft_” seems to refer to a player entity. A player skeleton has a single “ft_JObj” as the root of its structure. It basically works like a container by wrapping the root of a regular “hsd_JObj” skeleton with a base “hsd_DObj” display group.

The other JObj type, “ft_intp_JObj” appears to be used to double up the joints in each “bone” of a player skeleton -- presumably for the purpose of animating “interpolated” transformations.

---

DAT allocations

There are a few global structures in RAM that keep track of allocations that appear to be updated from some hardware interrupts involving the disk.

Frankly, I don’t know much about it other than the fact that it can be used to derive information about what files are currently in memory. It’s very useful for this reason.


DAT Allocation Chains = index of links in grouped allocation chains
Code:
DAT allocation chains
@80432078 * ??
0x0    P    points to another allocation link in this chain
              uses 0 nulls at end of group alloc
0x4    P    pointer to start of this allocation
              consists largely of loaded DAT files, and their corresponding
              relocation info tables.
0x8    W    length of allocation for loaded file
              this is padded to account for a 0x20 byte alignment,
              and possibly some header info.
DAT Allocation Index = header objects for files in an allocation chain
Code:
DAT Allocation Index
@80432124 * 0x50

DAT Allocation Index Element

0x00    b    unk -- written to conditionally by using an immediate value
0x01    b    unk -- passed as argument r3 in calls to 80017740
0x02    b    unk -- passed as argument r5 (?)
0x03    b    unk
0x04    b    unk -- passed as argument r10 (?)
0x05    b    unk
0x06    s    DVD Entrynum of pathname string for file
0x08    s    status-- 9999 for ready(0x270F)
               used to represent some kind of a status for loading things
               from DVD.
0x0A    s    unk
0x0C    W    file size
0x10    P    to HSD Allocation Link for File follow link pointer to go
               directly to file allocation.
0x14    P    to HSD Allocation Link for Relocation Info or use the relocation
               info table to use pointers to various sections of the file.
0x18    ?    unk



80432078    0x000    unk, start of global index container
8043207C    0x004    unk index of "Old" interrupt elements this index of data
                       is overwritten with the "New" version of the index.
  ...
804320C0    0x048    unk index of "New" interrupt elements this data is copied
                       over to the "Old" index.
  ...
80432104    0x08C    unk data
  ...
80432124    0x0AC    HSD Allocation Index Element slot 1 game functions use
                       (base of DAT Alloc index) + 0xAC to access each slot,
                       incrementing the index by 0x1C.
80432140    0x0C8    HSD Allocation Index Element slot 2
8043215C    0x0E4    HSD Allocation Index Element slot 3
  ...
804329C8    0x950    HSD Allocation Index Element slot 80 there is a strict
                       limit of 80 slots.
DAT Relocation Info Table = special allocations at end of loaded file -- helps relocate file offsets
Code:
DAT Relocation Info Table
these are allocated alongside files dynamically,
but are accessed from the above static structures.

# first 0x20 bytes = string copied directly from the header of a DAT file
0x00    W    File Size
0x04    W    data block size
0x08    W    relocation table count
0x0C    W    root count
0x10    W    root count 2
0x14    W    unk
0x18    W    unk
0x1C    W    unk

0x20    P    to Reloc Base Address
               file start + 0x20
0x24    P    to Reloc
               pointer table in file relocation table
0x28    P    to root node index 1
0x2C    P    to root node index 2
0x30    P    to Symbol Strings
               used by functions to find data sections within data body.
0x34    ?    to unk1
0x38    ?    to unk2
0x3C    ?    to unk3

0x40    P    to File Data Start file header start
               (as opposed to relocation base address)


From these structures, it’s possible to derive information about where in a file certain objects have come from. I have a little more information about how to use it here.

---

Global player HUD structure

The player HUD structure uses a global array of 6 allocations (one for each player slot) dedicated to storing information used to sort of “puppet” the persistent matrix in the JObjs used by HUD digits.

HUD Index = array of 6 player HUD structures
Code:
@804a10c8 0x64 * 6
0x00    P    HUD_parent_entity -- unk class type E?
0x04    P    next HUD entity? -- unsure about this one
0x08    B    Player slot -- 0-5 ; representing players 1-6
0x0A    S    damage % (int) -- Updated damage
0x0C    S    old damage % (int) -- Unupdated damage -- used for update condition in new color calculation
0x0E    B    damage from last attack
0x0F    B    Frames of "shake" effect remaining after being hit -- will be set to 10 perpetually by flag (20)
0x10    W    Flags: -- flags byte:
0x10    (80)  Explode Animation flag? -- appears to trigger whether to animate death explosion (of digits)
0x10    (20)  force digits to shake -- untested as of 11/27 - observed behavior at 802f5af4
0x10    (10)  unk
0x10    (06)  2-bit ID -- appears to be related to some kind of animation status -- used to trigger heal animation
0x10    (02)  unk -- can be observed in all active players?
0x10    (08)  hide all digits -- can be observed in pause and "GO!" screen
0x14    F    X translation 100's digit -- These are manipulated in order to "shake" the digits upon taking damage
0x18    F    X translation 10's -- (they appear to reset back to default JObj definition)
0x1C    F    X translation 1's
0x20    F    X translation % sign
0x24    F    Y translation 100's digit
0x28    F    Y translation 10's
0x2C    F    Y translation 1's
0x30    F    Y translation % sign
0x34    F    X Velocity 100's -- Upon death, these values seem to be given random numbers to cause the digits to explode
0x38    F    Y Velocity 100's -- all digits appear to add Y velocity to create a "falling" gravity effect
0x3C    F    X Velocity 10's
0x40    F    Y Velocity 10's
0x44    F    X Velocity 1's
0x48    F    Y Velocity 1's
0x4C    F    X Velocity % sign
0x50    F    Y Velocity % sign
0x54    P    to 100's JObj -- These JObjs are siblings, and share a parent that can be modified to transform entire display
0x58    P    to 10's JObj -- each digit connects to an animated TObj in order to display the digit textures
0x5C    P    to 1's JObj
0x60    P    to % sign JObj


The end of the index contains a footer structure that has information used to instantiate assets referenced in the array:
Code:
@804a10c8
0x25C - JObjDesc Parent
0x260 - JAnim Selection (Joints)
0x264 - JAnim Selection (Textures)
0x268 - (null)
I didn’t go over this in much detail, but a function involved in retrieving this information used the “symbol” name “DmgNum_Scene_Models”

I recall an error message referring to what I think we commonly refer to here as an element of the “string table” as a “symbol” with

Code:
803BA5B0 : "Cannot find symbol %s"
I believe that it’s unique for the IfAll.dat relocation table to have a dedicated global pointer, but this is how the HUD initialization function reaches it

https://i.imgur.com/cXs1M0e.png


---

JObj kings and Entity Emperors

There’s an interesting relationship between JObjs and what SSBM Data Sheet users call “Entities.”

Each entity in the game is given an ID that represents a type; such as players, items, and stage pieces.

Each can potentially contain 2 very valuable pointers in their structure:
0x28 - point to root JObj of skeleton (if applicable)
0x2C - point to start of unique data allocation for this instance, formatted by class type
# some entities don't use these data pointers, relying instead on global data allocations

JObjDescs like the one pointed to at 0x25C from the HUD index footer can be used to load instances.

Once a root JObj is loaded with HSD_JObjLoad, the entire skeleton and all of its assets will also become instantiated using the params described in a JObjDesc:

https://i.imgur.com/PDMmbOj.png


A live JObj will link back to its parent and JObjDesc in addition to its other defined parameters.

---

Entities wrap a JObj skeleton and a data allocation together. When calling functions related to players, the game passes around “player entities” like they were names. Achilles1515 Achilles1515 used to call these “external player data tables” in his notes.

Achilles also had some excellent notes about Entities in a post about a global structure that points to the root of several entity types. The structure can be reached using r13, which is a special register used to anchor a relative pointer for global read/write data.



I have some additional notes using samples taken from various circumstances in the game while monitoring this table of his. Some offsets really required some provocation; like doing Fox's special taunt.

Each entity stores a class ID:
Code:
# Entity Select ----------------------------

lwz r3, -0x3e74(r13)
r3 = 804D782C (points to start of entity select index)

00    point    Class ID 000E (on start of scene?)
04    point    Class ID 000F (during multispawn load? Classic Team Battle)
08    point    Class ID 000E
0C    point    Class ID 000D
10    point    Class ID 0002
14    point    Class ID 0003 (Stage Entity?)
18    point    Class ID 0001
1C    point    Class ID 0005 (Possibly related to pending scene transitions)
20    point    Class ID 0004 -- First Player Entity on Stage
24    point    Class ID 0006 -- First Item/Projectile Entity on Stage
28    point    Class ID 0007
2C    point    Class ID 0008 -- First (?) GFX entity (dust clouds, shine GFX)
30    point    Class ID 0008 -- GFX entity?
34    point    Class ID 0009 (on STAGE CLEAR screen)
38    point    Class ID 000E
3C    point    Class ID 000E
40    point    Class ID 000E
44    point    Class ID 000F (on Master Hand Classic stage)
48    point    Class ID 0010
4C    point    Class ID 0011 (on Fox special taunt, screen overlay?)
50    point    Class ID 0013
54    point    Class ID 0013
58    point    Class ID 0014
5C    point    Class ID 0016
60    point    Class ID 0015
64+   null?    not sure if there are more
With all that, I can say only the following about entity class IDs:

03 = stage entity
04 = player entity
06 = item entity
08 = GFX entity
0E ~ used for HUD entity skeleton root; damage percentage display
0F ~ used during multispawn load (?)
10 = camera entity
11 ~ used for fox special taunt (?)
16 ~ unk -- highest witnessed class ID

---

To relate this back to the player HUD structure...

Each player HUD has an entity that uses type “0E” to identify itself. These entities don’t seem to use a data table, but offset 0x28 points to a root JObj instance as a part of initialization.

Each JObj in the skeleton points back to its JObjDesc, allowing us to navigate through all of the involved structure by starting with the global HUD index as a base:

https://i.imgur.com/8rIAytl.png


From the index of HUD structures, it’s possible to access all of these children bones for the sake of animating them with RNG. The joints are simply wiggled around in random directions to make the “shake” effect on hits, and are thrown in random directions to make the death “explosion” effect.

Other animations use scripted transformations, however.

---

HSD_JObjAddAnim

When a JObj needs to be animated with scripted information, it uses an AObj.

The AObj declares the time and rate of an animation.
From each AObj is a link to a root in a chain of FObjs.
Once instantiated, each FObj parses a data string.
These data strings describe frame-based transformations to the JObj matrix over time.

---

For example, when a player initializes, the HUD digits are under the visible screen area, and are animated to rise up into view each time a player spawns.

Without AObjs assigned to the digits' JObjs; the digits would start out of view and never move into place.

It’s not directly obvious how a JObjDesc connects to an AObjDesc, however. The two seem to be separated at birth -- only to be combined procedurally as separate arguments for a function call to HSD_JObjAddAnim.

---

I don’t know what these are officially called, so I’ve been just calling them by their object letter followed by the suffix “-Anim.”


JAnim Select (Joints) and JAnim Select (Textures) are used to call JObjAddAnim when used with a JObj. Each is just an index of pointers, connecting to different animations:

JAnim Selection = index of animations to select from
Code:
to JAnim 1
to JAnim 2
to JAnim 3
...

Format used for both joint and texture JAnim roots
A function (8000c07c) that I’ve been calling “HSD_JObjAddAnimAll_Indexed” uses the following arguments to select these animations for some "HUD"-like displays:
r3 = JObj
r4 = JAnim Select (Joints)
r5 = JAnim Select (Textures)
r6 = JAnim Select (unk -- mesh flags?)

Each argument may be null, allowing for the assignments to be optional based on what’s linked to in each JAnim joint written in a file.

---

The JAnim structures mimic JObj relationships, and are used merely to walk the structure of joints in a skeleton. They are basically just complex containers used to deliver AObjs.

https://i.imgur.com/gFx3YsE.png


JAnim = Joint-level JObj -> AObj container for HSD_JObjAddAnim r4
Code:
0x00    P    to Child JAnim
0x04    P    to Sibling JAnim
0x08    P    to AobjDesc
0x0C    P    to RObj JAnim
0x10    W    flags for PObj (?)

A root JAnim structure can be used with the root JObj to call HSD_JObjAddAnimAll -- allowing a whole skeleton to be animated at once.

This is what the HSD_JObjAddAnimAll_Indexed function calls once it has selected a JAnim skeleton on the index provided. For player HUD digits, animation 0 is used to initialize digits. Animation 1 is used to stretch them out when healing from a heal item.

Individual JObjs can also be animated on their own with HSD_JObjAddAnim.

Each AObjDesc in the structure connects to a chain of FObjDescs that each instantiate their own parse of file data strings once turned into instances.

---

For JAnim (Texture) params, the structure continues even further.

https://i.imgur.com/UABQvva.png



T_JAnim = Joint-level TObj -> AObj assignment from for HSD_JObjAddAnim r5
Code:
0x00    P    to Child T_JAnim
0x04    P    to Sibling T_JAnim
0x08    P    to DAnim param

Texture assignment to Joints seems to be optional -- but is useful because Joints have a broader scope in structure than textures do. A Joint can have multiple joints, each possibly having multiple Display objects, each possibly having multiple Textures from their associated Materials.

Because of this, the structures continue to mimic the relationships of each necessary object to create parameters for their own “-AddAnim” functions:

DAnim = HSD_DObjAddAnim r4
Code:
0x00    P    to unk
0x04    P    to Sibling DAnim?
0x08    P    to MAnim/TAnim param

MAnim/TAnim = HSD_MObjAddAnim r4 -- HSD_TObjAddAnim r4
Code:
same struct passed for both cases
0x00    P    to unk
0x04    P    to unk
0x08    P    to AObjDesc
0x0C    P    to ImageDesc Array for ID transformations

The ImageDesc Array for HUD texture animations is used to animate which decimal number shows for each digit.

---

So here’s my attempt to illustrate all of this at once:

https://i.imgur.com/aTUbFGB.png


- Dotted rectangles represent the scope of each of the 4 skeletons (as used by JObjAddAnim)
- Square nodes represent data inside of a file that's been loaded into RAM
- Octagonal nodes represent instantiated objects with their own dynamic allocations.
- Arrows represent pointers. Line color reflects skeleton type.
- Dashed lines represent procedural assignments through function calls.

---

A lot of the graphs here were partially based on the rough notes I scribbled all over this screenshot that I took. I was using Cheat Engine's memory view feature to get a better understanding of how the player HUD parse data gets from point A to point B.

https://i.imgur.com/vQ4eW8Q.png
Wow, fantastic stuff, Punkline!

Also, double-post totally pardoned. An example like this is pretty functional/useful, since separating really large chunks of information helps with organization (visualy, as well as for linking, for example). I think this differs a bit with threads because threads and their related information can drift apart from one another within their forum/sub-forum.

Nice, pointing out the difference between object file descriptions and live RAM instances. I can see how the latter could be really fun to play with through code.

Do you know of some files that have RObjDesc structs? I looked in a few, but didn't see any.

It's great to see all of this documented. Thanks for posting all of this (I know posts like that take time). You always do such a good job with your diagrams. What do you use to create them?

I know @rmn was working on animations, but I don't know how far he has gotten. I think if a few of us worked together, we could build a pretty nice new tool for working with subactions and animations. It seems like we have enough information.
 

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
I haven't really looked at subactions or events, but I've been thinking that a new tool for subactions and animations sounds like one of the main things that the Melee community could use a new focus on. CrazyHand can do a lot, of course, but there's also so much it can't do; and the absence of the main developer and lack of good source code, and the limitations those incur (namely, not being able to update it with new events, or the addition of features) suggests we just need to start on something new.
I totally agree. Achilles showed us that custom events are a perfect interface for connecting codes to moveset data, and the moving parts are already there in the game for us to use. I’ve noticed UnclePunch UnclePunch picking up on this fact too.

With enough custom event codes in the DOL, it’d be possible to practically rewrite some character codes by just using data strings thrown in Pl**.dat files.

---

To briefly explain: subaction event data is formatted a bit like machine code + wait timers.

You have a 6-bit opcode that specifies what the rest of the parameters are used for, and -- when executed -- do something implied by the operation type.
Every parser function in the game concatenates their callback index on top of a universal control callback index.

From this shared index; the first 10 operations in the 6-bit opcode capacity are dedicated to changing the parse pointer, event timer, and operating on the parser’s 5-word memory stack to create up to 5 nested return pointers, 2 nested loop counters, or a combination of the two.

Additional operations are then concatenated on top of those 10 events based on whether it’s a player parse, projectile parse, etc.

With these first 10 control events, a string of data can create sectioned off keyframes with “timer” events and calls/branches with “goto” and “subroutine” events. In between these control events, other event ops can be used to run scripted functions with params read in from the event strings; resulting in specifically timed hitboxes, graphics, sound effects, etc.

Subaction event data is isolated from animations, but they are designed around them -- and share variables sensitive to frame speed. (AObjs)

---

While there's a lot left to document about vanilla events; there's also custom events. I’d very much like to follow Achilles’s original design for extending event opcodes.

I’ve been working on a DOL mod project that would conform with the game’s subtly enforced player event lengths in order to allow for (up to) thousands of “plugin” event functions to be added to the game as MCM standalone functions. It’d also eliminate the need for using the relocation table in the DAT file to create pointers for GoTo and Subroutine events. I hope to put a beta in the codes section fairly soon.

Many of the existing syntaxes don’t use all (or sometimes, ANY) of their param bits. By using these sparse syntaxes as a base, and then abiding to their explicitly given data length limitations -- it’s possible to safely use them as “hosts.”
By adding a 2-bit secondary opcode to a syntax that doesn’t use 0x03000000 in its param bits, you can split an event like the barren [60] syntax into [60] [61] [62] [63]

By adding an 8-bit tertiary opcode to the [61] [62] and [63] events, you may safely create room for 768 “plugin” events.

Un-ordered callback lists that specify a desired tertiary opcode would allow developers to easily distribute their custom event codes with an implied opcode syntax that could be ported in case of conflicts.

By modifying the player action resolution parser and player skip parser, it’d also be possible to teach the game how to skip variable-length events by reading an 8-bit word-length param that follows the opcode bits. We could also create exceptions for unused event opcodes EC-FC -- allowing us to safely use those opcodes as well.

This is all pretty simple to organize using standalone functions and callback lists made with the special branch syntax in MCM.

---

With all that in mind, I think a program that allows us to create our own syntax templates would be extremely useful to modders. Perhaps not just for subaction event data, but also FObj string data, or even aspects of powerPC and other stuff.

A file format describing templates would also help offload the responsibility of actually figuring out the syntaxes onto the community as a whole rather than just the core developers.

Do you know of some files that have RObjDesc structs? I looked in a few, but didn't see any.
No, I haven’t found any either. I’ve been trying to use breakpoints on the RObjLoadDesc function with only hits on null params -- which seems to be every JObjDesc I’ve ever looked at.

My basis for this offset being listed in JObjDesc is from the JObjLoad callback function, @ around 80370d94: https://i.imgur.com/XWgPiBt.png


r30 = JObjDesc
r29 = JObj

---

It's great to see all of this documented. Thanks for posting all of this (I know posts like that take time). You always do such a good job with your diagrams. What do you use to create them?
Glad to share what I can.

For graphs, I found a neat plugin for atom that lets you preview things with graphviz right in the editor. I use it to quickly knock out a big idea, then save the preview as an SVG to be edited in inkscape afterwards.
 
Last edited:

Tcll

Smash Lord
Joined
Jul 10, 2010
Messages
1,780
Location
The Gates of Darkness
NNID
Tcll5850
can someone explain to me or reference me the post explaining the structure of a Pl**Aj.dat sub-file

I see alot of info here explaining the AObj itself and internal structure, but not much relating to external structure...
unless I'm blind and am completely overlooking it... >_<

afaik, Zankyou was the last person to work with me on this a while back, and only got as far as deducing the structure was similar to that of a brchr file, but I don't see anything verifying that >_>
 
Last edited:

LuigiBlood

Smash Rookie
Joined
Jun 8, 2009
Messages
13
This explanation on JObjDesc and other types of objects has been really useful to get into Kirby Air Ride "reverse enginnering" of sorts that I've been doing. I got the models and animations to work on Smash Forge from some files from KAR.
I have seen some stuff similar to DAnim and TAnim but currently not sure if they are.
 

LuigiBlood

Smash Rookie
Joined
Jun 8, 2009
Messages
13
So, umm... I looked at Killer7 source code for a bit more. I think you guys were just stuck on the sysdolphin libraries?
There's a full source code of their Maya export plugin. Which has definitions of LITERALLY EVERYTHING SUPPORTED with names and everything.

EDIT: Okay not actually everything but certainly much more than just regular sysdolphin lib stuff, at least what's left of it.
 
Last edited:

SinsOfApathy

Smash Journeyman
Joined
Feb 24, 2015
Messages
474
NNID
Psion312
Punkline Punkline

Not gonna quote your post for the sake of saving my sanity, but your JObj is inaccurate, I think. Definitely helped me get to this point, so thanks for that.

The JObj pointers don't seem to be JObjDescs, they're actually pointers to other JObjs. You also noted that the DObj pointer wasn't actually a DObjDesc, yet still called it that. It seems like for clarity, you should just called the JObj/DObj pointers, instead of JObjDesc/DObjDesc pointers.

https://github.com/PsiLupan/MeleeReassembled/blob/master/src/hsd/hsd_jobj.c#L99

This code is an example of how I came to the conclusion it wasn't a Descriptor object, since the way the code was referencing seemed to be just going to child pointers. Otherwise, it would've been doing "jobj->childdesc.child;" which would've made no sense with how it actually operates.
 

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
Punkline Punkline Not gonna quote your post for the sake of saving my sanity, but your JObj is inaccurate, I think. Definitely helped me get to this point, so thanks for that.
Oh gosh, that’s a bad typo.

Thank you, SinsOfApathy SinsOfApathy , I must have accidentally edited the wrong table or something. If you find anything else like that let me know. A lot of these notes were accumulated over time, so I may have missed some things like that from record to record.

I’ve edited the post to reflect this. Just to be absolutely sure, these match up with your notes, correct?

JObjDesc:
Code:
...
0x08    P    to JObjDesc Child
0x0C    P    to JObjDesc Sibling
0x10    P    to DObjDesc
....
JObj:
Code:
...
0x08    P    to JObj Sibling
0x0C    P    to JObj Parent
0x10    P    to JObj Child
...
 

SinsOfApathy

Smash Journeyman
Joined
Feb 24, 2015
Messages
474
NNID
Psion312
Oh gosh, that’s a bad typo.

Thank you, SinsOfApathy SinsOfApathy , I must have accidentally edited the wrong table or something. If you find anything else like that let me know. A lot of these notes were accumulated over time, so I may have missed some things like that from record to record.

I’ve edited the post to reflect this. Just to be absolutely sure, these match up with your notes, correct?
Yep, thus far that matches up with what I've got.

Still working through JObj functions, but if you click that link again, you should see some additional ones that are either totally complete or partial with a massive comment block for things I was confused on.
 

WaxPython

Smash Ace
Joined
Jul 8, 2018
Messages
786
I have no idea what's going on in this thread but it sounds cool. Have a bump man
 

SinsOfApathy

Smash Journeyman
Joined
Feb 24, 2015
Messages
474
NNID
Psion312
Punkline Punkline

Rather than keep all my findings in PMs, another thing to add is this:

AObj has a pointer at 0x18, so it's 0x1C in length. Typically, it's a JObj, but that isn't always true from what I can tell. 8036539C and 803644CC both reference it, so that's how I know it exists. From what I can tell, it's a void* that's either pointing to HSD_Obj (which holds ref_count) or it's cast to HSD_JOBJ typically. You'll see an example of it in my code for this function if you look at my GitHub. I haven't committed it as I type this, but I'm sure I will later on.

Also, 0x0C of the AObjDesc, I've called obj_id. The reason being it's passed as the 2nd parameter to HSD_IDGetDataFromTable in 8036539C. I haven't looked further into that function though, so that name is subject to change.
 
Last edited:

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
Punkline Punkline

Rather than keep all my findings in PMs, another thing to add is this:

AObj has a pointer at 0x18, so it's 0x1C in length. Typically, it's a JObj, but that isn't always true from what I can tell. 8036539C and 803644CC both reference it, so that's how I know it exists. From what I can tell, it's a void* that's either pointing to HSD_Obj (which holds ref_count) or it's cast to HSD_JOBJ typically. You'll see an example of it in my code for this function if you look at my GitHub. I haven't committed it as I type this, but I'm sure I will later on.

Also, 0x0C of the AObjDesc, I've called obj_id. The reason being it's passed as the 2nd parameter to HSD_IDGetDataFromTable in 8036539C. I haven't looked further into that function though, so that name is subject to change.
Awesome stuff man. I went and edited the post to reflect some of the blanks you filled in so far for JObjs, TObjs, and these new discoveries for AObjs and AObjDescs.
 

SinsOfApathy

Smash Journeyman
Joined
Feb 24, 2015
Messages
474
NNID
Psion312
Committed LObj yesterday in near entirety. The LightDesc object has a union that holds pointers to some structs that I haven't implemented as standalone structs (they're effectively the same as the union in the LObj, except it doesn't hold pointers). Everything else should basically be there from what I can gather.

Also, WObjs are World Objects. The LObj uses them to hold position and "interest" vectors.

I haven't started working on CObj (Camera Object), but I'd assume the two are closely linked for dealing with worldspace to screenspace.
 

shuall

Smash Apprentice
Joined
Jun 26, 2013
Messages
155
Location
Philly
HSD Info tables describe a list of callback routines for an object of a specific class type.

These callbacks are used to create default behaviors for all objects of said type. The first 5 callbacks in the list are standardized as follows:

slot 1 - 0x28 - Obj Alloc
slot 2 -
0x2C - Obj Init
slot 3 -
0x30 - Obj Release
slot 4 -
0x34 - Obj Destroy
slot 5 -
0x38 - Obj Amnesia
slot 6+ (unique)


Each info table links a function to these slots. Some object info tables will contain additional callbacks, which serve unique purposes specific to that object type.
This sounds like vtables, which, if melee was written in cpp and these "_Obj"s you're describing are cpp objects, would make sense. I forget why, but at some point I assumed it was. Maybe it was the function signature names are mangled, which you don't need to do for normal C functions. I'd have to skim signatures again to verify that.
 

SinsOfApathy

Smash Journeyman
Joined
Feb 24, 2015
Messages
474
NNID
Psion312
This sounds like vtables, which, if melee was written in cpp and these "_Obj"s you're describing are cpp objects, would make sense. I forget why, but at some point I assumed it was. Maybe it was the function signature names are mangled, which you don't need to do for normal C functions. I'd have to skim signatures again to verify that.
It's definitely not C++, while I appreciate the sentiment in investigating it. Besides the filenames being in the DAT in various asserts, we have several Sysdolphin headers in their entirety for reference and there's an Init function in each HSD "class" that initializes the function table at runtime.

I've also personally reverse engineered most of them and I'm not far from completion.

https://github.com/PsiLupan/MeleeReassembled/tree/master/src/hsd
 

SinsOfApathy

Smash Journeyman
Joined
Feb 24, 2015
Messages
474
NNID
Psion312
So, have been making some big strides towards booting into the Title lately, and something I've known but hadn't fully implemented yet was that JObj doesn't always have a DObj. It has a union which holds a pointer to either a "PTCL" or the DObj, and 803749B0 checks the flags for how to display the JObj based on either. 8005DB20 is the callback function that gets set for handling the PTCLs, but I haven't looked into it yet.

Another thing I'm also aware of, as I've been dealing with it, is that the Menu files (IE. the title screen) load a Joint, AnimJoint, MatAnimJoint, ShapeAnimJoint, and an SObjDesc. I assume SObjDesc is a "Scene Object Descriptor," but I've not dug into it yet as it's seemingly unused for the setup for the Title Screen at least.

You can see that work here:
https://github.com/PsiLupan/FRAY/blob/master/src/scene.c#L336
https://github.com/PsiLupan/FRAY/blob/master/src/archive.c#L37

I've seen some indication that there's an HSD_Joint, but haven't fully debugged it, as I've seen it in Killer7's reimplementation of JObj with some additions. I already have MatAnimJoint and it's simply a struct of 3 pointers which are next, prev, and the JObj itself respectively. Hopefully, AnimJoint and ShapeAnimJoint are similarly basic, as the main thing is that the game loads the raw data directly from a DAT file and just casts the pointer to that struct, which means certain parts of my files have to be as close to implementation as possible. It also likely means all the JObj/DObj/etc. documentation we have on the DAT file information is actually the Descriptors, rather than raw objects.

Edit:
Did some investigative work and here's just my scratch notes:
Code:
GmTitle.dat

Anim_Joint
80BFA8EC - 80BFA900 00000000 00000000 00000000 00000001 
    80BFA900 (Child of 80BFA8EC) - 80BFA914 80bfa928 80BFA280 00000000 00000001
        80BFA914 (Child of 80BFA900) - 00000000 00000000 80BFA2B0 00000000 00000001
    80BFA928 (Next of 80BFA900) - 80BFA93C 80BFA9A0 00000000 00000000 00000001
        80BFA93C (Child of 80BFA928) - 00000000 80BFA950 80BFA34C 00000000 00000001
    
    80BFA280 (AObjDesc of 80BFA900) - 00000000 44C80000 80BFA26C 00000000
        80BFA2B0 (AObjDesc of 80BFA914) - 00000000 44C80000 80BFA29C 00000000

MatAnim_Joint
80C0C564 - 80C0C580 00000000 00000000 
    80C0C580 (Child of 80C0C564) - 80C0C58C 80C0C598 80C0C3A4
        80C0C58C (Child of 80C0C580) - 00000000 00000000 80C0C3B4
        
    80C0C3A4 (MatAnim of 80C0C580) - 00000000 80C07C18 00000000 00000000
        80C0C3B4 (MatAnim of 80C0C58C) - 80C0C3C4 80C0902C 00000000 00000000
        80C0C3C4 (Next of 80C0C3B4) - 00000000 80C08FF8 00000000 00000000
        
    80C07C18 (AObjDesc of 80C0C3A4) - 00000000 44C80000 80C07C04 00000000
        80C0902C (AObjDesc of 80C0C3B4) - 00000000 44C80000 80C09018 00000000
        80C08FF8 (AObjDesc of 80C0C3C4) - 00000000 44C80000 80C08FE4 00000000
    
    80C07C04 (FObjDesc of 80C07C18) - 00000000 0000000D 00000000 0a878800 80C07BF4
        80C09018 (FObjDesc of 80C0902C) - 00000000 0000000D 00000000 0a878800 80C09008

struct HSD_AnimJoint {
    struct _HSD_AnimJoint *child;
    struct _HSD_AnimJoint *next;
    struct _HSD_AObjDesc *anim;
    u32 unk;
    u32 unk2;
    u32 unk3;
}
struct HSD_AObjDesc {
    u32 flags; //0x00
    f32 end_frame; //0x04
    struct _HSD_FObjDesc* fobjdesc; //0x08
    u32 obj_id; //0x0C
}
struct HSD_FObjDesc {
    struct _HSD_FObjDesc* next;
    u32 str_len;
    u32 unk08;
    u32 flags;
    char* string;
}
struct HSD_MatAnimJoint {
    struct _HSD_MatAnimJoint *child;
    struct _HSD_MatAnimJoint *next;
    struct _HSD_MatAnim *matanim;
}
struct HSD_MatAnim {
    struct _HSD_MatAnim *next;
    HSD_AObjDesc *aobjdesc;
    HSD_TexAnim *texanim;
    struct _HSD_RenderAnim *renderanim;
}
 
Last edited:

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
So, have been making some big strides towards booting into the Title lately, and something I've known but hadn't fully implemented yet was that JObj doesn't always have a DObj. It has a union which holds a pointer to either a "PTCL" or the DObj, and 803749B0 checks the flags for how to display the JObj based on either. 8005DB20 is the callback function that gets set for handling the PTCLs, but I haven't looked into it yet.

Another thing I'm also aware of, as I've been dealing with it, is that the Menu files (IE. the title screen) load a Joint, AnimJoint, MatAnimJoint, ShapeAnimJoint, and an SObjDesc. I assume SObjDesc is a "Scene Object Descriptor," but I've not dug into it yet as it's seemingly unused for the setup for the Title Screen at least.

You can see that work here:
https://github.com/PsiLupan/FRAY/blob/master/src/scene.c#L336
https://github.com/PsiLupan/FRAY/blob/master/src/archive.c#L37

I've seen some indication that there's an HSD_Joint, but haven't fully debugged it, as I've seen it in Killer7's reimplementation of JObj with some additions. I already have MatAnimJoint and it's simply a struct of 3 pointers which are next, prev, and the JObj itself respectively. Hopefully, AnimJoint and ShapeAnimJoint are similarly basic, as the main thing is that the game loads the raw data directly from a DAT file and just casts the pointer to that struct, which means certain parts of my files have to be as close to implementation as possible. It also likely means all the JObj/DObj/etc. documentation we have on the DAT file information is actually the Descriptors, rather than raw objects.

Edit:
Did some investigative work and here's just my scratch notes:
Code:
GmTitle.dat

Anim_Joint
80BFA8EC - 80BFA900 00000000 00000000 00000000 00000001
    80BFA900 (Child of 80BFA8EC) - 80BFA914 80bfa928 80BFA280 00000000 00000001
        80BFA914 (Child of 80BFA900) - 00000000 00000000 80BFA2B0 00000000 00000001
    80BFA928 (Next of 80BFA900) - 80BFA93C 80BFA9A0 00000000 00000000 00000001
        80BFA93C (Child of 80BFA928) - 00000000 80BFA950 80BFA34C 00000000 00000001
  
    80BFA280 (AObjDesc of 80BFA900) - 00000000 44C80000 80BFA26C 00000000
        80BFA2B0 (AObjDesc of 80BFA914) - 00000000 44C80000 80BFA29C 00000000

MatAnim_Joint
80C0C564 - 80C0C580 00000000 00000000
    80C0C580 (Child of 80C0C564) - 80C0C58C 80C0C598 80C0C3A4
        80C0C58C (Child of 80C0C580) - 00000000 00000000 80C0C3B4
      
    80C0C3A4 (MatAnim of 80C0C580) - 00000000 80C07C18 00000000 00000000
        80C0C3B4 (MatAnim of 80C0C58C) - 80C0C3C4 80C0902C 00000000 00000000
        80C0C3C4 (Next of 80C0C3B4) - 00000000 80C08FF8 00000000 00000000
      
    80C07C18 (AObjDesc of 80C0C3A4) - 00000000 44C80000 80C07C04 00000000
        80C0902C (AObjDesc of 80C0C3B4) - 00000000 44C80000 80C09018 00000000
        80C08FF8 (AObjDesc of 80C0C3C4) - 00000000 44C80000 80C08FE4 00000000
  
    80C07C04 (FObjDesc of 80C07C18) - 00000000 0000000D 00000000 0a878800 80C07BF4
        80C09018 (FObjDesc of 80C0902C) - 00000000 0000000D 00000000 0a878800 80C09008

struct HSD_AnimJoint {
    struct _HSD_AnimJoint *child;
    struct _HSD_AnimJoint *next;
    struct _HSD_AObjDesc *anim;
    u32 unk;
    u32 unk2;
    u32 unk3;
}
struct HSD_AObjDesc {
    u32 flags; //0x00
    f32 end_frame; //0x04
    struct _HSD_FObjDesc* fobjdesc; //0x08
    u32 obj_id; //0x0C
}
struct HSD_FObjDesc {
    struct _HSD_FObjDesc* next;
    u32 str_len;
    u32 unk08;
    u32 flags;
    char* string;
}
struct HSD_MatAnimJoint {
    struct _HSD_MatAnimJoint *child;
    struct _HSD_MatAnimJoint *next;
    struct _HSD_MatAnim *matanim;
}
struct HSD_MatAnim {
    struct _HSD_MatAnim *next;
    HSD_AObjDesc *aobjdesc;
    HSD_TexAnim *texanim;
    struct _HSD_RenderAnim *renderanim;
}

I’ve been looking at some examples in MnSlMap.usd to see how the SSS uses these structures, and can confirm all of this. Thanks for all the info.

Here are my notes about TexAnims and some partial notes about ShapeAnims combined with your notes:
Code:
Anim nodes used by JObjAddAnim function variants:

AnimIndex Node:
# - used to select from a list of indexed animations for a top JObj Node
0x00  P to array of top AnimJoint Nodes
0x04  P to array of top MatAnimJoint Nodes
0x08  P to array of top ShapeAnim Nodes

AnimJoint Node:
# r4 argument for JObjAddAnimAll
# - used to create an AObj for a specific JObj using a mirrored tree structure
0x00  P to Child AnimJoint Node
0x04  P to Sibling AnimJoint Node
0x08  P to AObjDesc  (for JObj)
0x0C  P to RObj AnimJoint Node  (?)
0x10  W unknown flags for PObj  (?)


MatAnimJoint Node:
# r5 argument for JObjAddAnimAll
# - used to contain Anim nodes for MObjs and TObjs to reach from a JObj tree structure
0x00  P to Child MatAnimJoint Node
0x04  P to Sibling MatAnimJoint Node
0x08  P to MatAnim Node

MatAnim Node:
# - used to create an AObj for a specific MObj using a DObj sibling link structure
0x00  P to Sibling MatAnim Node  (walks along mirrored DObj sibling links)
0x04  P to AObjDesc  (for MObj)
0x08  P to TexAnim Node
0x0C  P to RenderAnim Node  (?)

TexAnim Node:
# - used to create an AObj for a specific TObj using a TObj sibling link structure
0x00  P to Sibling TexAnim Node
0x04  W GXTexMapID  (?)
0x08  P to AObjDesc  (for TObj)
0x0C  P to ImageDesc pointer Array
0x10  P to TLutDesc pointer Array
0x14  S number of ImageDescs (?)
0x16  S number of TLutDescs  (?)


ShapeAnimJoint Node:
# r6 argument for JObjAddAnimAll
# - used to contain Anim nodes for PObjs to reach from a JObj tree structure
0x00  ? ?
0x04  P to ShapeAnim Node
# (unknown length, likely contains more pointers for walking JObj tree

ShapeAnim Node:
# - used to create an AObj for a specific PObj
0x00  ? ?
0x04  P to AObjDesc (for PObj->Influence MTX)
# (unknown length, likely contains more pointers for walking DObj siblings)

8036fb5c - HSD_JObjAddAnimAll

# r3 = JObj Tree (TopN, instantiated)
# r4 = AnimJoint
# r5 = MatAnimJoint
# r6 = ShapeAnimJoint

If you have a set of animations to assign to a figure (like a player) -- you can arrest control over ANY JObj tree’s current animation by calling this function. Any or all of r4, r5, r6 may be left null. Any animation nodes you include however when calling this function will be generated and assigned to the given TREE of JObjs.

This means a full skeleton can be animated with just this call.
(well, you also need to call HSD_JObjAnimAll once per frame -- but that’s what GProcs are for.)


Also, TIL you can write uleb128 data with the .uleb128 ASM directive. This may help you play with fake FObj String data.
UnclePunch UnclePunch T tauKhan
 
Last edited:

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
While I was checking out the SSS icons, I learned a little bit about some nuances of FObjDescs that might be useful for creating things like image arrays in DAT files. I’ve only looked at TexAnim->AObjDesc->FObjDescs -- so things may be different for the other types of animations.


In the case of the SSS, a TexAnim is made for all 5 types of icons, plus one for the stage title graphic array. Each of the 4 main icon types use type 9 imageDescs to show graphics that use a 256-color palette.

Each icon TexAnim->AObjDesc points to a chain of 2 FObjDescs -- 1 for the imageDesc array, and 1 for the TLUTDesc array.

For reference, here are the offsets I'll be referring to in FObjDescs:
Code:
FObjDesc:
# Chains of these are parsed according to the frame timer set by an AObj owner
0x00    P  to Next FObjDesc
0x04    W  Data String length
0x08    F  Start Frame
0x0C    (FF) 8-bit Operation Type
0x0D    (E0) 3-bit Quantized Data Type
0x0D    (1F) 5-bit Dequantization Shift
0x10    P  to Data String
(Some of these value names are just what I used in my notes, and do not necessarily reflect any official terms found through assert messages)


The “Operation Type” is an 8-bit (FF) value that differentiates the imageDesc FObj from the TLUTDesc FObj. The IDs for each:
01 = Create ImageDesc changes at defined keyframes in the Data String
0A = Create TLUTDesc changes at defined keyframes in the Data String.

The SSS uses these operations to turn an AObj’s frame space into an index space for selecting a texture from an array of pointers (provided by the TexAnim node).


The “Quantized Data Type” is a 3-bit (E0) ID that defines what format of integer will be used in the data string for describing keyframes. Since frames in the AObj use a floating point value -- these are casted into floats to dequantize the integers into (potentially) non-integral values.
0 (00) = none (treat each value like 0.0)
1 (20) = signed 2-byte (little-endian)
2 (40) = unsigned 2-byte (little-endian)
3 (60) = signed byte
4 (80) = unsigned byte
5+ == 0

Types 1 and 2 are hwords, but they have their bytes in reverse order.


The “Dequantization Shift” is a 5-bit (1F) value that defines a shift amount to apply to the quantized integer once it has been dequantized as a floating point.
You can think of it like creating a ratio, similar to this:

packed integer : unpacked float
1<<X : 1.0


This means that if you use a shift value of X=0, then the ratio will be 1 : 1.0.
If you use a shift value of X=4, then the ratio will be 0x10 : 1.0.

This effectively defines a sort of mantissa size in the quantized value, but this imagined mantissa size may exceed the actual size of the integer. This allows quantized values with a high dequant shift to represent very small numbers once they are converted into dequantized values.

---


The Data String pointed to by each FObjDesc is a string of values that alternates between uleb128 and the Quantized Data Type specified in the FObjDesc.

uleb128 stands for “unsigned little-endian base-128”, and is used to create values with an arbitrary bit length. A uleb128 value concatenates 7 bits together for every byte contained in it. The 8th bit (80) is used to sign that there is another byte that comes after it that’s part of the same value; allowing it to be parsed byte-wise.

As a little-endian format, sequential bytes in a single value will be compiled in reverse order when emitted as big-endian values. Values that are 7-bit and under (<= 0x7F) look just like bytes, but any value larger than that become less familiar-looking:



The value 0x100 becomes 0x8002 because each byte only represents 7 bits, and the input becomes shifted and reversed in the process, with added 0x80’s sprinkled into every byte in the sequence.

---


Above are data strings describing the top row of icons in each of the 11 paired icons on the SSS. There are 2 blank images used for special icon statuses at the beginning of the array; making 13 total images. The red string shows the ImageDesc FObj data, while the blue string shows the TLUTDesc FObj data. Notice that they are identical.

In the FObjDescs below the strings, I’ve highlighted the Operation Type, Quantized Data Type, and Dequantization Shift values in yellow. As you can see, operation type 01 is used to define an ImageDesc array FObj operation; while 0A is used to define a TLUTDesc array FObj operation.

The Quantized Data Type is set to 4 (80) for these FObjDescs, which means that each frame is defined as 1 unsigned byte. The Dequantization shift is set to 4 as well (04), which means that each unsigned byte will be the frame number left-shifted by <<4.


The first value in the string is a uleb128 value that defines 2 variables. The first is a 4-bit (...000F) value that defines some kind of status for the FObj parser, while the second (...FFF0) is an array size for the ImageDesc and TLUTDesc operation to increment to. Attempting to index more images/palettes than defined here will cause the illegal indices to be ignored.


Edit - rewrote for clarity:

So, the first value used in the strings above, "D1 01" becomes "D1" when parsed:
(...D101)
(...
7F00) = 51 = (lowest 7 bits)
(...8000) = 80 = (flag = TRUE, so get next byte)
(...007F) = 01 = (highest 7 bits)
(...0080) = 00 = (flag = FALSE, so end of value)

(01 <<7) | 51 = 00D1

With 8 bits of data, this just barely requires 2 bytes from the uleb128 format.
As the first value, this then becomes split into 2 variables:

(00D1)
(000F) = 1 = Status value (1)
(FFF0) = D = Array Size (13 images)



After the first value, any following values in the string define a keyframe with a quantized integer followed by another uleb128 value.
This value pair defines a frame index, and a frame length.

With type 4, we can expect the quantized integer to be a single unsigned byte.
This is formatted like so:
(00 ...0001)
(
FF ...0000) = 00 = Quantized Frame Index (0.0)
(00 ...FFFF) = 0001 = 01 = Frame length (1.0)



One quirk about these definitions is that the frame value used to create an index does not seem to be displaced by varying frame lengths. So I guess rather than a literal frame, you are defining an intersection in an abstract frame space. (this can also be offset by the FObjDesc starting frame value.)

So when it sets the length to 01, it means that 1.0 worth of frames are assigned to the next image in the array. This makes it so that we can access each frame in the constructed AObj by setting the frame to a whole number. With a Dequantization shift of 4, we have a 4-bit mantissa that we can use to assign frames in-between whole numbers.

At the end of the string, you can see it assigning the last index with a ridiculous frame length:
(C0 ...B40C)
(FF ...0000) = 00C0 = Quantized Frame Index (12.0) (dequant gives 4-bit mantissa)
(00 ...FFFF) = B40C = 0634 = Frame length (1588.0)


This makes it so that if an AObj is set to a frame beyond its last index, it will remain on the last image instead of rewinding.

---


The Stage Title graphics are a little different from the icons. Instead of using 5 different concatenated arrays (we only looked at 1), it uses a single big array of 30 images.

Also, each image is a type 0 imageDescs to create alpha maps that don’t use TLUT palettes; so only 1 FObjDesc is needed to index imageDesc pointers with keyframes.

It otherwise works very similarly:


(...E103)
(...
7F00) = 61 = (lowest 7 bits)
(...8000) = 80 = (flag = TRUE, so get next byte)
(...007F) = 03 = (highest 7 bits)
(...0080) = 00 = (flag = FALSE, so end of value)

(03 <<7) | 61 = 01E1

(01E1)
(000F) = 1 = Status value (1)
(FFF0) = 1E = Array Size (30 images)



Instead of using increments of 0x01 (1.0), it uses increments of 0x14 (20.0).
This means that in order to reference each stage title, the game must multiply the target index by 20.0 to align it:
(00 ...0014)
(
FF ...0000) = 10 = Quantized Frame Index (2.0) (dequant gives 3-bit mantissa)
(00 ...FFFF) = 0014 = 14 = Frame length (20.0)



This example in particular helps illustrate how the frame index is just an intersection, rather than a real displacement of the starting frame.

Something I'm still not quite sure of is the blank entry at the end. It's apparent in both examples. It seems to re-state the last used frame index, and then follow up with a null byte like a terminator. I haven't yet checked to see how this null byte is treated, but there is a string length definition in the FObjDesc, and a terminator would be redundant.

---


Anyway, if you can see the pattern in these strings, then maybe you'll start seeing them in other kinds of FObjs too.
It would be pretty cool if we started figuring out what the various FObj operation types did for each animated object type.

AnimJoints for JObjs; MatAnims for MObjs; TexAnims for TObjs; ShapeAnims for PObjs

DRGN DRGN SinsOfApathy SinsOfApathy UnclePunch UnclePunch T tauKhan
 
Last edited:
Top Bottom