MKWii Network Protocol/RACEDATA

From Custom Mario Kart
Jump to: navigation, search

This pages is related to MKWii Network Protocol and describes the record type RACEDATA.


Data Structure

RACEDATA records contain the player specific race data of a client. Depending on the number of player on a Wii, one or two records are send. The RACEDATA records follow immediately the RACE record with general racing information.

Record structure of a complete racing packet
Size Count Type Description
0x08 0–1 SLOT Only used for redirected data via a proxy. The record identifies the original client by its slot number.
0x10 1 HEADER A header for a race packet.
0x28 1 RACEHEADER_1 Basic race data, 1 record per client.
0x28 0-1 RACEHEADER_2 Basic race data, 1 record per client. Not present in live view.
0x40 1–2 RACEDATA Race data (with positions) for each player of a client.
0xc0 0–1 USER A USER record containing mii data and friendcode(s).
0x08 1–2 ITEM Item in the box for each player of a client incl. handshaking to limit some items.
>= 0x18 1 EVENT A list with 24 byte entries. If a value is not 0x10, it declares an EVENTDATA field is following. After that list, up to 24 EVENTDATA records follow.

Here is the record read function in GNU C notation. The function notation is used, because some values are bit packed. This code was created by a code generator.

    d->position[0]	= be32(src+ 0x000 )   >> 4 & 0x0FFFFFFFu;
    d->position[1]	= be32(src+ 0x003 )        & 0x0FFFFFFFu;
    d->position[2]	= be32(src+ 0x007 )   >> 4 & 0x0FFFFFFFu;
    d->direction[0]	= be32(src+ 0x00a -1) >> 3 & 0x0001FFFFu;
    d->direction[1]	= be32(src+ 0x00c -1) >> 2 & 0x0001FFFFu;
    d->direction[2]	= be32(src+ 0x00e -1) >> 1 & 0x0001FFFFu;
    d->speed            = be16(src+ 0x011 ); 
    d->tilt_angle       = be32(src+ 0x018 ); 
    d->nunchuk_X_axis   =      src[ 0x025 ]   >> 4 &       0x0Fu;   
    d->nunchuk_Y_axis   =      src[ 0x026 ]   >> 4 &       0x0Fu;   
    d->thundercloud     =      src[ 0x026 ]        &       0x01u; 
    d->lakitu		=      src[ 0x027 ]   >> 6 &       0x03u;
    d->falldown         =      src[ 0x027 ]        &       0x01u;
    d->buttons		=      src[ 0x028 ]   >> 4 &       0x0Fu;
    d->mt_start         =      src[ 0x028 ]   >> 3 &       0x01u;
    d->goldenshroom     =      src[ 0x029 ]   >> 6 &       0x01u;
    d->blooper_ink      =      src[ 0x029 ]   >> 1 &       0x01u; 
    d->megamushroom     =      src[ 0x029 ]        &       0x01u;
    d->star             =      src[ 0x02a ]   >> 7 &       0x01u; 
    d->twanwan          =      src[ 0x02a ]   >> 2 &       0x01u; 
    d->thwomp_hit       =      src[ 0x02a ]        &       0x01u;
    d->fire             =      src[ 0x02b ]   >> 5 &       0x01u;
    d->cataquack        =      src[ 0x02b ]   >> 4 &       0x01u;
    d->star_hit         =      src[ 0x02c ]   >> 7 &       0x01u; 
    d->fakebox_hit      =      src[ 0x02c ]   >> 6 &       0x01u; 
    d->bomb_blue_hit    =      src[ 0x02c ]   >> 5 &       0x01u; 
    d->bomb_blue_half   =      src[ 0x02c ]   >> 4 &       0x01u; 
    d->goomba_hit       =      src[ 0x02c ]   >> 1 &       0x01u; 
    d->collision        =      src[ 0x02e ]        &       0x01u;
    d->wheelie_start    =      src[ 0x02f ]   >> 7 &       0x01u; 
    d->stunt            =      src[ 0x02f ]   >> 5 &       0x01u;
    d->hop              =      src[ 0x02f ]   >> 3 &       0x01u;
    d->cannon		= be16(src+ 0x02f )   >> 6 &     0x0007u;
    d->drift		=      src[ 0x032 ]   >> 6 &       0x03u;
    d->already_drifted	=      src[ 0x032 ]   >> 4 &       0x01u;
    d->rank		= be16(src+ 0x032 )   >> 7 &     0x000Fu;

    return 0x40; // record size

And here the code of a self written code generator script. The script creates data structures and the read function above. The byte offset is hex, all others are decimal numbers. The bit numbering goes from 0 for the most significant bit (MSB, 0x80) to 7 to the least significant bit (LSB, 0x01) because of big endian coding.

