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