mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2026-08-15 13:04:36 +00:00
Fix AutoDig mining timing
This commit is contained in:
parent
6331478e30
commit
b74364d465
10 changed files with 1576 additions and 899 deletions
211
.skills/mermaid-diagrams/SKILL.md
Normal file
211
.skills/mermaid-diagrams/SKILL.md
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
---
|
||||
name: mermaid-diagrams
|
||||
description: Creating and refining Mermaid diagrams with live reload. Use when users want flowcharts, sequence diagrams, class diagrams, ER diagrams, state diagrams, or any other Mermaid visualization. Provides best practices for syntax, styling, and the iterative workflow using mermaid_preview and mermaid_save tools.
|
||||
allowed-tools: mcp__mermaid__mermaid_preview, mcp__mermaid__mermaid_save
|
||||
---
|
||||
|
||||
# Mermaid Diagram Expert
|
||||
|
||||
You are an expert at creating, refining, and optimizing Mermaid diagrams using the MCP server tools.
|
||||
|
||||
## Core Workflow
|
||||
|
||||
1. **Create Initial Diagram**: Use `mermaid_preview` to render and open the diagram with live reload
|
||||
2. **Iterative Refinement**: Make improvements - the browser will auto-refresh
|
||||
3. **Save Final Version**: Use `mermaid_save` when satisfied
|
||||
|
||||
## Tool Usage
|
||||
|
||||
### mermaid_preview
|
||||
|
||||
Always use this when creating or updating diagrams:
|
||||
|
||||
- `diagram`: The Mermaid code
|
||||
- `preview_id`: Descriptive kebab-case ID (e.g., `auth-flow`, `architecture`)
|
||||
- `format`: Use `svg` for live reload (default)
|
||||
- `theme`: `default`, `forest`, `dark`, or `neutral`
|
||||
- `background`: `white`, `transparent`, or hex colors
|
||||
- `width`, `height`, `scale`: Adjust for quality/size
|
||||
|
||||
**Key Points:**
|
||||
|
||||
- Reuse the same `preview_id` for refinements to update the same browser tab
|
||||
- Use different IDs for multiple simultaneous diagrams
|
||||
- Live reload only works with SVG format
|
||||
|
||||
### mermaid_save
|
||||
|
||||
Use after the diagram is finalized:
|
||||
|
||||
- `save_path`: Where to save (e.g., `./docs/diagram.svg`)
|
||||
- `preview_id`: Must match the preview ID used earlier
|
||||
- `format`: Must match format from preview
|
||||
|
||||
## Diagram Types
|
||||
|
||||
### Flowcharts (`graph` or `flowchart`)
|
||||
|
||||
Direction: `LR`, `TB`, `RL`, `BT`
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[Start] --> B{Decision}
|
||||
B -->|Yes| C[Action]
|
||||
B -->|No| D[End]
|
||||
|
||||
style A fill:#e1f5ff
|
||||
style C fill:#d4edda
|
||||
```
|
||||
|
||||
### Sequence Diagrams (`sequenceDiagram`)
|
||||
|
||||
⚠️ **Do NOT use `style` statements** - not supported
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant App
|
||||
participant API
|
||||
|
||||
User->>App: Login
|
||||
App->>API: Authenticate
|
||||
API-->>App: Token
|
||||
App-->>User: Success
|
||||
```
|
||||
|
||||
### Class Diagrams (`classDiagram`)
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class User {
|
||||
+String name
|
||||
+String email
|
||||
+login()
|
||||
}
|
||||
class Order {
|
||||
+int id
|
||||
+Date created
|
||||
}
|
||||
User "1" --> "*" Order
|
||||
```
|
||||
|
||||
### Entity Relationship (`erDiagram`)
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
USER ||--o{ ORDER : places
|
||||
ORDER ||--|{ LINE_ITEM : contains
|
||||
|
||||
USER {
|
||||
int id PK
|
||||
string email
|
||||
string name
|
||||
}
|
||||
```
|
||||
|
||||
### State Diagrams (`stateDiagram-v2`)
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Idle
|
||||
Idle --> Processing : start
|
||||
Processing --> Complete : finish
|
||||
Complete --> [*]
|
||||
```
|
||||
|
||||
### Gantt Charts (`gantt`)
|
||||
|
||||
```mermaid
|
||||
gantt
|
||||
title Project Timeline
|
||||
section Phase 1
|
||||
Task 1 :a1, 2024-01-01, 30d
|
||||
Task 2 :after a1, 20d
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Preview IDs
|
||||
|
||||
- Use descriptive names: `architecture`, `auth-flow`, `data-model`
|
||||
- Keep the same ID during refinements
|
||||
- Use different IDs for concurrent diagrams
|
||||
|
||||
### Themes & Styling
|
||||
|
||||
- `default`: Clean, professional
|
||||
- `forest`: Green tones
|
||||
- `dark`: Dark background
|
||||
- `neutral`: Grayscale
|
||||
|
||||
Use `transparent` background for docs, `white` for standalone
|
||||
|
||||
### Common Patterns
|
||||
|
||||
**System Architecture:**
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
Client[Web App]
|
||||
API[API Gateway]
|
||||
DB[(Database)]
|
||||
|
||||
Client --> API --> DB
|
||||
```
|
||||
|
||||
**Authentication Flow:**
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
User->>App: Login Request
|
||||
App->>Auth: Validate
|
||||
Auth-->>App: JWT Token
|
||||
App-->>User: Access Granted
|
||||
```
|
||||
|
||||
## User Interaction
|
||||
|
||||
When a user requests a diagram:
|
||||
|
||||
1. **Clarify if needed**: What type? What level of detail?
|
||||
2. **Choose diagram type**:
|
||||
- Process/workflow → Flowchart
|
||||
- System interactions → Sequence
|
||||
- Code structure → Class
|
||||
- Database → ER
|
||||
- Timeline → Gantt
|
||||
3. **Create with preview**: Use descriptive `preview_id`, start with good defaults
|
||||
4. **Iterate**: Keep same `preview_id`, explain changes
|
||||
5. **Save**: Ask where/what format, use `mermaid_save`
|
||||
|
||||
## Proactive Behavior
|
||||
|
||||
- Always preview diagrams, don't just generate code
|
||||
- Use sensible defaults without asking
|
||||
- Reuse preview_id for refinements
|
||||
- Suggest improvements when you see opportunities
|
||||
- Explain your diagram type choice briefly
|
||||
|
||||
## Common Issues
|
||||
|
||||
**Syntax errors**: Check quotes, arrow syntax, keywords
|
||||
**Layout issues**: Try different directions (LR vs TB)
|
||||
**Text overlap**: Increase dimensions or shorten labels
|
||||
**Colors not working**: Verify CSS color format; remember sequence diagrams don't support styles
|
||||
|
||||
## Example Interaction
|
||||
|
||||
**User**: "Create an auth flow diagram"
|
||||
|
||||
**You**: "I'll create a sequence diagram showing the authentication flow."
|
||||
[Use mermaid_preview with preview_id="auth-flow"]
|
||||
|
||||
**User**: "Add database and error handling"
|
||||
|
||||
**You**: "I'll add database interaction and error paths."
|
||||
[Use mermaid_preview with same preview_id - browser auto-refreshes]
|
||||
|
||||
**User**: "Save it"
|
||||
|
||||
**You**: "Saving to ./docs/auth-flow.svg"
|
||||
[Use mermaid_save]
|
||||
|
|
@ -30,6 +30,12 @@ namespace MinecraftClient.ChatBots
|
|||
[TomlInlineComment("$ChatBot.AutoDig.Auto_Tool_Switch$")]
|
||||
public bool Auto_Tool_Switch = false;
|
||||
|
||||
[TomlInlineComment("$ChatBot.AutoDig.Apply_Efficiency_Enchantments$")]
|
||||
public bool Apply_Efficiency_Enchantments = true;
|
||||
|
||||
[TomlInlineComment("$ChatBot.AutoDig.Apply_Haste_Effects$")]
|
||||
public bool Apply_Haste_Effects = true;
|
||||
|
||||
[TomlInlineComment("$ChatBot.AutoDig.Durability_Limit$")]
|
||||
public int Durability_Limit = 2;
|
||||
|
||||
|
|
@ -322,6 +328,15 @@ namespace MinecraftClient.ChatBots
|
|||
return !IsBelowDurabilityLimit(currentTool);
|
||||
}
|
||||
|
||||
private static MiningCalculator.MiningOptions GetMiningOptions()
|
||||
{
|
||||
return new MiningCalculator.MiningOptions
|
||||
{
|
||||
ApplyEfficiencyEnchantments = Config.Apply_Efficiency_Enchantments,
|
||||
ApplyHasteEffects = Config.Apply_Haste_Effects
|
||||
};
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
lock (stateLock)
|
||||
|
|
@ -393,7 +408,7 @@ namespace MinecraftClient.ChatBots
|
|||
if (!EnsureSuitableTool(block.Type))
|
||||
return false;
|
||||
|
||||
if (DigBlock(blockLoc, Direction.Down, lookAtBlock: false))
|
||||
if (DigBlock(blockLoc, Direction.Down, lookAtBlock: false, miningOptions: GetMiningOptions()))
|
||||
{
|
||||
currentDig = blockLoc;
|
||||
if (Config.Log_Block_Dig)
|
||||
|
|
@ -457,7 +472,7 @@ namespace MinecraftClient.ChatBots
|
|||
if (!EnsureSuitableTool(targetBlock.Type))
|
||||
return false;
|
||||
|
||||
if (DigBlock(target, Direction.Down, lookAtBlock: true))
|
||||
if (DigBlock(target, Direction.Down, lookAtBlock: true, miningOptions: GetMiningOptions()))
|
||||
{
|
||||
currentDig = target;
|
||||
if (Config.Log_Block_Dig)
|
||||
|
|
@ -494,7 +509,7 @@ namespace MinecraftClient.ChatBots
|
|||
if (!EnsureSuitableTool(block.Type))
|
||||
return false;
|
||||
|
||||
if (DigBlock(blockLoc, Direction.Down, lookAtBlock: true))
|
||||
if (DigBlock(blockLoc, Direction.Down, lookAtBlock: true, miningOptions: GetMiningOptions()))
|
||||
{
|
||||
currentDig = blockLoc;
|
||||
if (Config.Log_Block_Dig)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -16,6 +16,15 @@ namespace MinecraftClient.Mapping
|
|||
/// </summary>
|
||||
public static class MiningCalculator
|
||||
{
|
||||
public sealed class MiningOptions
|
||||
{
|
||||
public static readonly MiningOptions Vanilla = new();
|
||||
|
||||
public bool ApplyEfficiencyEnchantments { get; init; } = true;
|
||||
|
||||
public bool ApplyHasteEffects { get; init; } = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of ticks required to break a block in survival mode.
|
||||
/// Returns 0 for instant-break blocks, -1 for unbreakable blocks.
|
||||
|
|
@ -37,8 +46,10 @@ namespace MinecraftClient.Mapping
|
|||
Dictionary<string, double> playerAttributes,
|
||||
bool isUnderwater,
|
||||
bool isOnGround,
|
||||
int protocolVersion)
|
||||
int protocolVersion,
|
||||
MiningOptions? options = null)
|
||||
{
|
||||
options ??= MiningOptions.Vanilla;
|
||||
float hardness = BlockHardness.GetHardness(blockMaterial);
|
||||
|
||||
if (hardness < 0)
|
||||
|
|
@ -49,7 +60,7 @@ namespace MinecraftClient.Mapping
|
|||
|
||||
float destroySpeed = GetDestroySpeed(
|
||||
blockMaterial, heldItem, helmetItem, effects, playerAttributes,
|
||||
isUnderwater, isOnGround, protocolVersion);
|
||||
isUnderwater, isOnGround, protocolVersion, options);
|
||||
|
||||
bool correctTool = HasCorrectToolForDrops(blockMaterial, heldItem, protocolVersion);
|
||||
int divisor = correctTool ? 30 : 100;
|
||||
|
|
@ -73,18 +84,22 @@ namespace MinecraftClient.Mapping
|
|||
Dictionary<string, double> playerAttributes,
|
||||
bool isUnderwater,
|
||||
bool isOnGround,
|
||||
int protocolVersion)
|
||||
int protocolVersion,
|
||||
MiningOptions options)
|
||||
{
|
||||
float speed = GetToolSpeed(blockMaterial, heldItem, protocolVersion);
|
||||
|
||||
if (speed > 1.0f)
|
||||
if (speed > 1.0f && options.ApplyEfficiencyEnchantments)
|
||||
{
|
||||
speed += GetEfficiencyBonus(heldItem, playerAttributes, protocolVersion);
|
||||
}
|
||||
|
||||
if (options.ApplyHasteEffects)
|
||||
{
|
||||
int digSpeedAmplifier = GetDigSpeedAmplifier(effects);
|
||||
if (digSpeedAmplifier >= 0)
|
||||
speed *= 1.0f + (digSpeedAmplifier + 1) * 0.2f;
|
||||
}
|
||||
|
||||
// Mining Fatigue
|
||||
if (effects.TryGetValue(Effects.MiningFatigue, out var fatigueData))
|
||||
|
|
|
|||
|
|
@ -2875,7 +2875,8 @@ namespace MinecraftClient
|
|||
/// <param name="location">Location of block to dig</param>
|
||||
/// <param name="swingArms">Also perform the "arm swing" animation</param>
|
||||
/// <param name="lookAtBlock">Also look at the block before digging</param>
|
||||
public bool DigBlock(Location location, Direction blockFace, bool swingArms = true, bool lookAtBlock = true, double duration = 0)
|
||||
public bool DigBlock(Location location, Direction blockFace, bool swingArms = true, bool lookAtBlock = true,
|
||||
double duration = 0, MiningCalculator.MiningOptions? miningOptions = null)
|
||||
{
|
||||
// TODO select best face from current player location
|
||||
|
||||
|
|
@ -2883,7 +2884,8 @@ namespace MinecraftClient
|
|||
return false;
|
||||
|
||||
if (InvokeRequired)
|
||||
return InvokeOnMainThread(() => DigBlock(location, blockFace, swingArms, lookAtBlock, duration));
|
||||
return InvokeOnMainThread(() => DigBlock(location, blockFace, swingArms, lookAtBlock, duration,
|
||||
miningOptions));
|
||||
|
||||
lock (DigLock)
|
||||
{
|
||||
|
|
@ -2898,10 +2900,12 @@ namespace MinecraftClient
|
|||
UpdateLocation(GetCurrentLocation(), location);
|
||||
|
||||
// Auto-compute dig duration for survival/adventure mode when not explicitly supplied
|
||||
bool autoComputedDuration = false;
|
||||
if (duration <= 0 && protocolversion >= Protocol18Handler.MC_1_8_Version
|
||||
&& gamemode is 0 or 2) // Survival or Adventure
|
||||
{
|
||||
duration = ComputeAutoDigDuration(location);
|
||||
autoComputedDuration = true;
|
||||
duration = ComputeAutoDigDuration(location, miningOptions);
|
||||
}
|
||||
|
||||
// Send dig start and dig end, will need to wait for server response to know dig result
|
||||
|
|
@ -2909,6 +2913,9 @@ namespace MinecraftClient
|
|||
bool result = handler.SendPlayerDigging(0, location, blockFace, sequenceId++)
|
||||
&& (!swingArms || DoAnimation((int)Hand.MainHand));
|
||||
|
||||
if (autoComputedDuration && duration <= 0)
|
||||
return result;
|
||||
|
||||
if (duration <= 0)
|
||||
result &= handler.SendPlayerDigging(2, location, blockFace, sequenceId++);
|
||||
else
|
||||
|
|
@ -2926,7 +2933,7 @@ namespace MinecraftClient
|
|||
/// enchantments, effects, attributes, and player state.
|
||||
/// Returns 0 for instant-break blocks.
|
||||
/// </summary>
|
||||
private double ComputeAutoDigDuration(Location location)
|
||||
private double ComputeAutoDigDuration(Location location, MiningCalculator.MiningOptions? miningOptions = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -2954,16 +2961,49 @@ namespace MinecraftClient
|
|||
playerAttributes,
|
||||
playerPhysics.InWater,
|
||||
playerPhysics.OnGround,
|
||||
protocolversion);
|
||||
protocolversion,
|
||||
miningOptions);
|
||||
|
||||
if (ticks <= 0)
|
||||
if (ticks < 0)
|
||||
return -1;
|
||||
|
||||
if (ticks == 0)
|
||||
return 0;
|
||||
|
||||
return (double)ticks / Settings.ClientTicksPerSecond;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return ComputeConservativeAutoDigDuration(location);
|
||||
}
|
||||
}
|
||||
|
||||
private double ComputeConservativeAutoDigDuration(Location location)
|
||||
{
|
||||
try
|
||||
{
|
||||
Block block = world.GetBlock(location);
|
||||
if (block.Type == Material.Air)
|
||||
return 0;
|
||||
|
||||
int ticks = MiningCalculator.ComputeDigTicks(
|
||||
blockMaterial: block.Type,
|
||||
heldItem: null,
|
||||
helmetItem: null,
|
||||
effects: new(),
|
||||
playerAttributes: new(),
|
||||
isUnderwater: playerPhysics.InWater,
|
||||
isOnGround: playerPhysics.OnGround,
|
||||
protocolVersion: protocolversion);
|
||||
|
||||
if (ticks < 0)
|
||||
return -1;
|
||||
|
||||
return ticks == 0 ? 1.0 : (double)ticks / Settings.ClientTicksPerSecond;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -394,6 +394,24 @@ namespace MinecraftClient {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Apply Efficiency enchantment speed when AutoDig computes mining time. Disable this for strict anti-cheat compatibility..
|
||||
/// </summary>
|
||||
internal static string ChatBot_AutoDig_Apply_Efficiency_Enchantments {
|
||||
get {
|
||||
return ResourceManager.GetString("ChatBot.AutoDig.Apply_Efficiency_Enchantments", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Apply Haste and Conduit Power speed effects when AutoDig computes mining time. Disable this for strict anti-cheat compatibility..
|
||||
/// </summary>
|
||||
internal static string ChatBot_AutoDig_Apply_Haste_Effects {
|
||||
get {
|
||||
return ResourceManager.GetString("ChatBot.AutoDig.Apply_Haste_Effects", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Mining a block for more than "Dig_Timeout" seconds will be considered a timeout..
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -242,6 +242,12 @@ For the naming of the block, please see https://mccteam.github.io/r/block/#L15</
|
|||
<data name="ChatBot.AutoDig.Auto_Tool_Switch" xml:space="preserve">
|
||||
<value>Automatically switch to the appropriate tool.</value>
|
||||
</data>
|
||||
<data name="ChatBot.AutoDig.Apply_Efficiency_Enchantments" xml:space="preserve">
|
||||
<value>Apply Efficiency enchantment speed when AutoDig computes mining time. Disable this for strict anti-cheat compatibility.</value>
|
||||
</data>
|
||||
<data name="ChatBot.AutoDig.Apply_Haste_Effects" xml:space="preserve">
|
||||
<value>Apply Haste and Conduit Power speed effects when AutoDig computes mining time. Disable this for strict anti-cheat compatibility.</value>
|
||||
</data>
|
||||
<data name="ChatBot.AutoDig.Dig_Timeout" xml:space="preserve">
|
||||
<value>Mining a block for more than "Dig_Timeout" seconds will be considered a timeout.</value>
|
||||
</data>
|
||||
|
|
|
|||
|
|
@ -1154,9 +1154,10 @@ namespace MinecraftClient.Scripting
|
|||
/// <param name="swingArms">Also perform the "arm swing" animation</param>
|
||||
/// <param name="lookAtBlock">Also look at the block before digging</param>
|
||||
/// <param name="duration">Dig duration in seconds. 0 = auto-compute for survival, or instant for creative</param>
|
||||
protected bool DigBlock(Location location, Direction direction, bool swingArms = true, bool lookAtBlock = true, double duration = 0)
|
||||
protected bool DigBlock(Location location, Direction direction, bool swingArms = true, bool lookAtBlock = true,
|
||||
double duration = 0, MiningCalculator.MiningOptions? miningOptions = null)
|
||||
{
|
||||
return Handler.DigBlock(location, direction, swingArms, lookAtBlock, duration);
|
||||
return Handler.DigBlock(location, direction, swingArms, lookAtBlock, duration, miningOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -763,6 +763,34 @@ redirectFrom:
|
|||
|
||||
- **Default:** `false`
|
||||
|
||||
#### `Apply_Efficiency_Enchantments`
|
||||
|
||||
- **Description:**
|
||||
|
||||
Include Efficiency enchantments when Auto Dig calculates how long it should wait before finishing a block break.
|
||||
|
||||
Disable this if a server's anti-cheat expects slower mining timing. This only changes MCC's timing calculation; it does not remove the enchantment from your tool.
|
||||
|
||||
- **Available values:** `true` and `false`
|
||||
|
||||
- **Type:** `boolean`
|
||||
|
||||
- **Default:** `true`
|
||||
|
||||
#### `Apply_Haste_Effects`
|
||||
|
||||
- **Description:**
|
||||
|
||||
Include Haste and Conduit Power effects when Auto Dig calculates how long it should wait before finishing a block break.
|
||||
|
||||
Disable this if a server's anti-cheat does not allow the faster timing. This only changes MCC's timing calculation; it does not remove the effect from your player.
|
||||
|
||||
- **Available values:** `true` and `false`
|
||||
|
||||
- **Type:** `boolean`
|
||||
|
||||
- **Default:** `true`
|
||||
|
||||
#### `Durability_Limit`
|
||||
|
||||
- **Description:**
|
||||
|
|
|
|||
87
tools/verify_mining_data.py
Normal file
87
tools/verify_mining_data.py
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Verify representative mining hardness and tool-requirement data."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
BLOCK_HARDNESS = REPO_ROOT / "MinecraftClient" / "Mapping" / "BlockHardness.cs"
|
||||
|
||||
EXPECTED_HARDNESS = {
|
||||
"AcaciaLog": 2.0,
|
||||
"Bedrock": -1.0,
|
||||
"Cobblestone": 2.0,
|
||||
"CopperOre": 3.0,
|
||||
"CutCopper": 3.0,
|
||||
"DeepslateBricks": 3.5,
|
||||
"Stone": 1.5,
|
||||
"StoneButton": 0.5,
|
||||
"Torch": 0.0,
|
||||
"WaxedCutCopperStairs": 3.0,
|
||||
}
|
||||
|
||||
EXPECTED_REQUIRES_TOOL = {
|
||||
"AcaciaLog": False,
|
||||
"CopperOre": True,
|
||||
"CutCopper": True,
|
||||
"DeepslateBricks": True,
|
||||
"Stone": True,
|
||||
"StoneButton": False,
|
||||
"WaxedCutCopperStairs": True,
|
||||
}
|
||||
|
||||
|
||||
def parse_hardness(source: str) -> dict[str, float]:
|
||||
return {
|
||||
material: float(value)
|
||||
for material, value in re.findall(
|
||||
r"\{\s*Material\.([A-Za-z0-9_]+),\s*(-?[0-9]+(?:\.[0-9]+)?)f\s*\}",
|
||||
source,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def parse_requires_tool(source: str) -> set[str]:
|
||||
set_match = re.search(
|
||||
r"RequiresCorrectToolSet\s*=\s*new HashSet<Material>\s*\{(?P<body>.*?)\}\.ToFrozenSet\(\)",
|
||||
source,
|
||||
re.S,
|
||||
)
|
||||
if set_match is None:
|
||||
raise AssertionError("Could not find RequiresCorrectToolSet")
|
||||
|
||||
return set(re.findall(r"Material\.([A-Za-z0-9_]+)", set_match.group("body")))
|
||||
|
||||
|
||||
def main() -> int:
|
||||
source = BLOCK_HARDNESS.read_text()
|
||||
hardness = parse_hardness(source)
|
||||
requires_tool = parse_requires_tool(source)
|
||||
|
||||
failures: list[str] = []
|
||||
|
||||
for material, expected in EXPECTED_HARDNESS.items():
|
||||
actual = hardness.get(material)
|
||||
if actual != expected:
|
||||
failures.append(f"{material} hardness: expected {expected}, got {actual}")
|
||||
|
||||
for material, expected in EXPECTED_REQUIRES_TOOL.items():
|
||||
actual = material in requires_tool
|
||||
if actual != expected:
|
||||
failures.append(f"{material} requires tool: expected {expected}, got {actual}")
|
||||
|
||||
if failures:
|
||||
print("Mining data verification failed:")
|
||||
for failure in failures:
|
||||
print(f" - {failure}")
|
||||
return 1
|
||||
|
||||
print("Mining data verification passed.")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Loading…
Add table
Add a link
Reference in a new issue