$npx -y skills add thedivergentai/GD-Agentic-Skills --skill godot-game-loop-harvestData-driven resource harvesting system (mining, logging, foraging) for Godot 4. Use when implementing gathering mechanics with tool/tier validation, health depletion, item spawning, and persistence.
| 1 | ## Godot 4.7 Baseline |
| 2 | |
| 3 | - Expert patterns in this skill target **Godot 4.7+** (stable, 2026-06-18). |
| 4 | - Consult the [Godot 4.7 migration guide](https://docs.godotengine.org/en/4.7/tutorials/migrating/upgrading_to_godot_4.7.html) when upgrading projects from 4.6. |
| 5 | - **NEVER** assume 4.6 defaults (stretch mode, audio area_mask, RichTextLabel percent flags) without checking 4.7 migration notes. |
| 6 | |
| 7 | # Godot Game Loop: Harvest |
| 8 | |
| 9 | Implement decoupled, data-driven gathering mechanics. This system handles tool validation, depletion, and respawning. |
| 10 | |
| 11 | ## 1. Component Reference |
| 12 | |
| 13 | | Component | Asset | Description | |
| 14 | | :--- | :--- | :--- | |
| 15 | | **Resource Data** | [resource_data.gd](scripts/resource_data.gd) | `Resource`: Defines health, yield, and tool requirements. | |
| 16 | | **Tool Data** | [harvest_tool_data.gd](scripts/harvest_tool_data.gd) | `Resource`: Defines damage, type, and tier. | |
| 17 | | **Harvestable Node** | [harvestable_node.gd](scripts/harvestable_node.gd) | `StaticBody3D`: The world interaction entity. | |
| 18 | | **Respawn Manager** | [harvest_respawn_manager.gd](scripts/harvest_respawn_manager.gd) | `Node`: (Singleton) Manages world persistence. | |
| 19 | | **Inventory Manager**| [harvest_inventory_manager.gd](scripts/harvest_inventory_manager.gd) | `Node`: Hub for resource collection. | |
| 20 | | **Auto-Save Manager**| [harvest_autosave_manager.gd](scripts/harvest_autosave_manager.gd) | `Node`: Interval-based progress safety. | |
| 21 | |
| 22 | ## 2. Implementation Guide |
| 23 | |
| 24 | ### Step 1: Resource Setup |
| 25 | - Create a `HarvestResourceData` resource in the inspector. |
| 26 | - Configure `Required Tool Type` (e.g., "pickaxe", "axe") and `Required Tier`. |
| 27 | - Set `Yield Range` (Vector2i) and optional `Item Scene` for physical drops. |
| 28 | |
| 29 | ### Step 2: Node Configuration |
| 30 | - Attach `harvestable_node.gd` to a `StaticBody3D` node. |
| 31 | - Assign the `ResourceData` from Step 1. |
| 32 | - Assign a child `Node3D` (e.g., a Mesh) to `mesh_to_shake` for visual feedback. |
| 33 | - **Physics**: Ensure the node is on **Layer 1** for interaction. |
| 34 | |
| 35 | ### Step 3: Global Systems (Recommended) |
| 36 | - Add `harvest_respawn_manager.gd` as an **Autoload** named `HarvestRespawnManager`. |
| 37 | - The `HarvestableNode` will automatically use this manager if it is found at `/root/HarvestRespawnManager`. |
| 38 | |
| 39 | ## 3. Interaction & Signals |
| 40 | |
| 41 | ### Calling Hits |
| 42 | When a player interacts (e.g., via RayCast), call `apply_hit(tool_data)`. |
| 43 | |
| 44 | ```gdscript |
| 45 | if collider is HarvestableNode: |
| 46 | collider.apply_hit(player_tool) |
| 47 | ``` |
| 48 | |
| 49 | ### Signal Map |
| 50 | | Signal | Payload | Integration | |
| 51 | | :--- | :--- | :--- | |
| 52 | | `harvested` | `(data, amount)` | Connect to `InventoryManager.add_resource`. | |
| 53 | | `took_damage` | `(curr, max)` | Connect to a Progress Bar or Damage Popups. | |
| 54 | | `interaction_failed`| `(reason: String)` | Handles `"wrong_tool"` or `"low_tier"` UI feedback. | |
| 55 | |
| 56 | ## NEVER Do |
| 57 | |
| 58 | - **NEVER use float variables to store massively accumulated harvest resources** — Large floats lose precision, which can lead to "missing" resources in idle/clicker games. Always use `int` for core counts. |
| 59 | - **NEVER process gathering logic in _process() without multiplying rates by delta** — If you don't use `delta`, the harvesting speed will fluctuate wildly based on the player's hardware performance/framerate. |
| 60 | - **NEVER run heavy array mathematics for thousands of resources on the main thread** — This will cause micro-stutters. Distribute heavy calculations using `WorkerThreadPool`. |
| 61 | - **NEVER leave a gathering game running at full GPU utilization** — For UI-heavy harvest games, enable `OS.low_processor_usage_mode` to drastically reduce battery drain on mobile/laptops. |
| 62 | - **NEVER trust OS.get_ticks_msec() for offline progress** — This only tracks system uptime. Rely on `Time.get_unix_time_from_system()` to calculate real-world time passed between sessions. |
| 63 | - **NEVER use Timer nodes for precise audio-visual harvesting synchronization** — Timer nodes are subject to framerate variations. For frame-perfect sync, use code-based timers or the animation system. |
| 64 | - **NEVER couple your resource logic directly to UI counters** — Use a signal bus or event system to notify the UI of changes, keeping the game logic decoupled from the presentation. |
| 65 | - **NEVER constantly instantiate and destroy Label nodes for "floating numbers"** — Frequent allocation/deallocation leads to memory fragmentation. Use an object pool for damage/harvest popups. |
| 66 | - **NEVER modify a globally shared Resource without calling duplicate()** — If you modify a shared `Resource` (like a base crop yield), every instance using that resource will be updated. Use `duplicate(true)`. |
| 67 | - **NEVER access shared harvest data from background threads without a Mutex** — Simultaneous access will eventually corrupt your inventory data. Always use a `Mutex` to lock sensitive blocks. |
| 68 | - **NEVER hardcode yield values in your gathe |