• 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!

Viewing character bones

zankyou

Smash Lord
Joined
Sep 12, 2014
Messages
1,055
Not sure how much this is gonna help anyone, but I thought it might help with moving to different bones so Ill post this here.
I converted the bone struct of the main characters and created an mdl0 file of them. So you can open them up and view them in brawlbox. The bones are indexed but theres no names so I just used the id for their name.
 

Attachments

zankyou

Smash Lord
Joined
Sep 12, 2014
Messages
1,055
I plan to name all of the melee bones according to their brawl counterpart. Might take a while though.

List of Characters

Captain->73
Mario->8
------
End of List

Mario::61
Bone_0=TopN
Bone_1=TransN
Bone_2=XRotN
Bone_3=YRotN
Bone_4=HipN
Bone_5=WaistN
Bone_6=LShoulderN
Bone_7=LShoulderJA
Bone_8=LShoulderJ
Bone_9=LArmJ
Bone_10=LHandN
Bone_11=L1stNa
Bone_12=L1stNb
Bone_13=L2ndNa
Bone_14=L2ndNb
Bone_15=L3rdNa
Bone_16=L3rdNb
Bone_17=L4thNa
Bone_18=L4thNb
Bone_19=LThumbNa
Bone_20=LThumbNb
Bone_21=LHandNb
Bone_22=NeckN
Bone_23=HeadN
Bone_24=HatN
Bone_25=LHigeN
Bone_26=MouthN
Bone_27=NoseN
Bone_28=RHigeN
Bone_29=RShoulderN
Bone_30=RShoulderJA
Bone_31=RShoulderJ
Bone_32=RArmJ
Bone_33=RHandN
Bone_34=R1stNa
Bone_35=R1stNb
Bone_36=R2ndNa
Bone_37=R2ndNb
Bone_38=R3rdNa
Bone_39=R3rdNb
Bone_40=R4thNa
Bone_41=R4thNb
Bone_42=RHaveN
Bone_43=RThumbNa
Bone_44=RThumbNb
Bone_45=RHandNb
Bone_46=WaistNb
Bone_47=LLegJA
Bone_48=LLegJ
Bone_49=LKneeJ
Bone_50=LFootJA
Bone_51=LFootJ
Bone_52=LToeN
Bone_53=RLegJA
Bone_54=RLegJ
Bone_55=RKneeJ
Bone_56=RFootJA
Bone_57=RFootJ
Bone_58=RToeN
Bone_59=ThrowN
Bone_60=EyeYellowM
------
End of Bone Names

Captain::63
Bone_0=TopN
Bone_1=TransN
Bone_2=XRotN
Bone_3=YRotN
Bone_4=HipN
Bone_5=HolsterN
Bone_6=LLegA
Bone_7=LLegJ
Bone_8=LKneeJ
Bone_9=LFootJA
Bone_10=LFootJ
Bone_11=LToeN
Bone_12=RLegA
Bone_13=RLegJ
Bone_14=RKneeJ
Bone_15=RFootJA
Bone_16=RToeN
Bone_17=RFootJ
Bone_18=WaistN
Bone_19=BustN
Bone_20=CollarN
Bone_21=LShoulderN
Bone_22=LShoulderJA
Bone_23=LShoulderJ
Bone_24=LArmJ
Bone_25=LHandN
Bone_26=L1stNa
Bone_27=L1stNb
Bone_28=L2ndNa
Bone_29=L2ndNb
Bone_30=L3rdNa
Bone_31=L3rdNb
Bone_32=L4thNa
Bone_33=L4thNb
Bone_34=LHandBN
Bone_35=LThumbNa
Bone_36=LThumbNb
Bone_37=LSideN
Bone_38=NeckN
Bone_39=HeadN
Bone_40=MouthBN
Bone_41=MouthN
Bone_42=RShoulderN
Bone_43=PadN
Bone_44=RShoulderJA
Bone_45=RShoulderJ
Bone_46=RArmJ
Bone_47=RHandN
Bone_48=R1stNa
Bone_49=R1stNb
Bone_50=R2ndNa
Bone_51=R2ndNb
Bone_52=R3rdNa
Bone_53=R3rdNb
Bone_54=R4thNa
Bone_55=R4thNb
Bone_56=RHandBN
Bone_57=RHaveN
Bone_58=RThumbNa
Bone_59=RThumbNb
Bone_60=RSideN
Bone_61=ThrowN
Bone_62=ToothClose_ -(YellowEye?)
------
End of Bone Names
 

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
Thanks for this, Z zankyou . I’ve been playing with this for a little while now. I’m new to brawlbox, and this was a gentle introduction.

