Network Protocol
AImation binary packet format
version 0.9.29, 2025-02-10
This paper describes the binary format used by AImation for engine connectors and data storage and explains how to connect over a socket to AImation Studio.
As we are in beta version, the format is not guaranteed to be stable.
All numbers are encoded in little-endian.
Each packet starts with 24 byte header composed of:
- 8 byte magic value AiMation (0x41 0x69 0x4d 0x61 0x74 0x69 0x6f 0x6e);
- 7 bytes reserved for future use (AImation Studio currently sets these to 0x55 0x55 0x55 0x5A 0xAA 0xAA
0xAA); - 1 byte format version, currently 0x00;
- 8 byte block counter
Header is followed by the block lookup table, which is followed by block data. The lookup table consists of block descriptions, the number of which is determined by the block counter in the header. Each block description consists of 12 bytes:
- 4 byte block type;
- 4 byte data offset from the beginning of the packet;
- 4 byte block metadata.
There is no padding between block descriptions. Blocks should be placed in the packet in the same order as they are in the lookup table, so the byte size of a block can be calculated as a difference of the consecutive offsets. For the same reason, there should be no padding between blocks. Block type determines what data is stored in a block and what is the meaning of the metadata value. In most cases metadata is equal to the block size in bytes. The currently used types are described by the following table.
Networking and connecting to AImation Studio
When the format is used for inter-process communication instead of data storage each packet must at a minimum contain a human readable json (type 0x06). This json contains a HandlerID key with the value being packet opcode (as an integer). Engine integration protocol uses four opcodes.
- Opcode 14. Sent by client application to request a connection. Besides the opcode, json contains ClientName key with string value naming the connection and RequestedPoseType with integer value 0 or 1. Pose type 0 requests local coordinate system, each bone position and rotation will be calculated with respect to the parent bone; pose type 1 request global coordinate system, bone positions will be calculated with respect to a common root.
As an example: {"HandlerID":14,"ClientName":"Unreal Engine5.4.2","RequestedPoseType":1}.
Pose type 1 does not currently support precalculating rotation.
This mode is intended for model retargeting and angle calculations depend on the target model. - Opcode 15. Sent by AImation studio as a response to connection request. Besides the opcode, json contains two integer values.
AimationPose describes what coordinate system will be used, it should be the same value as requested by client by RequestedPoseType.
Response indicates status, 0 is a success, 1 is a failure due to client name already in use, 2 indicates other errors.
An example: {"AimationPose":1,"HandlerID":15,"Response":0}. - Opcode 16. Sent by client to request a shutdown of a connection. Forgetting to send this opcode may cause rejections of further connections due to duplicate client name.
- Opcode 17. The actual data packet sent by AImation Studio. Besides the opcode, json contains three numeric values: FrameID, BoneCount, WorldTimeInSeconds; the names are self-explanatory. Moreover the packet has two more blocks, one containing a vector of bone locations (type 0x03) and one containing a vector of bone rotations (type 0x0B).
Ex 1) Packet for client registration.
Header contains 24 bytes
41 69 4d 61 74 69 6f 6e
00 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00
The header indicates that the packet contains one block of data. The block lookup table follows:
06 00 00 00 24 00 00 00
49 00 00 00
The block is of type json, it starts at the offset 0x24 and metadata (text length) is 73 bytes long. Directly
after the lookup table we have the actual data:
7b 22 48 61
6e 64 6c 65 72 49 44 22
3a 31 34 2c 22 43 6c 69
65 6e 74 4e 61 6d 65 22
3a 22 55 6e 72 65 61 6c
20 45 6e 67 69 6e 65 20
35 2e 34 2e 32 22 2c 22
52 65 71 75 65 73 74 65
64 50 6f 73 65 54 79 70
65 22 3a 31 7d
which is decoded as {"HandlerID":14,"ClientName":"Unreal Engine 5.4.2","RequestedPoseType":1}
Ex 2)Packet with data
Header contains 24 bytes:
41 69 4d 61 74 69 6f 6e
55 55 55 5a aa aa aa 00
03 00 00 00 00 00 00 00
The header indicates that the packet contains three blocks of data. The block lookup table follows:
06 00 00 00 3c 00 00 00
4e 00 00 00 03 00 00 00
8a 00 00 00 4d 00 00 00
0b 00 00 00 26 04 00 00
4d 00 00 00
The three blocks are: json at offset 0x3c of length 78; vector of points at offset 0x8a containing 77 elements;
vector of quaternions at offset 0x426 containing 77 elements. The first block is:
7b 22 42 6f
6e 65 43 6f 75 6e 74 22
3a 37 37 2c 22 46 72 61
6d 65 49 44 22 3a 30 2c
22 48 61 6e 64 6c 65 72
49 44 22 3a 31 37 2c 22
57 6f 72 6c 64 54 69 6d
65 49 6e 53 65 63 6f 6e
64 73 22 3a 32 30 33 30
38 31 31 2e 33 32 33 34
37 7d
which is decoded to a json
{"BoneCount":77,"FrameID":0,"HandlerID":17,"WorldTimeInSeconds":2030811.32347}.
The block of points starts with:
4d 41 9f c0 98 0b
04 c3 dd bd 15 42 ...
so the position of bone 0 in this frame is 0xc09f414d, 0xc3040b98, 0x4215bddd which translates to:
X= -4.9767213f, Y= -132.04529f, Z= 37.435413f
The quaternion block consists of entries that look like
00 00 00 80 00 00 00 80
00 00 00 80 00 00 80 3f
which are decoded to X=0.f, Y=0.f, Z=0.f, W=1.f, which represents an identity rotation.
An implementation of WebSocket connection can be viewed in our Unreal Engine plugin source-code, although a bit crude :)
https://github.com/Aimation-Studio/AImationLiveLink/blob/master/Plugins/AImationStudioConnector/Source/AImationStudioConnector/Private/AimationWebSocket.cpp#L83