Example: If the vector is 0a 4 6, then we have a 6 bit number beginning at offset 0x0a bit 4 (MSB, mask 0x0f) and ending at offset 0x0b bit 1 (LSB, mask 0xc0).

 !---------------------------------------------------------------------------------------
 !                        byte+bit
 ! type	name		 N offset bits	comment
 !---------------------------------------------------------------------------------------
   s32	position	 3   0  0 28	x+y+z positions in 1/16 units, 0x9f42410 is 0.0.
   u32	direction	 3  0a  4 17	Curious direction vector, see comment.
   s16  speed            -  11  0 16    Speed value (0x3e90 = 0, > 0x3e90 for forward, < 0x3e90 for backward).
   s32  tilt_angle       -  18  0 32    Float value for tilting angle - 1=center, <1=left, >1=right.
  ---------------------------------------------------------------------------------------
   u8   nunchuk_X_axis   -  25  0  4    nunchuk X axis - from 0 (left) to e (right). center = 7. 
   u8   nunchuk_Y_axis   -  26  0  4    nunchuk Y axis - from 0 (down) to e (up). center = 7. 
   u8   thundercloud     -  26  7  1    0: lost Thundercloud (by Thundercloud hit?), 1: got Thundercloud.
   u8	lakitu		 -  27  0  2	0: no Lakitu, 1: phase 1, 2: phase 2, 3: ?
   u8   falldown         -  27  7  1    Falldown, 1 during falldown animation, 0 at Lakitu/race.
   u8   buttons		 -  28  0  4	1: drive (A or Mushroom), 2: break/backwards(B), 3: A and B, 7: Hop or drift phase 1, 15: drift phase 2.
   u8   mt_start         -  28  4  1    This bit flips every time you release a Mini-Turbo (turbo start).
   u8   shroom           -  29  1  1    1 when you hit the item button, 0 when the single boost is finished.
   u8   blooper_ink      -  29  6  1    This bit flips every time you get hit by Blooper ink. 
   u8   megamushroom     -  29  7  1    This bit flips every time you use a Mega Mushroom.
   u8   star             -  2a  0  1    This bit flips every time you use a Star.
   u8   twanwan          -  2a  5  1    This bit flips every time the Chain Chomp in battle hits you.
   u8   thwomp_hit       -  2a  7  1    This bit flips every time you got hit by a Thwomp or the crushing machine at Toads Factory.
   u8   fire             -  2b  2  1    This bit flips every time you got hit by a Podoboo on DS Desert Hills (or by fire in general?).
   u8   cataquack        -  2b  3  1    This bit flips every time the Cataquack at GCN Peach Beach throws you in the air.
   u8   star_hit         -  2c  0  1    This bit flips every time you got hit by someone with a Star or drive into a cow (Moo Moo Meadows).
   u8   fakebox_hit      -  2c  1  1    This bit flips every time you collide with a Fake Item Box or Monty Mole.
   u8   bomb_blue_hit    -  2c  2  1    This bit flips every time you got completely hit with a Blue Shell or a Bob-omb. Also flips unknown highest bit at 0x38.
   u8   bomb_blue_half   -  2c  3  1    This bit flips every time you drive into an exploding Blue Shell, exploding Bob-Omb, cactus, Pokey (Dry Dry Ruins), Shy Guy snowboarder (DK Summit) or penguin (N64 Sherbet Land). Also flips unknown highest bit at 0x38.
   u8   goomba_hit       -  2c  6  1    This bit flips every time you drive into a Goomba. 
   u8   collision        -  2e  7  1    Flips with every collision (flips every packet when driving while touching an object) and flips when you end a wheelie.
   u8   wheelie_start    -  2f  0  1    Flips every time you start a wheelie (wheelie ends with "collision").
   u8   stunt            -  2f  2  1    Flips every time you do a stunt.
   u8   hop              -  2f  4  1    Flips with every hop/drift begun during driving.
   u8	cannon		 -  2f  7  3	Flips with cannon #0..2 activation.
   u8	drift		 -  32  0  2	0: no drift, 1: drift, 2: blue spark, 3: orange spark.
   u8  	already_drifted	 -  32  3  1	1: driver has drifted at least once.
   u8	rank		 -  32  5  4	Rank in race.
 !---------------------------------------------------------------------------------------

The values described with "This bit flips ..." do not indicate that you (for example) have a Star enabled, those values start at zero and every time you enable a Star, they flip. The duration of the actual event (when the Star or Mega Mushroom turns off again) is calculated by each Wii on its own.

