Skip to content

Instantly share code, notes, and snippets.

@capyvara
Created May 19, 2018 23:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save capyvara/63ced16b9033108a9574bb953969553a to your computer and use it in GitHub Desktop.
Save capyvara/63ced16b9033108a9574bb953969553a to your computer and use it in GitHub Desktop.
UNET transport layer structs
// Source: https://forum.unity.com/threads/binary-protocol-specification.417831/
//all 16 and 32 bit data are network ordered
//message length occupy 1 byte length if first bit == 0 or 2 bytes if it equal 1:
int SetLength(char* buffer, uint16_t messageLength)
{
int messageLengthSize = (messageLength > 0x7F) ? 2 : 1;
if (messageLengthSize == 1)
{
*buffer = (uint8_t)messageLength;
}
else
{
Assert(messageLength < 0x7FFF);
*buffer = (messageLength >> 8) | 0x80;
*(buffer + 1) = (uint8_t)messageLength & 0xFF;
}
return messageLengthSize;
}
//packets:
// header:
struct PacketBaseHeader
{
uint16_t connectionId; //if 0 it will be system packet
};
// user packet headers:
struct NetPacketHeader : public PacketBaseHeader
{
uint16_t packetId;
uint16_t sessionId; //never changed and always in network order
};
// if there are reliable channels
struct PacketAcksXX //XX == 32, 64, 96, 128
{
uint16_t ackMessageId;
uint32_t acks[x]; //x == 1,2,3,4
};
// system packets:
struct LocalDiscoveryPacket : public PacketBaseHeader //note that structure of broad cast packet is different from system!
{
uint8_t requestType;
uint16_t clientPort;
uint8_t guid[kUnetGUIDLength]; //kUnetGUIDLength == 36
uint32_t version;
uint32_t subversrion;
};
//helper for other structures described below
struct SystemPacket : public PacketBaseHeader
{
uint8_t requestType;
uint16_t packetId;
uint16_t sessionId; //never changed
uint16_t localConnectionId;
uint16_t remoteConnectionId;
};
struct ConnectPacket : public SystemPacket
{
uint32_t lib_version;
uint32_t crc;
};
struct DisconnectPacket : public SystemPacket
{
uint32_t lib_version;
uint8_t reason;
};
struct PingPacket : public SystemPacket
{
uint32_t sentPingTime; //timestamp when this ping was sent
uint32_t ackPingTime; //when we receive last ping from remote connection
uint32_t localTimeCorrection;//how many ms has been spent between time when we receive ackPingTime and time when we send this ping
uint8_t intDropRate; //how many packet (in % from 255) was dropped due lack storage in buffers
uint8_t extDropRate; //how many packet (in % from 255) was lost or delivered out of order due network conditions
uint16_t remoteSessionId; //ping packet serves as connection request acknowledging, to avoid scenario where wrong ping will be ack connection, both session should be taken into account
};
//Messages commons structure
//{message} == {channelId (uint8_t)|length(1 or 2 bytes)|message header|payload}
//special channels:
//reliable channelId == 255
//message == 255|length|NMReliableHeader|{message}{message}{message}
//and all messages lost its NMReliableHeader from message headers
//combined message - messages from one channel combined to one combined message and shared the same header
//channelId == 254
//message == 254|OriginChannelId{uint8_t)|length|{message in format: length|payload -- no header no channel number}
//headers:
//helpers:
struct NMReliableHeader //reliable header
{
uint16_t messageId;
};
struct NetMessageOrderedHeader //this header applied to sequenced and state update qos
{
uint8_t orderedMessageId;
};
struct NetMessageFragmentedHeader //this header applied to fragmented messages
{
uint8_t fragmentedMessageId; //id of fragmented message
uint8_t fragmentIdx; //id of fragment
uint8_t fragmentAmnt; // fragments total
};
//all reliable messages will be combined to one, except AllCost qos, so if channel has alacost host message = channelId|)|length(1 or 2 bytes)|NMReliableHeader|payload
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment