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