summaryrefslogtreecommitdiffstats
path: root/src/ClientHandle.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/ClientHandle.cpp185
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;
}