From 645fea423764e9d91e46b84a63aba5a47b954c6a Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 6 Nov 2020 14:58:47 +0000 Subject: [PATCH] Players are no longer kicked when clicking on bedrock (#5023) * Players are no longer kicked when clicking on bedrock * Fixes #5022 --- src/BlockInfo.cpp | 66 +++++++++++------------------------------ src/ClientHandle.cpp | 60 ++++++++++++++++--------------------- src/ClientHandle.h | 8 ++--- src/Entities/Player.cpp | 26 +++++----------- src/Entities/Player.h | 1 + 5 files changed, 57 insertions(+), 104 deletions(-) diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp index 44de0d659..d6c95f6a6 100644 --- a/src/BlockInfo.cpp +++ b/src/BlockInfo.cpp @@ -838,43 +838,13 @@ bool cBlockInfo::FullyOccupiesVoxel(const BLOCKTYPE Block) bool cBlockInfo::IsOneHitDig(const BLOCKTYPE Block) { - // One hit break blocks: - switch (Block) - { - case E_BLOCK_ACTIVE_COMPARATOR: - case E_BLOCK_BEETROOTS: - case E_BLOCK_BIG_FLOWER: - case E_BLOCK_BROWN_MUSHROOM: - case E_BLOCK_CARROTS: - case E_BLOCK_CROPS: - case E_BLOCK_DANDELION: - case E_BLOCK_DEAD_BUSH: - case E_BLOCK_END_ROD: - case E_BLOCK_FIRE: - case E_BLOCK_FLOWER: - case E_BLOCK_FLOWER_POT: - case E_BLOCK_INACTIVE_COMPARATOR: - case E_BLOCK_LILY_PAD: - case E_BLOCK_MELON_STEM: - case E_BLOCK_NETHER_WART: - case E_BLOCK_POTATOES: - case E_BLOCK_PUMPKIN_STEM: - case E_BLOCK_REDSTONE_REPEATER_OFF: - case E_BLOCK_REDSTONE_REPEATER_ON: - case E_BLOCK_REDSTONE_TORCH_OFF: - case E_BLOCK_REDSTONE_TORCH_ON: - case E_BLOCK_REDSTONE_WIRE: - case E_BLOCK_RED_MUSHROOM: - case E_BLOCK_REEDS: - case E_BLOCK_SAPLING: - case E_BLOCK_SLIME_BLOCK: - case E_BLOCK_TNT: - case E_BLOCK_TALL_GRASS: - case E_BLOCK_TORCH: - case E_BLOCK_TRIPWIRE_HOOK: - case E_BLOCK_TRIPWIRE: return true; - default: return false; - } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wfloat-equal" + + // GetHardness returns exactly 0 for one hit break blocks: + return GetHardness(Block) == 0; + +#pragma clang diagnostic pop } @@ -1325,10 +1295,10 @@ float cBlockInfo::GetHardness(const BLOCKTYPE Block) case E_BLOCK_ACTIVE_COMPARATOR: return 0.0f; case E_BLOCK_AIR: return 0.0f; case E_BLOCK_ANVIL: return 5.0f; - case E_BLOCK_BARRIER: return -1.0f; + case E_BLOCK_BARRIER: return INFINITY; case E_BLOCK_BEACON: return 3.0f; case E_BLOCK_BED: return 0.2f; - case E_BLOCK_BEDROCK: return -1.0f; + case E_BLOCK_BEDROCK: return INFINITY; case E_BLOCK_BEETROOTS: return 0.0f; case E_BLOCK_BIG_FLOWER: return 0.0f; case E_BLOCK_BIRCH_DOOR: return 3.0f; @@ -1354,7 +1324,7 @@ float cBlockInfo::GetHardness(const BLOCKTYPE Block) case E_BLOCK_CARPET: return 0.1f; case E_BLOCK_CARROTS: return 0.0f; case E_BLOCK_CAULDRON: return 2.0f; - case E_BLOCK_CHAIN_COMMAND_BLOCK: return -1.0f; + case E_BLOCK_CHAIN_COMMAND_BLOCK: return INFINITY; case E_BLOCK_CHEST: return 2.5f; case E_BLOCK_CHORUS_FLOWER: return 0.4f; case E_BLOCK_CHORUS_PLANT: return 0.4f; @@ -1365,7 +1335,7 @@ float cBlockInfo::GetHardness(const BLOCKTYPE Block) case E_BLOCK_COBBLESTONE_WALL: return 2.0f; case E_BLOCK_COBWEB: return 4.0f; case E_BLOCK_COCOA_POD: return 0.2f; - case E_BLOCK_COMMAND_BLOCK: return -1.0f; + case E_BLOCK_COMMAND_BLOCK: return INFINITY; case E_BLOCK_CONCRETE: return 1.8f; case E_BLOCK_CONCRETE_POWDER: return 0.5f; case E_BLOCK_CRAFTING_TABLE: return 2.5f; @@ -1394,9 +1364,9 @@ float cBlockInfo::GetHardness(const BLOCKTYPE Block) case E_BLOCK_ENCHANTMENT_TABLE: return 5.0f; case E_BLOCK_ENDER_CHEST: return 22.5f; case E_BLOCK_END_BRICKS: return 0.8f; - case E_BLOCK_END_GATEWAY: return -1.0f; - case E_BLOCK_END_PORTAL: return -1.0f; - case E_BLOCK_END_PORTAL_FRAME: return -1.0f; + case E_BLOCK_END_GATEWAY: return INFINITY; + case E_BLOCK_END_PORTAL: return INFINITY; + case E_BLOCK_END_PORTAL_FRAME: return INFINITY; case E_BLOCK_END_ROD: return 0.0f; case E_BLOCK_END_STONE: return 3.0f; case E_BLOCK_FARMLAND: return 0.6f; @@ -1467,7 +1437,7 @@ float cBlockInfo::GetHardness(const BLOCKTYPE Block) case E_BLOCK_NETHER_BRICK: return 2.0f; case E_BLOCK_NETHER_BRICK_FENCE: return 2.0f; case E_BLOCK_NETHER_BRICK_STAIRS: return 2.0f; - case E_BLOCK_NETHER_PORTAL: return -1.0f; + case E_BLOCK_NETHER_PORTAL: return INFINITY; case E_BLOCK_NETHER_QUARTZ_ORE: return 3.0f; case E_BLOCK_NETHER_WART: return 0.0f; case E_BLOCK_NETHER_WART_BLOCK: return 1.0f; @@ -1486,7 +1456,7 @@ float cBlockInfo::GetHardness(const BLOCKTYPE Block) case E_BLOCK_PINK_SHULKER_BOX: return 2.0f; case E_BLOCK_PISTON: return 0.5f; case E_BLOCK_PISTON_EXTENSION: return 0.5f; - case E_BLOCK_PISTON_MOVED_BLOCK: return -1.0f; + case E_BLOCK_PISTON_MOVED_BLOCK: return INFINITY; case E_BLOCK_PLANKS: return 2.0f; case E_BLOCK_POTATOES: return 0.0f; case E_BLOCK_POWERED_RAIL: return 0.7f; @@ -1519,7 +1489,7 @@ float cBlockInfo::GetHardness(const BLOCKTYPE Block) case E_BLOCK_RED_SANDSTONE_SLAB: return 2.0f; case E_BLOCK_RED_SANDSTONE_STAIRS: return 0.8f; case E_BLOCK_RED_SHULKER_BOX: return 2.0f; - case E_BLOCK_REPEATING_COMMAND_BLOCK: return -1.0f; + case E_BLOCK_REPEATING_COMMAND_BLOCK: return INFINITY; case E_BLOCK_SAND: return 0.5f; case E_BLOCK_SANDSTONE: return 0.8f; case E_BLOCK_SANDSTONE_STAIRS: return 0.8f; @@ -1549,7 +1519,7 @@ float cBlockInfo::GetHardness(const BLOCKTYPE Block) case E_BLOCK_STONE_BUTTON: return 0.5f; case E_BLOCK_STONE_PRESSURE_PLATE: return 0.5f; case E_BLOCK_STONE_SLAB: return 2.0f; - case E_BLOCK_STRUCTURE_BLOCK: return -1.0f; + case E_BLOCK_STRUCTURE_BLOCK: return INFINITY; case E_BLOCK_STRUCTURE_VOID: return 0.0f; case E_BLOCK_SUGARCANE: return 0.0f; case E_BLOCK_TALL_GRASS: return 0.0f; diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 2dd622b93..19d6516e8 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -1202,19 +1202,13 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB 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); + HandleBlockDigStarted(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); 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); + HandleBlockDigFinished(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); return; } @@ -1261,7 +1255,7 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB -void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_OldBlock, NIBBLETYPE a_OldMeta) +void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) { if ( m_HasStartedDigging && @@ -1274,10 +1268,14 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc return; } + BLOCKTYPE DiggingBlock; + NIBBLETYPE DiggingMeta; + m_Player->GetWorld()->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, DiggingBlock, DiggingMeta); + if ( m_Player->IsGameModeCreative() && ItemCategory::IsSword(m_Player->GetInventory().GetEquippedItem().m_ItemType) && - (m_Player->GetWorld()->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_FIRE) + (DiggingBlock != E_BLOCK_FIRE) ) { // Players can't destroy blocks with a sword in the hand. @@ -1301,11 +1299,14 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc m_LastDigBlockZ = a_BlockZ; if ( - (m_Player->IsGameModeCreative()) || // In creative mode, digging is done immediately - m_Player->CanInstantlyMine(a_OldBlock) // Sometimes the player is fast enough to instantly mine + m_Player->IsGameModeCreative() || // In creative mode, digging is done immediately + m_Player->CanInstantlyMine(DiggingBlock) // Sometimes the player is fast enough to instantly mine ) { - HandleBlockDigFinished(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta); + // Immediately done: + m_BreakProgress = 1; + + HandleBlockDigFinished(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); return; } @@ -1323,7 +1324,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc cWorld * World = m_Player->GetWorld(); cChunkInterface ChunkInterface(World->GetChunkMap()); - cBlockHandler::For(a_OldBlock).OnDigging(ChunkInterface, *World, *m_Player, {a_BlockX, a_BlockY, a_BlockZ}); + cBlockHandler::For(DiggingBlock).OnDigging(ChunkInterface, *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); @@ -1333,7 +1334,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc -void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_OldBlock, NIBBLETYPE a_OldMeta) +void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) { if ( !m_HasStartedDigging || // Hasn't received the DIG_STARTED packet @@ -1352,23 +1353,14 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo FinishDigAnimation(); + BLOCKTYPE DugBlock; + NIBBLETYPE DugMeta; + m_Player->GetWorld()->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, DugBlock, DugMeta); + if (!m_Player->IsGameModeCreative()) { - if (a_OldBlock == E_BLOCK_BEDROCK) - { - Kick("You can't break a bedrock!"); - return; - } - if (a_OldBlock == E_BLOCK_BARRIER) - { - Kick("You can't break a barrier!"); - return; - } - } + m_BreakProgress += m_Player->GetMiningProgressPerTick(DugBlock); - if (!m_Player->IsGameModeCreative() && !m_Player->CanInstantlyMine(a_OldBlock)) - { - m_BreakProgress += m_Player->GetMiningProgressPerTick(a_OldBlock); // Check for very fast tools. Maybe instead of FASTBREAK_PERCENTAGE we should check we are within x multiplied by the progress per tick if (m_BreakProgress < FASTBREAK_PERCENTAGE) { @@ -1384,7 +1376,7 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo cWorld * World = m_Player->GetWorld(); - if (cRoot::Get()->GetPluginManager()->CallHookPlayerBreakingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta)) + if (cRoot::Get()->GetPluginManager()->CallHookPlayerBreakingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, DugBlock, DugMeta)) { // 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); @@ -1393,7 +1385,7 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo return; } - if (a_OldBlock == E_BLOCK_AIR) + if (DugBlock == E_BLOCK_AIR) { return; } @@ -1402,7 +1394,7 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo m_Player->AddFoodExhaustion(0.025); // Damage the tool, but not for 0 hardness blocks: - m_Player->UseEquippedItem(cBlockInfo::IsOneHitDig(a_OldBlock) ? cItemHandler::dlaBreakBlockInstant : cItemHandler::dlaBreakBlock); + m_Player->UseEquippedItem(cBlockInfo::IsOneHitDig(DugBlock) ? cItemHandler::dlaBreakBlockInstant : cItemHandler::dlaBreakBlock); cChunkInterface ChunkInterface(World->GetChunkMap()); Vector3i absPos(a_BlockX, a_BlockY, a_BlockZ); @@ -1415,8 +1407,8 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo World->DigBlock(absPos, m_Player); } - World->BroadcastSoundParticleEffect(EffectID::PARTICLE_SMOKE, absPos, a_OldBlock, this); - cRoot::Get()->GetPluginManager()->CallHookPlayerBrokenBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta); + World->BroadcastSoundParticleEffect(EffectID::PARTICLE_SMOKE, absPos, DugBlock, this); + cRoot::Get()->GetPluginManager()->CallHookPlayerBrokenBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, DugBlock, DugMeta); } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index ab6e5e730..e955911bf 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -562,8 +562,8 @@ private: /** Shared pointer to self, so that this instance can keep itself alive when needed. */ cClientHandlePtr m_Self; - /** The fraction between 0 and 1, of how far through mining the currently mined block is. - 0 for just started, 1 for broken. Used for anti-cheat. */ + /** The fraction between 0 and 1 (or above), of how far through mining the currently mined block is. + 0 for just started, 1 and above for broken. Used for anti-cheat. */ float m_BreakProgress; /** Finish logging the user in after authenticating. */ @@ -576,10 +576,10 @@ private: void StreamChunk(int a_ChunkX, int a_ChunkZ, cChunkSender::Priority a_Priority); /** 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); + void HandleBlockDigStarted (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace); /** 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); + void HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace); /** The clients will receive a finished dig animation */ void FinishDigAnimation(); diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 888792773..a8afb2b95 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -3228,21 +3228,15 @@ float cPlayer::GetMiningProgressPerTick(BLOCKTYPE a_Block) { return 1; } - float BlockHardness = cBlockInfo::GetHardness(a_Block); + + const bool CanHarvest = GetEquippedItem().GetHandler()->CanHarvestBlock(a_Block); + const float BlockHardness = cBlockInfo::GetHardness(a_Block) * (CanHarvest ? 1.5f : 5.0f); ASSERT(BlockHardness > 0); // Can't divide by 0 or less, IsOneHitDig should have returned true - if (GetEquippedItem().GetHandler()->CanHarvestBlock(a_Block)) - { - BlockHardness *= 1.5f; - } - else - { - BlockHardness *= 5.0f; - } - float DigSpeed = GetDigSpeed(a_Block); + // LOGD("Time to mine block = %f", BlockHardness/DigSpeed); // Number of ticks to mine = (20 * BlockHardness)/DigSpeed; // Therefore take inverse to get fraction mined per tick: - return DigSpeed / (20.0f * BlockHardness); + return GetDigSpeed(a_Block) / (20.0f * BlockHardness); } @@ -3252,13 +3246,9 @@ float cPlayer::GetMiningProgressPerTick(BLOCKTYPE a_Block) bool cPlayer::CanInstantlyMine(BLOCKTYPE a_Block) { // Based on: https://minecraft.gamepedia.com/Breaking#Calculation - // Check it has non-zero hardness - if (cBlockInfo::IsOneHitDig(a_Block)) - { - return true; - } - // If the dig speed is greater than 30 times the hardness, then the wiki says we can instantly mine - return GetDigSpeed(a_Block) > 30 * cBlockInfo::GetHardness(a_Block); + + // If the dig speed is greater than 30 times the hardness, then the wiki says we can instantly mine: + return GetDigSpeed(a_Block) > (30 * cBlockInfo::GetHardness(a_Block)); } diff --git a/src/Entities/Player.h b/src/Entities/Player.h index a16a8d0d6..bdcacd608 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -798,6 +798,7 @@ protected: /** Returns the filename for the player data based on the UUID given. This can be used both for online and offline UUIDs. */ AString GetUUIDFileName(const cUUID & a_UUID); + private: /** Pins the player to a_Location until Unfreeze() is called.