1 /* 2 * Copyright (c) 2017-2019 sel-project 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to deal 6 * in the Software without restriction, including without limitation the rights 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 * copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in all 12 * copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 * 22 */ 23 /** 24 * Packets related to a player. The first field of every packet is an `hub id` 25 * that uniquely identifies a player in the hub and never changes until it disconnects. 26 * 27 * Copyright: Copyright (c) 2017-2019 sel-project 28 * License: MIT 29 * Authors: Kripth 30 * Source: $(HTTP github.com/sel-project/selery/source/selery/hncom/player.d, selery/hncom/player.d) 31 */ 32 module selery.hncom.player; 33 34 import std.socket : Address; 35 import std.uuid : UUID; 36 37 import selery.hncom.about; 38 import selery.hncom.io; 39 40 import xpacket : Custom; 41 42 /** 43 * Adds a player to the node. 44 */ 45 @clientbound class Add : HncomPacket { 46 47 enum ubyte ID = 24; 48 49 struct ServerAddress { string ip; ushort port; } 50 51 struct Skin { string name; ubyte[] data; ubyte[] cape; string geometryName; ubyte[] geometryData; } 52 53 // reason 54 enum : ubyte { 55 56 FIRST_JOIN = 0, /// The player has been automatically put on this node because it's a non-full main node. 57 TRANSFERRED = 1, /// The player has been transferred to this node. 58 FORCIBLY_TRANSFERRED = 2, /// The player was on a node that has wrongly disconnected (probably crashing) and the player has been transferred to the first non-full main node. 59 60 } 61 62 // permission level 63 enum : ubyte { 64 65 USER = 0, 66 OPERATOR = 1, 67 HOST = 2, 68 AUTOMATION = 3, 69 ADMIN = 4, 70 71 } 72 73 // input mode 74 enum : ubyte { 75 76 KEYBOARD = 0, 77 TOUCH = 1, 78 CONTROLLER = 2, 79 80 } 81 82 /** 83 * Player's unique id given by the hub. 84 */ 85 uint hubId; 86 87 /** 88 * Reason for which the player has been added to the node. 89 */ 90 ubyte reason; 91 92 /** 93 * Optional data set by the Transfer packet if the player was transferred from another node. 94 * The content depends on the node's implementation or even by one of its plugins. 95 */ 96 ubyte[] transferMessage; 97 98 /** 99 * Game used by the player, which could either be Minecraft: Java Edition or Minecraft (Bedrock Engine). 100 * It should be one of the keys given in NodeInfo's acceptedGames field. 101 */ 102 ubyte type; 103 104 /** 105 * Version of the protocol used by the client. Should be contained in the list given 106 * to the hub in the NodeInfo's acceptedGames field. 107 */ 108 uint protocol; 109 110 /** 111 * Client's UUID, given by Mojang's or Microsoft's services if the server is in 112 * online mode or given by the client (and not verified) if the server is in offline mode. 113 */ 114 @Custom!HncomUUID UUID uuid; 115 116 /** 117 * Username of the player. 118 */ 119 string username; 120 121 /** 122 * Display name of the player, which can contain formatting codes. By default it's equals 123 * to the username but it can be updated by the node using the UpdateDisplayName packet. 124 */ 125 string displayName; 126 127 /** 128 * Name of the game played by the client; for example Minecraft or Minecraft: Java Edition. 129 */ 130 string gameName; 131 132 /** 133 * Version of the game used by the client, usually in the format major.minor[.patch], 134 * calculated by the server or given by the client during the authentication process. 135 * The node should verify that the version exists and matches the protocol indicated 136 * in the protocol field. 137 */ 138 string gameVersion; 139 140 /** 141 * Player's permission level that indicates its administration power. It's set to USER 142 * by default, which has no particular permission. 143 */ 144 ubyte permissionLevel; 145 146 /** 147 * Dimension in which the player was playing before being transferred in the MCPE format 148 * (0: overworld, 1: nether, 2: end). It shouldn't be considered if the client just joined 149 * the server instead of being transferred. 150 */ 151 ubyte dimension; 152 153 /** 154 * Client's view distance (or chunk radius). 155 */ 156 uint viewDistance; 157 158 /** 159 * Remote address of the player. 160 */ 161 @Custom!HncomAddress Address clientAddress; 162 163 /** 164 * Address used by the client to connect to the server. The value of this field is the address 165 * the client has saved in its servers list. For example a client that joins through `localhost` 166 * and a client that joins through `127.0.0.1` will connect to the same server with the same ip 167 * but the field of this value will be different (`localhost` for the first client and 168 * `127.0.0.1` for the latter). 169 */ 170 ServerAddress serverAddress; 171 172 /** 173 * Client's skin, given by the client or downloaded from Mojang's services in online mode. 174 */ 175 Skin skin; 176 177 /** 178 * Client's language, in the same format as HubInfo's language field, which should be updated 179 * from the node when the client changes it. 180 */ 181 string language; 182 183 /** 184 * Client's input mode. May be a controller, a mouse/keyboard set or a touch screen. 185 */ 186 ubyte inputMode; 187 188 /** 189 * Additional JSON data. 190 * Example: 191 * --- 192 * // bedrock engine 193 * { 194 * "edu": false, 195 * "DeviceOS": 1, 196 * "DeviceModel": "ONEPLUS A0001" 197 * } 198 * --- 199 */ 200 string gameData; 201 202 mixin Make; 203 204 } 205 206 /** 207 * Removes a player from the node. 208 * If the player is removed using Kick or Transfer this packet is not sent. 209 */ 210 @clientbound class Remove : HncomPacket { 211 212 enum ubyte ID = 25; 213 214 // reason 215 enum : ubyte { 216 217 LEFT, /// The player has closed the connection. 218 TIMED_OUT, /// The hub has closed the connection because didn't had any response from the client for too long. 219 KICKED, /// The player has been manually kicked. 220 TRANSFERRED, /// The player has been transferred by the hub 221 222 } 223 224 /** 225 * Player's unique id given by the hub. 226 */ 227 uint hubId; 228 229 /** 230 * Reason of the disconnection. 231 */ 232 ubyte reason; 233 234 mixin Make; 235 236 } 237 238 /** 239 * Kicks a player from the node and the whole server. When a player is disconnected 240 * from the node using this packet the hub will not send the Remove packet. 241 */ 242 @serverbound class Kick : HncomPacket { 243 244 enum ubyte ID = 26; 245 246 /** 247 * Player to be kicked. 248 */ 249 uint hubId; 250 251 /** 252 * Reason of the disconnection that will be displayed in the client's 253 * disconnection screen. 254 */ 255 string reason; 256 257 /** 258 * Whether the previous string should be translated client-side or not. 259 */ 260 bool translation; 261 262 /** 263 * Optional parameters for the translation (Only for java clients). 264 */ 265 string[] parameters; 266 267 mixin Make; 268 269 } 270 271 /** 272 * Transfers a player to another node. When a player is transferred from the node the hub 273 * will not send the Remove packet and there's no way, for the node, to know whether the 274 * player was disconnected or successfully transferred, if not using messages through a 275 * user-defined protocol. 276 */ 277 @serverbound class Transfer : HncomPacket { 278 279 enum ubyte ID = 27; 280 281 // on fail 282 enum : ubyte { 283 284 DISCONNECT = 0, /// Disconnect with `End of Stream` message. 285 AUTO = 1, /// Connect to the first available node or disconnects if there isn't one. 286 RECONNECT = 2, /// Connect to the same node, but as a new player. 287 288 } 289 290 /** 291 * Player to be transferred. 292 */ 293 uint hubId; 294 295 /** 296 * Id of the node that player will be transferred to. It should be an id of a 297 * connected node (which can be calculated using AddNode and RemoveNode packets), 298 * otherwise the player will be disconnected or moved to another node (see the following field). 299 */ 300 uint node; 301 302 /** 303 * Optional data that will be always sent with the Add packet when the player is transferred. 304 * The content depends on the node's implementation or even by one of its plugins. 305 */ 306 ubyte[] message; 307 308 /** 309 * Indicates the action to be taken when a transfer fails because the indicated node is 310 * not connected anymore or it cannot accept the given player's game type or protocol. 311 * If the indicated node is full the player will be simply disconnected with the `Server Full` message. 312 */ 313 ubyte onFail = DISCONNECT; 314 315 mixin Make; 316 317 } 318 319 /** 320 * Updates the player's display name when it is changed. 321 * When this packet is sent by the node a copy is always sent back by the hub. 322 */ 323 @clientbound @serverbound class UpdateDisplayName : HncomPacket { 324 325 enum ubyte ID = 28; 326 327 /** 328 * Player's unique id given by the hub. 329 */ 330 uint hubId; 331 332 /** 333 * Player's display name that can contain formatting codes. Prefixes and suffixes should be avoided. 334 */ 335 string displayName; 336 337 mixin Make; 338 339 } 340 341 /** 342 * Updates the player's world. The player's dimension should be updated by 343 * the hub using worldId to identify the world added with AddWorld and 344 * removed with RemoveWorld. 345 */ 346 @serverbound class UpdateWorld : HncomPacket { 347 348 enum ubyte ID = 29; 349 350 /** 351 * Player's unique id given by the hub. 352 */ 353 uint hubId; 354 355 /** 356 * World's id, that should have been previously added with the 357 * AddWorld packet. 358 */ 359 uint worldId; 360 361 mixin Make; 362 363 } 364 365 /** 366 * Update the player's permission level. 367 * When this packet is sent by the node a copy is always sent back by the hub. 368 */ 369 @clientbound @serverbound class UpdatePermissionLevel : HncomPacket { 370 371 enum ubyte ID = 30; 372 373 // permission level 374 enum : ubyte { 375 376 USER = 0, 377 OPERATOR = 1, 378 HOST = 2, 379 AUTOMATION = 3, 380 ADMIN = 4, 381 382 } 383 384 /** 385 * Player's unique id given by the hub. 386 */ 387 uint hubId; 388 389 ubyte permissionLevel; 390 391 mixin Make; 392 393 } 394 395 /** 396 * Notifies the node that the player's view distance has been updated client-side. 397 * The node may decide to not accept the new view distance and not send the required chunks. 398 */ 399 @clientbound class UpdateViewDistance : HncomPacket { 400 401 enum ubyte ID = 31; 402 403 /** 404 * Player's unique id given by the hub. 405 */ 406 uint hubId; 407 408 /** 409 * Player's new view distance as indicated by the client. 410 */ 411 uint viewDistance; 412 413 mixin Make; 414 415 } 416 417 /** 418 * Updates the player's language when the client changes it. 419 */ 420 @clientbound class UpdateLanguage : HncomPacket { 421 422 enum ubyte ID = 32; 423 424 /** 425 * Player's unique id given by the hub. 426 */ 427 uint hubId; 428 429 /** 430 * Player's language in the same format as HubInfo's language field. 431 */ 432 string language; 433 434 mixin Make; 435 436 } 437 438 /** 439 * Updates the latency between the player and the hub. 440 */ 441 @clientbound class UpdateLatency : HncomPacket { 442 443 enum ubyte ID = 33; 444 445 /** 446 * Player's unique id given by the hub. 447 */ 448 uint hubId; 449 450 /** 451 * Player's latency in milliseconds. The latency between the client and the 452 * node is then calculated adding the latency between the node and the hub 453 * to this field's value. 454 */ 455 uint latency; 456 457 mixin Make; 458 459 } 460 461 /** 462 * Updates the packet loss between the player and the hub. 463 */ 464 @clientbound class UpdatePacketLoss : HncomPacket { 465 466 enum ubyte ID = 34; 467 468 /** 469 * Player's unique id given by the hub. 470 */ 471 uint hubId; 472 473 /** 474 * Percentage of lost packets, from 0% (no packet lost) to 100% (every 475 * packet lost). 476 */ 477 float packetLoss; 478 479 mixin Make; 480 481 } 482 483 @clientbound @serverbound class GamePacket : HncomPacket { 484 485 enum ubyte ID = 35; 486 487 /** 488 * Player's unique id given by the hub. 489 */ 490 uint hubId; 491 492 ubyte[] payload; 493 494 mixin Make; 495 496 } 497 498 @serverbound class SerializedGamePacket : HncomPacket { 499 500 enum ubyte ID = 36; 501 502 /** 503 * Player's unique id given by the hub. 504 */ 505 uint hubId; 506 507 ubyte[] payload; 508 509 mixin Make; 510 511 } 512 513 @serverbound class OrderedGamePacket : HncomPacket { 514 515 enum ubyte ID = 37; 516 517 /** 518 * Player's unique id given by the hub. 519 */ 520 uint hubId; 521 522 uint order; 523 524 ubyte[] payload; 525 526 mixin Make; 527 528 }