I briefly mentioned this in another thread, but I’m trying to learn more about an interesting pointer that player entities (in RAM) store at internal player data offset 0x5E8. The game appears to use it to define bone origins when assigning active hitboxes (and tons of other bone-oriented things, I think)

With your notes, I can label these Mario bones that can be found in-game by following the stored pointer:


The pointers stored in this table seem to have a lot to say about animated interpolations like those made to Mario’s fist during his upTilt and fAir:



I haven’t looked very closely at this interpolation data yet, but the results of what are clearly data parses appear to be kept in the interpolation data table, and presumably used to calculate the resulting rotations, scales, and offsets of bone dimensions referenced in the pointer of a bone on the 0x5E8 table.

It’s possible to exploit this in order to make adjustments to the skeleton of individual player entities loaded in the game. I’ve got some notes with a few simple demonstrations and a code in the spoiler below, for anyone interested in this sort of thing.

Table 1 - internal player data + 0x5E8 -> + (boneID * 16) ->
Table 2 - internal player data + 0x5E8 -> + (boneID * 16) + 4 ->
Table 3 - Table 1 or 2 + 0x84 ->

Tables 1/2
0x00 - dol data pointer
0x08 - next sibling?
0x0C - parent? previous?
0x10 - child? next?
0x1c - ZYX rotation
0x2c - ZYX scale
0x38 - ZYX offset
0x7C - Interpolation Pointer (0 when not interpolating)
0x84 - Default Bone Dimensions data pointer

Table 3
0x14 - ZYX rotation
0x20 - ZYX scale
0x2C - ZYX offset


Each entry in the 0x5E8 table is 0x10 bytes long and includes 2 pointers to other data tables. These 2 tables appear to be identical in length, and handle the same kind of data for a specific bone (in different ways.)


--The first table looks like it keeps track of readable data for things that want to reference bone dimensions after they’ve been interpolated by something like an attack animation. The values here appear to also determine the dimensions of a bone, so modifying them every frame produces almost-convincing permanent transformations.

I’ve played around with codes that modify the ZYX float values for final rotation (0x1C) scale (0x2C) and position (0x38) in the first table with satisfying results. However, presumably because of the fact that the effect of these transformations is interpolated--certain action states that attempt to animate these values will create single frames where any related transformations forced with the interpolation values on the first table (every frame) will break. I may try this again with a different hook to see if this can be easily taken care of.


--In the second table these same modifications appear to have much less power; however singular pokes in memory will last for entire action states. I haven’t experimented with it much. Try looking at costume3 mario from the provided code at the bottom of this spoiler, and maybe see how it behaves with other characters/bones:


--A third table is referenced at offset 0x84 of either of these other tables. It contains valuable data that appears to represent loaded default bone dimensions, (among other things.)



0x14 - ZYX rotation
0x20 - ZYX scale
0x2C - ZYX offset

Modifying THESE will have more permanent effects on the player skeleton than either of the other tables. However, any move that interpolates a bone modified this way will blend with the values defined by the interpolation:

(sidenote: these interpolations seem to be related to internal player data offsets 0x8E4 and 0x8E8)

If modifications to this third table are made in tandem with modifications to the interpolated frame data values in the first table; virtually permanent modifications to the skeleton can be written with codes. Rotation transformations still seem to be a problem with things like shield angle, sheik’s chain-whip animation, and other input-oriented transformations.

---

Offset 0x0 in each table holds an interesting pointer that appears to point to a function pointer baked inside of start.dol. The referenced function in the first table seems to be common to every single scene transition (including stage initialization.)



In the second table, the function for offset 0x0 appears to be related to player allocation.



In each, after the function is called--the space around the referenced function pointer becomes populated with pointers, and a flag seems to indicate that it has loaded something. I haven’t looked too far in on either function, but they both call the same function (80381c18) that makes a call to SYS_memcpy.

---

Offset 0x7C is pretty fascinating. A pointer will appear in this offset (on either table) whenever a bone is being interpolated. The pointer points to a table that appears to be allocated (or just repurposed) at the time of animation, and keeps simple data about the timing of the interpolation with another pointer to the actual interpolation data.

From the interpolation data table (pointed to by the interpolation timer table,) you can see the game making a parse of some cryptic data that somehow turns into floats and flags for the interpolation effect. I’ve not attempted to figure out the syntax yet, but I took note of the values used in Mario’s right hand while performing an upTilt animation:

