SMSG UPDATE OBJECT

From wowdev
Revision as of 13:12, 7 February 2016 by Gamhea (talk | contribs) (Created page with "When the server wants to notify the client that something (an object, a player, whatever) spawned, moved or disappeared from the world, it sends a SMSG_UPDATE_OBJECT packet wi...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

When the server wants to notify the client that something (an object, a player, whatever) spawned, moved or disappeared from the world, it sends a SMSG_UPDATE_OBJECT packet with only the relevant data, to save bandwidth.

Header

UpdateType (1.1.2.4125)
Name Value
PARTIAL 0
MOVEMENT 1
CREATE_OBJECT 2
FAR_OBJECTS 3
NEAR_OBJECTS 4

Update types can be grouped as follows:

  1. Update data of an object (PARTIAL)
  2. Spawn or move an object (MOVEMENT, CREATE_OBJECT)
  3. destroy object (FAR_OBJECTS, NEAR_OBJECTS)

Type 1 includes only update fields, types 2 and 3 include movement information block and update fields, types 4 and 5 are just list of GUIDs.

ObjectType (1.1.2.4125)
Name Value
OBJECT 0
ITEM 1
CONTAINER 2
UNIT 3
PLAYER 4
GAME_OBJECT 5
DYNAMIC_OBJECT 6
CORPSE 7
UpdateObjectPacketHeader (1.1.2.4125)
Type Name Description
uint32 count
uint8 hasTransport
uint8 update_type (see UpdateType)
uint64 guid

A note about the GUID: during Vanilla, the decision was taken that a meaningful optimisation would be that, as GUID are uint64, they should be packed like update fields. "Packed GUID" goes like this: first, an uint8 bit mask and then the actual data. Lets say the mask will be 1101001, then the "data" will contain 0-th, 3-rd, 5-th and 6-th bytes of uint64.

If the update type needs an object_type (e.g. CREATE_OBJECT needs it):

Type Name Description
uint8 object_type (see ObjectType)

Movement block

For all update types that need movement information:

MovementBlock (1.1.2.4125)
Type Name Description
uint32 flags
int32 unk
float[4] position position + orientation
uint64 tr_guid (flags & ON_TRANSPORT) transport GUID
float[4] tr_position (flags & ON_TRANSPORT) transport position and orientation
uint32 swim_pitch (flags & IS_SWIMMING)
uint32 time (flags & IS_FALLING)
float velocity (flags & IS_FALLING)
float sin (flags & IS_FALLING)
float cos (flags & IS_FALLING)
float xy_speed (flags & IS_FALLING)
float unk (flags & SPLINE_ELEVATION)
float[6] speeds walk, run, run backward, swim, swim backward and turn

There can be more data due to flags but I haven't look into that. These are sufficient for basic emulation though.

MovementFlags (1.1.2.4125) (incomplete)
Name Value
FORWARD 0x00000001
BACKWARD 0x00000002
STRAFE_LEFT 0x00000004
STRAFE_RIGHT 0x00000008
TURN_LEFT 0x00000010
TURN_RIGHT 0x00000020
IS_FALLING 0x00002000
IS_SWIMMING 0x00200000
ON_TRANSPORT 0x02000000
SPLINE_ELEVATION 0x04000000

Update fields

Before the update fields, for some update types (e.g. CREATE_OBJECT), there is information about the unit being updated:

UnitInformation (1.1.2.4125)
Type Name Description
uint32 is_player 1 if this object is in fact the player
uint32 attack_cycle
uint32 timer_id
uint64 victim_guid

Then come the update fields:

UpdateFields
Type Name Description
uint8 num_mask_blocks hard coded limit at 0x1C
uint32[] mask_blocks
uint32[] update_blocks

Every object has a lot of different characteristics, sometimes specific to their type. All objects have a GUID, but only an item has durability field; both players and units have a health field, but only players have a guild ID field.

There a lot of different fields (around a thousand), so to send this data to clients without dumping a full table of fields, only relevant fields are sent in an update packet, as update_blocks. And to know what fields are present in the update_blocks, the index of each field is set in the bitmasks of mask_blocks.

To not have to worry about the size of each field, they're all sent as uint32. Beware though, some fields like GUID are uint64, so they take 2 update blocks. The client knows how to parse each field.

Example with field values from 1.1.2.4125 (look in your binary for values): I have a Player, so it has object, unit and player fields, and I want to send to a client his GUID (id: 0), his health (id: 0x16) and his experience (id: 0x9E). I will have to send 2 update blocks for the GUID, one for the health and one for the experience: update_blocks has 4 elements. The indices to set are 0, 22 and 158, so we set bits 0 and 22 of the 0-th uint32 mask block, and the bit 30 of the 4-th mask block (because 158 // 4 = 30 and 158 % 32 = 4). The num_mask_blocks value will have to be 5 because we have at least 5 mask blocks.

Fields for each object type
Object type Fields
OBJECT object
ITEM object, item
CONTAINER object, item, container
UNIT object, unit
PLAYER object, unit, player
GAME_OBJECT object, game_object
DYNAMIC_OBJECT object, dynamic_object
CORPSE object, corpse