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