Code:
RHandN  - Z interpolation data for mario upTilt
frame 1? - 34 00 40 08 00 01 11 40 08 00 01 11 40 76 00
frame 2  - 01 FD 40 43 01
frame 3  - 03 05 17 02 12 1E 45
frame 6  - 01 5C 53
frame 7  - 05 04 62 55 F8 FD
frame 12 - 03 05 AE FD 02 1E 45
frame 15 - 04 14 1E 45 A9 FF
frame 19 - 0B 00 40 93 FF
frame 30 - 01 03 00 40 00 00
frame 31 - end

RHandN - Y interpolation data for mario upTilt
frame 1? - 34 00 40 00 00 01 00 40 00 00 01 00 40 82 00
frame 2  - 01 05 41 C2 01
frame 3  - 03 05 55 03 12 0A 47
frame 6  - 01 08 63
frame 7  - 05 04 0E 65 40 FC
frame 12 - 03 05 B7 FB 02 0A 47
frame 15 - 04 14 0A 47 88 FF
frame 19 - 0B 00 40 6A FF
frame 30 - 01 03 00 40 00 00
frame 31 - end

RHandN - X interpolation data for mario upTilt
frame 1? - 34 00 40 5F 00 01 BE 40 5F 00 01 BE 40 7A 02
frame 2  - 01 B3 45 C6 04
frame 3  - 03 05 6B 08 12 D7 53
frame 6  - 01 5A 65
frame 7  - 05 04 60 67 8F FD
frame 12 - 03 05 36 FD 02 D7 53
frame 15 - 04 14 D7 53 AE FE
frame 19 - 0B 00 40 59 FE
frame 30 - 01 03 00 40 00 00
frame 31 - end

0ing out this data causes the floats in the interpolation data table to also appear as 0--and the interpolation effect is circumvented. 0ing out the pointer to the interpolation timer also does this.


---

For now, I’ve only tried playing with the values in the 3 bone data tables. Just to reiterate, that’s the first and second tables referenced in the 0x5E8 lookup table, and the third one from offset 0x84 in either of those.

I wrote a quick code that eats an array of parameters to define bone dimension overwrites every single frame during the playerThink physics update. See the list of .long variables and their comments for information on how to use the code to experiment with overwrites of specific dimension values in these tables.

Code:
    -==-


Bone Dimension Overwrites
A means of testing stuff with bone data
[Punkline]
Version -- DOL Offset ------ Hex to Replace ---------- ASM Code
1.02 ----- 0x8006b84c --- 8803221F -> Branch

4800008C 4E800021        #branch to code
00010707 011B4080        #start of overwrites
00020707 021B4080
00040707 041B4080
151F0706 051B4080
091F0502 05583F00
091F0702 05590000
021F0702 05120000
071F0702 05110000
131F0702 055C3F00
131F0404 055B4080
131F0404 055C40C0
11100702 05054020
11100702 05163F00
11080702 052F4040
11080702 05354040
11080204 050440B0        #end of overwrites
FFFFFFFF 4BFFFF79        #start of code
7FC802A6 88A30619
80C30004 889E0000
280400FF 418200E4
7C043040 40A200D4
889E0001 5C842EF7
41A200C8 83A305E8
88FE0002 891E0003
893E0004 895E0005
A17E0006 556B801E
554A2036 7D4AEA14
71200001 41A20038
808A0000 3884001C
71000001 41A20008
48000061 38840010
71000002 41A20008
48000051 3884000C
71000004 41A20008
48000041 71200002
808A0004 41A2000C
712900FD 4BFFFFC0
71200004 41A2004C
712900FB 80840084
38840014 71000001
41A20008 4800000D
3884000C 4BFFFFAC
70E00001 41A20008
91640000 70E00002
41A20008 91640004
70E00004 41A20008
91640008 4E800020
3BDE0008 4BFFFF18
8803221F 00000000
$Bone Overwrite Test [Punkline]
C206B84C 00000032
4800008C 4E800021
00010707 011B4080
00020707 021B4080
00040707 041B4080
151F0706 051B4080
091F0502 05583F00
091F0702 05590000
021F0702 05120000
071F0702 05110000
131F0702 055D3F00
131F0404 055B4080
131F0404 055C40C0
11100702 05054020
11100702 05163F00
11080702 052F4040
11080702 05354040
11080204 050440B0

