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