Add automatic mining-speed and dig-duration handling

- Add BlockHardness.cs with hardness data for all 1053 blocks from MC 1.21.11
- Add MiningCalculator.cs with version-aware dig duration computation
  - Tool speed from ToolComponent (1.20.6+) or legacy hardcoded tables
  - Efficiency enchantment (legacy: level^2+1, 1.21.11+: mining_efficiency attribute)
  - Haste/Conduit Power/Mining Fatigue effects
  - BLOCK_BREAK_SPEED attribute (1.20.6+)
  - MINING_EFFICIENCY and SUBMERGED_MINING_SPEED attributes (1.21.11+)
  - Underwater penalty with Aqua Affinity support (legacy) or attribute (modern)
  - Airborne penalty
  - Correct tool for drops check (30 vs 100 divisor)
- Modify McClient.DigBlock to auto-compute duration for survival/adventure mode
- Cache player attributes from OnEntityProperties in McClient
- Expose duration parameter in ChatBot.cs scripting wrapper
- Add /downloads/ to .gitignore

Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/579df446-a335-4174-9a8b-4d66173c82b1

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-03-30 08:24:00 +00:00
parent c95fe131e3
commit 22455905a7
5 changed files with 1882 additions and 2 deletions

View file

@ -107,6 +107,9 @@ namespace MinecraftClient
// player effects
private readonly Dictionary<Effects, EffectData> playerEffects = new();
// player attributes (e.g., block_break_speed, mining_efficiency, submerged_mining_speed)
private readonly Dictionary<string, double> playerAttributes = new();
// Sneaking
public bool IsSneaking { get; set; } = false;
@ -2591,6 +2594,13 @@ namespace MinecraftClient
if (lookAtBlock)
UpdateLocation(GetCurrentLocation(), location);
// Auto-compute dig duration for survival/adventure mode when not explicitly supplied
if (duration <= 0 && protocolversion >= Protocol18Handler.MC_1_8_Version
&& gamemode is 0 or 2) // Survival or Adventure
{
duration = ComputeAutoDigDuration(location);
}
// Send dig start and dig end, will need to wait for server response to know dig result
// See https://wiki.vg/How_to_Write_a_Client#Digging for more details
bool result = handler.SendPlayerDigging(0, location, blockFace, sequenceId++)
@ -2608,6 +2618,52 @@ namespace MinecraftClient
}
}
/// <summary>
/// Compute the automatic dig duration in seconds for a block, based on held tool,
/// enchantments, effects, attributes, and player state.
/// Returns 0 for instant-break blocks.
/// </summary>
private double ComputeAutoDigDuration(Location location)
{
try
{
Block block = world.GetBlock(location);
Material blockMaterial = block.Type;
if (blockMaterial == Material.Air)
return 0;
// Get held item from player inventory
Item? heldItem = null;
Item? helmetItem = null;
if (inventories.TryGetValue(0, out var playerInv))
{
int hotbarSlot = 36 + CurrentSlot; // Hotbar slots are 36-44
playerInv.Items.TryGetValue(hotbarSlot, out heldItem);
playerInv.Items.TryGetValue(5, out helmetItem); // Slot 5 = helmet
}
int ticks = MiningCalculator.ComputeDigTicks(
blockMaterial,
heldItem,
helmetItem,
playerEffects,
playerAttributes,
playerPhysics.InWater,
playerPhysics.OnGround,
protocolversion);
if (ticks <= 0)
return 0;
return (double)ticks / Settings.ClientTicksPerSecond;
}
catch
{
return 0;
}
}
/// <summary>
/// Change active slot in the player inventory
/// </summary>
@ -3712,6 +3768,9 @@ namespace MinecraftClient
{
if (EntityID == playerEntityID)
{
foreach (var kvp in prop)
playerAttributes[kvp.Key] = kvp.Value;
DispatchBotEvent(bot => bot.OnPlayerProperty(prop));
}
}