FFFFFFFF 4BFFFF79
7FC802A6 88A30619
80C30004 889E0000
280400FF 418200E4
7C043040 40A200D4
889E0001 5C842EF7
41A200C8 83A305E8
88FE0002 891E0003
893E0004 895E0005
A17E0006 556B801E
554A2036 7D4AEA14
71200001 41A20038
808A0000 3884001C
71000001 41A20008
48000061 38840010
71000002 41A20008
48000051 3884000C
71000004 41A20008
48000041 71200002
808A0004 41A2000C
712900FD 4BFFFFC0
71200004 41A2004C
712900FB 80840084
38840014 71000001
41A20008 4800000D
3884000C 4BFFFFAC
70E00001 41A20008
91640000 70E00002
41A20008 91640004
70E00004 41A20008
91640008 4E800020
3BDE0008 4BFFFF18
8803221F 00000000
Code:
#@8006b84c: lbz    r0, 0x221F (r3)         (beginning of playerThink function; executes every frame for every player)
#r0, r4-r12, r26-r27, r29-r30, f30-f31, cr0, ctr, lr == all safe to use
#r28 == saved external player data pointer
#r3 == internal player data pointer
#--assigning bone dimension overwrites every frame. Testing the 3 known bone data tables accessible with player data 0x5E8
b codeStart
getOverwriteData:
blrl                            #data table is parsed for information put into registers if character/costume matches
                                #0x0 = CHID, 0x1 = costume flags (5bits,) 0x2 = dimension flags, 0x3 = transformation flags,
                                #0x4 = table flags, 0x5 = bone ID, 0x6 = 16-bit truncated float

.long 0x00010707                #Mario, costume4, ZYX, rotation/scale/offset, 1st table, bone 0x1B, 4.0
.long 0x011B4080                #--testing table 1 writes with mario4 (rotation, scale, offsets)
                                #--makes a stupid looking nose modification. Notice how the transformation breaks differently between costumes

.long 0x00020707                #Mario, costume3, ZYX, rotation/scale/offset, 2nd table, bone 0x1B, 4.0
.long 0x021B4080                #--testing table 2 writes with mario3

.long 0x00040707                #Mario, costume2, ZYX, rotation/scale/offset, 3rd table, bone 0x1B, 4.0
.long 0x041B4080                #--testing table 3 writes with mario2

.long 0x151F0706                #Doc, all costumes, ZYX, scale/offset, 1st/3rd table, bone 0x1B, 4.0
.long 0x051B4080                #--A version of the above that doesn't break transformations between animations
                                #--rotation transformations seem to be sensitive no matter what tables are used

.long 0x091f0502                #Peach, all costumes, ZY, scale, 1st/3rd table, bone 0x58, 0.5
.long 0x05583f00
.long 0x091f0702                #Peach, all costumes, ZXY, scale, 1st/3rd table, bone 0x59, 0.0
.long 0x05590000                #--short-hair Peach

.long 0x021f0702                #Cfalcon, all costumes, ZYX, scale only, 1st/3rd table, bone 0x11, 0.0 scale
.long 0x05120000                #--Falcon butt (artificially truncate skeleton by killing WaistN scale) (bones still have origins for hitboxes)

.long 0x071f0702                #Sheik, all costumes, ZYX, scale only, 1st/3rd table, bone 0x12, 0.0 scale
.long 0x05110000                #--Sheik butt (kill WaistN scale)

.long 0x131f0702                #Zelda, all costumes, ZYX, scale, 1st/3rd table, bone 0x5D, 0.5 scale
.long 0x055C3F00
.long 0x131f0404                #Zelda, all costumes, X, offset, 1st/3rd table, bone 0x5B, 3.0
.long 0x055B4080
.long 0x131f0404                #Zelda, all costumes, X, offset, 1st/3rd table, bone 0x5C, 4.0
.long 0x055C40C0                #--Rapunzel Zelda

.long 0x11100702                #Luigi, costume0, ZYX, scale, 1st/3rd table, bone 0x05, 2.5 scale
.long 0x05054020
.long 0x11100702                #Luigi, costume0, ZYX, scale, 1st/3rd table, bone 0x16, 0.5 scale
.long 0x05163F00                #GREEN GOLIATH

.long 0x11080702                #Luigi, costume1, ZYX, scale, 1st/3rd table, bone 0x2F, 3.0 scale
.long 0x052F4040
.long 0x11080702                #Luigi, costume1, ZYX, scale, 1st/3rd table, bone 0x35, 3.0 scale
.long 0x05354040
.long 0x11080204                #Luigi, costume1, Y, offset, 1st/3rd table, bone 0x04, 5.5
.long 0x050440B0                #LEGWEEGI -- interesting topN offset problem with ground

