From d158bfdf21a7b8b9c6df90e159c09db0c3166395 Mon Sep 17 00:00:00 2001 From: Anon Date: Mon, 30 Mar 2026 20:20:58 +0200 Subject: [PATCH] Fixed bugs --- MinecraftClient/Mapping/BlockHardness.cs | 4 +- MinecraftClient/Mapping/MiningCalculator.cs | 199 ++++++++++++++------ 2 files changed, 141 insertions(+), 62 deletions(-) diff --git a/MinecraftClient/Mapping/BlockHardness.cs b/MinecraftClient/Mapping/BlockHardness.cs index 311507b0..84cd8f92 100644 --- a/MinecraftClient/Mapping/BlockHardness.cs +++ b/MinecraftClient/Mapping/BlockHardness.cs @@ -249,8 +249,8 @@ namespace MinecraftClient.Mapping { Material.NetherSprouts, 0.0f }, { Material.NetherWart, 0.0f }, { Material.OakButton, 0.0f }, - { Material.OakLeaves, 0.0f }, - { Material.OakLog, 0.0f }, + { Material.OakLeaves, 0.2f }, + { Material.OakLog, 2.0f }, { Material.OakSapling, 0.0f }, { Material.OpenEyeblossom, 0.0f }, { Material.OrangeCandle, 0.0f }, diff --git a/MinecraftClient/Mapping/MiningCalculator.cs b/MinecraftClient/Mapping/MiningCalculator.cs index 38cf6d18..6f49fd4a 100644 --- a/MinecraftClient/Mapping/MiningCalculator.cs +++ b/MinecraftClient/Mapping/MiningCalculator.cs @@ -1,9 +1,12 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using MinecraftClient.Inventory; using MinecraftClient.Protocol.Handlers; using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6; +using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_5; +using MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents._1_20_6; namespace MinecraftClient.Mapping { @@ -74,27 +77,14 @@ namespace MinecraftClient.Mapping { float speed = GetToolSpeed(blockMaterial, heldItem, protocolVersion); - if (protocolVersion >= Protocol18Handler.MC_1_21_11_Version) + if (speed > 1.0f) { - // 1.21.11+: Efficiency is delivered via the MINING_EFFICIENCY attribute - if (speed > 1.0f && playerAttributes.TryGetValue("player.mining_efficiency", out double miningEff)) - speed += (float)miningEff; - } - else - { - // Pre-1.21.11: Efficiency enchantment adds level^2 + 1 - int effLevel = GetEnchantmentLevel(heldItem, Enchantments.Efficiency, protocolVersion); - if (speed > 1.0f && effLevel > 0) - speed += effLevel * effLevel + 1; + speed += GetEfficiencyBonus(heldItem, playerAttributes, protocolVersion); } - // Haste effect: multiply by 1 + 0.2 * (amplifier + 1) - if (effects.TryGetValue(Effects.Haste, out var hasteData)) - speed *= 1.0f + (hasteData.Amplifier + 1) * 0.2f; - - // Conduit Power also grants dig speed equivalent when in water - if (effects.TryGetValue(Effects.ConduitPower, out var conduitData)) - speed *= 1.0f + (conduitData.Amplifier + 1) * 0.2f; + int digSpeedAmplifier = GetDigSpeedAmplifier(effects); + if (digSpeedAmplifier >= 0) + speed *= 1.0f + (digSpeedAmplifier + 1) * 0.2f; // Mining Fatigue if (effects.TryGetValue(Effects.MiningFatigue, out var fatigueData)) @@ -155,19 +145,19 @@ namespace MinecraftClient.Mapping return 1.0f; // Modern path: use ToolComponent from structured components - if (protocolVersion >= Protocol18Handler.MC_1_20_6_Version) + if (protocolVersion >= Protocol18Handler.MC_1_20_6_Version + && TryGetToolRules(heldItem, out List? rules, out float defaultMiningSpeed)) { - var toolComp = heldItem.Components?.OfType().FirstOrDefault(); - if (toolComp is not null) + foreach (var rule in rules) { - // Check rules for matching blocks - foreach (var rule in toolComp.Rules) - { - if (rule.HasSpeed && MatchesBlockSet(rule.Blocks, blockMaterial)) - return rule.Speed; - } - return toolComp.DefaultMiningSpeed; + if (rule.HasSpeed && MatchesBlockSet(rule.Blocks, blockMaterial)) + return rule.Speed; } + + // Structured tool data covers modern mining rules, but keep the legacy fallback for + // explicit block holder-sets that MCC cannot resolve yet (for example cobweb). + if (defaultMiningSpeed > 1.0f) + return defaultMiningSpeed; } // Legacy path: hardcoded tool speed tables @@ -186,25 +176,48 @@ namespace MinecraftClient.Mapping return false; // Modern path: check ToolComponent rules - if (protocolVersion >= Protocol18Handler.MC_1_20_6_Version) + if (protocolVersion >= Protocol18Handler.MC_1_20_6_Version + && TryGetToolRules(heldItem, out List? rules, out _)) { - var toolComp = heldItem.Components?.OfType().FirstOrDefault(); - if (toolComp is not null) + foreach (var rule in rules) { - foreach (var rule in toolComp.Rules) - { - if (rule.HasCorrectDropForBlocks && rule.CorrectDropForBlocks - && MatchesBlockSet(rule.Blocks, blockMaterial)) - return true; - } + if (rule.HasCorrectDropForBlocks && MatchesBlockSet(rule.Blocks, blockMaterial)) + return rule.CorrectDropForBlocks; } - return false; } - // Legacy path: check if Material2Tool recommends this tool type + // Legacy path, plus a modern fallback for direct block holder-sets MCC cannot resolve yet. return IsCorrectToolLegacy(heldItem.Type, blockMaterial); } + private static bool TryGetToolRules( + Item heldItem, + [NotNullWhen(true)] out List? rules, + out float defaultMiningSpeed) + { + rules = null; + defaultMiningSpeed = 1.0f; + + if (heldItem.Components is null) + return false; + + if (heldItem.Components.OfType().FirstOrDefault() is ToolComponent toolComponent) + { + rules = toolComponent.Rules; + defaultMiningSpeed = toolComponent.DefaultMiningSpeed; + return true; + } + + if (heldItem.Components.OfType().FirstOrDefault() is ToolComponent1215 toolComponent1215) + { + rules = toolComponent1215.Rules; + defaultMiningSpeed = toolComponent1215.DefaultMiningSpeed; + return true; + } + + return false; + } + /// /// Match a block material against a ToolComponent BlockSetSubcomponent. /// @@ -241,20 +254,34 @@ namespace MinecraftClient.Mapping string tag = tagName.Replace("minecraft:", ""); ItemType[] tools = Material2Tool.GetCorrectToolForBlock(blockMaterial); - if (tools.Length == 0) - return false; - - ItemType firstTool = tools[0]; return tag switch { - "mineable/pickaxe" => IsPickaxe(firstTool), - "mineable/axe" => IsAxe(firstTool), - "mineable/shovel" => IsShovel(firstTool), - "mineable/hoe" => IsHoe(firstTool), + "mineable/pickaxe" => tools.Length > 0 && IsPickaxe(tools[0]), + "mineable/axe" => tools.Length > 0 && IsAxe(tools[0]), + "mineable/shovel" => tools.Length > 0 && IsShovel(tools[0]), + "mineable/hoe" => tools.Length > 0 && IsHoe(tools[0]), + "leaves" => IsLeaf(blockMaterial), + "wool" => IsWool(blockMaterial), + "incorrect_for_wooden_tool" => RequiresHigherTier(blockMaterial, 0), + "incorrect_for_gold_tool" => RequiresHigherTier(blockMaterial, 0), + "incorrect_for_stone_tool" => RequiresHigherTier(blockMaterial, 1), + "incorrect_for_copper_tool" => RequiresHigherTier(blockMaterial, 1), + "incorrect_for_iron_tool" => RequiresHigherTier(blockMaterial, 2), + "incorrect_for_diamond_tool" => RequiresHigherTier(blockMaterial, 3), + "incorrect_for_netherite_tool" => RequiresHigherTier(blockMaterial, 4), _ => false }; } + private static bool RequiresHigherTier(Material blockMaterial, int tier) + { + ItemType[] recommended = Material2Tool.GetCorrectToolForBlock(blockMaterial); + if (recommended.Length == 0) + return false; + + return GetRequiredTier(blockMaterial, recommended) > tier; + } + /// /// Get the enchantment level from an item, supporting both legacy NBT and modern structured components. /// @@ -330,6 +357,16 @@ namespace MinecraftClient.Mapping /// private static float GetLegacyToolSpeed(ItemType toolType, Material blockMaterial) { + float specialToolSpeed = toolType switch + { + ItemType.Shears => GetShearsSpeed(blockMaterial), + _ when IsSword(toolType) && blockMaterial == Material.Cobweb => 15.0f, + _ => 1.0f + }; + + if (specialToolSpeed > 1.0f) + return specialToolSpeed; + ItemType[] recommended = Material2Tool.GetCorrectToolForBlock(blockMaterial); if (recommended.Length == 0) return 1.0f; @@ -339,14 +376,7 @@ namespace MinecraftClient.Mapping ToolCategory neededCategory = GetToolCategory(recommended[0]); if (heldCategory == ToolCategory.None || heldCategory != neededCategory) - { - // Special cases: sword on cobweb, shears on specific blocks - if (toolType is ItemType.Shears && IsShearable(blockMaterial)) - return 1.5f; - if (IsSword(toolType) && blockMaterial == Material.Cobweb) - return 15.0f; return 1.0f; - } return GetBaseToolSpeed(toolType); } @@ -400,7 +430,13 @@ namespace MinecraftClient.Mapping ToolCategory neededCategory = GetToolCategory(recommended[0]); if (heldCategory == ToolCategory.None || heldCategory != neededCategory) + { + if (toolType == ItemType.Shears && blockMaterial == Material.Cobweb) + return true; + if (IsSword(toolType) && blockMaterial == Material.Cobweb) + return true; return false; + } // Check tool tier requirement int heldTier = GetToolTier(toolType); @@ -476,17 +512,60 @@ namespace MinecraftClient.Mapping item is ItemType.WoodenSword or ItemType.StoneSword or ItemType.IronSword or ItemType.GoldenSword or ItemType.DiamondSword or ItemType.NetheriteSword; + private static float GetShearsSpeed(Material block) + { + return block switch + { + Material.Cobweb => 15.0f, + Material.Vine or Material.GlowLichen => 2.0f, + _ when IsLeaf(block) => 15.0f, + _ when IsWool(block) => 5.0f, + _ => 1.0f + }; + } + private static bool IsShearable(Material block) => - block is Material.Cobweb or Material.OakLeaves or Material.SpruceLeaves - or Material.BirchLeaves or Material.JungleLeaves or Material.AcaciaLeaves - or Material.DarkOakLeaves or Material.CherryLeaves or Material.MangroveLeaves - or Material.AzaleaLeaves or Material.FloweringAzaleaLeaves - or Material.WhiteWool or Material.OrangeWool or Material.MagentaWool + block == Material.Cobweb || IsLeaf(block) || IsWool(block) || block is Material.Vine or Material.GlowLichen; + + private static bool IsLeaf(Material block) => + block is Material.OakLeaves or Material.SpruceLeaves or Material.BirchLeaves + or Material.JungleLeaves or Material.AcaciaLeaves or Material.DarkOakLeaves + or Material.CherryLeaves or Material.MangroveLeaves or Material.AzaleaLeaves + or Material.FloweringAzaleaLeaves or Material.PaleOakLeaves; + + private static bool IsWool(Material block) => + block is Material.WhiteWool or Material.OrangeWool or Material.MagentaWool or Material.LightBlueWool or Material.YellowWool or Material.LimeWool or Material.PinkWool or Material.GrayWool or Material.LightGrayWool or Material.CyanWool or Material.PurpleWool or Material.BlueWool or Material.BrownWool or Material.GreenWool or Material.RedWool - or Material.BlackWool or Material.Vine; + or Material.BlackWool; + + private static float GetEfficiencyBonus(Item? heldItem, Dictionary playerAttributes, int protocolVersion) + { + if (protocolVersion >= Protocol18Handler.MC_1_21_11_Version + && playerAttributes.TryGetValue("player.mining_efficiency", out double miningEfficiency) + && miningEfficiency > 0.0) + { + return (float)miningEfficiency; + } + + int efficiencyLevel = GetEnchantmentLevel(heldItem, Enchantments.Efficiency, protocolVersion); + return efficiencyLevel > 0 ? efficiencyLevel * efficiencyLevel + 1 : 0.0f; + } + + private static int GetDigSpeedAmplifier(Dictionary effects) + { + int amplifier = -1; + + if (effects.TryGetValue(Effects.Haste, out var hasteData)) + amplifier = Math.Max(amplifier, hasteData.Amplifier); + + if (effects.TryGetValue(Effects.ConduitPower, out var conduitData)) + amplifier = Math.Max(amplifier, conduitData.Amplifier); + + return amplifier; + } #endregion }