Skip to content

Latest commit

 

History

History
52 lines (37 loc) · 1.76 KB

0x22.md

File metadata and controls

52 lines (37 loc) · 1.76 KB

Packet 0x22

Packet 0x22 allows you to modify values in nested structures like list or dict.

And here how it looks like:

struct NestedPropertyChange {
    entity_id, = struct.unpack('I', stream.read(4))
    is_slice = struct.unpack('b', stream.read(1))[0] == 1
    payload_size, = struct.unpack('b', stream.read(1))

    unknown = stream.read(3)  # always 0x000000
    payload = stream.read()
}

Both setNested and setSlice starts with a packed path to the element being changed, it's necessary to read it bit by bit.

pOwner = entity

while bits.pop(0) == 1 && pOwner
   length = obj.childLength()  // array size || amount of keys in dict || amount of entity properties
   bits = bitsRequires(length)  // how many bits you need to store the index for the container above => ceil(log(length, 2))
   propertyId = readBits(bitsArray, bits) // read the required number of bits, the missing is completed with zeros

   pOwner = pOwner.getPropertyByIndex(propertyId)  // for the array - we take the element by the index, for the dictionary - by the serial number the property in the .def file, for the entity - by exposedId

Out of the while loop, differences begin, for setNested we read the index of the property being changed as usual:

maxBits = bitsRequires(pOwner.childLenght())
propertyId = readBits(bits, maxBits)

Rest bytes are the value, you can unpack the information using the data type from def / alias.xml.

  setSlice is a little bit different

maxBits = bitsRequires (pOwner.childLenght () + 1)
index1 = readBits (bits, maxBits)
index2 = readBits (bits, maxBits)

// if the index exceeds the number of elements in pOwner -> add a new one
// if index2 > index1 && payload == None -> delete slice from array
// replacements seem to be executed via setNested