diff options
Diffstat (limited to 'src/ClientHandle.cpp')
-rw-r--r-- | src/ClientHandle.cpp | 185 |
1 files changed, 90 insertions, 95 deletions
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index dd2116dbf..23ba4dbab 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -22,9 +22,6 @@ #include "Blocks/BlockSlab.h" #include "Blocks/ChunkInterface.h" -#include "Vector3f.h" -#include "Vector3d.h" - #include "Root.h" #include "Authenticator.h" @@ -36,22 +33,12 @@ - - -#define AddPistonDir(x, y, z, dir, amount) switch (dir) { case 0: (y)-=(amount); break; case 1: (y)+=(amount); break;\ - case 2: (z)-=(amount); break; case 3: (z)+=(amount); break;\ - case 4: (x)-=(amount); break; case 5: (x)+=(amount); break; } - - - - - -/** If the number of queued outgoing packets reaches this, the client will be kicked */ -#define MAX_OUTGOING_PACKETS 2000 - /** Maximum number of explosions to send this tick, server will start dropping if exceeded */ #define MAX_EXPLOSIONS_PER_TICK 20 +/** Maximum number of block change interactions a player can perform per tick - exceeding this causes a kick */ +#define MAX_BLOCK_CHANGE_INTERACTIONS 20 + /** How many ticks before the socket is closed after the client is destroyed (#31) */ static const int TICKS_BEFORE_CLOSE = 20; @@ -96,8 +83,8 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) : m_ShouldCheckDownloaded(false), m_NumExplosionsThisTick(0), m_UniqueID(0), - m_Locale("en_GB"), - m_HasSentPlayerChunk(false) + m_HasSentPlayerChunk(false), + m_Locale("en_GB") { m_Protocol = new cProtocolRecognizer(this); @@ -555,12 +542,25 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString } else if (a_Channel == "REGISTER") { + if (HasPluginChannel(a_Channel)) + { + SendPluginMessage("UNREGISTER", a_Channel); + return; // Can't register again if already taken - kinda defeats the point of plugin messaging! + } + RegisterPluginChannels(BreakApartPluginChannels(a_Message)); } else if (a_Channel == "UNREGISTER") { UnregisterPluginChannels(BreakApartPluginChannels(a_Message)); } + else if (!HasPluginChannel(a_Channel)) + { + // Ignore if client sent something but didn't register the channel first + LOGD("Player %s sent a plugin message on channel \"%s\", but didn't REGISTER it first", GetUsername().c_str(), a_Channel.c_str()); + SendPluginMessage("UNREGISTER", a_Channel); + return; + } cPluginManager::Get()->CallHookPluginMessage(*this, a_Channel, a_Message); } @@ -687,6 +687,14 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status ); + m_NumBlockChangeInteractionsThisTick++; + + if (!CheckBlockInteractionsRate()) + { + Kick("Too many blocks were destroyed per unit time - hacked client?"); + return; + } + cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager(); if (PlgMgr->CallHookPlayerLeftClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status)) { @@ -694,12 +702,6 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); return; } - - if (!CheckBlockInteractionsRate()) - { - // Too many interactions per second, simply ignore. Probably a hacked client, so don't even send bak the block - return; - } switch (a_Status) { @@ -819,7 +821,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc if ( (m_Player->IsGameModeCreative()) || // In creative mode, digging is done immediately - g_BlockOneHitDig[a_OldBlock] // One-hit blocks get destroyed immediately, too + cBlockInfo::IsOneHitDig(a_OldBlock) // One-hit blocks get destroyed immediately, too ) { HandleBlockDigFinished(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta); @@ -838,7 +840,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc cWorld * World = m_Player->GetWorld(); cChunkInterface ChunkInterface(World->GetChunkMap()); - cBlockHandler * Handler = cBlockHandler::GetBlockHandler(a_OldBlock); + cBlockHandler * Handler = cBlockInfo::GetHandler(a_OldBlock); Handler->OnDigging(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ); cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem()); @@ -852,7 +854,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc int pZ = a_BlockZ; AddFaceDirection(pX, pY, pZ, a_BlockFace); // Get the block in front of the clicked coordinates (m_bInverse defaulted to false) - Handler = cBlockHandler::GetBlockHandler(World->GetBlock(pX, pY, pZ)); + Handler = cBlockInfo::GetHandler(World->GetBlock(pX, pY, pZ)); if (Handler->IsClickedThrough()) { @@ -877,7 +879,7 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo LOGD("Prevented a dig/aim bug in the client (finish {%d, %d, %d} vs start {%d, %d, %d}, HSD: %s)", a_BlockX, a_BlockY, a_BlockZ, m_LastDigBlockX, m_LastDigBlockY, m_LastDigBlockZ, - m_HasStartedDigging + (m_HasStartedDigging ? "True" : "False") ); return; } @@ -920,21 +922,31 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, ItemToFullString(a_HeldItem).c_str() ); + cWorld * World = m_Player->GetWorld(); + cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager(); if (PlgMgr->CallHookPlayerRightClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ)) { // A plugin doesn't agree with the action, replace the block on the client and quit: - if (a_BlockFace > -1) + cChunkInterface ChunkInterface(World->GetChunkMap()); + BLOCKTYPE BlockType = World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); + cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType); + BlockHandler->OnCancelRightClick(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); + + if (a_BlockFace != BLOCK_FACE_NONE) { AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); - m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); + World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); + World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); //2 block high things } return; } + + m_NumBlockChangeInteractionsThisTick++; if (!CheckBlockInteractionsRate()) { - LOGD("Too many block interactions, aborting placement"); + Kick("Too many blocks were placed/interacted with per unit time - hacked client?"); return; } @@ -950,20 +962,18 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e ); // Let's send the current world block to the client, so that it can immediately "let the user know" that they haven't placed the block - if (a_BlockFace > -1) + if (a_BlockFace != BLOCK_FACE_NONE) { AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); - m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); + World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); } return; } - - cWorld * World = m_Player->GetWorld(); BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta); - cBlockHandler * BlockHandler = cBlockHandler::GetBlockHandler(BlockType); + cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType); if (BlockHandler->IsUseable() && !m_Player->IsCrouched()) { @@ -980,7 +990,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e cItemHandler * ItemHandler = cItemHandler::GetItemHandler(Equipped.m_ItemType); - if (ItemHandler->IsPlaceable() && (a_BlockFace > -1)) + if (ItemHandler->IsPlaceable() && (a_BlockFace != BLOCK_FACE_NONE)) { HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler); } @@ -1018,6 +1028,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e void cClientHandle::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) { + BLOCKTYPE EquippedBlock = (BLOCKTYPE)(m_Player->GetEquippedItem().m_ItemType); if (a_BlockFace < 0) { // Clicked in air @@ -1028,7 +1039,6 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e BLOCKTYPE ClickedBlock; NIBBLETYPE ClickedBlockMeta; - BLOCKTYPE EquippedBlock = (BLOCKTYPE)(m_Player->GetEquippedItem().m_ItemType); NIBBLETYPE EquippedBlockDamage = (NIBBLETYPE)(m_Player->GetEquippedItem().m_ItemDamage); if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height)) @@ -1045,8 +1055,8 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e cBlockSlabHandler::IsAnySlabType(EquippedBlock) && // Is the player placing another slab? ((ClickedBlockMeta & 0x07) == EquippedBlockDamage) && // Is it the same slab type? ( - (a_BlockFace == BLOCK_FACE_TOP) || // Clicking the top of a bottom slab - (a_BlockFace == BLOCK_FACE_BOTTOM) // Clicking the bottom of a top slab + (a_BlockFace == BLOCK_FACE_TOP) || // Clicking the top of a bottom slab + (a_BlockFace == BLOCK_FACE_BOTTOM) // Clicking the bottom of a top slab ) ) { @@ -1054,7 +1064,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e // If clicked top face and slab occupies the top voxel, we want a slab to be placed above it (therefore increment Y) // Else if clicked bottom face and slab occupies the bottom voxel, decrement Y for the same reason // Don't touch coordinates if anything else because a dblslab opportunity is present - if((ClickedBlockMeta & 0x08) && (a_BlockFace == BLOCK_FACE_TOP)) + if ((ClickedBlockMeta & 0x08) && (a_BlockFace == BLOCK_FACE_TOP)) { ++a_BlockY; } @@ -1130,7 +1140,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e // The actual block placement: World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta); - if (m_Player->GetGameMode() != gmCreative) + if (!m_Player->IsGameModeCreative()) { m_Player->GetInventory().RemoveOneEquippedItem(); } @@ -1447,7 +1457,7 @@ bool cClientHandle::HandleHandshake(const AString & a_Username) -void cClientHandle::HandleEntityAction(int a_EntityID, char a_ActionID) +void cClientHandle::HandleEntityCrouch(int a_EntityID, bool a_IsCrouching) { if (a_EntityID != m_Player->GetUniqueID()) { @@ -1455,35 +1465,37 @@ void cClientHandle::HandleEntityAction(int a_EntityID, char a_ActionID) return; } - switch (a_ActionID) + m_Player->SetCrouch(a_IsCrouching); +} + + + + + +void cClientHandle::HandleEntityLeaveBed(int a_EntityID) +{ + if (a_EntityID != m_Player->GetUniqueID()) { - case 1: // Crouch - { - m_Player->SetCrouch(true); - break; - } - case 2: // Uncrouch - { - m_Player->SetCrouch(false); - break; - } - case 3: // Leave bed - { - m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, 2); - break; - } - case 4: // Start sprinting - { - m_Player->SetSprint(true); - break; - } - case 5: // Stop sprinting - { - m_Player->SetSprint(false); - SendPlayerMaxSpeed(); - break; - } + // We should only receive entity actions from the entity that is performing the action + return; } + + m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, 2); +} + + + + + +void cClientHandle::HandleEntitySprinting(int a_EntityID, bool a_IsSprinting) +{ + if (a_EntityID != m_Player->GetUniqueID()) + { + // We should only receive entity actions from the entity that is performing the action + return; + } + + m_Player->SetSprint(a_IsSprinting); } @@ -1596,10 +1608,8 @@ void cClientHandle::MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket) m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ); } // for itr - Chunks[] - // Do NOT stream new chunks, the new world runs its own tick thread and may deadlock - // Instead, the chunks will be streamed when the client is moved to the new world's Tick list, - // by setting state to csAuthenticated - m_State = csAuthenticated; + // StreamChunks() called in cPlayer::MoveToWorld() after new world has been set + // Meanwhile here, we set last streamed values to bogus ones so everything is resent m_LastStreamedChunkX = 0x7fffffff; m_LastStreamedChunkZ = 0x7fffffff; m_HasSentPlayerChunk = false; @@ -1613,28 +1623,12 @@ bool cClientHandle::CheckBlockInteractionsRate(void) { ASSERT(m_Player != NULL); ASSERT(m_Player->GetWorld() != NULL); - /* - // TODO: _X 2012_11_01: This needs a total re-thinking and rewriting - int LastActionCnt = m_Player->GetLastBlockActionCnt(); - if ((m_Player->GetWorld()->GetTime() - m_Player->GetLastBlockActionTime()) < 0.1) - { - // Limit the number of block interactions per tick - m_Player->SetLastBlockActionTime(); //Player tried to interact with a block. Reset last block interation time. - m_Player->SetLastBlockActionCnt(LastActionCnt + 1); - if (m_Player->GetLastBlockActionCnt() > MAXBLOCKCHANGEINTERACTIONS) - { - // Kick if more than MAXBLOCKCHANGEINTERACTIONS per tick - LOGWARN("Player %s tried to interact with a block too quickly! (could indicate bot) Was Kicked.", m_Username.c_str()); - Kick("You're a baaaaaad boy!"); - return false; - } - } - else + + if (m_NumBlockChangeInteractionsThisTick > MAX_BLOCK_CHANGE_INTERACTIONS) { - m_Player->SetLastBlockActionCnt(0); // Reset count - m_Player->SetLastBlockActionTime(); // Player tried to interact with a block. Reset last block interation time. + return false; } - */ + return true; } @@ -1707,8 +1701,9 @@ void cClientHandle::Tick(float a_Dt) } } - // Reset explosion counter: + // Reset explosion & block change counters: m_NumExplosionsThisTick = 0; + m_NumBlockChangeInteractionsThisTick = 0; } |