summaryrefslogtreecommitdiffstats
path: root/source/ClientHandle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/ClientHandle.cpp')
-rw-r--r--source/ClientHandle.cpp478
1 files changed, 307 insertions, 171 deletions
diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp
index dff95d89c..bae06713b 100644
--- a/source/ClientHandle.cpp
+++ b/source/ClientHandle.cpp
@@ -89,8 +89,8 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance)
, m_LastStreamedChunkZ(0x7fffffff)
, m_ShouldCheckDownloaded(false)
, m_UniqueID(0)
- , m_BlockDigAnim(-1)
- , m_LastDigStatus(-1)
+ , m_BlockDigAnimStage(-1)
+ , m_HasStartedDigging(false)
{
m_Protocol = new cProtocolRecognizer(this);
@@ -231,7 +231,7 @@ void cClientHandle::Authenticate(void)
m_Player->SetIP (m_IPString);
- cRoot::Get()->GetPluginManager()->CallHook(cPluginManager::HOOK_PLAYER_JOIN, 1, m_Player);
+ cRoot::Get()->GetPluginManager()->CallHookPlayerJoined(*m_Player);
m_ConfirmPosition = m_Player->GetPosition();
@@ -260,7 +260,7 @@ void cClientHandle::Authenticate(void)
// Broadcast this player's spawning to all other players in the same chunk
m_Player->GetWorld()->BroadcastSpawn(*m_Player, this);
- cRoot::Get()->GetPluginManager()->CallHook(cPluginManager::HOOK_PLAYER_SPAWN, 1, m_Player);
+ cRoot::Get()->GetPluginManager()->CallHookPlayerSpawned(*m_Player);
}
@@ -501,125 +501,232 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ,
-void cClientHandle::HandleBlockDig(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status)
+void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status)
{
+ LOGD("HandleLeftClick: {%i, %i, %i}; Face: %i; Stat: %i",
+ a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status
+ );
+
+ cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
+ if (PlgMgr->CallHookPlayerLeftClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status))
+ {
+ // A plugin doesn't agree with the action, replace the block on the client and quit:
+ 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;
}
- LOGD("OnBlockDig: {%i, %i, %i}; Face: %i; Stat: %i LastStat: %i",
- a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status, m_LastDigStatus
- );
+ switch (a_Status)
+ {
+ case DIG_STATUS_DROP_HELD: // Drop held item
+ {
+ if (PlgMgr->CallHookPlayerTossingItem(*m_Player))
+ {
+ // A plugin doesn't agree with the tossing. The plugin itself is responsible for handling the consequences (possible inventory mismatch)
+ return;
+ }
+ m_Player->TossItem(false);
+ return;
+ }
+
+ case DIG_STATUS_SHOOT_EAT:
+ {
+ cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
+ if (ItemHandler->IsFood())
+ {
+ if (PlgMgr->CallHookPlayerEating(*m_Player))
+ {
+ // A plugin doesn't agree with the action. The plugin itself is responsible for handling the consequences (possible inventory mismatch)
+ return;
+ }
+ }
+ else
+ {
+ if (PlgMgr->CallHookPlayerShooting(*m_Player))
+ {
+ // A plugin doesn't agree with the action. The plugin itself is responsible for handling the consequences (possible inventory mismatch)
+ return;
+ }
+ }
+ LOGINFO("%s: Status SHOOT / EAT not implemented", __FUNCTION__);
+ return;
+ }
+
+ case DIG_STATUS_STARTED:
+ {
+ BLOCKTYPE OldBlock;
+ NIBBLETYPE OldMeta;
+ m_Player->GetWorld()->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, OldBlock, OldMeta);
+ HandleBlockDigStarted(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, OldBlock, OldMeta);
+ return;
+ }
+
+ case DIG_STATUS_FINISHED:
+ {
+ BLOCKTYPE OldBlock;
+ NIBBLETYPE OldMeta;
+ m_Player->GetWorld()->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, OldBlock, OldMeta);
+ HandleBlockDigFinished(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, OldBlock, OldMeta);
+ return;
+ }
+
+ default:
+ {
+ ASSERT(!"Unhandled DIG_STATUS");
+ return;
+ }
+ } // switch (a_Status)
+}
+
+
- // Do we want plugins to disable tossing items? Probably no, so toss item before asking plugins for permission
- if (a_Status == DIG_STATUS_DROP_HELD) // Drop held item
+
+
+void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_OldBlock, NIBBLETYPE a_OldMeta)
+{
+ if (
+ m_HasStartedDigging &&
+ (a_BlockX == m_LastDigBlockX) &&
+ (a_BlockY == m_LastDigBlockY) &&
+ (a_BlockZ == m_LastDigBlockZ)
+ )
{
- m_Player->TossItem(false);
+ // It is a duplicate packet, drop it right away
return;
}
-
- if (a_Status == DIG_STATUS_SHOOT_EAT)
+
+ if (cRoot::Get()->GetPluginManager()->CallHookPlayerBreakingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta))
{
- LOGINFO("BlockDig: Status SHOOT/EAT not implemented");
+ // A plugin doesn't agree with the breaking. Bail out. Send the block back to the client, so that it knows:
+ m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
return;
}
- cWorld * World = m_Player->GetWorld();
- BLOCKTYPE OldBlock;
- NIBBLETYPE OldMeta;
- World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, OldBlock, OldMeta);
+ // Set the last digging coords to the block being dug, so that they can be checked in DIG_FINISHED to avoid dig/aim bug in the client:
+ m_HasStartedDigging = true;
+ m_LastDigBlockX = a_BlockX;
+ m_LastDigBlockY = a_BlockY;
+ m_LastDigBlockZ = a_BlockZ;
- if (cRoot::Get()->GetPluginManager()->CallHookBlockDig(m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status, OldBlock, OldMeta))
+ // In creative mode, digging is done immediately
+ if (m_Player->GetGameMode() == eGameMode_Creative)
{
- // The plugin doesn't agree with the digging, replace the block on the client and quit:
- World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
+ HandleBlockDigFinished(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta);
return;
}
- bool bBroken = (
- ((a_Status == DIG_STATUS_FINISHED) &&
- //Don't allow to finish digging if not started yet:
- (m_LastDigStatus == 0) &&
- (m_LastDigX == a_BlockX) &&
- (m_LastDigY == a_BlockY) &&
- (m_LastDigZ == a_BlockZ)) ||
- (g_BlockOneHitDig[(int)OldBlock]) ||
- ((a_Status == DIG_STATUS_STARTED) && (m_Player->GetGameMode() == 1))
- );
+ // Start dig animation
+ // TODO: calculate real animation speed
+ // TODO: Send animation packets even without receiving any other packets
+ m_BlockDigAnimSpeed = 10;
+ m_BlockDigAnimX = a_BlockX;
+ m_BlockDigAnimY = a_BlockY;
+ m_BlockDigAnimZ = a_BlockZ;
+ m_BlockDigAnimStage = 0;
+ m_Player->GetWorld()->BroadcastBlockBreakAnimation(m_UniqueID, m_BlockDigAnimX, m_BlockDigAnimY, m_BlockDigAnimZ, 0, this);
+
+ cWorld * World = m_Player->GetWorld();
+
+ cBlockHandler * Handler = cBlockHandler::GetBlockHandler(a_OldBlock);
+ Handler->OnDigging(World, m_Player, a_BlockX, a_BlockY, a_BlockZ);
+
+ cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
+ ItemHandler->OnDiggingBlock(World, m_Player, &m_Player->GetEquippedItem(), a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+
+ // Check for clickthrough-blocks:
+ if (a_BlockFace != BLOCK_FACE_NONE)
+ {
+ int pX = a_BlockX;
+ int pY = a_BlockY;
+ int pZ = a_BlockZ;
+ AddFaceDirection(pX, pY, pZ, a_BlockFace);
+
+ Handler = cBlockHandler::GetBlockHandler(World->GetBlock(pX, pY, pZ));
+
+ // 2013_01_05 _X: This looks weird
+ // Why do we ask the block "behind" the one being clicked if it is clicked through? Shouldn't we ask the primary block instead?
+ if (Handler->IsClickedThrough())
+ {
+ Handler->OnDigging(World, m_Player, pX, pY, pZ);
+ }
+ }
+}
- m_LastDigStatus = a_Status;
- m_LastDigX = a_BlockX;
- m_LastDigY = a_BlockY;
- m_LastDigZ = a_BlockZ;
- if ((a_Status == DIG_STATUS_STARTED) && (m_Player->GetGameMode() != eGameMode_Creative))
+
+
+
+void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_OldBlock, NIBBLETYPE a_OldMeta)
+{
+ if (
+ !m_HasStartedDigging || // Hasn't received the DIG_STARTED packet
+ (m_LastDigBlockX != a_BlockX) || // DIG_STARTED has had different pos
+ (m_LastDigBlockY != a_BlockY) ||
+ (m_LastDigBlockZ != a_BlockZ)
+ )
{
- // Start dig animation
- // TODO: calculate real animation speed
- m_BlockDigAnimSpeed = 10;
- m_BlockDigX = a_BlockX;
- m_BlockDigY = a_BlockY;
- m_BlockDigZ = a_BlockZ;
- m_BlockDigAnim = 0;
- m_Player->GetWorld()->BroadcastBlockBreakAnimation(m_UniqueID, m_BlockDigX, m_BlockDigY, m_BlockDigZ, 0, this);
+ 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
+ );
+ return;
}
- else if (m_BlockDigAnim != -1)
+
+ m_HasStartedDigging = false;
+ if (m_BlockDigAnimStage != -1)
{
// End dig animation
- m_BlockDigAnim = -1;
+ m_BlockDigAnimStage = -1;
// It seems that 10 ends block animation
- m_Player->GetWorld()->BroadcastBlockBreakAnimation(m_UniqueID, m_BlockDigX, m_BlockDigY, m_BlockDigZ, 10, this);
+ m_Player->GetWorld()->BroadcastBlockBreakAnimation(m_UniqueID, m_BlockDigAnimX, m_BlockDigAnimY, m_BlockDigAnimZ, 10, this);
}
- cItem & Equipped = m_Player->GetInventory().GetEquippedItem();
- cItemHandler * ItemHandler = cItemHandler::GetItemHandler(Equipped.m_ItemID);
+ cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
- if (bBroken)
+ if (a_OldBlock == E_BLOCK_AIR)
{
- if(World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_AIR)
- {
- ItemHandler->OnBlockDestroyed(World, m_Player, &Equipped, a_BlockX, a_BlockY, a_BlockZ);
-
- BlockHandler(OldBlock)->OnDestroyedByPlayer(World, m_Player, a_BlockX, a_BlockY, a_BlockZ);
- World->BroadcastSoundParticleEffect(2001, a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, OldBlock, this);
- World->DigBlock(a_BlockX, a_BlockY, a_BlockZ);
- }
+ LOGD("Digged air? wtf?");
+ return;
}
- else
- {
- cBlockHandler * Handler = cBlockHandler::GetBlockHandler(OldBlock);
- Handler->OnDigging(World, m_Player, a_BlockX, a_BlockY, a_BlockZ);
-
- ItemHandler->OnDiggingBlock(World, m_Player, &Equipped, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
-
- // Check for clickthrough-blocks:
- if (a_BlockFace != BLOCK_FACE_NONE)
- {
- int pX = a_BlockX;
- int pY = a_BlockY;
- int pZ = a_BlockZ;
- AddDirection(pX, pY, pZ, a_BlockFace);
+
+ cWorld * World = m_Player->GetWorld();
+ ItemHandler->OnBlockDestroyed(World, m_Player, &m_Player->GetEquippedItem(), a_BlockX, a_BlockY, a_BlockZ);
+
+ BlockHandler(a_OldBlock)->OnDestroyedByPlayer(World, m_Player, a_BlockX, a_BlockY, a_BlockZ);
+ World->BroadcastSoundParticleEffect(2001, a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, a_OldBlock, this);
+ World->DigBlock(a_BlockX, a_BlockY, a_BlockZ);
- Handler = cBlockHandler::GetBlockHandler(World->GetBlock(pX, pY, pZ));
- if (Handler->IsClickedThrough())
- {
- Handler->OnDigging(World, m_Player, pX, pY, pZ);
- }
- }
- }
+ cRoot::Get()->GetPluginManager()->CallHookPlayerBrokenBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta);
}
-void cClientHandle::HandleBlockPlace(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, const cItem & a_HeldItem)
+void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, const cItem & a_HeldItem)
{
- LOGD("HandleBlockPlace: {%d, %d, %d}, face %d, HeldItem: %s",
+ LOGD("HandleRightClick: {%d, %d, %d}, face %d, HeldItem: %s",
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, ItemToFullString(a_HeldItem).c_str()
);
+ 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)
+ {
+ AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+ m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
+ }
+ return;
+ }
+
if (!CheckBlockInteractionsRate())
{
LOGD("Too many block interactions, aborting placement");
@@ -640,7 +747,7 @@ void cClientHandle::HandleBlockPlace(int a_BlockX, int a_BlockY, int a_BlockZ, c
// 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)
{
- AddDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+ AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
}
return;
@@ -648,104 +755,133 @@ void cClientHandle::HandleBlockPlace(int a_BlockX, int a_BlockY, int a_BlockZ, c
cWorld * World = m_Player->GetWorld();
- cBlockHandler *Handler = cBlockHandler::GetBlockHandler(World->GetBlock(a_BlockX, a_BlockY, a_BlockZ));
+ BLOCKTYPE BlockType;
+ NIBBLETYPE BlockMeta;
+ World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
+ cBlockHandler * Handler = cBlockHandler::GetBlockHandler(BlockType);
- // TODO: Wrap following if into another if which will call hook 'OnBlockUse' (or some nicer name)
if (Handler->IsUseable())
{
- Handler->OnUse(World, m_Player, a_BlockX, a_BlockY, a_BlockZ);
+ if (PlgMgr->CallHookPlayerUsingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
+ {
+ // A plugin doesn't agree with using the block, abort
+ return;
+ }
+ Handler->OnUse(World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
+ PlgMgr->CallHookPlayerUsedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
+ return;
}
- else
+
+ cItemHandler * ItemHandler = cItemHandler::GetItemHandler(Equipped.m_ItemType);
+
+ if (ItemHandler->IsPlaceable())
{
- cItemHandler * ItemHandler = cItemHandler::GetItemHandler(Equipped.m_ItemID);
-
- if (ItemHandler->OnItemUse(World, m_Player, &Equipped, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace))
+ HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler);
+ }
+ else if (ItemHandler->IsFood())
+ {
+ cItem Item;
+ Item.m_ItemType = Equipped.m_ItemType;
+ Item.m_ItemCount = 1;
+ if (ItemHandler->EatItem(m_Player, &Item))
{
- // Nothing here :P
+ ItemHandler->OnFoodEaten(World, m_Player, &Item);
+ m_Player->GetInventory().RemoveItem(Item);
+ return;
}
- else if (ItemHandler->IsPlaceable())
+ }
+ else
+ {
+ if (PlgMgr->CallHookPlayerUsingItem(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
{
- if (cRoot::Get()->GetPluginManager()->CallHookBlockPlace(m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, Equipped))
- {
- if (a_BlockFace > -1)
- {
- AddDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
- }
- return;
- }
-
- if (a_BlockFace < 0)
- {
- // clicked in air
- return;
- }
+ // A plugin doesn't agree with using the item, abort
+ return;
+ }
+ ItemHandler->OnItemUse(World, m_Player, &Equipped, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+ PlgMgr->CallHookPlayerUsedItem(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
+ }
+}
- BLOCKTYPE ClickedBlock = World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
- cBlockHandler *Handler = cBlockHandler::GetBlockHandler(ClickedBlock);
- if (Handler->DoesIgnoreBuildCollision())
- {
- Handler->OnDestroyedByPlayer(World, m_Player, a_BlockX, a_BlockY, a_BlockZ);
- // World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
- }
- else
- {
- AddDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- // Check for Blocks not allowing placement on top
- if ((a_BlockFace == BLOCK_FACE_TOP) && !Handler->DoesAllowBlockOnTop())
- {
- // Resend the old block
- // Some times the client still places the block O.o
- World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
- return;
- }
- BLOCKTYPE PlaceBlock = m_Player->GetWorld()->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
- if (!BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision())
- {
- // Tried to place a block *into* another?
- return; // Happens when you place a block aiming at side of block like torch or stem
- }
- }
-
- cBlockHandler * NewBlock = BlockHandler(ItemHandler->GetBlockType());
+void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, cItemHandler & a_ItemHandler)
+{
+ if (a_BlockFace < 0)
+ {
+ // Clicked in air
+ return;
+ }
+
+ cWorld * World = m_Player->GetWorld();
+
+ // Check if the block ignores build collision (water, grass etc.):
+ BLOCKTYPE ClickedBlock = World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ cBlockHandler * Handler = cBlockHandler::GetBlockHandler(ClickedBlock);
+ if (Handler->DoesIgnoreBuildCollision())
+ {
+ Handler->OnDestroyedByPlayer(World, m_Player, a_BlockX, a_BlockY, a_BlockZ);
+ // World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ }
+ else
+ {
+ AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+ // Check for Blocks not allowing placement on top
+ if ((a_BlockFace == BLOCK_FACE_TOP) && !Handler->DoesAllowBlockOnTop())
+ {
+ // Resend the old block
+ // Some times the client still places the block O.o
+ World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
+ return;
+ }
- // Cannot be placed on the side of an other block
- if ((a_BlockFace != BLOCK_FACE_TOP) && !NewBlock->CanBePlacedOnSide())
- {
- return;
- }
- if (NewBlock->CanBePlacedAt(World, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace))
- {
- ItemHandler->PlaceBlock(World, m_Player, &m_Player->GetInventory().GetEquippedItem(), a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- // Step sound with 0.8f pitch is used as block placement sound
- World->BroadcastSoundEffect(NewBlock->GetStepSound(),a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 0.8f);
- }
- else
- {
- LOGD("Block refused placement here, aborting");
- World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); // Send the old block back to the player
- return;
- }
-
- }
- else if (ItemHandler->IsFood())
+ BLOCKTYPE PlaceBlock = World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ if (!BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision())
{
- cItem Item;
- Item.m_ItemID = Equipped.m_ItemID;
- Item.m_ItemCount = 1;
- if (ItemHandler->EatItem(m_Player, &Item))
- {
- ItemHandler->OnFoodEaten(World, m_Player, &Item);
- m_Player->GetInventory().RemoveItem(Item);
- return;
- }
+ // Tried to place a block *into* another?
+ return; // Happens when you place a block aiming at side of block like torch or stem
}
}
+
+ BLOCKTYPE BlockType;
+ NIBBLETYPE BlockMeta;
+ if (!a_ItemHandler.GetPlacementBlockTypeMeta(World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
+ {
+ // Handler refused the placement, send that information back to the client:
+ World->SendBlockTo(a_BlockX, a_BlockY, a_BlockY, m_Player);
+ return;
+ }
+
+ cBlockHandler * NewBlock = BlockHandler(BlockType);
+
+ if ((a_BlockFace != BLOCK_FACE_TOP) && !NewBlock->CanBePlacedOnSide())
+ {
+ // Cannot be placed on the side of an other block
+ World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
+ return;
+ }
+
+ if (cRoot::Get()->GetPluginManager()->CallHookPlayerPlacingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
+ {
+ // A plugin doesn't agree with placing the block, revert the block on the client:
+ World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
+ return;
+ }
+
+ // The actual block placement:
+ World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
+ if (m_Player->GetGameMode() == eGameMode_Survival)
+ {
+ cItem Item(m_Player->GetEquippedItem().m_ItemType, 1);
+ m_Player->GetInventory().RemoveItem(Item);
+ }
+ NewBlock->OnPlacedByPlayer(World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
+
+ // Step sound with 0.8f pitch is used as block placement sound
+ World->BroadcastSoundEffect(NewBlock->GetStepSound(),a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 0.8f);
+ cRoot::Get()->GetPluginManager()->CallHookPlayerPlacedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
}
@@ -951,7 +1087,7 @@ void cClientHandle::HandleRespawn(void)
return;
}
m_Player->Respawn();
- cRoot::Get()->GetPluginManager()->CallHook(cPluginManager::HOOK_PLAYER_SPAWN, 1, m_Player);
+ cRoot::Get()->GetPluginManager()->CallHookPlayerSpawned(*m_Player);
}
@@ -1129,17 +1265,17 @@ void cClientHandle::Tick(float a_Dt)
}
// Handle block break animation:
- if ((m_Player != NULL) && (m_BlockDigAnim > -1))
+ if ((m_Player != NULL) && (m_BlockDigAnimStage > -1))
{
- int lastAnimVal = m_BlockDigAnim;
- m_BlockDigAnim += (int)(m_BlockDigAnimSpeed * a_Dt);
- if (m_BlockDigAnim > 9000)
+ int lastAnimVal = m_BlockDigAnimStage;
+ m_BlockDigAnimStage += (int)(m_BlockDigAnimSpeed * a_Dt);
+ if (m_BlockDigAnimStage > 9000)
{
- m_BlockDigAnim = 9000;
+ m_BlockDigAnimStage = 9000;
}
- if (m_BlockDigAnim / 1000 != lastAnimVal / 1000)
+ if (m_BlockDigAnimStage / 1000 != lastAnimVal / 1000)
{
- m_Player->GetWorld()->BroadcastBlockBreakAnimation(m_UniqueID, m_BlockDigX, m_BlockDigY, m_BlockDigZ, (char)(m_BlockDigAnim / 1000), this);
+ m_Player->GetWorld()->BroadcastBlockBreakAnimation(m_UniqueID, m_BlockDigAnimX, m_BlockDigAnimY, m_BlockDigAnimZ, (char)(m_BlockDigAnimStage / 1000), this);
}
}
}
@@ -1626,7 +1762,7 @@ void cClientHandle::SendConfirmPosition(void)
m_State = csConfirmingPos;
- if (!cRoot::Get()->GetPluginManager()->CallHook(cPluginManager::HOOK_PLAYER_JOIN, 1, m_Player))
+ if (!cRoot::Get()->GetPluginManager()->CallHookPlayerJoined(*m_Player))
{
// Broadcast that this player has joined the game! Yay~
cRoot::Get()->GetServer()->BroadcastChat(m_Username + " joined the game!", this);