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