Position Vector

The 3 coordinates of the position vector are send as three 28 bit unsigned integers packed without padding.

Get the coordinate :

  1. First add 0x3f800000 (hex representation of float value 1.0) as unsigned integer to the raw value.
  2. Now interpret the 32 bits as single precision float (IEEE 754) and subtract 1e6 (1 million).

C calculation example:

u32   temp = RAW + 0x3f800000;
float pos  = *(float*)&temp - 1e6;

Direction Vector

Note about new interpretation:
It seems, that 17 bits are also a minimized float:
  • 1 bit sign, 2 bits exponent and 14 bits mantissa.

Transformation:

  1. If sign bit is set, assume value 0 (seems to be -0.0, a rounding issue).
  2. Shift the number 9 bits to the left and add 0x3e800000 (hex representation of float 0.25).
  3. Interpret the 32 bit number as float and subtract 1.0.
All 3 coordinates together will build a unit vector (length always 1.0).

The direction vector is curious. It is a 17 bit signed integer number. Negative values are only seen for respawn points. See the following table; the second part are only the 4 main directions:

------------------------------------------
  3D vector in hex   horizontal
    x     y     z     direction  comment
------------------------------------------
[ 8000, 8000, c000]    0    S
[ ad41, 8000, ad41]   45    SO
[ b76b, 8000, a001]   60
[ bb20, 8000, 987d]   67.5 
[ c000, 8000, 7fff]   90    O
[ bb20, 8000, 4f04]  112.5 
[ b76b, 8000, 4006]  120
[ ad41, 8000, 257d]  135    NO
[ 9ffe, 8000, 112e]  150
[ 987d, 8000,  9be]  157.5 
[ 8000, 8000,    0]  180    N
[ 4f04, 8000,  9be]  202.5 
[ 4002, 8000, 112e]  210
[ 257d, 8000, 257d]  225    NW
[1ffff, 8000, 7fff]  270    W    1ffff=-1
[    0, 8000, 8000] ~270   ~W    a guess
[ 257d, 8000, ad41]  315    SW
------------------------------------------
[ 8000, 8000, c000]    0    S
[ c000, 8000, 7fff]   90    O
[1ffff, 8000, 7fff]  270    W    1ffff=-1
[ 8000, 8000,    0]  180    N
------------------------------------------

The following function print_direction() prints the X and Z direction for a given angle in degree, assuming tht the Y value is 0x8000 for a horizontal direction:

int calc_direction_vector ( double degree )
{
    // normalize degree (0 .. 359.9999)
    degree = fmod(degree,360.0);
    if ( degree < 0.0 )
	degree += 360.0;

    // math lib needs radiant and not degree
    const double rad = degree * M_PI / 180.0;

    return degree < 180.0
	? sin(rad) * 0x4000 + 0x8000
	: sin(rad) * 0x8000 + 0x8000;
	//: (int)( sin(rad) * 0x8000 + 0x7fff ) & 0x1ffff;
}

int normalze_direction_coordinate ( int val )
{
    // fix negative numbers and mask positive
    if ( val & 0x10000 )
	val = -(val & 0xffff);
    else
	val &= 0x0ffff;

    // subtract 0x8000
    val -= 0x8000;			

    // return normalized value
    return val >= 0 ? 2*val : val;
}

double calc_direction_degree ( int x, int z )
{
    //--- normalize  coordinates
    x = normalze_direction_coordinate(x);
    z = normalze_direction_coordinate(z);

    // calculate angle and covert into degree
    const double degree = atan2(x,z) * 180.0 / M_PI;

    // return a value between 0 and 360.00
    return degree < 0 ? degree + 360.0 : degree;
}

void print_direction ( double degree )
{
    // first: calc x and z positions
    const int x = calc_direction_vector( degree );
    const int z = calc_direction_vector( degree + 90.0 );

    // second: use x and z values toclauclate direction in degree
    const double degree2 = calc_direction_degree(x,z);

    // print out all results
    printf("%8.2f -> %5x %5x -> %6.2f\n",
	degree, x & 0x1ffff, z & 0x1ffff, degree2 );
}

Example run:

    0.00 ->  8000  c000 ->   0.00
   45.00 ->  ad41  ad41 ->  45.00
   90.00 ->  c000  8000 ->  90.00
  135.00 ->  ad41  257d -> 135.00
  180.00 ->  8000     0 -> 180.00
  225.00 ->  257d  257d -> 225.00
  270.00 ->     0  8000 -> 270.00
  315.00 ->  257d  ad41 -> 315.00
  360.00 ->  8000  c000 ->   0.00