{"id":16136424,"url":"https://github.com/vp817/raknetprotocoldoc","last_synced_at":"2026-02-16T23:09:07.609Z","repository":{"id":185860970,"uuid":"665666250","full_name":"vp817/RakNetProtocolDoc","owner":"vp817","description":"Raknet protocol documentation out of many out there","archived":false,"fork":false,"pushed_at":"2025-09-03T12:27:27.000Z","size":489,"stargazers_count":33,"open_issues_count":0,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-03T14:30:50.605Z","etag":null,"topics":["documentation","protocol","raknet","udp"],"latest_commit_sha":null,"homepage":"https://vp817.github.io/RakNetProtocolDoc","language":null,"has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vp817.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-07-12T18:03:51.000Z","updated_at":"2025-09-03T12:27:30.000Z","dependencies_parsed_at":"2024-04-06T21:29:43.433Z","dependency_job_id":"8a2a7d0f-e899-4381-9ab4-29830196cbbb","html_url":"https://github.com/vp817/RakNetProtocolDoc","commit_stats":{"total_commits":83,"total_committers":3,"mean_commits":"27.666666666666668","dds":0.02409638554216864,"last_synced_commit":"0a8020734d343b62d6e7ff8c32a13f02dda32b01"},"previous_names":["vp817/raknetprotocoldoc"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/vp817/RakNetProtocolDoc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vp817%2FRakNetProtocolDoc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vp817%2FRakNetProtocolDoc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vp817%2FRakNetProtocolDoc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vp817%2FRakNetProtocolDoc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vp817","download_url":"https://codeload.github.com/vp817/RakNetProtocolDoc/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vp817%2FRakNetProtocolDoc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279009511,"owners_count":26084609,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-11T02:00:06.511Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["documentation","protocol","raknet","udp"],"created_at":"2024-10-09T23:11:41.608Z","updated_at":"2025-10-12T00:45:13.037Z","avatar_url":"https://github.com/vp817.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# RakNet Protocol Documentation\n\nThis is a raknet protocol documentation. It has everything needed to create a server/client(the default raknet not other types).\n\nIf anything was incorrect or misspelled, you can pull request a fix to them if they really are wrong.\n\n## DataTypes\n\n| Type         | Size       | Note |\n| ------------ | ---------- | ---- |\n| uint8        | 1 byte     |      |\n| uint16       | 2 bytes    |      |\n| uint24       | 3 bytes    | Unsigned 24-bit integer with a minimum value of 0 and a maximum value of (2^24)-1 |\n| uint32       | 4 bytes    |      |\n| uint64       | 8 bytes    |      |\n| string       | variable   | UTF-8 encoded string preceding with 2 bytes(uint16-little endian) its length |\n| magic        | 16 bytes   | A uint8 array with a specific sequence `[0x00, 0xFF, 0xFF, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFD, 0xFD, 0x12, 0x34, 0x56, 0x78]` used to identify offline packets |\n| zero-padding | variable   | A single zero value uint8 recorded in sequence until the required size. |\n| bool         | 1 byte     | Written or read as a single uint8, with a value of 0 or 1 (0 represents false, and 1 represents true). |\n| address      | 7-29 bytes | See below(Address DataType). |\n| bit          | 1 bit   | a bit can be 1 or 0 where it is written as uint8 extended by 0s until 8 bits (the bits follow the MSb order) |\n| float        | 4 bytes | IEEE 754 single-precision floating-point number |\n\n### Address DataType\n\n| Field   | Type  |\n| ------- | ----- |\n| version | uint8 |\n| .....   | ....1 |\n\n**`....1` shall be recorded as:**\n\n#### If version is equals to 4:\n\n| Field   | Type   | Endianness |\n| ------- | ------ | ---------- |\n| address | uint32 | Big Endian |\n| port    | uint16 | Big Endian |\n\nan ipv4 string address always has 4 parts \"part1(MSB).part2.part3.part4(LSB)\".\n\nconverting an ipv4 string to an ipv4 address:\neach part shall be recorded from the MSB to the LSB then the address would be ~(the result).\n\nconverting an ipv4 address into an ipv4 string:\nthe value to extract each part into its place in the string from the MSB to the LSB would be ~address.\n\n#### If version is equals to 6:\n\n| Field          | Type      | Endianness    |\n| -------------- | --------- | ------------- |\n| address family | uint16    | Little Endian |\n| port           | uint16    | Big Endian    |\n| flow info      | uint32    | Big Endian    |\n| address        | uint8[16] | N/A           |\n| scope id       | uint32    | Big Endian    |\n\n## Minecraft\n\nThis documentation isn't related to minecraft but it's possible to follow it while aiming to implement a minecraft-only raknet.\n\nThe things that changes in \"General Constants\":\n- `MaximumMtuSize` is 1400.\n- `NumberOfLocalAddresses`: 20\n- `DefaultProtocolVersion`: 11 (this isn't always the same but the protocol does not seem to change)\n\nDatagram(not acks/nacks) sent packets are continous sent.\n\nFind the \"motd\" format from somewhere else and apply it as the \"UnconnectedPong\" `message` field.\n\n\u003e One way is to log it by sending the unconnected ping packet to a bds(bedrock dedicated server) and then logging the `message` field from a bds.\n\u003e It is also possible to log the protocol version of the minecraft client through the incompatible protocol version packet if it was ever updated.\n\n## General Constants\n\n| Name                      | Value     |\n| ------------------------- | --------- |\n| MaximumMtuSize            | 1492      |\n| UdpHeaderSize             | 28        |\n| PublicKeySize             | 294       |\n| RequstChallengeSize       | 64        |\n| RespondingEncryptionKey   | 128       |\n| MaxNumberOfLocalAddresses | 10        |\n| IdentityProofSize         | 294       |\n| ClientProofSize           | 32        |\n| DefaultProtocolVersion    | 6         |\n| NumberOfOrderedStreams    | 32(2 ^ 5) |\n\n## Packets\n\n### Identifiers\n\n| Name                           | ID   | Type    |\n| ------------------------------ | ---- | ------- |\n| UnconnectedPing                | 0x01 | OFFLINE |\n| UnconnectedPingOpenConnections | 0x02 | OFFLINE |\n| UnconnectedPong                | 0x1c | OFFLINE |\n| ConnectedPing                  | 0x00 | ONLINE  |\n| ConnectedPong                  | 0x03 | ONLINE  |\n| OpenConnectionRequest1         | 0x05 | OFFLINE |\n| OpenConnectionReply1           | 0x06 | OFFLINE |\n| OpenConnectionRequest2         | 0x07 | OFFLINE |\n| OpenConnectionReply2           | 0x08 | OFFLINE |\n| ConnectionRequest              | 0x09 | ONLINE  |\n| RemoteSystemRequiresPublicKey  | 0x0a | ONLINE  |\n| OurSystemRequiresSecurity      | 0x0b | OFFLINE |\n| ConnectionAttemptFailed        | 0x11 | BOTH    |\n| AlreadyConnected               | 0x12 | OFFLINE |\n| ConnectionRequestAccepted      | 0x10 | ONLINE  |\n| NewIncomingConnection          | 0x13 | ONLINE  |\n| DisconnectionNotification      | 0x15 | BOTH    |\n| ConnectionLost                 | 0x16 | BOTH    |\n| IncompatibleProtocolVersion    | 0x19 | OFFLINE |\n\n### Send and Receive Sequence\n\nThe first packets before a connection(not the socket connection) was craeted(still on unconnected packets) are the packets of the offline type, which means that those are the packets that is handled outside of datagrams(and the opposite holds true).\n\nBelow, there is no information on why this and that, but the packet name says all that is needed to be said.\n\nThe \"Datagrams\" to be handled and sent is all possible datagram types, where the `valid dgram` holds the online packets.\n\n- Client: UnconnectedPing\n   - Server: UnconnectedPong\n- Client: OpenConnectionRequest1\n   - Server: OpenConnectionReply1 / IncompatibleProtocolVersion\n- Client: OpenConnectionRequest2\n   - Server: OpenConnectionReply2 \u0026 Create connection.\n- Client: Datagrams\n   - Server: Handle accordingly.\n\n### UnconnectedPing / UnconnectedPingOpenConnections\n\nThis packet is used to determine if a server is online or not.\n\nFor unconnected ping open connections: the server will only send a reply if the client's connection to the server is currently open. This helps to prevent sending responses to clients that have closed their connections.\n\n| Field            | Type             | Endianness |\n| ---------------- | ---------------- | ---------- |\n| id               | uint8            | N/A        |\n| client send time | uint64           | Big Endian |\n| magic            | magic            | N/A        |\n| client guid      | uint64           | Big Endian |\n\n### UnconnectedPong\n\nThis packet is the response to an unconnected ping packet.\n\n| Field            | Type             | Endianness | Note |\n| ---------------- | ---------------- | ---------- | ---- |\n| id               | uint8            | N/A        |      |\n| client send time | uint64           | Big Endian |      |\n| server guid      | uint64           | Big Endian |      |\n| magic            | magic            | N/A        |      |\n| message          | string           | Big Endian | Response data usually used for server information. |\n\n### ConnectedPing\n\nThis packet is used to keep the connection alive between the client and the server.\n\n| Field            | Type   | Endianness |\n| ---------------- | ------ | ---------- |\n| id               | uint8  | N/A        |\n| client send time | uint64 | Big Endian |\n\n### ConnectedPong\n\nThis packet is the response to a connected ping packet.\n\n| Field            | Type   | Endianness |\n| ---------------- | ------ | ---------- |\n| id               | uint8  | N/A        |\n| client send time | uint64 | Big Endian |\n| server send time | uint64 | Big Endian |\n\n### OpenConnectionRequest1\n\nThis packet is used to initiate the handshake process between a client and a server.\n\n| Field            | Type             | Endianness | Note |\n| ---------------- | ---------------- | ---------- | ---- |\n| id               | uint8            | N/A        |      |\n| magic            | magic            | N/A        |      |\n| protocol version | uint8            | N/A        | Protocol version supported by the client |\n| mtu size         | zero-padding     | N/A        |      |\n\n\nThe `mtu size` value when using zero-padding:\n```\nreading from buffer:\n   - mtu size = zero-padding + reading position + UDP Header Size\nwriting into buffer:\n   - mtu size = (mtu size - writing position) - UDP Header Size\n```\n\n**client mtu size discovery:**\n\nin the original raknet the mtu sizes is an integer array with the size of 3 (it would be refered as number of mtu sizes below).\n\nthe mtu sizes are {`MaximumMtuSize`, 1200, 576}.\n\nMaximum mtu size chart:\n```\n1500. The largest Ethernet packet size. This is the typical setting for non-PPPoE, non-VPN connections. The default value for NETGEAR routers, adapters and switches.\n1492. The size PPPoE prefers.\n1472. Maximum size to use for pinging. (Bigger packets are fragmented.)\n1468. The size DHCP prefers.\n1460. Usable by AOL if you don't have large email attachments, etc.\n1430. The size VPN and PPTP prefer.\n1400. Maximum size for AOL DSL.\n576. Typical value to connect to dial-up ISPs.\n```\n\nThe one used in raknet by default is 1492(known as the size PPPoE prefers), so the `MaximumMtuSize` is equals to said value. But it can always be changed through user preferences.\n\nthe UDP Header Size is always the size of an ipv4 udp header + actual udp header size in the original raknet.\nWhich can be found by calculating the udp ipv4 header size(`(32 (src addr) + 32 (dst addr) + 8 (zeroes) + 8 (protocol) + 16 (udp len) + 16 (src port) + 16 (dest port) + 16 (len) + 16 (checksum)) / 8`) which is equals to 20 then plus the the udp header size (`(16 (src port) + 16 (dest port) + 16 (len) + 16 (checksum)) / 8`) which would be 8, so 20 + 8 would be 28.\n\nthe 576 would be known as the minimum of an ipv4 udp packet and the 1200 may be for the ipv6 udp (usually its 1280 so not sure what happened to the remaining 80, it may have been removed to keep the rest of the calculations consistent while still using the ipv4 values but can still serve as a middle point in ipv4).\n\nthe default mtu size is mtu sizes[number of mtu sizes - 1, with said value being the default index].\n\nthe reason why the mtu size is zero padding is because that if size of buffer is more than the currently choosen mtu size it wont be sent, so the client will know that and then change into another mtu size depending on the implemention.\n\nPsuedo code through the original raknet way:\n```cpp\nRequestingConnection: global\n{\n   SystemAddress: address;\n   RequestsMade;\n   SendConnectionAttemptCount defaults to 15;\n   IsConnecting;\n   NextRequestTime;\n   TimeBetweenConnectionAttempts defaults to 500;\n};\n\ng_RequestedConnections: DynamicArray;\n\ni := 0;\n\nloop i \u003c g_NumOfRequestedConnections then\n   s_rcs := g_RequestedConnections[i];\n   s_timeNow := current time ms;\n   if s_rcs-\u003eNextRequestTime \u003c s_timeNow then\n      s_unsetAddr := s_rcs-\u003eSystemAddress is unset;\n      s_tooManyRequests := s_rcs-\u003eRequestsMade is s_rcs-\u003eSendConnectionAttemptCount + 1\n      if s_unsetAddr or s_tooManyRequests then\n         if (s_tooManyRequests and !s_unsetAddr and s_rcs-\u003eIsConnecting) then\n            // send ConnectionAttemptFailed packet.\n         end\n         complete_unset s_rcs;\n      else\n         s_MtuSizeIndex := s_rcs-\u003eRequestsMade / (rcs-\u003eSendConnectionAttemptCount / num of mtu sizes);\n         if s_MtuSizeIndex \u003e num of mtu sizes then\n            s_MtuSizeIndex = index of default mtu size;\n         end\n         s_rcs-\u003eRequestsMade = s_rcs-\u003eRequestsMade + 1;\n         s_rcs-\u003eNextRequestTime = s_timeNow + s_rcs-\u003eTimeBetweenConnectionAttempts;\n\n         // send OpenConnectionRequest1 packet with mtu size being the mtu sizes[s_MtuSizeIndex].\n\n         s_SendToStart := current time ms;\n\n         if unable to send packet due to it being too big (error code: 10040) then\n            // \"don't use this mtu size again\" said in the original.\n            s_rcs-\u003eRequestsMade = (s_MtuSizeIndex + 1) * (s_rcs-\u003eSendConnectionAttemptCount / num of mtu sizes);\n            s_rcs-\u003eNextRequestTime = s_timeNow;\n         else\n            s_SendToEnd := current time ms;\n            if s_SendToStart - s_SendToEnd \u003c 100 then\n               // \"drop to the lowest mtu\" said in the original.\n               s_LowestMtuIndex := s_rcs-\u003eSendConnectionAttemptCount / num of mtu sizes * default mtu index;\n               if s_LowestMtuIndex \u003e s_rcs-\u003eRequestsMade then\n                  s_rcs-\u003eRequestsMade = s_LowestMtuIndex;\n                  s_rcs-\u003eNextRequestTime = s_timeNow;\n               else\n                  s_rcs-\u003eRequestsMade = s_rcs-\u003eSendConnectionAttemptCount + 1;\n               end\n            end\n         end\n         i = i + 1;\n      end\n   else\n      i = i + 1;\n   end\nend\n```\n\n### OpenConnectionReply1\n\nThis packet is the response to an open connection request one packet.\n\n| Field               | Type             | Endianness |\n| ------------------- | ---------------- | ---------- |\n| id                  | uint8            | N/A        |\n| magic               | magic            | N/A        |\n| server guid         | uint64           | Big Endian |\n| server has security | bool             | N/A        |\n| .....               | ....1            | ....       |\n| mtu size            | uint16           | Big Endian |\n\n**`....1` shall be recorded as:**\n\nif ServerHasSecurity \u0026 Libcat:\n\n| Field               | Type             | Endianness |\n| ------------------- | ---------------- | ---------- |\n| has cookie          | bool             | N/A        |\n| cookie              | uint32           | Big Endian |\n| server public key   | uint8[294]       | N/A        |\n\nif ServerHasSecurity \u0026 Nothing:\n\n| Field               | Type             | Endianness |\n| ------------------- | ---------------- | ---------- |\n| cookie              | uint32           | Big Endian |\n\nThe `server has security` shall have a global variable that specifies if the server has security for later usage(if libcat) in the implemention.\n\n### OpenConnectionRequest2\n\nThis packet is used to complete the handshake process between a client and a server.\n\n| Field          | Type             | Endianness |\n| -------------- | ---------------- | ---------- |\n| id             | uint8            | N/A        |\n| magic          | magic            | N/A        |\n| .....          | ....1            | .....      |\n| server address | address          | N/A        |\n| mtu size       | uint16           | Big Endian |\n| client guid    | uint64           | Big Endian |\n\n**`....1` shall be recorded as:** \n\nIf server has security(Libcat)\n\n| Field              | Type             | Endianness | Note |\n| ------------------ | ---------------- | ---------- | ---- |\n| cookie             | uint32           | Big Endian |      |\n| contains challenge | bool             | N/A        | Whether the system requires handshake challenge |\n| challenge          | uint8[64]        | N/A        | The system handshake challenge bytes |\n\n\u003e if the server has security but this packet does not contain a challenge, then the client will be required to send a RemoteSystemRequiresPublicKey packet to notify the server that there was no challenge in the packet.\n\n**Connection outcome**:\n\nIf the `client guid` of the client address does not exists in list then you may mark this connection as a new connnection. if both already exists(even if address isn't same but guid is already used or vice versa) then it shall not connect.\n\nIf it can connect then the sent packet would be the `OpenConnectionReply2` packet.\n\nIf vice versa it would be the `AlreadyConnected` packet.\n\n### OpenConnectionReply2\n\nThis packet is the response to an open connection request two packet.\n\n| Field               | Type             | Endianness | Note |\n| ------------------- | ---------------- | ---------- | ---- |\n| id                  | uint8            | N/A        |      |\n| magic               | magic            | N/A        |      |\n| server guid         | uint64           | Big Endian |      |\n| client address      | address          | N/A        |      |\n| mtu size            | uint16           | Big Endian |      |\n| requires encryption | bit              | N/A        |      |\n| encryption key      | uint8[128]       | N/A        | The encryption key of the client - it is only used if the `requiresEncryption` field is set to true. |\n\n### ConnectionRequest\n\nThis packet is used to establish a connection between a client and a server with security enabled or disabled.\n\n| Field            | Type       | Endianness | Note |\n| ---------------- | ---------- | ---------- | ---- |\n| id               | uint8      | N/A        |      |\n| client guid      | uint64     | Big Endian |      |\n| client send time | uint64     | Big Endian |      |\n| do security      | bool       | N/A        |      |\n| client proof     | uint8[32]  | N/A        | Proof of client authentication |\n| do identity      | bool       | N/A        |      |\n| identity proof   | uint8[294] | N/A        | Proof of client identity |\n\n\u003e If the `identity proof` is invalid and `do identity` is set to true, immediately send a `RemoteSystemRequiresPublicKey` packet with a type ID of `ClientIdentityIsInvalid`. If set to false and there is no `identity proof`, send a `RemoteSystemRequiresPublicKey` packet with a type ID of `ClientIdentityIsMissing`.\n\n### RemoteSystemRequiresPublicKey\n\nThis packet is used to throw the errors related to public key requests for client authentication and identification.\n\n| Field   | Type  |\n| ------- | ----- |\n| id      | uint8 |\n| type id | uint8 |\n\n#### Type Ids:\n\n| Name                     | ID |\n| ------------------------ | -- |\n| ServerPublicKeyIsMissing | 0  |\n| ClientIdentityIsMissing  | 1  |\n| ClientIdentityIsInvalid  | 2  |\n\n### OurSystemRequiresSecurity\n\nThis packet is sent when the server does not need security (libcat) but it is still required.\n\n| Field          | Type        | Endianness |\n| -------------- | ----------- | ---------- |\n| id             | uint8       | N/A        |\n| client address | address     |            |\n| server guid    | uint64      | Big Endian |\n\n### ConnectionAttemptFailed\n\nThis packet is sent when the attempt count trying to join the server is higher than a certain amount (depending on your implementation) or the client does not contain an assigned address; this is what to check and send if the requirements are met before sending the `OpenConnectionRequest1` packet.\n\n| Field | Type  | Endianness |\n| ----- | ----- | ---------- |\n| id    | uint8 | N/A        |\n\n### AlreadyConnected\n\nThis packet is sent when the client is already connected.\n\n| Field       | Type             | Endianness |\n| ----------- | ---------------- | ---------- |\n| id          | uint8            | N/A        |\n| magic       | magic            | N/A        |\n| client guid | uint64           | Big Endian |\n\n### ConnectionRequestAccepted\n\nThis packet is the response to a connection request.\n\n| Field                | Type        | Endianness | Note |\n| -------------------- | ----------- | ---------- | ---- |\n| id                   | uint8       | N/A        |      |\n| client address       | address     | N/A        |      |\n| client index         | uint16      | Big Endian | Current client index in list |\n| server net addresses | address[10] | N/A        | Server local network addresses |\n| client send time     | uint64      | Big Endian |      |\n| server send time     | uint64      | Big Endian |      |\n\n### NewIncomingConnection\n\nThis packet is sent from the client to the server .\n\n| Field                | Type        | Endianness | Note |\n| -------------------- | ----------- | ---------- | ---- |\n| id                   | uint8       | N/A        |      |\n| server address       | address     | N/A        |      |\n| client net addresses | address[10] | N/A        | Client local network addresses |\n| client send time     | uint64      | Big Endian |      |\n| server send time     | uint64      | Big Endian |      |\n\nSend the `ConnectedPing` packet or `ConnectedPong` packet depending on the side of the action.\n\n### DisconnectionNotification\n\nThis packet is sent when a client disconnects from the server.\n\n| Field | Type  |\n| ----- | ----- |\n| id    | uint8 |\n\n### ConnectionLost\n\n| Field          | Type        | Endianness |\n| -------------- | ----------- | ---------- |\n| id             | uint8       | N/A        |\n| client guid    | uint64      | Big Endian |\n| client address | address     | N/A        |\n\n### IncompatibleProtocolVersion\n\nThis packet is sent when a client attempts to connect to a server with an incompatible protocol version.\n\n| Field            | Type             | Endianness | Note |\n| ---------------- | ---------------- | ---------- | ---- |\n| id               | uint8            | N/A        |      |\n| protocol version | uint8            | N/A        | Protocol version supported by the server |\n| magic            | magic            | N/A        |      |\n| server guid      | uint64           | Big Endian | Unique identifier of the server |\n\n### Datagram\n\n---\n\n#### Partial Terminology\n\n#### 1. Dgram\n1. valid dgram: a datagram that is not ack nor nack.\n2. ack dgram: an acked datagram.\n3. nack dgram: a nacked datagram.\n\n#### 2. Reliability\n1. reliable - the reliability is of any type that is reliable.\n2. sequenced - the reliability is both unreliable sequenced and reliable sequenced.\n3. sequenced and ordered - the reliability is `Sequenced` and reliable ordered and reliable ordered with ack recepit.\n4. reliable or in sequence - the reliability is reliable or reliable sequenced or reliable ordered.\n\n### Reliability\n\nEach valid dgram sent is assigned a reliability that specifies how the data should be handled by the protocol. The following table lists the available reliability ids and their properties:\n\n| Name                           | ID  | Is Reliable | Is Ordered | Is Sequenced |\n| ------------------------------ | --- | ----------- | ---------- | ------------ |\n| Unreliable                     | 0   | No          | No         | No           |\n| UnreliableSequenced            | 1   | No          | Yes        | Yes          |\n| Reliable                       | 2   | Yes         | No         | No           |\n| ReliableOrdered                | 3   | Yes         | Yes        | No           |\n| ReliableSequenced              | 4   | Yes         | Yes        | Yes          |\n| UnreliableWithAckReceipt       | 5   | No          | No         | No           |\n| ReliableWithAckReceipt         | 6   | Yes         | No         | No           |\n| ReliableOrderedWithAckReceipt  | 7   | Yes         | Yes        | No           |\n\n### Set of things required in your implemention\n\n- Retransmission: retransmit a datagram if not acknowledged.\n- Reassembly: reconstruct split packets into a valid normal packet.\n\nEvery datagram is and must be valid.\n\n| Field    | Type | Endianness | Body    |\n| -------- | ---- | ---------- | ------- |\n| is valid | bit  | N/A        | `....1` |\n| is ack   | bit  | N/A        | `....2` |\n| is nack  | bit  | N/A        | `....3` |\n\n**`....1` shall be recorded as:**\n\n| Field              | Type              | Endianness    |\n| ------------------ | ----------------- | ------------- |\n| is packet pair     | bit               | N/A           |\n| is continuous send | bit               | N/A           |\n| requires B and AS  | bit               | N/A           |\n| range number       | uint24            | Little Endian |\n| capsules           | DatagramCapsule[] | N/A           |\n\nThe `range number` is known as the sequence number in other words.\n\n**`....2` shall be recorded as:**\n\n| Field              | Type      | Endianness |\n| ------------------ | --------- | ---------- |\n| requires B and AS  | bit       | N/A        |\n| AS                 | float     | N/A        |\n| ranges             | RangeList | N/A        |\n\nThere would be a float `B` field below the `requires B and AS` but is commented out in the original raknet.\n\n**`....3` shall be recorded as:**\n\n| Field              | Type      | Endianness |\n| ------------------ | --------- | ---------- |\n| ranges             | RangeList | N/A        |\n\n\u003c/br\u003e\n\nvalid dgram header size: `2 + 3 + 4 * 1` in bytes which seems to be: `2 (nack rangelist size field) + 3 (range number of a valid dgram) + 4 * 1 (AS of ack dgram, would be * 2 instead of * 1 if B field was not commented out)` so the 1 byte that informs dgram type is excluded.\n\n\u003e Note: in a valid dgram every new range number must be removed from the nack range list since the datagram was received and added to the ack range list.\n\nThe \"finding\" this and that below is all for the valid dgram.\n\n**Finding `skipped ranges count` for the datagram to check if there was some packets missing**:\n\nPsuedo code:\n\n```py\nglobal:`expected range number` := 0\nmethod:`skipped msg count` := 0\n\nif current datagram:`range number` is not equals to global:`expected range number` then\n   method:`skipped msg count` := current datagram:`range number` - global:`expected range number`\n   if method:`skipped msg count` is greater than 1000 then\n      if method:`skipped msg count` is greater than 50000 then\n         # nat related and the check can be removed if not dealing with that\n      end\n      method:`skipped msg count` := 1000\n   end\nend\n\nfunction:`insert into ack list/queue`(`range number`: current datagram:`range number`)\nglobal:`expected range number` := current datagram:`range number` + 1\n\nif method:`skipped msg count` is greater than 0 then\n   for tmp:`skipped msg offset` := method:`skipped msg count`; tmp:`skipped msg offset` is greater than 0; tmp:`skipped msg offset` -= 1 then\n      function:`insert into nack list/queue`(`range number`: current datagram:`range number` - tmp:`skipped msg offset`)\n   end\nend\n```\n\n**Checking for corrupt ordering channels**:\n(the datagram must be `Sequenced And Ordered (No ack receipt)`)\n\nif `ordering channel` is greater or equals to the `NumberOfOrderedStreams` available then it is correupted(skip and do what is needed).\n\nevery datagram ordering type of an array max value is the `NumberOfOrderedStreams` and must not be greater or equals to.\n\n**Finding hole in received reliable datagrams**:\n(the datagram must be `Reliable or in sequence`)\n\nit's basically an index order validator where the current reliable index is checked with the last reliable index and the hole is whats in between(over simplified)\nand if whats in between is more than than 0 then the capsule/datgram/capsule is skipped.\n\n### Range\n\nThis structure is used to represent the ranges of datagrams that is acknowledged and the missing ranges in non-acknowledged datagrams.\n\n| Field     | Type   | Endianness | Note |\n| --------- | ------ | ---------- | ---- |\n| is single | bool   | N/A        | If min == max, then this is set to true |\n| min       | uint24 | Little Endian | Minimum value in the range|\n| max       | uint24 | Little Endian | Maximum value in the range - Is not wrote if is single |\n\n### RangeList\n\nThe range list contains an array of nodes of the min index and the max index for each datagram range number that needs to be inserted.\n\n| Field     | Type    | Endianness | Note |\n| --------- | ------- | ---------- | ---- |\n| size      | uint16  | Big Endian | Nodes count |\n| nodes     | Range[] | N/A        |      |\n\nwhen inserting into the nodes, the the amount of nodes in there must be reduced to not waste the buffer, that is why min and max exists.\n\nfor example lets say you have an array of min and max nodes where each of them is single:\n\n```\n[\n   \u003cmin 0, max: 0\u003e\n   \u003cmin: 2, max: 2\u003e\n   \u003cmin: 3, max: 3\u003e\n   \u003cmin: 5, max: 5\u003e\n   \u003cmin: 6, max: 6\u003e\n   \u003cmin: 8, max: 8\u003e\n   \u003cmin: 8, max: 8\u003e - there shouldn't be any duplicates in a real-world implementation.\n   \u003cmin: 8, max: 8\u003e\n   \u003cmin: 10, max: 10\u003e\n   \u003cmin: 12, max: 12\u003e\n   \u003cmin: 13, max: 13\u003e\n   \u003cmin: 14, max: 14\u003e\n   \u003cmin: 15, max: 15\u003e\n]\n```\n\nIt shall turn into what is below(remember they must always be sorted):\n\n```\n[\n   \u003cmin: 0, max: 0\u003e\n   \u003cmin: 2, max: 3\u003e\n   \u003cmin: 5, max: 6\u003e\n   \u003cmin: 8, max: 8\u003e\n   \u003cmin: 10, max: 10\u003e\n   \u003cmin: 12, max: 15\u003e\n]\n```\n\n### DatagramCapsule\n\nThis structure represents a capsule in a ValidDatagram.\n\n| Field                   | Type    | Endianness    | Note |\n| ----------------------- | ------- | ------------- | ---- |\n| reliability             | 3 bits  | Big Endian    |      |\n| is split                | bit     | N/A           | If true, the packet is a split packet |\n| buffer size             | uint16  | Big Endian    | Size in bits |\n| reliable capsule index  | uint24  | Little Endian | Index used for reliable packets (requires reliability check) |\n| sequenced capsule index | uint24  | Little Endian | Index used for sequenced packets (requires reliability check) |\n| order                   | ....1   | .....         |      |\n| split packet info       | ....2   | .....         |      |\n| buffer                  | uint8[] | N/A           |      |\n\n**`....1` shall be recorded as:**\n\n| Field            | Type      | Endianness    |\n| ---------------- | --------- | ------------- |\n| ordering index   | uint24    | Little Endian |\n| ordering channel | uint8     | N/A           |\n\n**`....2` shall be recorded as:**\n\n| Field            | Type      | Endianness | Note |\n| ---------------- | --------- | ---------- | ---- |\n| size             | uint32    | Big Endian | size of the split packet |\n| id               | uint16    | Big Endian | id of the split packet |\n| index            | uint32    | Big Endian | index of the current split |\n\n## Datagram related\n\n### Capsule Size\nTo determine the size of the capsule, you can follow these steps:\n1. Increment the byte by 1 to represent the reliability.\n2. Increment the byte by 2 to represent the size of the buffer.\n3. If the reliability is any type of reliable, increment the byte by 3 to represent the `reliable capsule index`.\n4. If the reliability is sequenced, increment the byte by 3 to represent the `sequenced capsule index`.\n5. If the reliability is sequenced and ordered increment the byte by 3 for the `ordering index`, and then by 1 step for the `ordering channel`.\n6. If the capsule is segmented, increment the byte by 4 for the `size`, 2 for the `id`, and 4 for the `index` of the segment.\n\n### UserPacketEnum\nThe UserPacketEnum id is `0x86`, which marks the beginning of where you can start using your packet ids (for user packets).\n\nThe id sent over network would be `UserPacketEnumId` + user packet id (it must not make the `UserPacketEnumId` surpass the `uint8 limit`; it can start from 0, 1, ...).\n\nIt is recommended is to create a packet that contains the compressed payload that will then be decompressed when decoding the packet considering you have a completed implementation to not exceed the `uint8 limit` while sending smaller data compared to normal (may be slower than a raw payload depending on the compressor).\n\n### Sending a RakNet Packet\n\n#### Sending an online packet\n\nThe online packets(internal packets sent over valid dgram) are all reliable except the ping/pong; the online packets are not sequenced or ordered, just reliable or unreliable.\n\n#### Sending a user packet\n\nPsuedo code:\n\nThis follows the default raknet splitting algorithm.\n\n```py\nglobal/method(depends on your choice):`max payload size` := client mtu size - valid dgram header size\nif libcat \u0026 server has security then\n   global/method:`max payload size` -= libcat:auth:enc:OVERHEAD_BYTES or 11\nend\n\nmethod:`max block size` := global/method:`max payload size` - capsule:`size` # the size is not the buffer size but the calculated capsule size.\n\nmethod:`packet buffer len` := len(capsule:`buffer`)\n\nmethod:`split packet` := method:`packet buffer len` is greater than method:`max block size`\n\n# split packets must not be unreliable. if they are, convert them to reliable packets so they are successfully sent and each part is in order to reassemble.\n# once the converting is done you can do stuff like sequenced index and reliable index and ordering stuff and so on.\n# then you can split the data.\n\nif method:`split packet` then\n   method:`split packet count` := int(math.ceil(method:`packet buffer len` / method:`max block size`))\n\n   for tmp:`i` := 0; tmp:`i` is lower than method:`split packet count`; tmp:`i` += 1 then\n      tmp:`start offset` := tmp:`i` * method:`max block size`\n      tmp:`bytes to send` := method:`packet buffer len` - tmp:`start offset`\n      if tmp:`bytes to send` \u003e method:`max block size` the\n         tmp:`bytes to send` = method:`max block size`\n      end\n      tmp:`end offset` := tmp:`bytes to send`\n      if tmp:`bytes to send` is not equals to method:`max block size` then\n         tmp:`end offset` = method:`packet buffer len` - tmp:`i` * method:`max block size`\n      end\n      # construct split packet capsule and the buffer inside would be the buffer that was going to be sent sliced with start offset and end offset of the values defined before.\n   end\nend\n```\n\n## Info Sources\n\nWhere the information was gathered from.\n\n- \u003ca href=\"https://github.com/facebookarchive/RakNet\"\u003eOriginal RakNet\u003c/a\u003e: nearly everything.\n- \u003ca href=\"http://www.jenkinssoftware.com/raknet/manual/programmingtips.html\"\u003eJenkins software programming tips\u003c/a\u003e: mtu size chart.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvp817%2Fraknetprotocoldoc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvp817%2Fraknetprotocoldoc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvp817%2Fraknetprotocoldoc/lists"}