diff options
Diffstat (limited to 'enigma-server/docs')
| -rw-r--r-- | enigma-server/docs/protocol.md | 50 |
1 files changed, 42 insertions, 8 deletions
diff --git a/enigma-server/docs/protocol.md b/enigma-server/docs/protocol.md index 83ef4c0..f642e13 100644 --- a/enigma-server/docs/protocol.md +++ b/enigma-server/docs/protocol.md | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | # Enigma protocol | 1 | # Enigma protocol |
| 2 | |||
| 2 | Enigma uses TCP sockets for communication. Data is sent in each direction as a continuous stream, with packets being | 3 | Enigma uses TCP sockets for communication. Data is sent in each direction as a continuous stream, with packets being |
| 3 | concatenated one after the other. | 4 | concatenated one after the other. |
| 4 | 5 | ||
| @@ -10,6 +11,7 @@ use the same modified UTF format as in `DataOutputStream`, I repeat, the normal | |||
| 10 | Strings, see below. | 11 | Strings, see below. |
| 11 | 12 | ||
| 12 | ## Login protocol | 13 | ## Login protocol |
| 14 | |||
| 13 | ``` | 15 | ``` |
| 14 | Client Server | 16 | Client Server |
| 15 | | | | 17 | | | |
| @@ -22,6 +24,7 @@ Client Server | |||
| 22 | | ConfirmChange | | 24 | | ConfirmChange | |
| 23 | | >>>>>>>>>>>>> | | 25 | | >>>>>>>>>>>>> | |
| 24 | ``` | 26 | ``` |
| 27 | |||
| 25 | 1. On connect, the client sends a login packet to the server. This allows the server to test the validity of the client, | 28 | 1. On connect, the client sends a login packet to the server. This allows the server to test the validity of the client, |
| 26 | as well as allowing the client to declare metadata about itself, such as the username. | 29 | as well as allowing the client to declare metadata about itself, such as the username. |
| 27 | 1. After validating the login packet, the server sends all its mappings to the client, and the client will apply them. | 30 | 1. After validating the login packet, the server sends all its mappings to the client, and the client will apply them. |
| @@ -29,15 +32,18 @@ Client Server | |||
| 29 | has received the mappings and is in sync with the server. Once the server receives this packet, the client will be | 32 | has received the mappings and is in sync with the server. Once the server receives this packet, the client will be |
| 30 | allowed to modify mappings. | 33 | allowed to modify mappings. |
| 31 | 34 | ||
| 32 | The server will not accept any other packets from the client until this entire exchange has been completed. | 35 | The server will not accept any other packets from the client until this entire exchange has been completed. |
| 33 | 36 | ||
| 34 | ## Kicking clients | 37 | ## Kicking clients |
| 38 | |||
| 35 | When the server kicks a client, it may optionally send a `Kick` packet immediately before closing the connection, which | 39 | When the server kicks a client, it may optionally send a `Kick` packet immediately before closing the connection, which |
| 36 | contains the reason why the client was kicked (so the client can display it to the user). This is not required though - | 40 | contains the reason why the client was kicked (so the client can display it to the user). This is not required though - |
| 37 | the server may simply terminate the connection. | 41 | the server may simply terminate the connection. |
| 38 | 42 | ||
| 39 | ## Changing mappings | 43 | ## Changing mappings |
| 44 | |||
| 40 | This section uses the example of renaming, but the same pattern applies to all mapping changes. | 45 | This section uses the example of renaming, but the same pattern applies to all mapping changes. |
| 46 | |||
| 41 | ``` | 47 | ``` |
| 42 | Client A Server Client B | 48 | Client A Server Client B |
| 43 | | | | | 49 | | | | |
| @@ -66,19 +72,23 @@ Client A Server Client B | |||
| 66 | server will unlock that mapping for that client and allow them to make changes again. | 72 | server will unlock that mapping for that client and allow them to make changes again. |
| 67 | 73 | ||
| 68 | ## Packets | 74 | ## Packets |
| 75 | |||
| 69 | ```c | 76 | ```c |
| 70 | struct Packet { | 77 | struct Packet { |
| 71 | unsigned short packet_id; | 78 | unsigned short packet_id; |
| 72 | data[]; // depends on packet_id | 79 | data[]; // depends on packet_id |
| 73 | } | 80 | } |
| 74 | ``` | 81 | ``` |
| 82 | |||
| 75 | The IDs for client-to-server packets are as follows: | 83 | The IDs for client-to-server packets are as follows: |
| 84 | |||
| 76 | - 0: `Login` | 85 | - 0: `Login` |
| 77 | - 1: `ConfirmChange` | 86 | - 1: `ConfirmChange` |
| 78 | - 6: `Message` | 87 | - 6: `Message` |
| 79 | - 7: `EntryChange` | 88 | - 7: `EntryChange` |
| 80 | 89 | ||
| 81 | The IDs for server-to-client packets are as follows: | 90 | The IDs for server-to-client packets are as follows: |
| 91 | |||
| 82 | - 0: `Kick` | 92 | - 0: `Kick` |
| 83 | - 1: `SyncMappings` | 93 | - 1: `SyncMappings` |
| 84 | - 6: `Message` | 94 | - 6: `Message` |
| @@ -86,17 +96,20 @@ The IDs for server-to-client packets are as follows: | |||
| 86 | - 8: `EntryChange` | 96 | - 8: `EntryChange` |
| 87 | 97 | ||
| 88 | ### The utf struct | 98 | ### The utf struct |
| 99 | |||
| 89 | ```c | 100 | ```c |
| 90 | struct utf { | 101 | struct utf { |
| 91 | unsigned short length; | 102 | unsigned short length; |
| 92 | byte data[length]; | 103 | byte data[length]; |
| 93 | } | 104 | } |
| 94 | ``` | 105 | ``` |
| 106 | |||
| 95 | - `length`: The number of bytes in the UTF-8 encoding of the string. Note, this may not be the same as the number of | 107 | - `length`: The number of bytes in the UTF-8 encoding of the string. Note, this may not be the same as the number of |
| 96 | Unicode characters in the string. | 108 | Unicode characters in the string. |
| 97 | - `data`: A standard UTF-8 encoded byte array representing the string. | 109 | - `data`: A standard UTF-8 encoded byte array representing the string. |
| 98 | 110 | ||
| 99 | ### The Entry struct | 111 | ### The Entry struct |
| 112 | |||
| 100 | ```c | 113 | ```c |
| 101 | enum EntryType { | 114 | enum EntryType { |
| 102 | ENTRY_CLASS = 0, ENTRY_FIELD = 1, ENTRY_METHOD = 2, ENTRY_LOCAL_VAR = 3; | 115 | ENTRY_CLASS = 0, ENTRY_FIELD = 1, ENTRY_METHOD = 2, ENTRY_LOCAL_VAR = 3; |
| @@ -121,9 +134,10 @@ struct Entry { | |||
| 121 | } | 134 | } |
| 122 | } | 135 | } |
| 123 | ``` | 136 | ``` |
| 137 | |||
| 124 | - `type`: The type of entry this is. One of `ENTRY_CLASS`, `ENTRY_FIELD`, `ENTRY_METHOD` or `ENTRY_LOCAL_VAR`. | 138 | - `type`: The type of entry this is. One of `ENTRY_CLASS`, `ENTRY_FIELD`, `ENTRY_METHOD` or `ENTRY_LOCAL_VAR`. |
| 125 | - `parent`: The parent entry. Only class entries may have no parent. fields, methods and inner classes must have their | 139 | - `parent`: The parent entry. Only class entries may have no parent. fields, methods and inner classes must have their |
| 126 | containing class as their parent. Local variables have a method as a parent. | 140 | containing class as their parent. Local variables have a method as a parent. |
| 127 | - `name`: The class/field/method/variable name. | 141 | - `name`: The class/field/method/variable name. |
| 128 | - `javadoc`: The javadoc of an entry, if present. | 142 | - `javadoc`: The javadoc of an entry, if present. |
| 129 | - `descriptor`: The field/method descriptor. | 143 | - `descriptor`: The field/method descriptor. |
| @@ -131,6 +145,7 @@ struct Entry { | |||
| 131 | - `parameter`: Whether the local variable is a parameter. | 145 | - `parameter`: Whether the local variable is a parameter. |
| 132 | 146 | ||
| 133 | ### The Message struct | 147 | ### The Message struct |
| 148 | |||
| 134 | ```c | 149 | ```c |
| 135 | enum MessageType { | 150 | enum MessageType { |
| 136 | MESSAGE_CHAT = 0, | 151 | MESSAGE_CHAT = 0, |
| @@ -176,8 +191,9 @@ struct Message { | |||
| 176 | } data; | 191 | } data; |
| 177 | }; | 192 | }; |
| 178 | ``` | 193 | ``` |
| 194 | |||
| 179 | - `type`: The type of message this is. One of `MESSAGE_CHAT`, `MESSAGE_CONNECT`, `MESSAGE_DISCONNECT`, | 195 | - `type`: The type of message this is. One of `MESSAGE_CHAT`, `MESSAGE_CONNECT`, `MESSAGE_DISCONNECT`, |
| 180 | `MESSAGE_EDIT_DOCS`, `MESSAGE_MARK_DEOBF`, `MESSAGE_REMOVE_MAPPING`, `MESSAGE_RENAME`. | 196 | `MESSAGE_EDIT_DOCS`, `MESSAGE_MARK_DEOBF`, `MESSAGE_REMOVE_MAPPING`, `MESSAGE_RENAME`. |
| 181 | - `chat`: Chat message. Use in case `type` is `MESSAGE_CHAT` | 197 | - `chat`: Chat message. Use in case `type` is `MESSAGE_CHAT` |
| 182 | - `connect`: Sent when a user connects. Use in case `type` is `MESSAGE_CONNECT` | 198 | - `connect`: Sent when a user connects. Use in case `type` is `MESSAGE_CONNECT` |
| 183 | - `disconnect`: Sent when a user disconnects. Use in case `type` is `MESSAGE_DISCONNECT` | 199 | - `disconnect`: Sent when a user disconnects. Use in case `type` is `MESSAGE_DISCONNECT` |
| @@ -191,6 +207,7 @@ struct Message { | |||
| 191 | - `new_name`: The new name for the entry. | 207 | - `new_name`: The new name for the entry. |
| 192 | 208 | ||
| 193 | ### The entry_change struct | 209 | ### The entry_change struct |
| 210 | |||
| 194 | ```c | 211 | ```c |
| 195 | typedef enum tristate_change { | 212 | typedef enum tristate_change { |
| 196 | TRISTATE_CHANGE_UNCHANGED = 0, | 213 | TRISTATE_CHANGE_UNCHANGED = 0, |
| @@ -224,6 +241,7 @@ struct entry_change { | |||
| 224 | } | 241 | } |
| 225 | } | 242 | } |
| 226 | ``` | 243 | ``` |
| 244 | |||
| 227 | - `entry`: The entry this change gets applied to. | 245 | - `entry`: The entry this change gets applied to. |
| 228 | - `flags`: See definition of `entry_change_flags`. | 246 | - `flags`: See definition of `entry_change_flags`. |
| 229 | - `deobf_name`: The new deobfuscated name, if deobf_name_change == TRISTATE_CHANGE_SET | 247 | - `deobf_name`: The new deobfuscated name, if deobf_name_change == TRISTATE_CHANGE_SET |
| @@ -231,6 +249,7 @@ struct entry_change { | |||
| 231 | - `access_modifiers`: The new access modifier, if access_change == TRISTATE_CHANGE_SET (otherwise 0) | 249 | - `access_modifiers`: The new access modifier, if access_change == TRISTATE_CHANGE_SET (otherwise 0) |
| 232 | 250 | ||
| 233 | ### Login (client-to-server) | 251 | ### Login (client-to-server) |
| 252 | |||
| 234 | ```c | 253 | ```c |
| 235 | struct LoginC2SPacket { | 254 | struct LoginC2SPacket { |
| 236 | unsigned short protocol_version; | 255 | unsigned short protocol_version; |
| @@ -240,47 +259,57 @@ struct LoginC2SPacket { | |||
| 240 | utf username; | 259 | utf username; |
| 241 | } | 260 | } |
| 242 | ``` | 261 | ``` |
| 262 | |||
| 243 | - `protocol_version`: the version of the protocol. If the version does not match on the server, then the client will be | 263 | - `protocol_version`: the version of the protocol. If the version does not match on the server, then the client will be |
| 244 | kicked immediately. Currently always equal to 0. | 264 | kicked immediately. Currently always equal to 0. |
| 245 | - `checksum`: the SHA-1 hash of the JAR file the client has open. If this does not match the SHA-1 hash of the JAR file | 265 | - `checksum`: the SHA-1 hash of the JAR file the client has open. If this does not match the SHA-1 hash of the JAR file |
| 246 | the server has open, the client will be kicked. | 266 | the server has open, the client will be kicked. |
| 247 | - `password`: the password needed to log into the server. Note that each `char` is 2 bytes, as per the Java data type. | 267 | - `password`: the password needed to log into the server. Note that each `char` is 2 bytes, as per the Java data type. |
| 248 | If this password is incorrect, the client will be kicked. | 268 | If this password is incorrect, the client will be kicked. |
| 249 | - `username`: the username of the user logging in. If the username is not unique, the client will be kicked. | 269 | - `username`: the username of the user logging in. If the username is not unique, the client will be kicked. |
| 250 | 270 | ||
| 251 | ### ConfirmChange (client-to-server) | 271 | ### ConfirmChange (client-to-server) |
| 272 | |||
| 252 | ```c | 273 | ```c |
| 253 | struct ConfirmChangeC2SPacket { | 274 | struct ConfirmChangeC2SPacket { |
| 254 | unsigned short sync_id; | 275 | unsigned short sync_id; |
| 255 | } | 276 | } |
| 256 | ``` | 277 | ``` |
| 278 | |||
| 257 | - `sync_id`: the sync ID to confirm. | 279 | - `sync_id`: the sync ID to confirm. |
| 258 | 280 | ||
| 259 | ### Message (client-to-server) | 281 | ### Message (client-to-server) |
| 282 | |||
| 260 | ```c | 283 | ```c |
| 261 | struct MessageC2SPacket { | 284 | struct MessageC2SPacket { |
| 262 | utf message; | 285 | utf message; |
| 263 | } | 286 | } |
| 264 | ``` | 287 | ``` |
| 288 | |||
| 265 | - `message`: The text message the user sent. | 289 | - `message`: The text message the user sent. |
| 266 | 290 | ||
| 267 | ### EntryChange (client-to-server) | 291 | ### EntryChange (client-to-server) |
| 292 | |||
| 268 | ```c | 293 | ```c |
| 269 | struct EntryChangeC2SPacket { | 294 | struct EntryChangeC2SPacket { |
| 270 | entry_change change; | 295 | entry_change change; |
| 271 | } | 296 | } |
| 272 | ``` | 297 | ``` |
| 298 | |||
| 273 | - `change`: The change to apply. | 299 | - `change`: The change to apply. |
| 274 | 300 | ||
| 275 | ### Kick (server-to-client) | 301 | ### Kick (server-to-client) |
| 302 | |||
| 276 | ```c | 303 | ```c |
| 277 | struct KickS2CPacket { | 304 | struct KickS2CPacket { |
| 278 | utf reason; | 305 | utf reason; |
| 279 | } | 306 | } |
| 280 | ``` | 307 | ``` |
| 308 | |||
| 281 | - `reason`: the reason for the kick, may or may not be a translation key for the client to display to the user. | 309 | - `reason`: the reason for the kick, may or may not be a translation key for the client to display to the user. |
| 282 | 310 | ||
| 283 | ### SyncMappings (server-to-client) | 311 | ### SyncMappings (server-to-client) |
| 312 | |||
| 284 | ```c | 313 | ```c |
| 285 | struct SyncMappingsS2CPacket { | 314 | struct SyncMappingsS2CPacket { |
| 286 | int num_roots; | 315 | int num_roots; |
| @@ -296,6 +325,7 @@ struct MappingNode { | |||
| 296 | } | 325 | } |
| 297 | typedef { Entry but without the has_parent or parent fields } NoParentEntry; | 326 | typedef { Entry but without the has_parent or parent fields } NoParentEntry; |
| 298 | ``` | 327 | ``` |
| 328 | |||
| 299 | - `roots`: The root mapping nodes, containing all the entries without parents. | 329 | - `roots`: The root mapping nodes, containing all the entries without parents. |
| 300 | - `obf_entry`: The value of a node, containing the obfuscated name and descriptor of the entry. | 330 | - `obf_entry`: The value of a node, containing the obfuscated name and descriptor of the entry. |
| 301 | - `name`: The deobfuscated name of the entry, if it exists, otherwise the empty string. | 331 | - `name`: The deobfuscated name of the entry, if it exists, otherwise the empty string. |
| @@ -303,6 +333,7 @@ typedef { Entry but without the has_parent or parent fields } NoParentEntry; | |||
| 303 | - `children`: The children of this node | 333 | - `children`: The children of this node |
| 304 | 334 | ||
| 305 | ### Message (server-to-client) | 335 | ### Message (server-to-client) |
| 336 | |||
| 306 | ```c | 337 | ```c |
| 307 | struct MessageS2CPacket { | 338 | struct MessageS2CPacket { |
| 308 | Message message; | 339 | Message message; |
| @@ -310,6 +341,7 @@ struct MessageS2CPacket { | |||
| 310 | ``` | 341 | ``` |
| 311 | 342 | ||
| 312 | ### UserList (server-to-client) | 343 | ### UserList (server-to-client) |
| 344 | |||
| 313 | ```c | 345 | ```c |
| 314 | struct UserListS2CPacket { | 346 | struct UserListS2CPacket { |
| 315 | unsigned short len; | 347 | unsigned short len; |
| @@ -318,11 +350,13 @@ struct UserListS2CPacket { | |||
| 318 | ``` | 350 | ``` |
| 319 | 351 | ||
| 320 | ### EntryChange (server-to-client) | 352 | ### EntryChange (server-to-client) |
| 353 | |||
| 321 | ```c | 354 | ```c |
| 322 | struct EntryChangeS2CPacket { | 355 | struct EntryChangeS2CPacket { |
| 323 | uint16_t sync_id; | 356 | uint16_t sync_id; |
| 324 | entry_change change; | 357 | entry_change change; |
| 325 | } | 358 | } |
| 326 | ``` | 359 | ``` |
| 360 | |||
| 327 | - `sync_id`: The sync ID of the change for locking purposes. | 361 | - `sync_id`: The sync ID of the change for locking purposes. |
| 328 | - `change`: The change to apply. \ No newline at end of file | 362 | - `change`: The change to apply. \ No newline at end of file |