1 /* 2 * This file was automatically generated by sel-utils and 3 * released under the MIT License. 4 * 5 * License: https://github.com/sel-project/sel-utils/blob/master/LICENSE 6 * Repository: https://github.com/sel-project/sel-utils 7 * Generated from https://github.com/sel-project/sel-utils/blob/master/xml/protocol/hncom2.xml 8 */ 9 /** 10 * Packets related to a player. The first field of every packet is an `hub id` that 11 * uniquely identifies a player in the hub and never changes until it's disconnected. 12 */ 13 module sul.protocol.hncom2.player; 14 15 import std.bitmanip : write, peek; 16 static import std.conv; 17 import std.system : Endian; 18 import std.typetuple : TypeTuple; 19 import std.typecons : Tuple; 20 import std.uuid : UUID; 21 22 import sul.utils.buffer; 23 import sul.utils.var; 24 25 static import sul.protocol.hncom2.types; 26 27 static if(__traits(compiles, { import sul.metadata.hncom2; })) import sul.metadata.hncom2; 28 29 alias Packets = TypeTuple!(Add, Remove, Kick, Transfer, UpdateDisplayName, UpdateWorld, UpdateViewDistance, UpdateLanguage, UpdateGamemode, UpdateInputMode, UpdateLatency, UpdatePacketLoss, GamePacket, OrderedGamePacket); 30 31 /** 32 * Adds a player to the node. 33 */ 34 class Add : Buffer { 35 36 public enum ubyte ID = 17; 37 38 public enum bool CLIENTBOUND = true; 39 public enum bool SERVERBOUND = false; 40 41 // reason 42 public enum ubyte FIRST_JOIN = 0; 43 public enum ubyte TRANSFERRED = 1; 44 public enum ubyte FORCIBLY_TRANSFERRED = 2; 45 46 // dimension 47 public enum ubyte OVERWORLD = 0; 48 public enum ubyte NETHER = 1; 49 public enum ubyte END = 2; 50 51 // input mode 52 public enum ubyte KEYBOARD = 0; 53 public enum ubyte TOUCH = 1; 54 public enum ubyte CONTROLLER = 2; 55 56 public enum string[] FIELDS = ["hubId", "reason", "type", "protocol", "vers", "username", "displayName", "dimension", "viewDistance", "clientAddress", "serverAddress", "serverPort", "uuid", "skin", "language", "inputMode", "latency"]; 57 58 public uint hubId; 59 60 /** 61 * Reason for which the player has been added to the node. 62 */ 63 public ubyte reason; 64 65 /** 66 * Game of the client, which could either be Minecraft or Minecraft: Pocket Edition. 67 */ 68 public ubyte type; 69 70 /** 71 * Version of the protocol used by the client. 72 */ 73 public uint protocol; 74 75 /** 76 * Version of the game used by the client, usually in the format major.minor[.patch], 77 * calculated by the server or passed by the client during the authentication process. 78 * The node should verify that the version exists and matches the protocol in the previous 79 * field. 80 */ 81 public string vers; 82 83 /** 84 * Username of the player. 85 */ 86 public string username; 87 88 /** 89 * Display name of the player, which can contain formatting codes. By default it's 90 * equals to the username but it can be updated by the node using UpdateDisplayName. 91 */ 92 public string displayName; 93 94 /** 95 * Dimension in which the player was playing before being transferred. 96 * It's used to send the game's change dimension packet to despawn old entities and 97 * delete old chunks. 98 */ 99 public ubyte dimension; 100 101 /** 102 * Client's view distance (or chunk radius). See [UpdateViewDistance.viewDistance](#player_update-view-distance_view-distance) 103 * for more informations. 104 */ 105 public uint viewDistance; 106 107 /** 108 * Remote address of the client. 109 */ 110 public sul.protocol.hncom2.types.Address clientAddress; 111 112 /** 113 * Ip used by the client to connect to the server. The value of this field is the address 114 * the client has saved in its servers list. For example a client that joins through 115 * `localhost` and a client that joins through `127.0.0.1` will connect to the same 116 * server but the field of this value will be different (`localhost` for the first 117 * client and `127.0.0.1` for the second). 118 */ 119 public string serverAddress; 120 121 /** 122 * Port used by the client to connect to the server. 123 */ 124 public ushort serverPort; 125 126 /** 127 * Client's UUID, given by Mojang's or Microsoft's services if the server is in online 128 * mode or given by the client (and not verified) if the server is in offline mode. 129 */ 130 public UUID uuid; 131 132 /** 133 * Client's skin, given by the client or downloaded from Mojang's services in online 134 * mode. 135 */ 136 public sul.protocol.hncom2.types.Skin skin; 137 138 /** 139 * Client's language, in the same format as HubInfo.language, which should be updated 140 * from the node when the client changes it. See also UpdateLanguage.language. 141 */ 142 public string language; 143 144 /** 145 * Client's input mode. See UpdateInputMode.inputMode for more informations. 146 */ 147 public ubyte inputMode; 148 149 /** 150 * Client's latency (ping time). See UpdateLatency.latency for more informations. 151 */ 152 public uint latency; 153 154 public pure nothrow @safe @nogc this() {} 155 156 public pure nothrow @safe @nogc this(uint hubId, ubyte reason=ubyte.init, ubyte type=ubyte.init, uint protocol=uint.init, string vers=string.init, string username=string.init, string displayName=string.init, ubyte dimension=ubyte.init, uint viewDistance=uint.init, sul.protocol.hncom2.types.Address clientAddress=sul.protocol.hncom2.types.Address.init, string serverAddress=string.init, ushort serverPort=ushort.init, UUID uuid=UUID.init, sul.protocol.hncom2.types.Skin skin=sul.protocol.hncom2.types.Skin.init, string language=string.init, ubyte inputMode=ubyte.init, uint latency=uint.init) { 157 this.hubId = hubId; 158 this.reason = reason; 159 this.type = type; 160 this.protocol = protocol; 161 this.vers = vers; 162 this.username = username; 163 this.displayName = displayName; 164 this.dimension = dimension; 165 this.viewDistance = viewDistance; 166 this.clientAddress = clientAddress; 167 this.serverAddress = serverAddress; 168 this.serverPort = serverPort; 169 this.uuid = uuid; 170 this.skin = skin; 171 this.language = language; 172 this.inputMode = inputMode; 173 this.latency = latency; 174 } 175 176 public pure nothrow @safe ubyte[] encode(bool writeId=true)() { 177 _buffer.length = 0; 178 static if(writeId){ writeBigEndianUbyte(ID); } 179 writeBytes(varuint.encode(hubId)); 180 writeBigEndianUbyte(reason); 181 writeBigEndianUbyte(type); 182 writeBytes(varuint.encode(protocol)); 183 writeBytes(varuint.encode(cast(uint)vers.length)); writeString(vers); 184 writeBytes(varuint.encode(cast(uint)username.length)); writeString(username); 185 writeBytes(varuint.encode(cast(uint)displayName.length)); writeString(displayName); 186 if(reason!=0){ writeBigEndianUbyte(dimension); } 187 if(reason!=0){ writeBytes(varuint.encode(viewDistance)); } 188 clientAddress.encode(bufferInstance); 189 writeBytes(varuint.encode(cast(uint)serverAddress.length)); writeString(serverAddress); 190 writeBigEndianUshort(serverPort); 191 writeBytes(uuid.data); 192 skin.encode(bufferInstance); 193 writeBytes(varuint.encode(cast(uint)language.length)); writeString(language); 194 writeBigEndianUbyte(inputMode); 195 writeBytes(varuint.encode(latency)); 196 return _buffer; 197 } 198 199 public pure nothrow @safe void decode(bool readId=true)() { 200 static if(readId){ ubyte _id; _id=readBigEndianUbyte(); } 201 hubId=varuint.decode(_buffer, &_index); 202 reason=readBigEndianUbyte(); 203 type=readBigEndianUbyte(); 204 protocol=varuint.decode(_buffer, &_index); 205 uint dvc=varuint.decode(_buffer, &_index); vers=readString(dvc); 206 uint dnc5bu=varuint.decode(_buffer, &_index); username=readString(dnc5bu); 207 uint zlcxe5bu=varuint.decode(_buffer, &_index); displayName=readString(zlcxe5bu); 208 if(reason!=0){ dimension=readBigEndianUbyte(); } 209 if(reason!=0){ viewDistance=varuint.decode(_buffer, &_index); } 210 clientAddress.decode(bufferInstance); 211 uint cvdvqrcv=varuint.decode(_buffer, &_index); serverAddress=readString(cvdvqrcv); 212 serverPort=readBigEndianUshort(); 213 if(_buffer.length>=_index+16){ ubyte[16] dvz=_buffer[_index.._index+16].dup; _index+=16; uuid=UUID(dvz); } 214 skin.decode(bufferInstance); 215 uint bfzvzu=varuint.decode(_buffer, &_index); language=readString(bfzvzu); 216 inputMode=readBigEndianUbyte(); 217 latency=varuint.decode(_buffer, &_index); 218 } 219 220 public static pure nothrow @safe Add fromBuffer(bool readId=true)(ubyte[] buffer) { 221 Add ret = new Add(); 222 ret._buffer = buffer; 223 ret.decode!readId(); 224 return ret; 225 } 226 227 public override string toString() { 228 return "Add(hubId: " ~ std.conv.to!string(this.hubId) ~ ", reason: " ~ std.conv.to!string(this.reason) ~ ", type: " ~ std.conv.to!string(this.type) ~ ", protocol: " ~ std.conv.to!string(this.protocol) ~ ", vers: " ~ std.conv.to!string(this.vers) ~ ", username: " ~ std.conv.to!string(this.username) ~ ", displayName: " ~ std.conv.to!string(this.displayName) ~ ", dimension: " ~ std.conv.to!string(this.dimension) ~ ", viewDistance: " ~ std.conv.to!string(this.viewDistance) ~ ", clientAddress: " ~ std.conv.to!string(this.clientAddress) ~ ", serverAddress: " ~ std.conv.to!string(this.serverAddress) ~ ", serverPort: " ~ std.conv.to!string(this.serverPort) ~ ", uuid: " ~ std.conv.to!string(this.uuid) ~ ", skin: " ~ std.conv.to!string(this.skin) ~ ", language: " ~ std.conv.to!string(this.language) ~ ", inputMode: " ~ std.conv.to!string(this.inputMode) ~ ", latency: " ~ std.conv.to!string(this.latency) ~ ")"; 229 } 230 231 alias _encode = encode; 232 233 enum string variantField = "type"; 234 235 alias Variants = TypeTuple!(Pocket, Minecraft, Console); 236 237 /** 238 * A Minecraft: Pocket Edition client. 239 */ 240 public class Pocket { 241 242 public enum typeof(type) TYPE = 1; 243 244 // device os 245 public enum ubyte UNKNOWN = 0; 246 public enum ubyte ANDROID = 1; 247 public enum ubyte IOS = 2; 248 public enum ubyte OSX = 3; 249 public enum ubyte FIRE_OS = 4; 250 public enum ubyte GEAR_VR = 5; 251 public enum ubyte HOLOLENS = 6; 252 public enum ubyte WINDOWS10 = 7; 253 public enum ubyte WINDOWS32 = 8; 254 public enum ubyte DEDICATED = 9; 255 256 public enum string[] FIELDS = ["xuid", "edu", "packetLoss", "deviceOs", "deviceModel"]; 257 258 /** 259 * XBOX Live id, which is a unique identifier for authenticated players or 0 if the 260 * server is in offline mode. 261 */ 262 public long xuid; 263 264 /** 265 * Indicates whether the client is using the Education Edition variant of the game. 266 */ 267 public bool edu; 268 269 /** 270 * Client's packet loss calculated from the hub. See UpdatePacketLoss.packetLoss for 271 * more informations. 272 */ 273 public float packetLoss; 274 275 /** 276 * Client's operative system, if supplied by the client. This field's value may be 277 * used to divide players that play from a phone from players that play on a computer. 278 */ 279 public ubyte deviceOs; 280 281 /** 282 * Client's device model, if supplied by the client. This field is usually a string 283 * in the format `MANUFACTURER MODEL`: for example, the Oneplus one is `ONEPLUS A0001`. 284 * This field's value may be used to ban low-end devices. 285 */ 286 public string deviceModel; 287 288 public pure nothrow @safe @nogc this() {} 289 290 public pure nothrow @safe @nogc this(long xuid, bool edu=bool.init, float packetLoss=float.init, ubyte deviceOs=ubyte.init, string deviceModel=string.init) { 291 this.xuid = xuid; 292 this.edu = edu; 293 this.packetLoss = packetLoss; 294 this.deviceOs = deviceOs; 295 this.deviceModel = deviceModel; 296 } 297 298 public pure nothrow @safe ubyte[] encode(bool writeId=true)() { 299 type = 1; 300 _encode!writeId(); 301 writeBytes(varlong.encode(xuid)); 302 writeBigEndianBool(edu); 303 writeBigEndianFloat(packetLoss); 304 writeBigEndianUbyte(deviceOs); 305 writeBytes(varuint.encode(cast(uint)deviceModel.length)); writeString(deviceModel); 306 return _buffer; 307 } 308 309 public pure nothrow @safe void decode() { 310 xuid=varlong.decode(_buffer, &_index); 311 edu=readBigEndianBool(); 312 packetLoss=readBigEndianFloat(); 313 deviceOs=readBigEndianUbyte(); 314 uint zvant9zw=varuint.decode(_buffer, &_index); deviceModel=readString(zvant9zw); 315 } 316 317 public override string toString() { 318 return "Add.Pocket(xuid: " ~ std.conv.to!string(this.xuid) ~ ", edu: " ~ std.conv.to!string(this.edu) ~ ", packetLoss: " ~ std.conv.to!string(this.packetLoss) ~ ", deviceOs: " ~ std.conv.to!string(this.deviceOs) ~ ", deviceModel: " ~ std.conv.to!string(this.deviceModel) ~ ")"; 319 } 320 321 } 322 323 /** 324 * A Minecraft client. 325 */ 326 public class Minecraft { 327 328 public enum typeof(type) TYPE = 2; 329 330 public enum string[] FIELDS = ["properties"]; 331 332 /** 333 * Additional properties like textures when the server is on online mode. 334 */ 335 public sul.protocol.hncom2.types.Property[] properties; 336 337 public pure nothrow @safe @nogc this() {} 338 339 public pure nothrow @safe @nogc this(sul.protocol.hncom2.types.Property[] properties) { 340 this.properties = properties; 341 } 342 343 public pure nothrow @safe ubyte[] encode(bool writeId=true)() { 344 type = 2; 345 _encode!writeId(); 346 writeBytes(varuint.encode(cast(uint)properties.length)); foreach(cjcvdlc;properties){ cjcvdlc.encode(bufferInstance); } 347 return _buffer; 348 } 349 350 public pure nothrow @safe void decode() { 351 properties.length=varuint.decode(_buffer, &_index); foreach(ref cjcvdlc;properties){ cjcvdlc.decode(bufferInstance); } 352 } 353 354 public override string toString() { 355 return "Add.Minecraft(properties: " ~ std.conv.to!string(this.properties) ~ ")"; 356 } 357 358 } 359 360 public class Console { 361 362 public enum typeof(type) TYPE = 3; 363 364 public enum string[] FIELDS = []; 365 366 public pure nothrow @safe ubyte[] encode(bool writeId=true)() { 367 type = 3; 368 _encode!writeId(); 369 return _buffer; 370 } 371 372 public pure nothrow @safe void decode() { 373 } 374 375 public override string toString() { 376 return "Add.Console()"; 377 } 378 379 } 380 381 } 382 383 /** 384 * Removes a player from the node. If the player is removed using Kick or Transfer 385 * this packet is not sent. 386 */ 387 class Remove : Buffer { 388 389 public enum ubyte ID = 18; 390 391 public enum bool CLIENTBOUND = true; 392 public enum bool SERVERBOUND = false; 393 394 // reason 395 public enum ubyte LEFT = 0; 396 public enum ubyte TIMED_OUT = 1; 397 public enum ubyte KICKED = 2; 398 public enum ubyte TRANSFERRED = 3; 399 400 public enum string[] FIELDS = ["hubId", "reason"]; 401 402 public uint hubId; 403 404 /** 405 * Reason of the disconnection. 406 */ 407 public ubyte reason; 408 409 public pure nothrow @safe @nogc this() {} 410 411 public pure nothrow @safe @nogc this(uint hubId, ubyte reason=ubyte.init) { 412 this.hubId = hubId; 413 this.reason = reason; 414 } 415 416 public pure nothrow @safe ubyte[] encode(bool writeId=true)() { 417 _buffer.length = 0; 418 static if(writeId){ writeBigEndianUbyte(ID); } 419 writeBytes(varuint.encode(hubId)); 420 writeBigEndianUbyte(reason); 421 return _buffer; 422 } 423 424 public pure nothrow @safe void decode(bool readId=true)() { 425 static if(readId){ ubyte _id; _id=readBigEndianUbyte(); } 426 hubId=varuint.decode(_buffer, &_index); 427 reason=readBigEndianUbyte(); 428 } 429 430 public static pure nothrow @safe Remove fromBuffer(bool readId=true)(ubyte[] buffer) { 431 Remove ret = new Remove(); 432 ret._buffer = buffer; 433 ret.decode!readId(); 434 return ret; 435 } 436 437 public override string toString() { 438 return "Remove(hubId: " ~ std.conv.to!string(this.hubId) ~ ", reason: " ~ std.conv.to!string(this.reason) ~ ")"; 439 } 440 441 } 442 443 /** 444 * Kicks a player from the node and the whole server. When a player is disconnected 445 * from the node using this packet the hub will not send the Remove packet. 446 */ 447 class Kick : Buffer { 448 449 public enum ubyte ID = 19; 450 451 public enum bool CLIENTBOUND = false; 452 public enum bool SERVERBOUND = true; 453 454 public enum string[] FIELDS = ["hubId", "reason", "translation", "parameters"]; 455 456 public uint hubId; 457 458 /** 459 * Reason of the disconnection that will be displayed in the client's disconnection 460 * screen. 461 */ 462 public string reason; 463 464 /** 465 * Whether the previous string should be translated client-side or not. 466 */ 467 public bool translation; 468 469 /** 470 * Optional parameters for the translation. 471 */ 472 public string[] parameters; 473 474 public pure nothrow @safe @nogc this() {} 475 476 public pure nothrow @safe @nogc this(uint hubId, string reason=string.init, bool translation=bool.init, string[] parameters=(string[]).init) { 477 this.hubId = hubId; 478 this.reason = reason; 479 this.translation = translation; 480 this.parameters = parameters; 481 } 482 483 public pure nothrow @safe ubyte[] encode(bool writeId=true)() { 484 _buffer.length = 0; 485 static if(writeId){ writeBigEndianUbyte(ID); } 486 writeBytes(varuint.encode(hubId)); 487 writeBytes(varuint.encode(cast(uint)reason.length)); writeString(reason); 488 writeBigEndianBool(translation); 489 if(translation==true){ writeBytes(varuint.encode(cast(uint)parameters.length)); foreach(cfy1dvc;parameters){ writeBytes(varuint.encode(cast(uint)cfy1dvc.length)); writeString(cfy1dvc); } } 490 return _buffer; 491 } 492 493 public pure nothrow @safe void decode(bool readId=true)() { 494 static if(readId){ ubyte _id; _id=readBigEndianUbyte(); } 495 hubId=varuint.decode(_buffer, &_index); 496 uint cvc9=varuint.decode(_buffer, &_index); reason=readString(cvc9); 497 translation=readBigEndianBool(); 498 if(translation==true){ parameters.length=varuint.decode(_buffer, &_index); foreach(ref cfy1dvc;parameters){ uint yzmry=varuint.decode(_buffer, &_index); cfy1dvc=readString(yzmry); } } 499 } 500 501 public static pure nothrow @safe Kick fromBuffer(bool readId=true)(ubyte[] buffer) { 502 Kick ret = new Kick(); 503 ret._buffer = buffer; 504 ret.decode!readId(); 505 return ret; 506 } 507 508 public override string toString() { 509 return "Kick(hubId: " ~ std.conv.to!string(this.hubId) ~ ", reason: " ~ std.conv.to!string(this.reason) ~ ", translation: " ~ std.conv.to!string(this.translation) ~ ", parameters: " ~ std.conv.to!string(this.parameters) ~ ")"; 510 } 511 512 } 513 514 /** 515 * Transfers a player to another node. When a player is transferred from the node the 516 * hub will not send the Remove packet and there's no way, for the node, to know whether 517 * the player was disconnected or successfully transferred, if not using messages through 518 * a user-defined protocol. 519 */ 520 class Transfer : Buffer { 521 522 public enum ubyte ID = 20; 523 524 public enum bool CLIENTBOUND = false; 525 public enum bool SERVERBOUND = true; 526 527 // on fail 528 public enum ubyte DISCONNECT = 0; 529 public enum ubyte AUTO = 1; 530 public enum ubyte RECONNECT = 2; 531 532 public enum string[] FIELDS = ["hubId", "node", "onFail"]; 533 534 public uint hubId; 535 536 /** 537 * Id of the node that player will be transferred to. It should be an id of a connected 538 * node (which can be calculated using AddNode and RemoveNode), otherwise the player 539 * will be disconnected or moved to another node (see the following field). 540 */ 541 public uint node; 542 543 /** 544 * Indicates the action to be taken when a transfer fails because the indicated node 545 * is not connected anymore or it cannot accept the given player's game type or protocol. 546 * If the indicated node is full the player will be simply disconnected with the `Server 547 * Full` message. 548 */ 549 public ubyte onFail; 550 551 public pure nothrow @safe @nogc this() {} 552 553 public pure nothrow @safe @nogc this(uint hubId, uint node=uint.init, ubyte onFail=ubyte.init) { 554 this.hubId = hubId; 555 this.node = node; 556 this.onFail = onFail; 557 } 558 559 public pure nothrow @safe ubyte[] encode(bool writeId=true)() { 560 _buffer.length = 0; 561 static if(writeId){ writeBigEndianUbyte(ID); } 562 writeBytes(varuint.encode(hubId)); 563 writeBytes(varuint.encode(node)); 564 writeBigEndianUbyte(onFail); 565 return _buffer; 566 } 567 568 public pure nothrow @safe void decode(bool readId=true)() { 569 static if(readId){ ubyte _id; _id=readBigEndianUbyte(); } 570 hubId=varuint.decode(_buffer, &_index); 571 node=varuint.decode(_buffer, &_index); 572 onFail=readBigEndianUbyte(); 573 } 574 575 public static pure nothrow @safe Transfer fromBuffer(bool readId=true)(ubyte[] buffer) { 576 Transfer ret = new Transfer(); 577 ret._buffer = buffer; 578 ret.decode!readId(); 579 return ret; 580 } 581 582 public override string toString() { 583 return "Transfer(hubId: " ~ std.conv.to!string(this.hubId) ~ ", node: " ~ std.conv.to!string(this.node) ~ ", onFail: " ~ std.conv.to!string(this.onFail) ~ ")"; 584 } 585 586 } 587 588 /** 589 * Updates the player's display name when it changes. 590 */ 591 class UpdateDisplayName : Buffer { 592 593 public enum ubyte ID = 21; 594 595 public enum bool CLIENTBOUND = false; 596 public enum bool SERVERBOUND = true; 597 598 public enum string[] FIELDS = ["hubId", "displayName"]; 599 600 public uint hubId; 601 602 /** 603 * Player's display name that can contain formatting codes. Prefixes and suffixes should 604 * be avoided. 605 */ 606 public string displayName; 607 608 public pure nothrow @safe @nogc this() {} 609 610 public pure nothrow @safe @nogc this(uint hubId, string displayName=string.init) { 611 this.hubId = hubId; 612 this.displayName = displayName; 613 } 614 615 public pure nothrow @safe ubyte[] encode(bool writeId=true)() { 616 _buffer.length = 0; 617 static if(writeId){ writeBigEndianUbyte(ID); } 618 writeBytes(varuint.encode(hubId)); 619 writeBytes(varuint.encode(cast(uint)displayName.length)); writeString(displayName); 620 return _buffer; 621 } 622 623 public pure nothrow @safe void decode(bool readId=true)() { 624 static if(readId){ ubyte _id; _id=readBigEndianUbyte(); } 625 hubId=varuint.decode(_buffer, &_index); 626 uint zlcxe5bu=varuint.decode(_buffer, &_index); displayName=readString(zlcxe5bu); 627 } 628 629 public static pure nothrow @safe UpdateDisplayName fromBuffer(bool readId=true)(ubyte[] buffer) { 630 UpdateDisplayName ret = new UpdateDisplayName(); 631 ret._buffer = buffer; 632 ret.decode!readId(); 633 return ret; 634 } 635 636 public override string toString() { 637 return "UpdateDisplayName(hubId: " ~ std.conv.to!string(this.hubId) ~ ", displayName: " ~ std.conv.to!string(this.displayName) ~ ")"; 638 } 639 640 } 641 642 /** 643 * Updates player's world and dimension. 644 */ 645 class UpdateWorld : Buffer { 646 647 public enum ubyte ID = 22; 648 649 public enum bool CLIENTBOUND = false; 650 public enum bool SERVERBOUND = true; 651 652 public enum string[] FIELDS = ["hubId", "world"]; 653 654 public uint hubId; 655 public uint world; 656 657 public pure nothrow @safe @nogc this() {} 658 659 public pure nothrow @safe @nogc this(uint hubId, uint world=uint.init) { 660 this.hubId = hubId; 661 this.world = world; 662 } 663 664 public pure nothrow @safe ubyte[] encode(bool writeId=true)() { 665 _buffer.length = 0; 666 static if(writeId){ writeBigEndianUbyte(ID); } 667 writeBytes(varuint.encode(hubId)); 668 writeBytes(varuint.encode(world)); 669 return _buffer; 670 } 671 672 public pure nothrow @safe void decode(bool readId=true)() { 673 static if(readId){ ubyte _id; _id=readBigEndianUbyte(); } 674 hubId=varuint.decode(_buffer, &_index); 675 world=varuint.decode(_buffer, &_index); 676 } 677 678 public static pure nothrow @safe UpdateWorld fromBuffer(bool readId=true)(ubyte[] buffer) { 679 UpdateWorld ret = new UpdateWorld(); 680 ret._buffer = buffer; 681 ret.decode!readId(); 682 return ret; 683 } 684 685 public override string toString() { 686 return "UpdateWorld(hubId: " ~ std.conv.to!string(this.hubId) ~ ", world: " ~ std.conv.to!string(this.world) ~ ")"; 687 } 688 689 } 690 691 /** 692 * Update's the player's view distance (or chunk radius). This packet is sent when 693 * the client updates its view distance and the server accepts it. 694 */ 695 class UpdateViewDistance : Buffer { 696 697 public enum ubyte ID = 23; 698 699 public enum bool CLIENTBOUND = false; 700 public enum bool SERVERBOUND = true; 701 702 public enum string[] FIELDS = ["hubId", "viewDistance"]; 703 704 public uint hubId; 705 public uint viewDistance; 706 707 public pure nothrow @safe @nogc this() {} 708 709 public pure nothrow @safe @nogc this(uint hubId, uint viewDistance=uint.init) { 710 this.hubId = hubId; 711 this.viewDistance = viewDistance; 712 } 713 714 public pure nothrow @safe ubyte[] encode(bool writeId=true)() { 715 _buffer.length = 0; 716 static if(writeId){ writeBigEndianUbyte(ID); } 717 writeBytes(varuint.encode(hubId)); 718 writeBytes(varuint.encode(viewDistance)); 719 return _buffer; 720 } 721 722 public pure nothrow @safe void decode(bool readId=true)() { 723 static if(readId){ ubyte _id; _id=readBigEndianUbyte(); } 724 hubId=varuint.decode(_buffer, &_index); 725 viewDistance=varuint.decode(_buffer, &_index); 726 } 727 728 public static pure nothrow @safe UpdateViewDistance fromBuffer(bool readId=true)(ubyte[] buffer) { 729 UpdateViewDistance ret = new UpdateViewDistance(); 730 ret._buffer = buffer; 731 ret.decode!readId(); 732 return ret; 733 } 734 735 public override string toString() { 736 return "UpdateViewDistance(hubId: " ~ std.conv.to!string(this.hubId) ~ ", viewDistance: " ~ std.conv.to!string(this.viewDistance) ~ ")"; 737 } 738 739 } 740 741 /** 742 * Updates the player's language when the client changes it. 743 */ 744 class UpdateLanguage : Buffer { 745 746 public enum ubyte ID = 24; 747 748 public enum bool CLIENTBOUND = false; 749 public enum bool SERVERBOUND = true; 750 751 public enum string[] FIELDS = ["hubId", "language"]; 752 753 public uint hubId; 754 755 /** 756 * Player's language in the same format as HubInfo.language. 757 */ 758 public string language; 759 760 public pure nothrow @safe @nogc this() {} 761 762 public pure nothrow @safe @nogc this(uint hubId, string language=string.init) { 763 this.hubId = hubId; 764 this.language = language; 765 } 766 767 public pure nothrow @safe ubyte[] encode(bool writeId=true)() { 768 _buffer.length = 0; 769 static if(writeId){ writeBigEndianUbyte(ID); } 770 writeBytes(varuint.encode(hubId)); 771 writeBytes(varuint.encode(cast(uint)language.length)); writeString(language); 772 return _buffer; 773 } 774 775 public pure nothrow @safe void decode(bool readId=true)() { 776 static if(readId){ ubyte _id; _id=readBigEndianUbyte(); } 777 hubId=varuint.decode(_buffer, &_index); 778 uint bfzvzu=varuint.decode(_buffer, &_index); language=readString(bfzvzu); 779 } 780 781 public static pure nothrow @safe UpdateLanguage fromBuffer(bool readId=true)(ubyte[] buffer) { 782 UpdateLanguage ret = new UpdateLanguage(); 783 ret._buffer = buffer; 784 ret.decode!readId(); 785 return ret; 786 } 787 788 public override string toString() { 789 return "UpdateLanguage(hubId: " ~ std.conv.to!string(this.hubId) ~ ", language: " ~ std.conv.to!string(this.language) ~ ")"; 790 } 791 792 } 793 794 /** 795 * The client (node) always send a confirmation to the hub when this packet is received. 796 */ 797 class UpdateGamemode : Buffer { 798 799 public enum ubyte ID = 25; 800 801 public enum bool CLIENTBOUND = true; 802 public enum bool SERVERBOUND = true; 803 804 public enum string[] FIELDS = ["hubId", "gamemode"]; 805 806 public uint hubId; 807 public ubyte gamemode; 808 809 public pure nothrow @safe @nogc this() {} 810 811 public pure nothrow @safe @nogc this(uint hubId, ubyte gamemode=ubyte.init) { 812 this.hubId = hubId; 813 this.gamemode = gamemode; 814 } 815 816 public pure nothrow @safe ubyte[] encode(bool writeId=true)() { 817 _buffer.length = 0; 818 static if(writeId){ writeBigEndianUbyte(ID); } 819 writeBytes(varuint.encode(hubId)); 820 writeBigEndianUbyte(gamemode); 821 return _buffer; 822 } 823 824 public pure nothrow @safe void decode(bool readId=true)() { 825 static if(readId){ ubyte _id; _id=readBigEndianUbyte(); } 826 hubId=varuint.decode(_buffer, &_index); 827 gamemode=readBigEndianUbyte(); 828 } 829 830 public static pure nothrow @safe UpdateGamemode fromBuffer(bool readId=true)(ubyte[] buffer) { 831 UpdateGamemode ret = new UpdateGamemode(); 832 ret._buffer = buffer; 833 ret.decode!readId(); 834 return ret; 835 } 836 837 public override string toString() { 838 return "UpdateGamemode(hubId: " ~ std.conv.to!string(this.hubId) ~ ", gamemode: " ~ std.conv.to!string(this.gamemode) ~ ")"; 839 } 840 841 } 842 843 /** 844 * Update the player's current input mode. 845 */ 846 class UpdateInputMode : Buffer { 847 848 public enum ubyte ID = 26; 849 850 public enum bool CLIENTBOUND = true; 851 public enum bool SERVERBOUND = false; 852 853 // input mode 854 public enum ubyte KEYBOARD = 0; 855 public enum ubyte TOUCH = 1; 856 public enum ubyte CONTROLLER = 2; 857 858 public enum string[] FIELDS = ["hubId", "inputMode"]; 859 860 public uint hubId; 861 862 /** 863 * Player's input mode. 864 */ 865 public ubyte inputMode; 866 867 public pure nothrow @safe @nogc this() {} 868 869 public pure nothrow @safe @nogc this(uint hubId, ubyte inputMode=ubyte.init) { 870 this.hubId = hubId; 871 this.inputMode = inputMode; 872 } 873 874 public pure nothrow @safe ubyte[] encode(bool writeId=true)() { 875 _buffer.length = 0; 876 static if(writeId){ writeBigEndianUbyte(ID); } 877 writeBytes(varuint.encode(hubId)); 878 writeBigEndianUbyte(inputMode); 879 return _buffer; 880 } 881 882 public pure nothrow @safe void decode(bool readId=true)() { 883 static if(readId){ ubyte _id; _id=readBigEndianUbyte(); } 884 hubId=varuint.decode(_buffer, &_index); 885 inputMode=readBigEndianUbyte(); 886 } 887 888 public static pure nothrow @safe UpdateInputMode fromBuffer(bool readId=true)(ubyte[] buffer) { 889 UpdateInputMode ret = new UpdateInputMode(); 890 ret._buffer = buffer; 891 ret.decode!readId(); 892 return ret; 893 } 894 895 public override string toString() { 896 return "UpdateInputMode(hubId: " ~ std.conv.to!string(this.hubId) ~ ", inputMode: " ~ std.conv.to!string(this.inputMode) ~ ")"; 897 } 898 899 } 900 901 /** 902 * Updates the latency between the player and the hub. 903 */ 904 class UpdateLatency : Buffer { 905 906 public enum ubyte ID = 27; 907 908 public enum bool CLIENTBOUND = true; 909 public enum bool SERVERBOUND = false; 910 911 public enum string[] FIELDS = ["hubId", "latency"]; 912 913 public uint hubId; 914 915 /** 916 * Player's latency in milliseconds. The latency between the client and the node is 917 * then calculated adding the latency between the node and the hub (calculated using 918 * HubInfo.time) to this field's value. 919 */ 920 public uint latency; 921 922 public pure nothrow @safe @nogc this() {} 923 924 public pure nothrow @safe @nogc this(uint hubId, uint latency=uint.init) { 925 this.hubId = hubId; 926 this.latency = latency; 927 } 928 929 public pure nothrow @safe ubyte[] encode(bool writeId=true)() { 930 _buffer.length = 0; 931 static if(writeId){ writeBigEndianUbyte(ID); } 932 writeBytes(varuint.encode(hubId)); 933 writeBytes(varuint.encode(latency)); 934 return _buffer; 935 } 936 937 public pure nothrow @safe void decode(bool readId=true)() { 938 static if(readId){ ubyte _id; _id=readBigEndianUbyte(); } 939 hubId=varuint.decode(_buffer, &_index); 940 latency=varuint.decode(_buffer, &_index); 941 } 942 943 public static pure nothrow @safe UpdateLatency fromBuffer(bool readId=true)(ubyte[] buffer) { 944 UpdateLatency ret = new UpdateLatency(); 945 ret._buffer = buffer; 946 ret.decode!readId(); 947 return ret; 948 } 949 950 public override string toString() { 951 return "UpdateLatency(hubId: " ~ std.conv.to!string(this.hubId) ~ ", latency: " ~ std.conv.to!string(this.latency) ~ ")"; 952 } 953 954 } 955 956 /** 957 * Updates the player's packet loss if it uses a connectionless protocol like UDP. 958 */ 959 class UpdatePacketLoss : Buffer { 960 961 public enum ubyte ID = 28; 962 963 public enum bool CLIENTBOUND = true; 964 public enum bool SERVERBOUND = false; 965 966 public enum string[] FIELDS = ["hubId", "packetLoss"]; 967 968 public uint hubId; 969 970 /** 971 * Percentage of lost packets in range 0 (no packet lost) to 100 (every packet lost). 972 */ 973 public float packetLoss; 974 975 public pure nothrow @safe @nogc this() {} 976 977 public pure nothrow @safe @nogc this(uint hubId, float packetLoss=float.init) { 978 this.hubId = hubId; 979 this.packetLoss = packetLoss; 980 } 981 982 public pure nothrow @safe ubyte[] encode(bool writeId=true)() { 983 _buffer.length = 0; 984 static if(writeId){ writeBigEndianUbyte(ID); } 985 writeBytes(varuint.encode(hubId)); 986 writeBigEndianFloat(packetLoss); 987 return _buffer; 988 } 989 990 public pure nothrow @safe void decode(bool readId=true)() { 991 static if(readId){ ubyte _id; _id=readBigEndianUbyte(); } 992 hubId=varuint.decode(_buffer, &_index); 993 packetLoss=readBigEndianFloat(); 994 } 995 996 public static pure nothrow @safe UpdatePacketLoss fromBuffer(bool readId=true)(ubyte[] buffer) { 997 UpdatePacketLoss ret = new UpdatePacketLoss(); 998 ret._buffer = buffer; 999 ret.decode!readId(); 1000 return ret; 1001 } 1002 1003 public override string toString() { 1004 return "UpdatePacketLoss(hubId: " ~ std.conv.to!string(this.hubId) ~ ", packetLoss: " ~ std.conv.to!string(this.packetLoss) ~ ")"; 1005 } 1006 1007 } 1008 1009 /** 1010 * Sends data to client or handles data received from the client. 1011 */ 1012 class GamePacket : Buffer { 1013 1014 public enum ubyte ID = 29; 1015 1016 public enum bool CLIENTBOUND = true; 1017 public enum bool SERVERBOUND = true; 1018 1019 public enum string[] FIELDS = ["hubId", "packet"]; 1020 1021 public uint hubId; 1022 1023 /** 1024 * Serialised packet ready to be encrypted or encapsulated and sent to the client when 1025 * this packet is serverbound or packet already unencrypted and uncompressed ready 1026 * to be handled by the node otherwise. 1027 * 1028 * <h4>Format</h4> 1029 * 1030 * <h5>Minecraft (serverbound)</h5> 1031 * The packet is prefixed with a varuint-encoded 0 if the packet is not compressed 1032 * or with the uncompressed packet's length encoded as a varuint if the packet is compressed. 1033 * 1034 * <h5>Minecraft (clientbound)</h5> 1035 * The packet is already unencrypted and uncompressed and ready to be handled as a 1036 * serverbound packet. 1037 * 1038 * <h5>Minecraft: Pocket Edition (serverbound)</h5> 1039 * The packet is simply encoded (may be compressed in a Batch packet) and ready to 1040 * be encapsulated using RakNet. 1041 * 1042 * <h5>Minecraft: Pocket Edition (clientbound)</h5> 1043 * The packet is already unencrypted and uncompressed if it was a Batch packet and 1044 * ready to be handled as a serverbound packet. 1045 */ 1046 public ubyte[] packet; 1047 1048 public pure nothrow @safe @nogc this() {} 1049 1050 public pure nothrow @safe @nogc this(uint hubId, ubyte[] packet=(ubyte[]).init) { 1051 this.hubId = hubId; 1052 this.packet = packet; 1053 } 1054 1055 public pure nothrow @safe ubyte[] encode(bool writeId=true)() { 1056 _buffer.length = 0; 1057 static if(writeId){ writeBigEndianUbyte(ID); } 1058 writeBytes(varuint.encode(hubId)); 1059 writeBytes(packet); 1060 return _buffer; 1061 } 1062 1063 public pure nothrow @safe void decode(bool readId=true)() { 1064 static if(readId){ ubyte _id; _id=readBigEndianUbyte(); } 1065 hubId=varuint.decode(_buffer, &_index); 1066 packet=_buffer[_index..$].dup; _index=_buffer.length; 1067 } 1068 1069 public static pure nothrow @safe GamePacket fromBuffer(bool readId=true)(ubyte[] buffer) { 1070 GamePacket ret = new GamePacket(); 1071 ret._buffer = buffer; 1072 ret.decode!readId(); 1073 return ret; 1074 } 1075 1076 public override string toString() { 1077 return "GamePacket(hubId: " ~ std.conv.to!string(this.hubId) ~ ", packet: " ~ std.conv.to!string(this.packet) ~ ")"; 1078 } 1079 1080 } 1081 1082 /** 1083 * Sends data to the client but order it because it could be sent by the node unordered, 1084 * due to compressed packet sent delayed. 1085 */ 1086 class OrderedGamePacket : Buffer { 1087 1088 public enum ubyte ID = 30; 1089 1090 public enum bool CLIENTBOUND = false; 1091 public enum bool SERVERBOUND = true; 1092 1093 public enum string[] FIELDS = ["hubId", "order", "packet"]; 1094 1095 public uint hubId; 1096 1097 /** 1098 * Order of the packet. If the hub receives a packet with an id different from 0 or 1099 * the latest ordered packet's order + 1 it should wait for the packets with the missing 1100 * order(s) before sending. 1101 */ 1102 public uint order; 1103 1104 /** 1105 * Serialised packet (see GamePacket.packet). 1106 */ 1107 public ubyte[] packet; 1108 1109 public pure nothrow @safe @nogc this() {} 1110 1111 public pure nothrow @safe @nogc this(uint hubId, uint order=uint.init, ubyte[] packet=(ubyte[]).init) { 1112 this.hubId = hubId; 1113 this.order = order; 1114 this.packet = packet; 1115 } 1116 1117 public pure nothrow @safe ubyte[] encode(bool writeId=true)() { 1118 _buffer.length = 0; 1119 static if(writeId){ writeBigEndianUbyte(ID); } 1120 writeBytes(varuint.encode(hubId)); 1121 writeBytes(varuint.encode(order)); 1122 writeBytes(packet); 1123 return _buffer; 1124 } 1125 1126 public pure nothrow @safe void decode(bool readId=true)() { 1127 static if(readId){ ubyte _id; _id=readBigEndianUbyte(); } 1128 hubId=varuint.decode(_buffer, &_index); 1129 order=varuint.decode(_buffer, &_index); 1130 packet=_buffer[_index..$].dup; _index=_buffer.length; 1131 } 1132 1133 public static pure nothrow @safe OrderedGamePacket fromBuffer(bool readId=true)(ubyte[] buffer) { 1134 OrderedGamePacket ret = new OrderedGamePacket(); 1135 ret._buffer = buffer; 1136 ret.decode!readId(); 1137 return ret; 1138 } 1139 1140 public override string toString() { 1141 return "OrderedGamePacket(hubId: " ~ std.conv.to!string(this.hubId) ~ ", order: " ~ std.conv.to!string(this.order) ~ ", packet: " ~ std.conv.to!string(this.packet) ~ ")"; 1142 } 1143 1144 } 1145