summaryrefslogtreecommitdiffstats
path: root/src/ClientHandle.h
blob: 24031119d3cfc1d79cc913a19e8bc29bd413d6c4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431

// cClientHandle.h

// Interfaces to the cClientHandle class representing a client connected to this server. The client need not be a player yet





#pragma once
#ifndef CCLIENTHANDLE_H_INCLUDED
#define CCLIENTHANDLE_H_INCLUDED

#include "Defines.h"
#include "Vector3.h"
#include "OSSupport/SocketThreads.h"
#include "ChunkDef.h"
#include "ByteBuffer.h"
#include "Scoreboard.h"
#include "Map.h"
#include "Enchantments.h"
#include "UI/SlotArea.h"
#include "json/json.h"





class cChunkDataSerializer;
class cInventory;
class cMonster;
class cPawn;
class cExpOrb;
class cPainting;
class cPickup;
class cPlayer;
class cProtocol;
class cWindow;
class cFallingBlock;
class cItemHandler;
class cWorld;
class cCompositeChat;
class cStatManager;





class cClientHandle :  // tolua_export
	public cSocketThreads::cCallback
{  // tolua_export
public:
	
#if defined(ANDROID_NDK)
	static const int DEFAULT_VIEW_DISTANCE = 4;  // The default ViewDistance (used when no value is set in Settings.ini)
#else
	static const int DEFAULT_VIEW_DISTANCE = 10;
#endif
	static const int MAX_VIEW_DISTANCE = 32;
	static const int MIN_VIEW_DISTANCE = 1;
	
	cClientHandle(const cSocket * a_Socket, int a_ViewDistance);
	virtual ~cClientHandle();

	const AString & GetIPString(void) const { return m_IPString; }
	
	cPlayer * GetPlayer(void) { return m_Player; }  // tolua_export

	/** Returns the player's UUID, as used by the protocol, in the short form (no dashes) */
	const AString & GetUUID(void) const { return m_UUID; }  // tolua_export
	
	void SetUUID(const AString & a_UUID) { m_UUID = a_UUID; }

	const Json::Value & GetProperties(void) const { return m_Properties; }
	
	/** Generates an UUID based on the username stored for this client, and stores it in the m_UUID member.
	This is used for the offline (non-auth) mode, when there's no UUID source.
	Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same.
	Internally calls the GenerateOfflineUUID static function. */
	void GenerateOfflineUUID(void);
	
	/** Generates an UUID based on the player name provided.
	This is used for the offline (non-auth) mode, when there's no UUID source.
	Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same.
	Returns a 32-char UUID (no dashes). */
	static AString GenerateOfflineUUID(const AString & a_Username);  // tolua_export
	
	/** Returns true if the UUID is generated by online auth, false if it is an offline-generated UUID.
	We use Version-3 UUIDs for offline UUIDs, online UUIDs are Version-4, thus we can tell them apart.
	Accepts both 32-char and 36-char UUIDs (with and without dashes).
	If the string given is not a valid UUID, returns false. */
	static bool IsUUIDOnline(const AString & a_UUID);  // tolua_export
	
	/** Formats the type of message with the proper color and prefix for sending to the client. **/
	static AString FormatMessageType(bool ShouldAppendChatPrefixes, eMessageType a_ChatPrefix, const AString & a_AdditionalData);
	
	static AString FormatChatPrefix(bool ShouldAppendChatPrefixes, AString a_ChatPrefixS, AString m_Color1, AString m_Color2);

	void Kick(const AString & a_Reason);  // tolua_export

	/** Authenticates the specified user, called by cAuthenticator */
	void Authenticate(const AString & a_Name, const AString & a_UUID, const Json::Value & a_Properties);

	void StreamChunks(void);
	
	// Removes the client from all chunks. Used when switching worlds or destroying the player
	void RemoveFromAllChunks(void);
	
	inline bool IsLoggedIn(void) const { return (m_State >= csAuthenticating); }

	/** Called while the client is being ticked from the world via its cPlayer object */
	void Tick(float a_Dt);
	
	/** Called while the client is being ticked from the cServer object */
	void ServerTick(float a_Dt);

	void Destroy(void);
	
	bool IsPlaying   (void) const { return (m_State == csPlaying); }
	bool IsDestroyed (void) const { return (m_State == csDestroyed); }
	bool IsDestroying(void) const { return (m_State == csDestroying); }

	// The following functions send the various packets:
	// (Please keep these alpha-sorted)
	void SendAttachEntity        (const cEntity & a_Entity, const cEntity * a_Vehicle);
	void SendBlockAction         (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType);
	void SendBlockBreakAnim      (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage);
	void SendBlockChange         (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);  // tolua_export
	void SendBlockChanges        (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes);
	void SendChat                (const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData = "");
	void SendChat                (const cCompositeChat & a_Message);
	void SendChunkData           (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer);
	void SendCollectEntity       (const cEntity & a_Entity, const cPlayer & a_Player);
	void SendDestroyEntity       (const cEntity & a_Entity);
	void SendDisconnect          (const AString & a_Reason);
	void SendEditSign            (int a_BlockX, int a_BlockY, int a_BlockZ);
	void SendEntityEffect        (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration);
	void SendEntityEquipment     (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item);
	void SendEntityHeadLook      (const cEntity & a_Entity);
	void SendEntityLook          (const cEntity & a_Entity);
	void SendEntityMetadata      (const cEntity & a_Entity);
	void SendEntityProperties    (const cEntity & a_Entity);
	void SendEntityRelMove       (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ);
	void SendEntityRelMoveLook   (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ);
	void SendEntityStatus        (const cEntity & a_Entity, char a_Status);
	void SendEntityVelocity      (const cEntity & a_Entity);
	void SendExplosion           (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion);
	void SendGameMode            (eGameMode a_GameMode);
	void SendHealth              (void);
	void SendInventorySlot       (char a_WindowID, short a_SlotNum, const cItem & a_Item);
	void SendMapColumn           (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length);
	void SendMapDecorators       (int a_ID, const cMapDecoratorList & a_Decorators);
	void SendMapInfo             (int a_ID, unsigned int a_Scale);
	void SendPaintingSpawn       (const cPainting & a_Painting);
	void SendPickupSpawn         (const cPickup & a_Pickup);
	void SendEntityAnimation     (const cEntity & a_Entity, char a_Animation);  // tolua_export
	void SendParticleEffect      (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount);
	void SendPlayerAbilities     (void);
	void SendPlayerListItem      (const cPlayer & a_Player, bool a_IsOnline);
	void SendPlayerMaxSpeed      (void);  ///< Informs the client of the maximum player speed (1.6.1+)
	void SendPlayerMoveLook      (void);
	void SendPlayerPosition      (void);
	void SendPlayerSpawn         (const cPlayer & a_Player);
	void SendPluginMessage       (const AString & a_Channel, const AString & a_Message);  // Exported in ManualBindings.cpp
	void SendRemoveEntityEffect  (const cEntity & a_Entity, int a_EffectID);
	void SendRespawn             (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks = false);
	void SendExperience          (void);
	void SendExperienceOrb       (const cExpOrb & a_ExpOrb);
	void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode);
	void SendScoreUpdate         (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode);
	void SendDisplayObjective    (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display);
	void SendSoundEffect         (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch);  // tolua_export
	void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data);
	void SendSpawnFallingBlock   (const cFallingBlock & a_FallingBlock);
	void SendSpawnMob            (const cMonster & a_Mob);
	void SendSpawnObject         (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch);
	void SendSpawnVehicle        (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType = 0);
	void SendStatistics          (const cStatManager & a_Manager);
	void SendTabCompletionResults(const AStringVector & a_Results);
	void SendTeleportEntity      (const cEntity & a_Entity);
	void SendThunderbolt         (int a_BlockX, int a_BlockY, int a_BlockZ);
	void SendTimeUpdate          (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle);  // tolua_export
	void SendUnloadChunk         (int a_ChunkX, int a_ChunkZ);
	void SendUpdateBlockEntity   (cBlockEntity & a_BlockEntity);
	void SendUpdateSign          (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4);
	void SendUseBed              (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ);
	void SendWeather             (eWeather a_Weather);
	void SendWholeInventory      (const cWindow & a_Window);
	void SendWindowClose         (const cWindow & a_Window);
	void SendWindowOpen          (const cWindow & a_Window);
	void SendWindowProperty      (const cWindow & a_Window, int a_Property, int a_Value);

	// tolua_begin
	const AString & GetUsername(void) const;
	void SetUsername( const AString & a_Username);
	
	inline short GetPing(void) const { return m_Ping; }
	
	void SetViewDistance(int a_ViewDistance);
	int  GetViewDistance(void) const { return m_ViewDistance; }
	
	void SetLocale(AString & a_Locale) { m_Locale = a_Locale; }
	AString GetLocale(void) const { return m_Locale; }

	int GetUniqueID(void) const { return m_UniqueID; }
	
	bool HasPluginChannel(const AString & a_PluginChannel);
	
	// tolua_end
	
	/** Returns true if the client wants the chunk specified to be sent (in m_ChunksToSend) */
	bool WantsSendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
	
	/** Adds the chunk specified to the list of chunks wanted for sending (m_ChunksToSend) */
	void AddWantedChunk(int a_ChunkX, int a_ChunkZ);
	
	// Calls that cProtocol descendants use to report state:
	void PacketBufferFull(void);
	void PacketUnknown(UInt32 a_PacketType);
	void PacketError(unsigned char a_PacketType);

	// Calls that cProtocol descendants use for handling packets:
	void HandleAnimation        (char a_Animation);
	void HandleChat             (const AString & a_Message);
	void HandleCreativeInventory(short a_SlotNum, const cItem & a_HeldItem);
	void HandleDisconnect       (const AString & a_Reason);
	void HandleEntityCrouch     (int a_EntityID, bool a_IsCrouching);
	void HandleEntityLeaveBed   (int a_EntityID);
	void HandleEntitySprinting  (int a_EntityID, bool a_IsSprinting);
	
	/** Called when the protocol handshake has been received (for protocol versions that support it;
	otherwise the first instant when a username is received).
	Returns true if the player is to be let in, false if they were disconnected
	*/
	bool HandleHandshake        (const AString & a_Username);
	
	void HandleKeepAlive        (int a_KeepAliveID);
	void HandleLeftClick        (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, char a_Status);
	void HandlePing             (void);
	void HandlePlayerAbilities  (bool a_CanFly, bool a_IsFlying, float FlyingSpeed, float WalkingSpeed);
	void HandlePlayerLook       (float a_Rotation, float a_Pitch, bool a_IsOnGround);
	void HandlePlayerMoveLook   (double a_PosX, double a_PosY, double a_PosZ, double a_Stance, float a_Rotation, float a_Pitch, bool a_IsOnGround);  // While m_bPositionConfirmed (normal gameplay)
	void HandlePlayerPos        (double a_PosX, double a_PosY, double a_PosZ, double a_Stance, bool a_IsOnGround);
	void HandlePluginMessage    (const AString & a_Channel, const AString & a_Message);
	void HandleRespawn          (void);
	void HandleRightClick       (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, const cItem & a_HeldItem);
	void HandleSlotSelected     (short a_SlotNum);
	void HandleSteerVehicle     (float Forward, float Sideways);
	void HandleTabCompletion    (const AString & a_Text);
	void HandleUpdateSign       (
		int a_BlockX, int a_BlockY, int a_BlockZ,
		const AString & a_Line1, const AString & a_Line2,
		const AString & a_Line3, const AString & a_Line4
	);
	void HandleUnmount          (void);
	void HandleUseEntity        (int a_TargetEntityID, bool a_IsLeftClick);
	void HandleWindowClick      (char a_WindowID, short a_SlotNum, eClickAction a_ClickAction, const cItem & a_HeldItem);
	void HandleWindowClose      (char a_WindowID);

	/** Called when the protocol has finished logging the user in.
	Return true to allow the user in; false to kick them.
	*/
	bool HandleLogin(int a_ProtocolVersion, const AString & a_Username);
	
	void SendData(const char * a_Data, size_t a_Size);
	
	/** Called when the player moves into a different world.
	Sends an UnloadChunk packet for each loaded chunk and resets the streamed chunks. */
	void RemoveFromWorld(void);
	
	/** Called when the player will enchant a Item */
	void HandleEnchantItem(Byte & a_WindowID, Byte & a_Enchantment);
	
