From 27e77a28fa434805905dc49f49800f8987d0957d Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 20 Feb 2014 23:24:39 +0100 Subject: cClientHandle manages the client-registered plugin channels. Fixes #706. --- src/ClientHandle.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++++++------ src/ClientHandle.h | 72 +++++++++++++++++++++++++++---------------- 2 files changed, 123 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 84286fc41..3711262b6 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -542,19 +542,23 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString & a_Message) { - if (a_Channel == "MC|AdvCdm") // Command block, set text, Client -> Server + if (a_Channel == "MC|AdvCdm") { - const char* Data = a_Message.c_str(); - HandleCommandBlockMessage(Data, a_Message.size()); - return; + // Command block, set text, Client -> Server + HandleCommandBlockMessage(a_Message.c_str(), a_Message.size()); } - else if (a_Channel == "MC|Brand") // Client <-> Server branding exchange + else if (a_Channel == "MC|Brand") { - // We are custom, - // We are awesome, - // We are MCServer. + // Client <-> Server branding exchange SendPluginMessage("MC|Brand", "MCServer"); - return; + } + else if (a_Channel == "REGISTER") + { + RegisterPluginChannels(BreakApartPluginChannels(a_Message)); + } + else if (a_Channel == "UNREGISTER") + { + UnregisterPluginChannels(BreakApartPluginChannels(a_Message)); } cPluginManager::Get()->CallHookPluginMessage(*this, a_Channel, a_Message); @@ -564,7 +568,61 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString -void cClientHandle::HandleCommandBlockMessage(const char* a_Data, unsigned int a_Length) +AStringVector cClientHandle::BreakApartPluginChannels(const AString & a_PluginChannels) +{ + // Break the string on each NUL character. + // Note that StringSplit() doesn't work on this because NUL is a special char - string terminator + size_t len = a_PluginChannels.size(); + size_t first = 0; + AStringVector res; + for (size_t i = 0; i < len; i++) + { + if (a_PluginChannels[i] != 0) + { + continue; + } + if (i > first) + { + res.push_back(a_PluginChannels.substr(first, i - first)); + } + first = i + 1; + } // for i - a_PluginChannels[] + if (first < len) + { + res.push_back(a_PluginChannels.substr(first, len - first)); + } + return res; +} + + + + + +void cClientHandle::RegisterPluginChannels(const AStringVector & a_ChannelList) +{ + for (AStringVector::const_iterator itr = a_ChannelList.begin(), end = a_ChannelList.end(); itr != end; ++itr) + { + m_PluginChannels.insert(*itr); + } // for itr - a_ChannelList[] +} + + + + + +void cClientHandle::UnregisterPluginChannels(const AStringVector & a_ChannelList) +{ + for (AStringVector::const_iterator itr = a_ChannelList.begin(), end = a_ChannelList.end(); itr != end; ++itr) + { + m_PluginChannels.erase(*itr); + } // for itr - a_ChannelList[] +} + + + + + +void cClientHandle::HandleCommandBlockMessage(const char * a_Data, unsigned int a_Length) { if (a_Length < 14) { @@ -2463,6 +2521,15 @@ void cClientHandle::SetViewDistance(int a_ViewDistance) +bool cClientHandle::HasPluginChannel(const AString & a_PluginChannel) +{ + return (m_PluginChannels.find(a_PluginChannel) != m_PluginChannels.end()); +} + + + + + bool cClientHandle::WantsSendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { if (m_State >= csDestroying) diff --git a/src/ClientHandle.h b/src/ClientHandle.h index aefca7233..e0447d3f7 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -72,10 +72,10 @@ public: inline bool IsLoggedIn(void) const { return (m_State >= csAuthenticating); } - /// Called while the client is being ticked from the world via its cPlayer object + /** 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 + /** Called while the client is being ticked from the cServer object */ void ServerTick(float a_Dt); void Destroy(void); @@ -150,23 +150,28 @@ public: void SendWindowOpen (const cWindow & a_Window); void SendWindowProperty (const cWindow & a_Window, int a_Property, int a_Value); - const AString & GetUsername(void) const; // tolua_export - void SetUsername( const AString & a_Username ); // tolua_export + // tolua_begin + const AString & GetUsername(void) const; + void SetUsername( const AString & a_Username ); - inline short GetPing(void) const { return m_Ping; } // tolua_export + inline short GetPing(void) const { return m_Ping; } - void SetViewDistance(int a_ViewDistance); // tolua_export - int GetViewDistance(void) const { return m_ViewDistance; } // tolua_export + void SetViewDistance(int a_ViewDistance); + int GetViewDistance(void) const { return m_ViewDistance; } - void SetLocale(AString & a_Locale) { m_Locale = a_Locale; } // tolua_export - AString GetLocale(void) const { return m_Locale; } // tolua_export + void SetLocale(AString & a_Locale) { m_Locale = a_Locale; } + AString GetLocale(void) const { return m_Locale; } - int GetUniqueID() const { return m_UniqueID; } // tolua_export + int GetUniqueID(void) const { return m_UniqueID; } - /// Returns true if the client wants the chunk specified to be sent (in m_ChunksToSend) + 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) + /** 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: @@ -217,14 +222,17 @@ public: void SendData(const char * a_Data, int a_Size); - /// Called when the player moves into a different world; queues sreaming the new chunks + /** Called when the player moves into a different world; queues sreaming the new chunks */ void MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket); - /// Handles the block placing packet when it is a real block placement (not block-using, item-using or eating) + /** 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); private: + /** The type used for storing the names of registered plugin channels. */ + typedef std::set cChannels; + int m_ViewDistance; // Number of chunks the player can see in each direction; 4 is the minimum ( http://wiki.vg/Protocol_FAQ#.E2.80.A6all_connecting_clients_spasm_and_jerk_uncontrollably.21 ) static const int GENERATEDISTANCE = 2; // Server generates this many chunks AHEAD of player sight. 2 is the minimum, since foliage is generated 1 step behind chunk terrain generation @@ -257,7 +265,7 @@ private: int m_LastStreamedChunkX; int m_LastStreamedChunkZ; - /// Seconds since the last packet data was received (updated in Tick(), reset in DataReceived()) + /** Seconds since the last packet data was received (updated in Tick(), reset in DataReceived()) */ float m_TimeSinceLastPacket; short m_Ping; @@ -279,7 +287,7 @@ private: int m_LastDigBlockY; int m_LastDigBlockZ; - /// Used while csDestroyedWaiting for counting the ticks until the connection is closed + /** Used while csDestroyedWaiting for counting the ticks until the connection is closed */ int m_TicksSinceDestruction; enum eState @@ -299,10 +307,10 @@ private: 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 + /** 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() + /** If set to true during csDownloadingWorld, the tick thread calls CheckIfWorldDownloaded() */ bool m_ShouldCheckDownloaded; /** Number of explosions sent this tick */ @@ -311,27 +319,39 @@ private: static int s_ClientCount; int m_UniqueID; - /// Set to true when the chunk where the player is is sent to the client. Used for spawning the player + /** 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 + /** Client Settings */ AString m_Locale; + + /** The plugin channels that the client has registered. */ + cChannels m_PluginChannels; - /// Returns true if the rate block interactions is within a reasonable limit (bot protection) + /** 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() + /** 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: + /** 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: + /** 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); - /// Handles the "MC|AdvCdm" plugin message - void HandleCommandBlockMessage(const char* a_Data, unsigned int a_Length); + /** 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|AdvCdm" plugin message */ + void HandleCommandBlockMessage(const char * a_Data, unsigned int a_Length); // cSocketThreads::cCallback overrides: virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client -- cgit v1.2.3