.long 0xffffffff                #termination code

codeStart:
bl getOverwriteData
mflr r30                #r30 = pointer to parse data
lbz r5, 0x619(r3)        #r5 = costume ID
lwz r6, 4(r3)           #r6 = character ID

loop:
#first make sure this character/costume has any entries in our in-line data array
lbz r4, 0(r30)
cmplwi r4, 0xFF                 #if character ID is FF, this is a termination code
beq- exitLoop
cmplw r4, r6
bne+ nextEntry                  #if character ID doesn't match, parse next entry

lbz r4, 1(r30)
rlwnm. r4, r4, r5, 27, 27       #if costume ID isn't == to the placement of one of the costume bits, parse next entry
beq+ nextEntry

#if character/costume matches, then load the rest of the data
lwz r29, 0x5E8(r3)      #r29 = bone lookup table
lbz r7, 2(r30)          #r7 = dimension flags (Z, X, Y)
lbz r8, 3(r30)          #r8 = transformation flags (rotation, scale, offset)
lbz r9, 4(r30)          #r9 = bone table flags (interpolation-frame, interpolation-state, interpolation-default)
lbz r10, 5(r30)                 #r10 = bone ID
lhz r11, 6(r30)     
slwi r11, r11, 16       #r11 = float value
slwi r10, r10, 4
add r10, r10, r29      #r10 = pointer to bone data entry

#and now for some complicated bit conditions
checkT1:                        #write floats to tables that are flagged in r9, through transformations flagged in r8, of dimensions in r7
andi. r0, r9, 1                 #checking for table 1 flag
beq+ checkT2
lwz r4, 0(r10)
writeT2:
addi r4, r4, 0x1C               #start of table1/2 rotation
andi. r0, r8, 1
beq+ 0x8                        #(skip if unflagged)
bl writeFloat
addi r4, r4, 0x10               #start of table1/2 scale
writeT3:
andi. r0, r8, 2
beq+ 0x8
bl writeFloat
addi r4, r4, 0xC                #start of table1/2/3 offset
andi. r0, r8, 4
beq+ 0x8
bl writeFloat

checkT2:
andi. r0, r9, 2
lwz r4, 4(r10)
beq+ checkT3
andi. r9, r9, 0xFD              #mask out T2 condition so it doesn't loop forever
b writeT2                       #table 1 and 2 offsets are identical

checkT3:
andi. r0, r9, 4
beq+ nextEntry                  #start parsing next entry if T3 isn't flagged
andi. r9, r9, 0xFB              #mask out T3 condition so it doesn't loop forever
lwz r4, 0x84(r4)
addi r4, r4, 0x14               #start of table 3 rotation
andi. r0, r8, 1
beq+ 0x8                        #(skip if unflagged)
bl writeFloat
addi r4, r4, 0xC                #start of table 3 scale
b writeT3                       #table 3 has different offsets than tables 1 and 2

writeFloat:                     #writes the float to each dimension flagged in r7
checkZ:
andi. r0, r7, 1
beq+ checkX
stw r11, 0(r4)
checkX:
andi. r0, r7, 2
beq+ checkY
stw r11, 4(r4)
checkY:
andi. r0, r7, 4
beq+ finishWriteFloat
stw r11, 8(r4)
finishWriteFloat:
blr

nextEntry:                      #move pointer and restart loop to parse next entry
addi r30, r30, 0x8
b loop

exitLoop:                       #when termination code is found, return
return:
lbz r0, 0x221F (r3)

I’ve highlighted the in-line data table in RED. For information about the syntax, see the ASM comments. The default overwrites do the following:

Mario4 (costume 4) = Table 1 test (XYZ transformations to rotation, scale, and offset of mario’s nose)
Mario3 = Table 2 test
Mario2 = Table 3 test
Dr Mario = Table 1 and 3 test (no rotation transformations) (modifications don’t break)

Luigi0 = “Green Goliath”
Luigi1 = “Legweegi” (exploring topN(?) problems, floating ground plane)

Sheik = 0-scale torso (safely truncate the skeleton in a way that keeps the bones)
CFalcon = 0-scale torso

Peach = short-hair (above truncation method applied to dangly bones)
Zelda = “Rapunzelda” (long-hair)

 
Last edited:

zankyou

Smash Lord
Joined
Sep 12, 2014
Messages
1,055
Im glad someone besides me is getting use out of them. I found that function a while ago and was going to try and use it to brute force animations by recording the bone transformations but then revel saved the day and gave an insight into animation files far deeper than I ever could have gone.
 
Top Bottom