private:

	/** The type used for storing the names of registered plugin channels. */
	typedef std::set<AString> cChannels;

	/** Number of chunks the player can see in each direction */
	int m_ViewDistance;
	
	/** Server generates this many chunks AHEAD of player sight. */
	static const int GENERATEDISTANCE = 2;
	
	AString m_IPString;

	AString m_Username;
	AString m_Password;
	Json::Value m_Properties;

	cCriticalSection m_CSChunkLists;
	cChunkCoordsList m_LoadedChunks;  // Chunks that the player belongs to
	cChunkCoordsList m_ChunksToSend;  // Chunks that need to be sent to the player (queued because they weren't generated yet or there's not enough time to send them)

	cProtocol * m_Protocol;
	
	cCriticalSection m_CSIncomingData;
	AString          m_IncomingData;
	
	cCriticalSection m_CSOutgoingData;
	cByteBuffer      m_OutgoingData;
	AString          m_OutgoingDataOverflow;  ///< For data that didn't fit into the m_OutgoingData ringbuffer temporarily

	Vector3d m_ConfirmPosition;

	cPlayer * m_Player;
	
	bool m_HasSentDC;  ///< True if a D/C packet has been sent in either direction
	
	// Chunk position when the last StreamChunks() was called; used to avoid re-streaming while in the same chunk
	int m_LastStreamedChunkX;
	int m_LastStreamedChunkZ;

	/** Seconds since the last packet data was received (updated in Tick(), reset in DataReceived()) */
	float m_TimeSinceLastPacket;
	
	short m_Ping;
	int   m_PingID;
	long long m_PingStartTime;
	long long m_LastPingTime;
	static const unsigned short PING_TIME_MS = 1000;  // Vanilla sends 1 per 20 ticks (1 second or every 1000 ms)
	
	// Values required for block dig animation
	int m_BlockDigAnimStage;  // Current stage of the animation; -1 if not digging
	int m_BlockDigAnimSpeed;  // Current speed of the animation (units ???)
	int m_BlockDigAnimX;
	int m_BlockDigAnimY;
	int m_BlockDigAnimZ;

	// To avoid dig/aim bug in the client, store the last position given in a DIG_START packet and compare to that when processing the DIG_FINISH packet:
	bool m_HasStartedDigging;
	int m_LastDigBlockX;
	int m_LastDigBlockY;
	int m_LastDigBlockZ;

	enum eState
	{
		csConnected,         ///< The client has just connected, waiting for their handshake / login
		csAuthenticating,    ///< The client has logged in, waiting for external authentication
		csAuthenticated,     ///< The client has been authenticated, will start streaming chunks in the next tick
		csDownloadingWorld,  ///< The client is waiting for chunks, we're waiting for the loader to provide and send them
		csConfirmingPos,     ///< The client has been sent the position packet, waiting for them to repeat the position back
		csPlaying,           ///< Normal gameplay
		csDestroying,        ///< The client is being destroyed, don't queue any more packets / don't add to chunks
		csDestroyed,         ///< The client has been destroyed, the destructor is to be called from the owner thread
		
		// TODO: Add Kicking here as well
	} ;
	
	eState m_State;
	
	/** m_State needs to be locked in the Destroy() function so that the destruction code doesn't run twice on two different threads */
	cCriticalSection m_CSDestroyingState;

	/** If set to true during csDownloadingWorld, the tick thread calls CheckIfWorldDownloaded() */
	bool m_ShouldCheckDownloaded;

	/** Number of explosions sent this tick */
	int m_NumExplosionsThisTick;

	/** Number of place or break interactions this tick */
	int m_NumBlockChangeInteractionsThisTick;
	
	static int s_ClientCount;
	
	/** ID used for identification during authenticating. Assigned sequentially for each new instance. */
	int m_UniqueID;
	
	/** Contains the UUID used by Mojang to identify the player's account. Short UUID stored here (without dashes) */
	AString m_UUID;
	
	/** Set to true when the chunk where the player is is sent to the client. Used for spawning the player */
	bool m_HasSentPlayerChunk;

	/** Client Settings */
	AString m_Locale;
	
	/** The plugin channels that the client has registered. */
	cChannels m_PluginChannels;


	/** Handles the block placing packet when it is a real block placement (not block-using, item-using or eating) */
	void HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, cItemHandler & a_ItemHandler);

	/** Returns true if the rate block interactions is within a reasonable limit (bot protection) */
	bool CheckBlockInteractionsRate(void);
	
	/** Adds a single chunk to be streamed to the client; used by StreamChunks() */
	void StreamChunk(int a_ChunkX, int a_ChunkZ);
	
	/** Handles the DIG_STARTED dig packet: */
	void HandleBlockDigStarted (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_OldBlock, NIBBLETYPE a_OldMeta);
	
	/** Handles the DIG_FINISHED dig packet: */
	void HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_OldBlock, NIBBLETYPE a_OldMeta);

	/** The clients will receive a finished dig animation */
	void FinishDigAnimation();

	/** Converts the protocol-formatted channel list (NUL-separated) into a proper string vector. */
	AStringVector BreakApartPluginChannels(const AString & a_PluginChannels);
	
	/** Adds all of the channels to the list of current plugin channels. Handles duplicates gracefully. */
	void RegisterPluginChannels(const AStringVector & a_ChannelList);
	
	/** Removes all of the channels from the list of current plugin channels. Ignores channels that are not found. */
	void UnregisterPluginChannels(const AStringVector & a_ChannelList);

	/** Handles the "MC|Beacon" plugin message */
	void HandleBeaconSelection(const char * a_Data, size_t a_Length);

	/** Handles the "MC|AdvCdm" plugin message */
	void HandleCommandBlockMessage(const char * a_Data, size_t a_Length);

	/** Handles the "MC|ItemName" plugin message */
	void HandleAnvilItemName(const char * a_Data, size_t a_Length);
	
	// cSocketThreads::cCallback overrides:
	virtual bool DataReceived   (const char * a_Data, size_t a_Size) override;  // Data is received from the client
	virtual void GetOutgoingData(AString & a_Data) override;  // Data can be sent to client
	virtual void SocketClosed   (void) override;  // The socket has been closed for any reason
};  // tolua_export




#endif  // CCLIENTHANDLE_H_INCLUDED