From cd1b50774512e09736b78df025163ab9b26bd528 Mon Sep 17 00:00:00 2001 From: KingCol13 <48412633+KingCol13@users.noreply.github.com> Date: Fri, 2 Oct 2020 23:57:17 +0300 Subject: Fix instant mining of blocks not being recognised, tweak anti-cheat (#4938) * Tried to fix a small issue... Ended up rewriting a bunch of god awful, opaque code with no source and no sense. Who names a function GetPlayerRelativeBlockHardness??? It's gone now. We're safe again. * Testing anti-cheat. * Tidy up debug logging. * Remove empty member declaration. * Rewrite GetDigSpeed slightly for better readability. * GetMiningProgressPerTick now returns 1 when instantly mined. Fixed hasily written typo. * Comment style and typo fixes. --- src/Entities/Player.cpp | 86 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 19 deletions(-) (limited to 'src/Entities/Player.cpp') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index d7455f371..d0d729567 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -3156,61 +3156,109 @@ bool cPlayer::IsInsideWater() float cPlayer::GetDigSpeed(BLOCKTYPE a_Block) { - float f = GetEquippedItem().GetHandler()->GetBlockBreakingStrength(a_Block); - if (f > 1.0f) + // Based on: https://minecraft.gamepedia.com/Breaking#Speed + + // Get the base speed multiplier of the equipped tool for the mined block + float MiningSpeed = GetEquippedItem().GetHandler()->GetBlockBreakingStrength(a_Block); + + // If we can harvest the block then we can apply material and enchantment bonuses + if (GetEquippedItem().GetHandler()->CanHarvestBlock(a_Block)) { - unsigned int efficiencyModifier = GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::eEnchantment::enchEfficiency); - if (efficiencyModifier > 0) + if (MiningSpeed > 1.0f) // If the base multiplier for this block is greater than 1, now we can check enchantments { - f += (efficiencyModifier * efficiencyModifier) + 1; + unsigned int EfficiencyModifier = GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::eEnchantment::enchEfficiency); + if (EfficiencyModifier > 0) // If an efficiency enchantment is present, apply formula as on wiki + { + MiningSpeed += (EfficiencyModifier * EfficiencyModifier) + 1; + } } } + else // If we can't harvest the block then no bonuses: + { + MiningSpeed = 1; + } + // Haste increases speed by 20% per level auto Haste = GetEntityEffect(cEntityEffect::effHaste); if (Haste != nullptr) { int intensity = Haste->GetIntensity() + 1; - f *= 1.0f + (intensity * 0.2f); + MiningSpeed *= 1.0f + (intensity * 0.2f); } + // Mining fatigue decreases speed a lot auto MiningFatigue = GetEntityEffect(cEntityEffect::effMiningFatigue); if (MiningFatigue != nullptr) { int intensity = MiningFatigue->GetIntensity(); switch (intensity) { - case 0: f *= 0.3f; break; - case 1: f *= 0.09f; break; - case 2: f *= 0.0027f; break; - default: f *= 0.00081f; break; + case 0: MiningSpeed *= 0.3f; break; + case 1: MiningSpeed *= 0.09f; break; + case 2: MiningSpeed *= 0.0027f; break; + default: MiningSpeed *= 0.00081f; break; } } + // 5x speed loss for being in water if (IsInsideWater() && !(GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::eEnchantment::enchAquaAffinity) > 0)) { - f /= 5.0f; + MiningSpeed /= 5.0f; } + // 5x speed loss for not touching ground if (!IsOnGround()) { - f /= 5.0f; + MiningSpeed /= 5.0f; } - return f; + return MiningSpeed; } -float cPlayer::GetPlayerRelativeBlockHardness(BLOCKTYPE a_Block) +float cPlayer::GetMiningProgressPerTick(BLOCKTYPE a_Block) { - float blockHardness = cBlockInfo::GetHardness(a_Block); - float digSpeed = GetDigSpeed(a_Block); - float canHarvestBlockDivisor = GetEquippedItem().GetHandler()->CanHarvestBlock(a_Block) ? 30.0f : 100.0f; - // LOGD("blockHardness: %f, digSpeed: %f, canHarvestBlockDivisor: %f\n", blockHardness, digSpeed, canHarvestBlockDivisor); - return (blockHardness < 0) ? 0 : ((digSpeed / blockHardness) / canHarvestBlockDivisor); + // Based on https://minecraft.gamepedia.com/Breaking#Calculation + // If we know it's instantly breakable then quit here: + if (cBlockInfo::IsOneHitDig(a_Block)) + { + return 1; + } + float BlockHardness = cBlockInfo::GetHardness(a_Block); + ASSERT(BlockHardness > 0); // Can't divide by 0 or less, IsOneHitDig should have returned true + if (GetEquippedItem().GetHandler()->CanHarvestBlock(a_Block)) + { + BlockHardness*=1.5; + } + else + { + BlockHardness*=5; + } + 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 * BlockHardness); +} + + + + + +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); } -- cgit v1.2.3