From 43e684071933adef93040e8d4b830d5c6b71cf9a Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Sat, 12 Jan 2013 04:46:01 +0000 Subject: Merged branch "branches/hooks" into "trunk". git-svn-id: http://mc-server.googlecode.com/svn/trunk@1139 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/ClientHandle.cpp | 478 +++++++++++++++++++++++++++++++----------------- 1 file changed, 307 insertions(+), 171 deletions(-) (limited to 'source/ClientHandle.cpp') 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); -- cgit v1.2.3