Просмотр исходного кода

重构世界系统并清理旧素材

- 重写 world_system.lua(849 行变更)
- 删除旧 foliage 等素材,新增字体与 sphere.glsl
- 多处系统文件清理调整

Co-Authored-By: Claude <noreply@anthropic.com>
nonvioce 2 месяцев назад
Родитель
Сommit
c38ff1b7a1
100 измененных файлов с 292 добавлено и 1627 удалено
  1. 0 8
      app/src/embed/assets/.busted
  2. 0 0
      app/src/embed/assets/.gitkeep
  3. 0 198
      app/src/embed/assets/.kiro/settings/lsp.json
  4. 0 1
      app/src/embed/assets/.kiro/specs/layered-architecture-refactor/.config.kiro
  5. 0 884
      app/src/embed/assets/.kiro/specs/layered-architecture-refactor/design.md
  6. 0 166
      app/src/embed/assets/.kiro/specs/layered-architecture-refactor/requirements.md
  7. 0 186
      app/src/embed/assets/.kiro/specs/layered-architecture-refactor/tasks.md
  8. 292 184
      app/src/embed/assets/README.md
  9. 0 0
      app/src/embed/assets/VonwaonBitmap-16px.ttf
  10. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_big_cactus_02.png
  11. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_big_cactus_03.png
  12. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_big_cactus_04.png
  13. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_big_flower_01.png
  14. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Agave_Cactus_01.png
  15. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Agave_Cactus_02.png
  16. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Agave_Cactus_03.png
  17. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Agave_Cactus_04.png
  18. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Bush_01.png
  19. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Bush_02.png
  20. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_02.png
  21. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_03.png
  22. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_04.png
  23. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_05.png
  24. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_06.png
  25. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_07.png
  26. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_09.png
  27. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_10.png
  28. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_11.png
  29. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_12.png
  30. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_13.png
  31. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_14.png
  32. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_15.png
  33. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Flower_01.png
  34. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Flower_02.png
  35. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Flower_03.png
  36. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Flower_04.png
  37. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_big_cypress_01.png
  38. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_big_cypress_02.png
  39. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_big_cypress_03.png
  40. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_big_stone_01.png
  41. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_big_stone_02.png
  42. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_big_tree_leaf_01.png
  43. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_big_tree_needle_03.png
  44. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_big_tree_needle_04.png
  45. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_deadBush (3).png
  46. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_deadTree (1).png
  47. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_deadTree (2).png
  48. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_deadTree (4).png
  49. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_deadbush(5).png
  50. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_bush_01.png
  51. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_bush_02.png
  52. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_clover_01.png
  53. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_clover_02.png
  54. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_clover_03.png
  55. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_fern_01.png
  56. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_fern_02.png
  57. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_flower_01.png
  58. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_flower_02.png
  59. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_flower_03.png
  60. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_grass_01.png
  61. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_grass_02.png
  62. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_grass_03.png
  63. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_grass_04.png
  64. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_grass_05.png
  65. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_grass_06.png
  66. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_grass_07.png
  67. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_grass_08.png
  68. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_mushroom_01.png
  69. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_mushroom_02.png
  70. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_mushroom_03.png
  71. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_mushroom_04.png
  72. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_tree_log_01.png
  73. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_tree_log_02.png
  74. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_tree_log_03.png
  75. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_tree_stump_01.png
  76. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_tree_stump_02.png
  77. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_tree_stump_03.png
  78. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_bamboo (1).png
  79. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_bamboo (2).png
  80. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_bamboo (3).png
  81. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_bamboo (4).png
  82. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_bamboo (5).png
  83. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_bamboo (6).png
  84. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_bamboo (7).png
  85. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_bamboo (8).png
  86. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_desert_skull_01.png
  87. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_desert_skull_02.png
  88. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_desert_skull_03.png
  89. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_forest_berrybush.png
  90. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_forest_bush (4).png
  91. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_forest_bush (5).png
  92. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_reed (1).png
  93. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_reed (2).png
  94. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_reed (3).png
  95. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_reed (4).png
  96. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_reed (5).png
  97. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_reed (6).png
  98. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_reed (7).png
  99. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_reed (8).png
  100. BIN
      app/src/embed/assets/assets/foliage/GSS_Foliage_stone (1).png

+ 0 - 8
app/src/embed/assets/.busted

@@ -1,8 +0,0 @@
-return {
-  default = {
-    lua        = "lua",
-    pattern    = "_spec",
-    ROOT       = {"spec"},
-    ["lua-path"] = "./?.lua",
-  },
-}

+ 0 - 0
app/src/embed/assets/.gitkeep


+ 0 - 198
app/src/embed/assets/.kiro/settings/lsp.json

@@ -1,198 +0,0 @@
-{
-  "languages": {
-    "python": {
-      "name": "pyright",
-      "command": "pyright-langserver",
-      "args": [
-        "--stdio"
-      ],
-      "file_extensions": [
-        "py"
-      ],
-      "project_patterns": [
-        "pyproject.toml",
-        "setup.py",
-        "requirements.txt",
-        "pyrightconfig.json"
-      ],
-      "exclude_patterns": [
-        "**/__pycache__/**",
-        "**/venv/**",
-        "**/.venv/**",
-        "**/.pytest_cache/**"
-      ],
-      "multi_workspace": false,
-      "initialization_options": {},
-      "request_timeout_secs": 60
-    },
-    "java": {
-      "name": "jdtls",
-      "command": "jdtls",
-      "args": [],
-      "file_extensions": [
-        "java"
-      ],
-      "project_patterns": [
-        "pom.xml",
-        "build.gradle",
-        "build.gradle.kts",
-        ".project"
-      ],
-      "exclude_patterns": [
-        "**/target/**",
-        "**/build/**",
-        "**/.gradle/**"
-      ],
-      "multi_workspace": false,
-      "initialization_options": {
-        "settings": {
-          "java": {
-            "compile": {
-              "nullAnalysis": {
-                "mode": "automatic"
-              }
-            },
-            "configuration": {
-              "annotationProcessing": {
-                "enabled": true
-              }
-            }
-          }
-        }
-      },
-      "request_timeout_secs": 60
-    },
-    "go": {
-      "name": "gopls",
-      "command": "gopls",
-      "args": [],
-      "file_extensions": [
-        "go"
-      ],
-      "project_patterns": [
-        "go.mod",
-        "go.sum"
-      ],
-      "exclude_patterns": [
-        "**/vendor/**"
-      ],
-      "multi_workspace": false,
-      "initialization_options": {
-        "usePlaceholders": true,
-        "completeUnimported": true
-      },
-      "request_timeout_secs": 60
-    },
-    "cpp": {
-      "name": "clangd",
-      "command": "clangd",
-      "args": [
-        "--background-index"
-      ],
-      "file_extensions": [
-        "cpp",
-        "cc",
-        "cxx",
-        "c",
-        "h",
-        "hpp",
-        "hxx"
-      ],
-      "project_patterns": [
-        "CMakeLists.txt",
-        "compile_commands.json",
-        "Makefile"
-      ],
-      "exclude_patterns": [
-        "**/build/**",
-        "**/cmake-build-**/**"
-      ],
-      "multi_workspace": false,
-      "initialization_options": {},
-      "request_timeout_secs": 60
-    },
-    "typescript": {
-      "name": "typescript-language-server",
-      "command": "typescript-language-server",
-      "args": [
-        "--stdio"
-      ],
-      "file_extensions": [
-        "ts",
-        "js",
-        "tsx",
-        "jsx"
-      ],
-      "project_patterns": [
-        "package.json",
-        "tsconfig.json"
-      ],
-      "exclude_patterns": [
-        "**/node_modules/**",
-        "**/dist/**"
-      ],
-      "multi_workspace": false,
-      "initialization_options": {
-        "preferences": {
-          "disableSuggestions": false
-        }
-      },
-      "request_timeout_secs": 60
-    },
-    "rust": {
-      "name": "rust-analyzer",
-      "command": "rust-analyzer",
-      "args": [],
-      "file_extensions": [
-        "rs"
-      ],
-      "project_patterns": [
-        "Cargo.toml"
-      ],
-      "exclude_patterns": [
-        "**/target/**"
-      ],
-      "multi_workspace": false,
-      "initialization_options": {
-        "cargo": {
-          "buildScripts": {
-            "enable": true
-          }
-        },
-        "diagnostics": {
-          "enable": true,
-          "enableExperimental": true
-        },
-        "workspace": {
-          "symbol": {
-            "search": {
-              "scope": "workspace"
-            }
-          }
-        }
-      },
-      "request_timeout_secs": 60
-    },
-    "ruby": {
-      "name": "solargraph",
-      "command": "solargraph",
-      "args": [
-        "stdio"
-      ],
-      "file_extensions": [
-        "rb"
-      ],
-      "project_patterns": [
-        "Gemfile",
-        "Rakefile"
-      ],
-      "exclude_patterns": [
-        "**/vendor/**",
-        "**/tmp/**"
-      ],
-      "multi_workspace": false,
-      "initialization_options": {},
-      "request_timeout_secs": 60
-    }
-  }
-}

+ 0 - 1
app/src/embed/assets/.kiro/specs/layered-architecture-refactor/.config.kiro

@@ -1 +0,0 @@
-{"specId": "35f356fd-aba0-4b40-a8d8-502ef1cc78c2", "workflowType": "requirements-first", "specType": "feature"}

+ 0 - 884
app/src/embed/assets/.kiro/specs/layered-architecture-refactor/design.md

@@ -1,884 +0,0 @@
-# 技术设计文档:分层架构重构
-
-## 概述
-
-本文档描述对 LÖVE2D Lua 农场游戏进行分层架构重构的技术方案。
-
-### 当前问题
-
-| 问题 | 位置 | 影响 |
-|------|------|------|
-| 上帝对象 | `game.lua` | 同时持有 systems 层和 render 层引用,承担过多职责 |
-| 反向依赖 | `render/ui_renderer.lua` | 顶层 `require("systems/farm")`、`require("systems/state")` |
-| 跨层调用 | `systems/player.lua` | 通过注入的 `_world` 变量调用 `WorldRenderer` 方法 |
-| love 直接调用 | `render/` 所有文件 | 直接调用 `love.graphics.*`,无法在无 LÖVE 环境下测试渲染逻辑 |
-| love 直接调用 | `engine/particles.lua`、`engine/engine.lua` | 部分 Engine 层模块直接调用 `love.*`,未通过适配器隔离 |
-| 缺少层注释 | 全部文件 | 无法快速定位模块所属层次 |
-| OOP 不统一 | 全部文件 | 部分用 `Class.__index = Class`,部分用 classic,不一致 |
-
-### 重构目标
-
-引入清晰的五层架构,使用 `classic` 库统一接口定义,通过接口隔离各层,消除跨层调用和反向依赖。**只有最底层的 Love 适配层(`love_adapter/`)允许直接调用 `love.*` API;Engine 层通过适配层接口访问框架能力;Render 层通过 `IGraphics` 接口调用绘图;Systems 层完全不接触 love。更换游戏引擎时,只需重写 `love_adapter/` 目录下的实现,其余所有层无需改动。**
-
----
-
-## 架构
-
-### 五层架构总览
-
-```
-┌─────────────────────────────────────────────────────────┐
-│                    协调层 (game.lua)                      │
-│  负责组装各层对象、注入接口实现、转发框架事件              │
-└──────────────────────┬──────────────────────────────────┘
-                       │ 创建 + 注入
-          ┌────────────┴────────────┐
-          ▼                         ▼
-┌─────────────────┐       ┌─────────────────────┐
-│   Systems 层     │       │     Render 层         │
-│  业务逻辑        │◄──────│  通过接口读取状态      │
-│  farm / player  │  接口  │  通过 IGraphics 绘图  │
-│  world / pet    │       │  不调用任何 love.*    │
-└────────┬────────┘       └──────────┬────────────┘
-         │ 依赖                       │ 依赖 IGraphics
-         ▼                           ▼
-┌─────────────────────────────────────────────────────────┐
-│                     Engine 层                             │
-│  EventBus / Camera / Save / Audio / Registry / Anim      │
-│  通过 Love 适配层接口访问框架能力,不直接调用 love.*       │
-└──────────────────────────────────────────────────────────┘
-         │ 依赖(通过接口)
-         ▼
-┌─────────────────────────────────────────────────────────┐
-│               Love 适配层 (love_adapter/)                 │
-│  IGraphics / IFilesystem / IAudio / IWindow 的实现        │
-│  ★ 唯一允许直接调用 love.* 的层                           │
-│  更换引擎时只需重写此层                                    │
-└──────────────────────────────────────────────────────────┘
-         ▲
-         │ 只读数据
-┌─────────────────────────────────────────────────────────┐
-│                      Data 层                              │
-│  crops / tools / items / blocks / config(纯静态表)      │
-└──────────────────────────────────────────────────────────┘
-```
-
-### love 隔离原则
-
-**只有 Love 适配层(`love_adapter/`)允许直接调用 `love.*` API。** 各层隔离方式:
-
-| 层 | love 隔离方式 | 现状 |
-|----|--------------|------|
-| Love 适配层 | 唯一调用 `love.*` 的层,实现各框架接口 | 待创建 |
-| Engine 层 | 通过注入的适配层接口访问框架能力,不直接调用 `love.*` | 部分满足(save/audio 已注入隔离,particles/engine.lua 待整理) |
-| Systems 层 | 完全不使用 love | 已满足(world_system、lighting_system 等均无 love 调用) |
-| Render 层 | 通过 `IGraphics` 接口调用绘图,不直接调用 `love.*` | 待重构 |
-| Data 层 | 纯静态表,无任何 love 调用 | 已满足 |
-
-### 依赖方向规则
-
-```
-Love 适配层  ←  Engine 层(Engine 通过接口依赖适配层)
-Engine 层    ←  Systems 层(Systems 依赖 Engine + Data,不调用 love)
-Engine 层    ←  Render 层(Render 依赖 Engine,通过 IGraphics 绘图)
-Systems 层   ✗  Render 层(禁止)
-Render 层    ✗  Systems 层(禁止直接 require)
-Engine 层    ✗  love.*(禁止,通过适配层接口访问)
-Systems 层   ✗  love.*(禁止)
-Render 层    ✗  love.*(禁止)
-```
-
-### 接口隔离机制
-
-```
-Systems 层                    Render 层
-┌──────────────┐              ┌──────────────────┐
-│ WorldSystem  │              │ WorldRenderer    │
-│ implements   │◄─────────────│ 构造时注入        │
-│ IWorldQuery  │   接口引用    │ IWorldQuery      │
-└──────────────┘              └──────────────────┘
-
-┌──────────────┐              ┌──────────────────┐
-│ FarmSystem   │◄─────────────│ UIRenderer       │
-│ implements   │   接口引用    │ FarmRenderer     │
-│ IFarmQuery   │              │ 构造时注入        │
-└──────────────┘              │ IFarmQuery       │
-                              └──────────────────┘
-
-Love 适配层                   Engine 层 / Render 层
-┌──────────────────────┐      ┌──────────────────────┐
-│ LoveGraphics         │      │ Engine 模块(如 Anim)│
-│ implements IGraphics │◄─────│ Render 层所有渲染器   │
-│ 唯一调用 love.graphics│      │ 构造时注入 IGraphics  │
-└──────────────────────┘      └──────────────────────┘
-
-┌──────────────────────┐      ┌──────────────────────┐
-│ LoveFilesystem       │      │ engine/save.lua       │
-│ implements           │◄─────│ engine/mod_loader.lua │
-│ IFilesystem          │      │ 通过注入接口访问文件系统│
-└──────────────────────┘      └──────────────────────┘
-
-┌──────────────────────┐      ┌──────────────────────┐
-│ LoveAudio            │      │ engine/audio.lua      │
-│ implements IAudio    │◄─────│ engine/sfx.lua        │
-└──────────────────────┘      └──────────────────────┘
-
-┌──────────────────────┐      ┌──────────────────────┐
-│ LoveWindow           │      │ engine/engine.lua     │
-│ implements IWindow   │◄─────│ engine/camera.lua     │
-└──────────────────────┘      └──────────────────────┘
-```
-
----
-
-## 组件与接口
-
-### Love 适配层(love_adapter/)
-
-**这是整个项目唯一允许调用 `love.*` 的目录。** 包含四个适配器文件,每个文件实现一个框架接口。更换引擎时,只需重写此目录下的文件。
-
-#### love_adapter/graphics.lua — IGraphics 实现
-
-```lua
--- [Love适配层] IGraphics 的 LÖVE2D 实现,封装所有 love.graphics 调用
-local IGraphics = require("engine/interface").IGraphics
-
-local LoveGraphics = IGraphics:extend()
-
-function LoveGraphics:setColor(r, g, b, a)              love.graphics.setColor(r, g, b, a) end
-function LoveGraphics:getWidth()                        return love.graphics.getWidth() end
-function LoveGraphics:getHeight()                       return love.graphics.getHeight() end
-function LoveGraphics:setScissor(x, y, w, h)            love.graphics.setScissor(x, y, w, h) end
-function LoveGraphics:rectangle(mode, x, y, w, h, rx)   love.graphics.rectangle(mode, x, y, w, h, rx) end
-function LoveGraphics:circle(mode, x, y, r)             love.graphics.circle(mode, x, y, r) end
-function LoveGraphics:print(text, x, y, r, sx, sy)      love.graphics.print(text, x, y, r, sx, sy) end
-function LoveGraphics:printf(text, x, y, lim, align)    love.graphics.printf(text, x, y, lim, align) end
-function LoveGraphics:newImage(path)                    return love.graphics.newImage(path) end
-function LoveGraphics:newQuad(x, y, w, h, sw, sh)       return love.graphics.newQuad(x, y, w, h, sw, sh) end
-function LoveGraphics:draw(drawable, x, y, r, sx, sy, ox, oy)
-    love.graphics.draw(drawable, x, y, r, sx, sy, ox, oy)
-end
-function LoveGraphics:push()                            love.graphics.push() end
-function LoveGraphics:pop()                             love.graphics.pop() end
-function LoveGraphics:translate(x, y)                   love.graphics.translate(x, y) end
-function LoveGraphics:scale(sx, sy)                     love.graphics.scale(sx, sy) end
-function LoveGraphics:newCanvas(w, h)                   return love.graphics.newCanvas(w, h) end
-function LoveGraphics:setCanvas(canvas)                 love.graphics.setCanvas(canvas) end
-function LoveGraphics:clear(r, g, b, a)                 love.graphics.clear(r, g, b, a) end
-function LoveGraphics:newShader(code)                   return love.graphics.newShader(code) end
-function LoveGraphics:setShader(shader)                 love.graphics.setShader(shader) end
-function LoveGraphics:newFont(path, size)               return love.graphics.newFont(path, size) end
-function LoveGraphics:setFont(font)                     love.graphics.setFont(font) end
-function LoveGraphics:getFont()                         return love.graphics.getFont() end
-
-return LoveGraphics
-```
-
-#### love_adapter/filesystem.lua — IFilesystem 实现
-
-```lua
--- [Love适配层] IFilesystem 的 LÖVE2D 实现,封装所有 love.filesystem 调用
-local IFilesystem = require("engine/interface").IFilesystem
-
-local LoveFilesystem = IFilesystem:extend()
-
-function LoveFilesystem:read(path)           return love.filesystem.read(path) end
-function LoveFilesystem:write(path, data)    return love.filesystem.write(path, data) end
-function LoveFilesystem:exists(path)         return love.filesystem.getInfo(path) ~= nil end
-function LoveFilesystem:remove(path)         return love.filesystem.remove(path) end
-function LoveFilesystem:getInfo(path)        return love.filesystem.getInfo(path) end
-function LoveFilesystem:getDirectoryItems(p) return love.filesystem.getDirectoryItems(p) end
-function LoveFilesystem:createDirectory(p)   return love.filesystem.createDirectory(p) end
-function LoveFilesystem:load(path)           return love.filesystem.load(path) end
-
-return LoveFilesystem
-```
-
-#### love_adapter/audio.lua — IAudio 实现
-
-```lua
--- [Love适配层] IAudio 的 LÖVE2D 实现,封装所有 love.audio / love.sound 调用
-local IAudio = require("engine/interface").IAudio
-
-local LoveAudio = IAudio:extend()
-
-function LoveAudio:newSoundData(samples, rate, bits, channels)
-    return love.sound.newSoundData(samples, rate, bits, channels)
-end
-function LoveAudio:newSource(soundData)
-    return love.audio.newSource(soundData)
-end
-
-return LoveAudio
-```
-
-#### love_adapter/window.lua — IWindow 实现
-
-```lua
--- [Love适配层] IWindow 的 LÖVE2D 实现,封装 love.graphics 屏幕尺寸查询
-local IWindow = require("engine/interface").IWindow
-
-local LoveWindow = IWindow:extend()
-
-function LoveWindow:getWidth()  return love.graphics.getWidth() end
-function LoveWindow:getHeight() return love.graphics.getHeight() end
-
-return LoveWindow
-```
-
-### engine/interface.lua — 接口基础设施
-
-所有跨层接口的基类,依赖 `classic.lua`,不依赖任何其他项目模块。同时定义所有框架接口(`IGraphics`、`IFilesystem`、`IAudio`、`IWindow`)和业务接口(`IWorldQuery`、`IFarmQuery`、`IGameStateQuery`)。
-
-```lua
--- [Engine层] 接口基类定义,所有跨层接口继承自此
-local Object = require("classic")
-
-local Interface_Base = Object:extend()
-
-local function makeUnimplemented(interfaceName, methodName)
-    return function()
-        error(interfaceName .. "." .. methodName .. " 未实现")
-    end
-end
-```
-
-**框架接口**(供 Engine 层模块使用,由 Love 适配层实现):
-
-**IGraphics 接口**(覆盖 Render 层和 Engine 层所需的绘图方法):
-
-```lua
-local IGraphics = Interface_Base:extend()
-function IGraphics:setColor(r, g, b, a)                  end
-function IGraphics:getWidth()                            end
-function IGraphics:getHeight()                           end
-function IGraphics:setScissor(x, y, w, h)                end
-function IGraphics:rectangle(mode, x, y, w, h, rx, ry)   end
-function IGraphics:circle(mode, x, y, r)                 end
-function IGraphics:line(...)                             end
-function IGraphics:print(text, x, y, r, sx, sy)          end
-function IGraphics:printf(text, x, y, limit, align)      end
-function IGraphics:newImage(path)                        end
-function IGraphics:newQuad(x, y, w, h, sw, sh)           end
-function IGraphics:draw(drawable, x, y, r, sx, sy, ox, oy) end
-function IGraphics:push()                                end
-function IGraphics:pop()                                 end
-function IGraphics:translate(x, y)                       end
-function IGraphics:scale(sx, sy)                         end
-function IGraphics:newCanvas(w, h)                       end
-function IGraphics:setCanvas(canvas)                     end
-function IGraphics:clear(r, g, b, a)                     end
-function IGraphics:newShader(code)                       end
-function IGraphics:setShader(shader)                     end
-function IGraphics:newFont(path, size)                   end
-function IGraphics:setFont(font)                         end
-function IGraphics:getFont()                             end
-```
-
-**IFilesystem 接口**(供 `engine/save.lua`、`engine/mod_loader.lua` 使用):
-
-```lua
-local IFilesystem = Interface_Base:extend()
-function IFilesystem:read(path)                end
-function IFilesystem:write(path, data)         end
-function IFilesystem:exists(path)              end
-function IFilesystem:remove(path)              end
-function IFilesystem:getInfo(path)             end
-function IFilesystem:getDirectoryItems(path)   end
-function IFilesystem:createDirectory(path)     end
-function IFilesystem:load(path)                end
-```
-
-**IAudio 接口**(供 `engine/audio.lua`、`engine/sfx.lua` 使用):
-
-```lua
-local IAudio = Interface_Base:extend()
-function IAudio:newSoundData(samples, rate, bits, channels) end
-function IAudio:newSource(soundData)                        end
-```
-
-**IWindow 接口**(供 `engine/camera.lua`、`engine/engine.lua` 使用):
-
-```lua
-local IWindow = Interface_Base:extend()
-function IWindow:getWidth()  end
-function IWindow:getHeight() end
-```
-
-**MockGraphics**(测试用,不依赖 love,定义于 `engine/interface.lua` 或独立测试辅助文件):
-
-```lua
--- [Engine层] IGraphics 的测试 mock 实现,不调用任何 love API
-local MockGraphics = IGraphics:extend()
-function MockGraphics:new()
-    self.calls = {}
-    self._w, self._h = 480, 854
-end
-function MockGraphics:setColor(r, g, b, a)
-    table.insert(self.calls, {"setColor", r, g, b, a})
-end
-function MockGraphics:getWidth()  return self._w end
-function MockGraphics:getHeight() return self._h end
--- ... 其余方法均记录调用
-```
-
-### classic.lua — OOP 基础库
-
-来自 rxi/classic,放置于项目根目录。提供 `Object:extend()`、`Object:new()` 等方法。所有 Systems 层和 Render 层的主要类通过 `classic` 定义。
-
-### Engine 层模块说明
-
-Engine 层模块通过构造时注入的适配层接口访问框架能力,不直接调用 `love.*`:
-
-- `engine/save.lua`:已通过 `Save.setFS(IFilesystem)` 注入文件系统接口,无需修改
-- `engine/audio.lua`:已通过 `Audio.setLove(IAudio)` 注入音频接口,无需修改
-- `engine/camera.lua`:已通过 `Camera.setScreenSize(w, h)` 注入屏幕尺寸,无需修改
-- `engine/particles.lua`:当前直接调用 `love.graphics.*`,需重构为接收 `IGraphics` 注入
-- `engine/engine.lua`:当前直接调用 `love.*`,需重构为通过 `IGraphics`、`IFilesystem`、`IWindow` 接口访问
-- `engine/mod_loader.lua`:当前直接调用 `love.filesystem.*`,需重构为通过 `IFilesystem` 接口访问
-
-### Systems 层类定义
-
-**WorldSystem**(实现 IWorldQuery):
-
-```lua
--- [Systems层] 世界地图数据与逻辑
-local Object = require("classic")
-local IWorldQuery = require("engine/interface").IWorldQuery
-
-local WorldSystem = IWorldQuery:extend()
-
-function WorldSystem:new(seed)
-    -- 初始化地图数据
-    self._baseData    = nil
-    self._overlayData = nil
-    -- ... 生成地图
-    self:init(seed)
-end
-
--- 实现 IWorldQuery 的所有方法
-function WorldSystem:isPath(row, col) ... end
-function WorldSystem:isCollision(row, col) ... end
--- ... 其余 12 个方法
-```
-
-**FarmSystem**(实现 IFarmQuery):
-
-```lua
--- [Systems层] 农场业务逻辑
-local Object = require("classic")
-local IFarmQuery = require("engine/interface").IFarmQuery
-
-local FarmSystem = IFarmQuery:extend()
-
-function FarmSystem:new()
-    self.farmData = {}
-end
-
--- 实现 IFarmQuery
-function FarmSystem:getTile(row, col) ... end
-function FarmSystem:getProgress(row, col, speedMult) ... end
-function FarmSystem:getRemaining(row, col, speedMult) ... end
-function FarmSystem:countNeighborCrops(row, col) ... end
-
--- FarmSystem 自有方法(不在接口中)
-function FarmSystem:till(row, col) ... end
-function FarmSystem:plant(row, col, cropId, gene) ... end
-function FarmSystem:water(row, col) ... end
-function FarmSystem:harvest(row, col, stats) ... end
-function FarmSystem:setWorldPave(fn) ... end
-```
-
-**PlayerSystem**(接收 IWorldQuery):
-
-```lua
--- [Systems层] 玩家控制与工具操作
-local Object = require("classic")
-
-local PlayerSystem = Object:extend()
-
--- 构造函数接收 IWorldQuery 接口实例
-function PlayerSystem:new(farmSystem, gameState, blockSystem, worldQuery)
-    self.farm      = farmSystem
-    self.state     = gameState
-    self.blocks    = blockSystem
-    self._world    = worldQuery  -- IWorldQuery 实例,替代模块级 _world 变量
-    self.character = Character:new(50, 51)
-    -- ...
-end
-```
-
-**Character**(接收 IWorldQuery):
-
-```lua
--- [Systems层] 角色状态机与寻路移动
-local Object = require("classic")
-
-local Character = Object:extend()
-
-function Character:new(startRow, startCol, worldQuery)
-    -- worldQuery 用于 isPath 查询(替代注入函数 _isPath)
-    self._world = worldQuery
-    -- ...
-end
-```
-
-**Pet**(接收 IWorldQuery):
-
-```lua
--- [Systems层] 宠物跟随与离线收益
-local Object = require("classic")
-
-local Pet = Object:extend()
-
-function Pet:new(worldQuery)
-    self._world = worldQuery  -- 替代模块级 _isCollision 函数
-    -- ...
-end
-```
-
-### Render 层类定义
-
-Render 层所有类通过构造函数接收 `IGraphics` 实例,**不直接调用 `love.graphics.*`**。
-
-**WorldRenderer**(接收 IWorldQuery + IGraphics):
-
-```lua
--- [Render层] 世界地图渲染,通过 IGraphics 绘图,不直接调用 love
-local Object = require("classic")
-
-local WorldRenderer = Object:extend()
-
-function WorldRenderer:new(worldQuery, graphics)
-    self._world    = worldQuery  -- IWorldQuery
-    self._gfx      = graphics   -- IGraphics,替代直接调用 love.graphics
-    self._animTime = 0
-    self._tileImgs = {}
-end
-
-function WorldRenderer:update(dt) ... end
-function WorldRenderer:drawBackground(brightnessMap, baseBrightness)
-    -- 使用 self._gfx:setColor(...)、self._gfx:draw(...) 等
-    -- 不出现任何 love.graphics.* 调用
-end
-```
-
-**FarmRenderer**(接收 IFarmQuery + IGraphics):
-
-```lua
--- [Render层] 农场格子渲染
-local Object = require("classic")
-
-local FarmRenderer = Object:extend()
-
-function FarmRenderer:new(farmQuery, graphics)
-    self._farm = farmQuery  -- IFarmQuery
-    self._gfx  = graphics  -- IGraphics
-end
-
-function FarmRenderer:draw(camera) ... end
-function FarmRenderer.getTileCenter(row, col) ... end
-```
-
-**UIRenderer**(接收 IFarmQuery + IGameStateQuery + IGraphics):
-
-```lua
--- [Render层] HUD、商店、消息等 UI 渲染
-local Object = require("classic")
-
-local UIRenderer = Object:extend()
-
-function UIRenderer:new(farmQuery, gameStateQuery, graphics)
-    self._farm      = farmQuery       -- IFarmQuery
-    self._gameState = gameStateQuery  -- IGameStateQuery
-    self._gfx       = graphics        -- IGraphics
-end
-```
-
-所有其他 Render 层类(`BlockRenderer`、`CharacterRenderer`、`CropRenderer`、`DropsRenderer`、`EffectRenderer`、`InventoryRenderer`、`PetRenderer`、`TalentRenderer`、`WorkbenchRenderer`、`DungeonRenderer`、`ForgeRenderer`)均同样接收 `IGraphics` 实例,不直接调用 `love.graphics.*`。
-
-### 协调层 game.lua
-
-`game.lua` 重构为薄协调层,职责:
-1. 创建 Love 适配层实例(`LoveGraphics`、`LoveFilesystem`、`LoveAudio`、`LoveWindow`)
-2. 将适配层实例注入到 Engine 层模块
-3. 创建所有 Systems 层对象
-4. 将 Systems 对象包装为接口实现
-5. 将接口(含 `IGraphics`)注入到 Render 层模块
-6. 转发框架事件给对应系统
-
-```lua
--- [协调层] 游戏主控制器,负责组装各层对象并传递接口
-function Game:new()
-    -- 1. 创建 Love 适配层实例(唯一 require love_adapter/ 的地方)
-    local LoveGraphics    = require("love_adapter/graphics")
-    local LoveFilesystem  = require("love_adapter/filesystem")
-    local LoveAudio       = require("love_adapter/audio")
-    local LoveWindow      = require("love_adapter/window")
-
-    self.graphics   = LoveGraphics:new()
-    self.filesystem = LoveFilesystem:new()
-    self.audio      = LoveAudio:new()
-    self.window     = LoveWindow:new()
-
-    -- 2. 将适配层注入 Engine 层模块
-    local Save      = require("engine/save")
-    local Audio     = require("engine/audio")
-    local ModLoader = require("engine/mod_loader")
-    Save.setFS(self.filesystem)
-    Audio.setLove(self.audio)
-    ModLoader.setFS(self.filesystem)
-
-    -- 3. 创建 Systems 层对象
-    self.worldSystem = WorldSystem:new(os.time())
-    self.farmSystem  = FarmSystem:new()
-    -- ...
-
-    -- 4. 创建 Render 层对象,注入接口(含 IGraphics)
-    self.worldRenderer = WorldRenderer:new(self.worldSystem, self.graphics)
-    self.farmRenderer  = FarmRenderer:new(self.farmSystem, self.graphics)
-    self.uiRenderer    = UIRenderer:new(
-        self.farmSystem,
-        GameStateAdapter:new(self.gameState),
-        self.graphics
-    )
-
-    -- 5. 创建需要接口的 Systems 对象
-    self.playerSystem = PlayerSystem:new(
-        self.farmSystem, self.gameState, self.blockSystem, self.worldSystem
-    )
-    -- ...
-end
-```
-
-**GameStateAdapter**(IGameStateQuery 适配器):
-
-由于 `systems/state.lua` 是纯数据表(非 classic 类),需要一个适配器将其包装为 `IGameStateQuery`:
-
-```lua
--- [协调层] GameState 到 IGameStateQuery 的适配器
-local IGameStateQuery = require("engine/interface").IGameStateQuery
-
-local GameStateAdapter = IGameStateQuery:extend()
-
-function GameStateAdapter:new(gs)
-    self._gs = gs
-end
-
-function GameStateAdapter:getMoney()    return self._gs.money end
-function GameStateAdapter:getLevel()    return self._gs.level end
--- ... 其余方法
-```
-
----
-
-## 数据模型
-
-### 接口继承层次
-
-```
-classic.Object
-  └── Interface_Base
-        ├── IGraphics
-        │     ├── LoveGraphics(Love适配层实现,唯一调用 love.graphics)
-        │     └── MockGraphics(测试用,不依赖 love)
-        ├── IFilesystem
-        │     ├── LoveFilesystem(Love适配层实现)
-        │     └── MockFilesystem(测试用)
-        ├── IAudio
-        │     └── LoveAudio(Love适配层实现)
-        ├── IWindow
-        │     └── LoveWindow(Love适配层实现)
-        ├── IWorldQuery
-        │     └── WorldSystem(实现)
-        ├── IFarmQuery
-        │     └── FarmSystem(实现)
-        └── IGameStateQuery
-              └── GameStateAdapter(适配器实现)
-
-classic.Object
-  ├── PlayerSystem(持有 IWorldQuery)
-  ├── Character(持有 IWorldQuery)
-  ├── Pet(持有 IWorldQuery)
-  ├── WorldRenderer(持有 IWorldQuery + IGraphics)
-  ├── FarmRenderer(持有 IFarmQuery + IGraphics)
-  ├── UIRenderer(持有 IFarmQuery + IGameStateQuery + IGraphics)
-  └── 其他 Renderer(持有 IGraphics)
-```
-
-### 目录结构与层归属
-
-```
-love_adapter/          ← Love 适配层(唯一调用 love.* 的目录)
-  graphics.lua         -- [Love适配层] IGraphics 的 LÖVE2D 实现
-  filesystem.lua       -- [Love适配层] IFilesystem 的 LÖVE2D 实现
-  audio.lua            -- [Love适配层] IAudio 的 LÖVE2D 实现
-  window.lua           -- [Love适配层] IWindow 的 LÖVE2D 实现
-engine/                ← Engine 层(不调用 love.*,通过接口访问适配层)
-  interface.lua        -- [Engine层] 所有接口定义(含框架接口和业务接口)
-  camera.lua           -- [Engine层] 摄像机(通过 setScreenSize 注入)
-  save.lua             -- [Engine层] 存档(通过 setFS 注入 IFilesystem)
-  audio.lua            -- [Engine层] 音频合成(通过 setLove 注入 IAudio)
-  ...
-data/                  ← Data 层(纯静态表)
-systems/               ← Systems 层(不调用 love.*)
-render/                ← Render 层(通过 IGraphics 绘图,不调用 love.*)
-game.lua               ← 协调层(创建适配层实例并注入)
-main.lua               ← 协调层(LÖVE2D 入口,转发事件给 engine/engine.lua)
-```
-
-### 层归属注释格式
-
-每个文件第一行必须包含:
-
-| 目录 | 注释格式 | 示例 |
-|------|----------|------|
-| `love_adapter/` | `-- [Love适配层] 说明` | `-- [Love适配层] IGraphics 的 LÖVE2D 实现` |
-| `engine/` | `-- [Engine层] 说明` | `-- [Engine层] 事件总线,解耦模块间通信` |
-| `data/` | `-- [Data层] 说明` | `-- [Data层] 作物静态数据表` |
-| `systems/` | `-- [Systems层] 说明` | `-- [Systems层] 农场业务逻辑` |
-| `render/` | `-- [Render层] 说明` | `-- [Render层] 世界地图渲染` |
-| 根目录协调 | `-- [协调层] 说明` | `-- [协调层] 游戏主控制器,组装各层对象` |
-
-### 依赖检查规则(静态分析)
-
-```
-love_adapter/ 下文件 → 允许调用 love.*,不得 require 其他层(除 engine/interface)
-engine/       下文件 → 不得包含 love. 字符串(通过适配层接口访问)
-engine/       下文件 → 不得包含 require("systems/ 或 require("render/
-systems/      下文件 → 不得包含 love. 字符串
-systems/      下文件 → 不得包含 require("render/
-render/       下文件 → 不得包含 love. 字符串(通过 IGraphics 接口调用)
-render/       下文件 → 不得包含顶层 require("systems/
-data/         下文件 → 不得包含任何 require(除 data/ 内部)
-```
-
----
-
-## 正确性属性
-
-*属性是在系统所有有效执行中都应成立的特征或行为——本质上是关于系统应该做什么的形式化陈述。属性是人类可读规范与机器可验证正确性保证之间的桥梁。*
-
-### 属性 1:接口未实现方法抛出格式化错误
-
-*对于任意* 接口名称和方法名称,当通过未实现该方法的子类调用时,系统应抛出包含 `"接口名.方法名 未实现"` 格式的错误信息。
-
-**验证:需求 1.3**
-
-### 属性 2:IWorldQuery 接口方法完整性
-
-*对于* IWorldQuery 接口声明的每一个方法,当通过未实现的子类调用时,系统应抛出包含该方法名的错误(证明方法已被声明且有默认未实现行为)。
-
-**验证:需求 1.4**
-
-### 属性 3:IFarmQuery 接口方法完整性
-
-*对于* IFarmQuery 接口声明的每一个方法,当通过未实现的子类调用时,系统应抛出包含该方法名的错误。
-
-**验证:需求 1.5**
-
-### 属性 4:IGameStateQuery 接口方法完整性
-
-*对于* IGameStateQuery 接口声明的每一个方法,当通过未实现的子类调用时,系统应抛出包含该方法名的错误。
-
-**验证:需求 1.6**
-
-### 属性 5:所有 Lua 源文件包含层归属注释
-
-*对于* 项目中 `engine/`、`data/`、`systems/`、`render/` 目录下的任意 Lua 源文件,其第一行应匹配 `-- [*层] ` 格式的层归属注释。
-
-**验证:需求 2.1、2.2、2.3、2.4、2.5**
-
-### 属性 6:Systems 层不依赖 Render 层
-
-*对于* `systems/` 目录下的任意 Lua 源文件,其文件内容不应包含 `require("render/` 字符串。
-
-**验证:需求 3.1、3.6、9.3**
-
-### 属性 7:Render 层不直接 require Systems 层
-
-*对于* `render/` 目录下的任意 Lua 源文件,其文件内容不应包含顶层(文件加载时执行的)`require("systems/` 字符串。
-
-**验证:需求 4.1、4.5、9.4**
-
-### 属性 11:Render 层不直接调用 love API
-
-*对于* `render/` 目录下的任意 Lua 源文件,其文件内容不应包含 `love.` 字符串(所有绘图调用均通过 `IGraphics` 接口)。
-
-**验证:需求 9.4(扩展)**
-
-### 属性 12:Systems 层不直接调用 love API
-
-*对于* `systems/` 目录下的任意 Lua 源文件,其文件内容不应包含 `love.` 字符串。
-
-**验证:需求 9.3(扩展)**
-
-### 属性 8:通过接口访问与直接调用等价
-
-*对于任意* 有效的地图坐标 `(row, col)`,通过 `IWorldQuery` 接口调用 `WorldSystem` 的查询方法,应与直接调用 `WorldSystem` 对应方法返回相同的结果。
-
-**验证:需求 8.4**
-
-### 属性 9:农场操作状态机转换正确性
-
-*对于任意* 有效的农场格子初始状态和操作序列(耕地→播种→浇水→收获),FarmSystem 的状态转换应满足:`EMPTY →(till)→ TILLED →(plant)→ SEEDED →(harvest when ready)→ EMPTY`,且每步操作返回值与状态变更一致。
-
-**验证:需求 8.3**
-
-### 属性 10:Engine 层不依赖上层模块且不直接调用 love
-
-*对于* `engine/` 目录下的任意 Lua 源文件,其文件内容不应包含 `require("systems/`、`require("render/` 或 `require("data/` 字符串;同时不应包含 `love.` 字符串(Engine 层通过适配层接口访问框架能力)。
-
-**验证:需求 9.1**
-
-### 属性 13:Love 适配层是唯一调用 love 的层
-
-*对于* `engine/`、`systems/`、`render/`、`data/` 目录下的任意 Lua 源文件,其文件内容不应包含 `love.` 字符串。只有 `love_adapter/` 目录下的文件允许包含 `love.` 字符串。
-
-**验证:love 隔离原则**
-
----
-
-## 错误处理
-
-### 接口未实现错误
-
-当调用未被子类覆盖的接口方法时,`Interface_Base` 的默认实现抛出 Lua error:
-
-```lua
-error("IWorldQuery.isPath 未实现")
-```
-
-调用方(Systems 层或 Render 层)不需要捕获此错误——它代表编程错误(忘记实现接口),应在开发阶段暴露。
-
-### 接口注入缺失
-
-若 `game.lua` 忘记注入接口实例,相关模块在首次调用接口方法时会因 `nil` 调用而报错。为提前发现此类问题,各模块构造函数应做断言:
-
-```lua
-function PlayerSystem:new(farmSystem, gameState, blockSystem, worldQuery)
-    assert(worldQuery, "PlayerSystem:new 需要 IWorldQuery 实例")
-    -- ...
-end
-```
-
-### 依赖方向违规检测
-
-在 CI/测试阶段,通过静态扫描脚本检测违规 `require`。违规时输出文件名和行号,阻止合并。
-
----
-
-## 测试策略
-
-### 双轨测试方法
-
-- **单元测试**:验证具体示例、边界条件、错误情况
-- **属性测试**:验证跨所有输入的通用属性
-
-使用 [busted](https://lunarmodules.github.io/busted/) 框架(已配置于 `.busted`),属性测试使用 [lua-quickcheck](https://github.com/mcmtroffaes/lua-quickcheck) 或手动生成随机输入。
-
-### 属性测试配置
-
-每个属性测试最少运行 **100 次迭代**,标签格式:
-
-```lua
--- Feature: layered-architecture-refactor, Property N: 属性描述
-```
-
-### 测试文件组织
-
-```
-spec/
-  helpers/
-    love_mock.lua          -- 已有 LÖVE2D mock(仅用于 love_adapter 层测试)
-    interface_helpers.lua  -- 接口测试辅助函数(新增)
-    mock_graphics.lua      -- MockGraphics 实现(新增,供 Engine/Render 层测试使用)
-    mock_filesystem.lua    -- MockFilesystem 实现(新增,供 Engine 层测试使用)
-  layered_arch/
-    property_interface_spec.lua   -- 属性 1-4:接口正确性(含框架接口)
-    property_layer_deps_spec.lua  -- 属性 5-7、10-13:层依赖约束(含 love 隔离检查)
-    property_equivalence_spec.lua -- 属性 8:接口等价性
-    property_farm_spec.lua        -- 属性 9:农场状态机
-```
-
-### 属性测试示例
-
-**属性 1 — 接口未实现方法抛出格式化错误**:
-
-```lua
--- Feature: layered-architecture-refactor, Property 1: 接口未实现方法抛出格式化错误
-it("对任意方法名,未实现时调用应抛出包含方法名的错误", function()
-    local Interface_Base = require("engine/interface").Interface_Base
-    -- 生成随机方法名列表
-    local methodNames = { "foo", "bar", "doSomething", "query_x", "get123" }
-    for _ = 1, 100 do
-        local name = methodNames[math.random(#methodNames)] .. tostring(math.random(1000))
-        local TestIface = Interface_Base:extend()
-        TestIface[name] = function() error("TestIface." .. name .. " 未实现") end
-        local impl = TestIface:extend()
-        local obj = impl:new()
-        local ok, err = pcall(function() obj[name](obj) end)
-        assert.is_false(ok)
-        assert.truthy(err:find(name))
-    end
-end)
-```
-
-**属性 8 — 接口访问与直接调用等价**:
-
-```lua
--- Feature: layered-architecture-refactor, Property 8: 通过接口访问与直接调用等价
-it("对任意坐标,IWorldQuery 接口调用与 WorldSystem 直接调用结果相同", function()
-    local WorldSystem = require("systems/world_system")
-    WorldSystem.init(42)  -- 固定 seed
-    for _ = 1, 100 do
-        local row = math.random(1, 100)
-        local col = math.random(1, 100)
-        assert.equal(WorldSystem:isPath(row, col),     WorldSystem.isPath(row, col))
-        assert.equal(WorldSystem:isCollision(row, col), WorldSystem.isCollision(row, col))
-        assert.equal(WorldSystem:isObstacle(row, col),  WorldSystem.isObstacle(row, col))
-    end
-end)
-```
-
-**属性 9 — 农场状态机转换**:
-
-```lua
--- Feature: layered-architecture-refactor, Property 9: 农场操作状态机转换正确性
-it("对任意坐标,农场状态机转换 EMPTY→TILLED→SEEDED→READY 正确", function()
-    local FarmSystem = require("systems/farm")
-    for _ = 1, 100 do
-        local farm = FarmSystem:new()
-        local row, col = math.random(1, 100), math.random(1, 100)
-        -- 先开垦
-        farm:clearGrass(row, col)
-        assert.equal("empty", farm:getTile(row, col).state)
-        -- 耕地
-        local ok = farm:till(row, col)
-        assert.is_true(ok)
-        assert.equal("tilled", farm:getTile(row, col).state)
-        -- 播种
-        ok = farm:plant(row, col, "carrot", nil)
-        assert.is_true(ok)
-        assert.equal("seeded", farm:getTile(row, col).state)
-    end
-end)
-```
-
-### 单元测试覆盖
-
-- `engine/interface.lua`:接口定义、错误格式(含 IGraphics、IFilesystem、IAudio、IWindow)
-- `love_adapter/graphics.lua`:LoveGraphics 委托行为(需 love mock)
-- `systems/world_system.lua`:地图查询方法
-- `systems/farm.lua`:农场操作、状态转换
-- `systems/player.lua`:通过 MockGraphics + mock IWorldQuery 验证注入
-- `render/ui_renderer.lua`:通过 MockGraphics + mock IFarmQuery/IGameStateQuery 验证注入,不依赖 love
-- 层依赖静态检查:扫描所有 `.lua` 文件的 `require` 调用和 `love.` 字符串,验证只有 `love_adapter/` 下文件包含 `love.`
-
-### 回归测试
-
-重构完成后,运行现有 `spec/` 下所有测试套件,确保全部通过:
-
-```bash
-busted --run
-```

+ 0 - 166
app/src/embed/assets/.kiro/specs/layered-architecture-refactor/requirements.md

@@ -1,166 +0,0 @@
-# 需求文档
-
-## 简介
-
-本项目是一款基于 LÖVE2D 框架的 Lua 农场游戏。当前代码库存在以下架构问题:
-
-- `game.lua` 同时持有 systems 层和 render 层的直接引用,充当了"上帝对象"
-- `render/ui_renderer.lua` 直接 `require` systems 层模块(如 `FarmSystem`、`State`),造成渲染层反向依赖业务层
-- `systems/player.lua` 通过注入的 `_world` 变量直接调用 `WorldRenderer` 的方法,造成 systems 层依赖 render 层
-- 各文件缺少层归属注释,难以快速定位模块所属层次
-- 缺乏统一的面向对象接口规范,模块间耦合方式不一致
-
-本次重构目标是引入清晰的四层架构(Engine → Data → Systems → Render),使用 `classic` 库统一接口定义,通过接口隔离各层,消除跨层调用和反向依赖。
-
----
-
-## 词汇表
-
-- **Engine 层**:最底层,提供与 LÖVE2D 框架交互的基础设施,包括事件总线、摄像机、存档、音频、注册中心等。不依赖任何上层模块。
-- **Data 层**:纯数据定义层,包含作物、工具、物品、方块、配置等静态数据表。不含任何逻辑或副作用。
-- **Systems 层**:业务逻辑层,包含农场、玩家、世界、背包、天气等系统。只依赖 Engine 层和 Data 层,不依赖 Render 层。
-- **Render 层**:渲染层,负责将 Systems 层的状态绘制到屏幕。只依赖 Engine 层,通过接口(Interface)读取 Systems 层数据,不直接 `require` Systems 层模块。
-- **classic 库**:一个轻量级 Lua OOP 库,提供 `Class:extend()`、`Class:new()` 等方法,用于定义类和接口。
-- **Interface(接口)**:用 classic 定义的抽象基类,声明方法签名但不提供实现,用于隔离层间依赖。
-- **IWorldQuery**:世界地图查询接口,供 Systems 层(player、pet 等)使用,隔离对 WorldSystem 的直接依赖。
-- **IFarmQuery**:农场状态查询接口,供 Render 层使用,隔离对 FarmSystem 的直接依赖。
-- **IGameStateQuery**:游戏状态查询接口,供 Render 层使用,隔离对 State 的直接依赖。
-- **EventBus**:事件总线,已存在于 `engine/eventbus.lua`,用于跨层异步通信。
-- **跨层调用**:某层直接 `require` 并调用了不相邻层的模块(如 render 层直接调用 systems 层)。
-- **反向依赖**:低层模块依赖高层模块(如 systems 层依赖 render 层)。
-- **层归属注释**:每个文件开头的注释,格式为 `-- [层名称层] 文件说明`,明确标注该文件所属架构层次。
-
----
-
-## 需求
-
-### 需求 1:引入 classic 库并建立接口基础设施
-
-**用户故事:** 作为开发者,我希望项目中有统一的 OOP 基础设施,以便用接口(抽象类)来隔离各层之间的依赖。
-
-#### 验收标准
-
-1. THE 项目 SHALL 在根目录包含 `classic.lua` 文件(来自 rxi/classic 库)。
-2. THE 项目 SHALL 在 `engine/interface.lua` 中定义所有跨层接口的基类,使用 classic 的 `Class:extend()` 机制。
-3. WHEN 某接口方法被调用但未被子类实现时,THE Interface_Base SHALL 抛出包含方法名的错误信息,格式为 `"[接口名].[方法名] 未实现"`。
-4. THE 项目 SHALL 定义 `IWorldQuery` 接口,包含以下方法:`isPath(row, col)`、`isCollision(row, col)`、`isObstacle(row, col)`、`isTree(row, col)`、`isWell(row, col)`、`isGrass(row, col)`、`removeGrass(row, col)`、`isMushroom(row, col)`、`pickMushroom(row, col)`、`isBush(row, col)`、`chopBush(row, col)`、`chopTree(row, col)`、`isGravelPile(row, col)`、`mineGravelPile(row, col)`。
-5. THE 项目 SHALL 定义 `IFarmQuery` 接口,包含以下方法:`getTile(row, col)`、`getProgress(row, col, speedMult)`、`getRemaining(row, col, speedMult)`、`countNeighborCrops(row, col)`。
-6. THE 项目 SHALL 定义 `IGameStateQuery` 接口,包含以下方法:`getMoney()`、`getLevel()`、`getExp()`、`getStamina()`、`getMaxStamina()`、`getPlayerRow()`、`getPlayerCol()`、`getInventory()`、`getEquippedSlots()`、`getWateringCanWater()`。
-
----
-
-### 需求 2:为所有文件添加层归属注释
-
-**用户故事:** 作为开发者,我希望每个文件开头都有明确的层归属注释,以便快速理解模块所属层次和职责。
-
-#### 验收标准
-
-1. THE 项目 SHALL 在每个 Lua 源文件的第一行添加层归属注释,格式为 `-- [层名称层] 文件简要说明`。
-2. THE Engine_Layer 注释 SHALL 使用格式 `-- [Engine层] 说明`,适用于 `engine/` 目录下所有文件。
-3. THE Data_Layer 注释 SHALL 使用格式 `-- [Data层] 说明`,适用于 `data/` 目录下所有文件。
-4. THE Systems_Layer 注释 SHALL 使用格式 `-- [Systems层] 说明`,适用于 `systems/` 目录下所有文件。
-5. THE Render_Layer 注释 SHALL 使用格式 `-- [Render层] 说明`,适用于 `render/` 目录下所有文件。
-6. WHERE 文件属于入口或跨层协调模块(如 `game.lua`、`main.lua`),THE 注释 SHALL 使用格式 `-- [协调层] 说明` 并说明其协调职责。
-
----
-
-### 需求 3:消除 Systems 层对 Render 层的依赖
-
-**用户故事:** 作为开发者,我希望 systems 层的模块不直接依赖 render 层,以便在无渲染环境(如单元测试)中独立运行业务逻辑。
-
-#### 验收标准
-
-1. THE Systems_Layer SHALL 不包含任何对 `render/` 目录下模块的 `require` 调用。
-2. WHEN `systems/player.lua` 需要查询世界地图状态时,THE PlayerSystem SHALL 通过 `IWorldQuery` 接口访问,而非直接调用 `WorldRenderer` 或 `WorldSystem` 的具体方法。
-3. WHEN `systems/pet.lua` 需要查询碰撞信息时,THE PetSystem SHALL 通过 `IWorldQuery` 接口访问。
-4. WHEN `systems/character.lua` 需要查询路径信息时,THE Character SHALL 通过 `IWorldQuery` 接口访问。
-5. THE `systems/farm.lua` SHALL 通过注入的 `IWorldQuery` 接口调用 `pave` 相关方法,不直接依赖 `WorldRenderer`。
-6. IF `systems/` 目录下任意文件包含 `require("render/` 字符串,THEN THE 构建检查 SHALL 报告违规错误。
-
----
-
-### 需求 4:消除 Render 层对 Systems 层的直接 require 依赖
-
-**用户故事:** 作为开发者,我希望 render 层不直接 require systems 层模块,以便渲染逻辑与业务逻辑解耦,支持独立替换渲染实现。
-
-#### 验收标准
-
-1. THE Render_Layer SHALL 不包含任何对 `systems/` 目录下模块的顶层 `require` 调用(文件加载时执行的 require)。
-2. WHEN `render/ui_renderer.lua` 需要显示农场格子信息时,THE UIRenderer SHALL 通过 `IFarmQuery` 接口获取数据,而非直接 `require("systems/farm")`。
-3. WHEN `render/ui_renderer.lua` 需要显示玩家状态(金币、等级、精力等)时,THE UIRenderer SHALL 通过 `IGameStateQuery` 接口获取数据,而非直接 `require("systems/state")`。
-4. WHEN `render/farm_renderer.lua` 需要读取农场瓦片数据时,THE FarmRenderer SHALL 通过 `IFarmQuery` 接口获取,而非直接持有 FarmSystem 引用。
-5. IF `render/` 目录下任意文件包含顶层 `require("systems/` 字符串,THEN THE 构建检查 SHALL 报告违规错误。
-
----
-
-### 需求 5:重构 game.lua 为薄协调层
-
-**用户故事:** 作为开发者,我希望 `game.lua` 只负责组装各层对象并传递接口,不包含业务逻辑,以便降低核心文件的复杂度。
-
-#### 验收标准
-
-1. THE `game.lua` SHALL 负责创建所有 Systems 层对象、Render 层对象,并将接口实现注入到需要的模块中。
-2. THE `game.lua` SHALL 将 `WorldSystem` 的实例包装为 `IWorldQuery` 的实现,并注入到 `PlayerSystem`、`PetSystem`、`Character` 等需要世界查询的模块。
-3. THE `game.lua` SHALL 将 `FarmSystem` 的实例包装为 `IFarmQuery` 的实现,并注入到 `UIRenderer`、`FarmRenderer` 等需要农场数据的渲染模块。
-4. THE `game.lua` SHALL 将 `GameState` 包装为 `IGameStateQuery` 的实现,并注入到 `UIRenderer` 等需要状态数据的渲染模块。
-5. WHEN `game.lua` 处理用户输入事件时,THE `game.lua` SHALL 将事件转发给对应的 Systems 层方法或通过 EventBus 发布,不直接操作渲染状态。
-6. THE `game.lua` 中的业务逻辑代码行数 SHALL 不超过重构前的 30%(即大部分逻辑应迁移到对应层)。
-
----
-
-### 需求 6:使用 classic 库统一 Systems 层的类定义
-
-**用户故事:** 作为开发者,我希望 systems 层的主要类使用 classic 库定义,以便获得统一的继承、构造和方法调用规范。
-
-#### 验收标准
-
-1. THE `systems/farm.lua` SHALL 使用 `classic` 的 `Class:extend()` 定义 `FarmSystem` 类,并实现 `IFarmQuery` 接口。
-2. THE `systems/player.lua` SHALL 使用 `classic` 的 `Class:extend()` 定义 `PlayerSystem` 类,构造函数接收 `IWorldQuery` 接口实例。
-3. THE `systems/world_system.lua` SHALL 使用 `classic` 的 `Class:extend()` 定义 `WorldSystem` 类,并实现 `IWorldQuery` 接口。
-4. THE `systems/character.lua` SHALL 使用 `classic` 的 `Class:extend()` 定义 `Character` 类,构造函数接收 `IWorldQuery` 接口实例。
-5. WHEN 使用 classic 定义的类被实例化时,THE 类 SHALL 通过 `ClassName:new(...)` 或 `ClassName(...)` 方式创建实例,保持与 classic 库的一致性。
-6. THE `systems/pet.lua` SHALL 使用 `classic` 的 `Class:extend()` 定义 `Pet` 类,构造函数接收 `IWorldQuery` 接口实例。
-
----
-
-### 需求 7:使用 classic 库统一 Render 层的类定义
-
-**用户故事:** 作为开发者,我希望 render 层的主要渲染器使用 classic 库定义,以便获得统一的接口注入和方法调用规范。
-
-#### 验收标准
-
-1. THE `render/ui_renderer.lua` SHALL 使用 `classic` 的 `Class:extend()` 定义 `UIRenderer` 类,构造函数接收 `IFarmQuery` 和 `IGameStateQuery` 接口实例。
-2. THE `render/farm_renderer.lua` SHALL 使用 `classic` 的 `Class:extend()` 定义 `FarmRenderer` 类,构造函数接收 `IFarmQuery` 接口实例。
-3. THE `render/world_renderer.lua` SHALL 使用 `classic` 的 `Class:extend()` 定义 `WorldRenderer` 类,构造函数接收 `IWorldQuery` 接口实例。
-4. WHEN Render 层类被实例化时,THE 类 SHALL 通过构造函数参数接收所需接口,不在方法内部 `require` Systems 层模块。
-5. THE `render/character_renderer.lua` SHALL 使用 `classic` 的 `Class:extend()` 定义 `CharacterRenderer` 类。
-
----
-
-### 需求 8:保持现有功能完整性
-
-**用户故事:** 作为玩家,我希望重构后游戏的所有功能与重构前完全一致,以便重构不引入任何功能回归。
-
-#### 验收标准
-
-1. WHEN 重构完成后运行现有测试套件(`spec/` 目录下所有 `_spec.lua` 文件)时,THE 测试套件 SHALL 全部通过,无新增失败用例。
-2. THE 游戏 SHALL 在重构后正常启动,显示开始界面,支持新游戏和继续游戏。
-3. WHEN 玩家执行农场操作(耕地、播种、浇水、收获)时,THE FarmSystem SHALL 产生与重构前相同的状态变更和事件。
-4. WHEN 玩家移动时,THE PlayerSystem SHALL 通过 `IWorldQuery` 接口获得与直接调用 `WorldSystem` 相同的碰撞检测结果。
-5. WHEN 游戏存档和读档时,THE SaveSystem SHALL 正确序列化和反序列化所有游戏状态,与重构前格式兼容(version 字段保持为 17)。
-6. IF 重构后任何现有 spec 测试失败,THEN THE 开发者 SHALL 在合并前修复该测试。
-
----
-
-### 需求 9:层间依赖方向约束
-
-**用户故事:** 作为开发者,我希望架构中的依赖方向是单向的,以便防止循环依赖和架构腐化。
-
-#### 验收标准
-
-1. THE Engine_Layer SHALL 不依赖 Data 层、Systems 层或 Render 层的任何模块。
-2. THE Data_Layer SHALL 不依赖 Engine 层、Systems 层或 Render 层的任何模块。
-3. THE Systems_Layer SHALL 只依赖 Engine 层和 Data 层,不依赖 Render 层。
-4. THE Render_Layer SHALL 只依赖 Engine 层,通过接口(Interface)与 Systems 层通信,不直接 `require` Systems 层或 Data 层模块。
-5. WHEN 新增文件时,THE 开发者 SHALL 在文件开头的层归属注释中声明所属层,并确保 `require` 调用不违反上述依赖方向约束。
-6. THE `engine/interface.lua` SHALL 只依赖 `classic.lua`,不依赖任何其他项目模块。

+ 0 - 186
app/src/embed/assets/.kiro/specs/layered-architecture-refactor/tasks.md

@@ -1,186 +0,0 @@
-# 实现计划:分层架构重构
-
-## 概述
-
-将 LÖVE2D Lua 农场游戏重构为清晰的五层架构(Love适配层 → Engine → Data → Systems → Render),通过 `classic` 库统一接口定义,消除跨层调用和反向依赖。**核心原则:只有 `love_adapter/` 目录下的文件允许直接调用 `love.*`;Engine 层通过适配层接口访问框架能力;Render 层通过 `IGraphics` 接口绘图;Systems 层完全不接触 love。更换引擎时只需重写 `love_adapter/`。** 重构按以下顺序推进:先建立接口基础设施和适配层,再逐层修改各模块,最后重构协调层并补充测试。
-
-## 任务
-
-- [x] 1. 引入 classic 库并创建接口基础设施
-  - 确认 `classic.lua` 已存在于项目根目录,若不存在则从 rxi/classic 获取并放置
-  - 创建 `engine/interface.lua`,定义 `Interface_Base` 基类,使用 `makeUnimplemented` 工厂函数为每个接口方法生成默认抛错实现
-  - 在 `engine/interface.lua` 中定义 `IWorldQuery` 接口,声明全部 14 个方法
-  - 在 `engine/interface.lua` 中定义 `IFarmQuery` 接口,声明全部 4 个方法
-  - 在 `engine/interface.lua` 中定义 `IGameStateQuery` 接口,声明全部 10 个方法
-  - 文件第一行添加 `-- [Engine层] 跨层接口基础设施定义` 注释
-  - _需求:1.1、1.2、1.3、1.4、1.5、1.6、9.6_
-
-  - [x] 1.1 为接口基础设施编写属性测试
-    - **属性 1:接口未实现方法抛出格式化错误**
-    - **验证:需求 1.3**
-    - 创建 `spec/layered_arch/property_interface_spec.lua`,对随机方法名循环 100 次验证错误格式
-    - **属性 2:IWorldQuery 接口方法完整性**(需求 1.4)
-    - **属性 3:IFarmQuery 接口方法完整性**(需求 1.5)
-    - **属性 4:IGameStateQuery 接口方法完整性**(需求 1.6)
-
-- [x] 1.5 创建 Love 适配层(love_adapter/)
-  - 创建 `love_adapter/` 目录,这是整个项目**唯一允许调用 `love.*` 的目录**
-  - 在 `engine/interface.lua` 中补充定义框架接口:`IGraphics`(绘图)、`IFilesystem`(文件系统)、`IAudio`(音频)、`IWindow`(窗口/屏幕尺寸)
-  - 创建 `love_adapter/graphics.lua`,实现 `LoveGraphics`(继承 `IGraphics`),每个方法委托给对应的 `love.graphics.*` 调用,文件第一行添加 `-- [Love适配层] IGraphics 的 LÖVE2D 实现` 注释
-  - 创建 `love_adapter/filesystem.lua`,实现 `LoveFilesystem`(继承 `IFilesystem`),封装所有 `love.filesystem.*` 调用,文件第一行添加 `-- [Love适配层] IFilesystem 的 LÖVE2D 实现` 注释
-  - 创建 `love_adapter/audio.lua`,实现 `LoveAudio`(继承 `IAudio`),封装 `love.sound.newSoundData`、`love.audio.newSource`,文件第一行添加 `-- [Love适配层] IAudio 的 LÖVE2D 实现` 注释
-  - 创建 `love_adapter/window.lua`,实现 `LoveWindow`(继承 `IWindow`),封装屏幕尺寸查询,文件第一行添加 `-- [Love适配层] IWindow 的 LÖVE2D 实现` 注释
-  - _需求:9.4(扩展)、love 隔离原则_
-
-- [x] 2. 为所有现有文件添加层归属注释
-  - 为 `engine/` 目录下所有 `.lua` 文件第一行添加 `-- [Engine层] 说明` 注释
-  - 为 `data/` 目录下所有 `.lua` 文件第一行添加 `-- [Data层] 说明` 注释
-  - 为 `systems/` 目录下所有 `.lua` 文件第一行添加 `-- [Systems层] 说明` 注释
-  - 为 `render/` 目录下所有 `.lua` 文件第一行添加 `-- [Render层] 说明` 注释
-  - 为 `game.lua`、`main.lua` 添加 `-- [协调层] 说明` 注释
-  - _需求:2.1、2.2、2.3、2.4、2.5、2.6_
-
-  - [x] 2.1 为层归属注释编写属性测试
-    - **属性 5:所有 Lua 源文件包含层归属注释**
-    - **验证:需求 2.1、2.2、2.3、2.4、2.5**
-    - 创建 `spec/layered_arch/property_layer_deps_spec.lua`,扫描各目录下所有 `.lua` 文件,验证第一行匹配 `-- [*层] ` 格式
-
-- [x] 3. 重构 systems/world_system.lua 实现 IWorldQuery
-  - 将 `WorldSystem` 改为通过 `IWorldQuery:extend()` 定义,使其成为 `IWorldQuery` 的实现类
-  - 确保 `WorldSystem:new(seed)` 构造函数使用 classic 风格
-  - 实现 `IWorldQuery` 的全部 14 个方法,将现有逻辑迁移进来
-  - 文件第一行注释更新为 `-- [Systems层] 世界地图数据与逻辑,实现 IWorldQuery 接口`
-  - _需求:3.1、6.3、8.4_
-
-  - [x] 3.1 为 IWorldQuery 接口等价性编写属性测试
-    - **属性 8:通过接口访问与直接调用等价**
-    - **验证:需求 8.4**
-    - 在 `spec/layered_arch/property_equivalence_spec.lua` 中,对随机坐标循环 100 次,验证通过接口调用与直接调用 `WorldSystem` 方法结果相同
-
-- [x] 4. 重构 systems/farm.lua 实现 IFarmQuery
-  - 将 `FarmSystem` 改为通过 `IFarmQuery:extend()` 定义,使其成为 `IFarmQuery` 的实现类
-  - 确保 `FarmSystem:new()` 构造函数使用 classic 风格
-  - 实现 `IFarmQuery` 的全部 4 个方法(`getTile`、`getProgress`、`getRemaining`、`countNeighborCrops`)
-  - 保留 `FarmSystem` 自有方法(`till`、`plant`、`water`、`harvest`、`setWorldPave` 等)
-  - 文件第一行注释更新为 `-- [Systems层] 农场业务逻辑,实现 IFarmQuery 接口`
-  - _需求:6.1、8.3_
-
-  - [x] 4.1 为农场状态机编写属性测试
-    - **属性 9:农场操作状态机转换正确性**
-    - **验证:需求 8.3**
-    - 在 `spec/layered_arch/property_farm_spec.lua` 中,对随机坐标循环 100 次,验证 `EMPTY→TILLED→SEEDED` 状态转换正确
-
-- [x] 5. 重构 systems/character.lua 接收 IWorldQuery
-  - 将 `Character` 改为通过 `Object:extend()` 定义(classic 风格)
-  - 修改 `Character:new(startRow, startCol, worldQuery)` 构造函数,接收 `IWorldQuery` 实例替代注入函数
-  - 将内部所有 `_isPath` 函数调用替换为 `self._world:isPath(row, col)`
-  - 添加 `assert(worldQuery, "Character:new 需要 IWorldQuery 实例")` 断言
-  - 文件第一行注释更新为 `-- [Systems层] 角色状态机与寻路移动`
-  - _需求:3.4、6.4_
-
-- [x] 6. 重构 systems/pet.lua 接收 IWorldQuery
-  - 将 `Pet` 改为通过 `Object:extend()` 定义(classic 风格)
-  - 修改 `Pet:new(worldQuery)` 构造函数,接收 `IWorldQuery` 实例
-  - 将内部所有碰撞检测函数调用替换为 `self._world:isCollision(row, col)`
-  - 添加 `assert(worldQuery, "Pet:new 需要 IWorldQuery 实例")` 断言
-  - 文件第一行注释更新为 `-- [Systems层] 宠物跟随与离线收益`
-  - _需求:3.3、6.6_
-
-- [x] 7. 重构 systems/player.lua 接收 IWorldQuery
-  - 将 `PlayerSystem` 改为通过 `Object:extend()` 定义(classic 风格)
-  - 修改 `PlayerSystem:new(farmSystem, gameState, blockSystem, worldQuery)` 构造函数,接收 `IWorldQuery` 实例
-  - 将模块级 `_world` 变量替换为 `self._world`,消除对 `WorldRenderer` 的直接调用
-  - 添加 `assert(worldQuery, "PlayerSystem:new 需要 IWorldQuery 实例")` 断言
-  - 确认文件中不含任何 `require("render/` 字符串
-  - 文件第一行注释更新为 `-- [Systems层] 玩家控制与工具操作`
-  - _需求:3.1、3.2、6.2_
-
-- [x] 8. 检查点 — Systems 层重构完成
-  - 确保所有测试通过,向用户确认如有疑问请提出。
-
-- [x] 8.5 重构 Engine 层模块消除直接 love 调用
-  - 重构 `engine/particles.lua`:修改为接收 `IGraphics` 注入(通过构造函数或 setter),将所有 `love.graphics.*` 调用替换为接口调用,确认文件中不含 `love.` 字符串
-  - 重构 `engine/engine.lua`:将 `love.graphics.*` 调用替换为通过注入的 `IGraphics` 接口,将 `love.filesystem.*` 调用替换为通过注入的 `IFilesystem` 接口,确认文件中不含 `love.` 字符串
-  - 重构 `engine/mod_loader.lua`:将所有 `love.filesystem.*` 调用替换为通过注入的 `IFilesystem` 接口(新增 `ModLoader.setFS(fs)` setter),确认文件中不含 `love.` 字符串
-  - 确认 `engine/save.lua`、`engine/audio.lua`、`engine/camera.lua` 已满足(无 `love.` 调用)
-  - _需求:Engine 层 love 隔离_
-
-- [x] 9. 重构 render/world_renderer.lua 接收 IWorldQuery 和 IGraphics
-  - 将 `WorldRenderer` 改为通过 `Object:extend()` 定义(classic 风格)
-  - 修改 `WorldRenderer:new(worldQuery, graphics)` 构造函数,接收 `IWorldQuery` 和 `IGraphics` 实例
-  - 移除文件中所有顶层 `require("systems/` 调用
-  - 将所有 `love.graphics.*` 调用替换为 `self._gfx:对应方法()`
-  - 确认文件中不含任何 `love.` 字符串
-  - 文件第一行注释更新为 `-- [Render层] 世界地图渲染`
-  - _需求:4.1、7.3_
-
-- [x] 10. 重构 render/farm_renderer.lua 接收 IFarmQuery 和 IGraphics
-  - 将 `FarmRenderer` 改为通过 `Object:extend()` 定义(classic 风格)
-  - 修改 `FarmRenderer:new(farmQuery, graphics)` 构造函数,接收 `IFarmQuery` 和 `IGraphics` 实例
-  - 移除文件中所有顶层 `require("systems/` 调用,改为通过 `self._farm` 接口访问
-  - 将所有 `love.graphics.*` 调用替换为 `self._gfx:对应方法()`
-  - 确认文件中不含任何 `love.` 字符串
-  - 文件第一行注释更新为 `-- [Render层] 农场格子渲染`
-  - _需求:4.4、7.2_
-
-- [x] 11. 重构 render/ui_renderer.lua 接收 IFarmQuery、IGameStateQuery 和 IGraphics
-  - 将 `UIRenderer` 改为通过 `Object:extend()` 定义(classic 风格)
-  - 修改 `UIRenderer:new(farmQuery, gameStateQuery, graphics)` 构造函数,接收三个接口实例
-  - 移除文件中所有顶层 `require("systems/farm")` 和 `require("systems/state")` 调用
-  - 将所有直接访问 `FarmSystem` 的调用替换为 `self._farm:方法名()`
-  - 将所有直接访问 `State` 的调用替换为 `self._gameState:方法名()`
-  - 将所有 `love.graphics.*` 调用替换为 `self._gfx:对应方法()`
-  - 确认文件中不含任何 `love.` 字符串
-  - 文件第一行注释更新为 `-- [Render层] HUD、商店、消息等 UI 渲染`
-  - _需求:4.1、4.2、4.3、7.1_
-
-- [x] 11.5 重构其余 Render 层文件接收 IGraphics
-  - 对 `render/block_renderer.lua`、`render/character_renderer.lua`、`render/crop_renderer.lua`、`render/drops_renderer.lua`、`render/effect_renderer.lua`、`render/inventory_renderer.lua`、`render/pet_renderer.lua`、`render/talent_renderer.lua`、`render/workbench_renderer.lua`、`render/dungeon_renderer.lua`、`render/forge_renderer.lua`、`render/render_pipeline.lua` 逐一:
-    - 将类改为通过 `Object:extend()` 定义(classic 风格)
-    - 构造函数接收 `IGraphics` 实例(`graphics` 参数)
-    - 将所有 `love.graphics.*` 调用替换为 `self._gfx:对应方法()`
-    - 确认文件中不含任何 `love.` 字符串
-  - _需求:7.4、7.5_
-
-- [x] 12. 检查点 — Render 层重构完成
-  - 确保所有测试通过,向用户确认如有疑问请提出。
-
-  - [x] 12.1 为层依赖约束编写属性测试
-    - **属性 6:Systems 层不依赖 Render 层**(需求 3.1、3.6、9.3)
-    - 扫描 `systems/` 目录所有 `.lua` 文件,验证不含 `require("render/` 字符串
-    - **属性 7:Render 层不直接 require Systems 层**(需求 4.1、4.5、9.4)
-    - 扫描 `render/` 目录所有 `.lua` 文件,验证不含顶层 `require("systems/` 字符串
-    - **属性 10:Engine 层不依赖上层模块且不直接调用 love**(需求 9.1)
-    - 扫描 `engine/` 目录所有 `.lua` 文件,验证不含 `require("systems/`、`require("render/`、`require("data/` 或 `love.` 字符串
-    - **属性 11:Render 层不直接调用 love API**
-    - 扫描 `render/` 目录所有 `.lua` 文件,验证不含 `love.` 字符串
-    - **属性 12:Systems 层不直接调用 love API**
-    - 扫描 `systems/` 目录所有 `.lua` 文件,验证不含 `love.` 字符串
-    - **属性 13:Love 适配层是唯一调用 love 的层**
-    - 扫描除 `love_adapter/` 外所有 `.lua` 文件,验证均不含 `love.` 字符串
-
-- [x] 13. 重构 game.lua 为薄协调层
-  - 在 `game.lua` 中创建 `GameStateAdapter` 类(实现 `IGameStateQuery`)
-  - 修改 `Game:new()` 按以下顺序组装对象:
-    1. 创建 Love 适配层实例(`LoveGraphics`、`LoveFilesystem`、`LoveAudio`、`LoveWindow`),这是整个项目中唯一 `require("love_adapter/...")` 的地方
-    2. 将适配层实例注入 Engine 层模块(`Save.setFS`、`Audio.setLove`、`ModLoader.setFS` 等)
-    3. 创建所有 Systems 层对象(`WorldSystem`、`FarmSystem`、`BlockSystem` 等)
-    4. 创建 `GameStateAdapter` 包装 `gameState`
-    5. 创建 Render 层对象并注入接口(`WorldRenderer(worldSystem, graphics)`、`FarmRenderer(farmSystem, graphics)`、`UIRenderer(farmSystem, gameStateAdapter, graphics)`,其余 Renderer 同样注入 `graphics`)
-    6. 创建需要接口的 Systems 对象(`PlayerSystem(farm, state, blocks, worldSystem)`、`Pet(worldSystem)` 等)
-  - 移除 `game.lua` 中所有业务逻辑代码,确保业务逻辑行数不超过重构前 30%
-  - 文件第一行注释更新为 `-- [协调层] 游戏主控制器,负责组装各层对象并传递接口`
-  - _需求:5.1、5.2、5.3、5.4、5.5、5.6_
-
-- [x] 14. 最终检查点 — 全量回归测试
-  - 运行 `spec/` 目录下所有现有测试套件,确保全部通过,无新增失败用例
-  - 确保所有测试通过,向用户确认如有疑问请提出。
-  - _需求:8.1、8.2、8.5、8.6_
-
-## 备注
-
-- 标有 `*` 的子任务为可选项,可跳过以加快 MVP 进度
-- 每个任务均引用具体需求条款,保证可追溯性
-- 检查点任务确保增量验证,避免积累问题
-- 属性测试验证跨所有输入的通用正确性,单元测试验证具体示例和边界条件
-- 测试框架使用 busted(已配置于 `.busted`),属性测试每个属性最少运行 100 次迭代

+ 292 - 184
app/src/embed/assets/README.md

@@ -1,4 +1,4 @@
-# 荷锄 — 种田游戏
+# 种田物语 — 项目文档
 
 基于 LÖVE2D (LuaJIT) 的竖屏触控农场游戏,支持 Android 打包与 Mod 系统。
 
@@ -7,249 +7,331 @@
 ## 快速上手
 
 ```bash
-# 运行游戏(桌面)
-& 'C:\Program Files\LOVE\lovec.exe' --console .
-
-# 运行测试
-busted .
+love .          # 桌面运行
 ```
 
 存档位置:
-- Windows: `%APPDATA%\LOVE\farm\`
 - Linux:   `~/.local/share/love/farm/`
+- Windows: `%APPDATA%/LOVE/farm/`
 - Android: `/sdcard/Android/data/<包名>/files/`
 
-日志文件:`%APPDATA%\LOVE\farm\game.log`(运行时错误会写入此处)
-
 ---
 
 ## 分层架构
 
 ```
-main.lua          ← LÖVE2D 回调入口,只做转发,不含逻辑
-    │
-engine/           基础设施层:引擎主循环、存档、事件总线、Mod加载
-    │
-love_adapter/     LÖVE2D 适配层:将 love API 包装为接口,隔离平台依赖
+main.lua  (23行,love 回调 → Engine 转发)
     │
-game.lua          协调层:组装所有子系统,处理输入分发与绘制调度
+engine/   基础设施层(无游戏逻辑,可独立测试)
     │
-systems/          游戏逻辑层:农场、玩家、世界、背包等纯逻辑
+systems/  游戏逻辑层(依赖 engine/ 和 data/)
     │
-render/           渲染层:所有绘制代码,依赖 systems/ 提供的接口
+render/   渲染层(依赖 systems/ 和 engine/,含 love.graphics)
     │
-data/             纯数据层:Lua table 定义,无副作用,无依赖
+data/     纯数据层(无依赖,Lua table 定义)
 ```
 
 **依赖规则:** 上层可依赖下层,同层通过 `engine/eventbus` 解耦,禁止下层依赖上层。
 
 ---
 
-## 关键设计决策
+## engine/ — 基础设施
 
-### 接口隔离(engine/interface.lua)
+| 文件 | 职责 |
+|------|------|
+| `engine.lua` | 初始化总入口(BGM/SFX/字体/Game实例/自动存档) |
+| `eventbus.lua` | 发布/订阅事件总线 |
+| `registry.lua` | 统一数据访问(getCrop/getItem/getBlock/getTool) |
+| `save.lua` | 多存档读写(save_1~3.lua),含序列化/反序列化 |
+| `camera.lua` | 摄像机(环形世界坐标,zoom,tileToScreen) |
+| `mod_loader.lua` | Mod 加载、API 工厂、钩子分发 |
+| `audio.lua` | 程序化音频合成(tone/sweep/noise/click) |
+| `sfx.lua` | 音效预合成与 Bus 事件绑定 |
+| `anim.lua` | 动画帧计时工具 |
+| `pathfinding.lua` | A* 寻路(环形地图) |
+| `particles.lua` | 粒子效果系统 |
+
+### 关键常量(engine/camera.lua)
+
+```lua
+Camera.TILE_PX  = 32      -- 每格像素
+Camera.MAP_COLS = 100     -- 地图宽(格)
+Camera.MAP_ROWS = 100     -- 地图高(格)
+```
 
-所有跨层传递的对象都通过接口定义,用 `classic.lua` 的 `Object:extend()` 实现:
+### 存档版本
 
-- `IWorldQuery` — systems 层查询世界地图(WorldSystem 实现)
-- `IFarmQuery` — render 层查询农场状态(FarmSystem 实现)
-- `IGameStateQuery` — render 层查询玩家状态(game.lua 内 GameStateAdapter 实现)
-- `IGraphics` — 绘图接口(love_adapter/graphics.lua 实现,测试用 MockGraphics)
-- `IFilesystem` — 文件系统接口(love_adapter/filesystem.lua 实现)
-- `IAudio` / `IWindow` — 音频/窗口接口
+当前版本:**17**(`engine/save.lua`)。版本不兼容时提示删除旧存档。
+多存档文件:`save_1.lua` / `save_2.lua` / `save_3.lua`,旧版兼容 `save.lua`。
 
-这样 systems/ 和 render/ 完全不直接调用 `love.*`,可以在无 LÖVE 环境下单元测试。
+---
+
+## systems/ — 游戏逻辑
+
+### 核心状态
+
+**`systems/state.lua`** — gameState 表的创建与操作
+
+```lua
+-- gameState 主要字段
+gameState.money          -- 金币
+gameState.level          -- 等级
+gameState.exp            -- 经验
+gameState.stamina        -- 当前精力
+gameState.maxStamina     -- 精力上限
+gameState.inventory      -- Inventory 实例
+gameState.equippedSlots  -- { [1]=equipId, [2]=equipId, ... }
+gameState.talents        -- { talentId: count }
+gameState.race           -- 种族 id
+gameState.class          -- 职业 id
+gameState.redeemedCodes  -- 已兑换码集合
+gameState.achievements   -- { achieveId: progress }
+gameState.quizDoneDay    -- 今日是否已答题(os.date yday)
+gameState.specialTreeDay -- 节气彩色树生成日
+gameState.lastInterestDay-- 上次利息日
+
+-- 重要函数
+State.new()                        -- 创建初始状态
+State.addExp(state, amount)        -- 加经验(自动升级+天赋选择)
+State.useStamina(state, amount)    -- 消耗精力,不足返回 false
+State.updateStamina(state)         -- 精力回复(每5分钟+1)
+State.sellAll(state)               -- 出售所有作物,返回收益
+State.sellSlot(state, slotIdx)     -- 出售单格,返回收益
+State.buySeed(state, cropId)       -- 购买种子
+State.buyItem(state, itemId)       -- 购买物品
+State.buyTool(state, toolId)       -- 购买工具
+State.rollTalentChoices(state)     -- 随机抽3个天赋选项
+State.pickTalent(state, talentId)  -- 选择天赋
+```
 
-### 对象实例化(classic.lua)
+### 农场
 
-项目使用 [classic](https://github.com/rxi/classic) 作为 OOP 基础。**正确的实例化方式是调用类本身**(触发 `__call`),而不是 `:new()`:
+**`systems/farm.lua`** — 农场格子(10×10,可扩展)
 
 ```lua
--- 正确
-local obj = MyClass(arg1, arg2)
+FarmSystem.STATE = { EMPTY, TILLED, SEEDED, READY }
+
+farm:till(row, col)                    -- 耕地
+farm:plant(row, col, cropId, gene)     -- 播种
+farm:water(row, col)                   -- 浇水
+farm:harvest(row, col, stats)          -- 收获,返回 cropId, gene, dropSeed
+farm:checkGrowth(speedMult, stats)     -- 检查生长(每60秒调用)
+farm:getTile(row, col)                 -- 返回 { state, cropId, gene, watered, plantedAt }
+farm:eachTile(fn)                      -- 遍历所有格子
+```
+
+### 背包
 
--- 错误(:new() 直接调用方法,返回 nil)
-local obj = MyClass:new(arg1, arg2)
+**`systems/inventory.lua`**
+
+```lua
+Inventory.COLS = 6   -- 列数
+Inventory.ROWS = 5   -- 行数(含快捷栏)
+Inventory.HOT_SIZE = 6  -- 快捷栏格数
+
+inv:addSeed(cropId, gene)          -- 添加种子(同基因叠加)
+inv:addCrop(cropId, gene)          -- 添加作物
+inv:addItem(item)                  -- 添加物品 { id, count }
+inv:addTool(toolId, slotIdx)       -- 添加工具
+inv:findEmpty()                    -- 找空槽,满返回 nil
+inv:getSlot(idx)                   -- 获取槽位物品
+inv:getHotItem()                   -- 获取当前快捷栏选中物品
+inv:serialize() / Inventory.deserialize(data)
 ```
 
-`new()` 方法里直接给 `self` 赋字段,不需要 `return self`(`__call` 负责返回实例)。
+### 世界地图
 
-### 适配层注入顺序(game.lua)
+**`systems/world_system.lua`** — 100×100 环形地图,双层(底层+覆盖层)
 
-`Game.new()` 按固定顺序初始化,顺序不能乱:
+```lua
+WorldSystem.init(seed)             -- 生成新地图
+WorldSystem.getTile(row, col)      -- 覆盖层优先,返回瓦片ID
+WorldSystem.setTile(row, col, id)  -- 写入(自动判断底层/覆盖层)
+WorldSystem.getBase(row, col)      -- 仅读底层
+WorldSystem.isPath/isObstacle/isCollision/isTree/isBush/isWell/isGrass/isMushroom/isGravelPile/isQuizNpc
+WorldSystem.chopTree/chopBush/pickMushroom/removeGrass/mineGravelPile
+WorldSystem.pave(row, col)         -- 铺路/拆路(自动更新连接纹理)
+WorldSystem.paveAll(blocks, farm)  -- 修路药水:全图铺路
+WorldSystem.getMapData() / loadMap(data)  -- 存读档
+WorldSystem.getBaseData() / getOverlayData()  -- 供渲染层读取
+```
 
-1. 创建 love_adapter 实例(`LoveGraphics()` 等)
-2. 将适配层注入 engine 模块(`Save.setFS`、`ModLoader.setFS`、`Anim.setGraphics` 等)
-3. 创建 systems 层对象(`FarmSystem()`、`WorldSystem()` 等)
-4. 创建 GameStateAdapter(包装 gameState 为 IGameStateQuery)
-5. 创建 render 层对象,注入接口
-6. 创建依赖接口的 systems 对象(`PlayerSystem`)
-7. 注入跨系统引用(`TickSystem.setWorld`、`Save.setWorld` 等)
+**瓦片 ID(底层):** 0/1/2=草地,12-38=路,43=碎石堆,44-82=栅栏/房屋
+**瓦片 ID(覆盖层):** 3/4=橘/绿树冠,5=灌木,15/16=树干,17=高草,29/30=蘑菇,92/104=水井,111=问答NPC
 
-### Save 模块的调用方式
+### 玩家
 
-`engine/save.lua` 里的 `_fs` 是 `IFilesystem` 实例,所有调用必须用冒号语法:
+**`systems/player.lua`** — 整合角色移动+工具操作
 
 ```lua
-_fs:exists(path)   -- 正确
-_fs.exists(path)   -- 错误(self 会变成 path,导致 getInfo(nil))
+player:useToolAt(row, col)         -- 寻路到目标格后使用工具
+player:walkTo(row, col, callback)  -- A* 寻路移动
+player:placeBlock(row, col, itemId)-- 放置方块
+player._isBlocked                  -- 碰撞检测函数(可被副本覆盖)
+player.row, player.col             -- 当前格坐标
+player.character                   -- Character 实例(含 pixX/pixY)
+player.pet                         -- Pet 实例
+player.state                       -- gameState 引用
 ```
 
----
+### 其他系统
 
-## 目录结构
+| 系统 | 关键接口 |
+|------|---------|
+| `block_system.lua` | `bs:place/mine/hasBlock/isSolid/interact/eachBlock` |
+| `tick_system.lua` | `tick:update(dt)` 每0.5秒驱动物流方块 |
+| `time.lua` | `Time.getBrightness()` `getDayNightState()` `getSolarTerm()` |
+| `weather.lua` | `weather:isRaining()` `weather:update(dt, farm)` |
+| `genetics.lua` | `Genetics.cross(a,b)` `phenotypes(gene)` `harvestCount(gene)` `sellPrice(base,gene)` |
+| `talent_stats.lua` | `TalentStats.fromState(gameState)` → stats 表 |
+| `market.lua` | `Market.getSeedPrice/getSellPrice(cropId)` `onNewDay()` |
+| `achievement_system.lua` | `AchSys.init(gameState, callback)` `_check(event, data)` |
+| `consumable_system.lua` | `ConsumableSystem.use(slotIdx, gs, farm, world)` → msg/false |
+| `equipment_system.lua` | `EquipSystem.equip/unequip/swapSlots/getStats(gs,...)` |
+| `shop_system.lua` | `shop:onTap(action, data)` → msg/nil |
+| `workbench_system.lua` | `wb:craft(recipeId)` → ok, msg |
+| `forge_system.lua` | `fg:forge(slotKey)` → ok, msg, success |
+| `quiz_npc_system.lua` | `quiz:open()` `quiz:answer(idx)` `quiz:canOpenToday()` |
+| `lighting_system.lua` | `LightingSystem.buildBrightnessMap(...)` |
+| `drops.lua` | `drops:add(item, pixX, pixY)` `drops:update(dt, ...)` |
+| `dungeon.lua` | `Dungeon.getCell/isObstacle/doTrade` `SPAWN_ROW/COL` |
+| `pet.lua` | `pet:update(dt,...)` `pet:calcOfflineReward()` |
+
+### TalentStats 返回的 stats 字段
 
 ```
-main.lua              LÖVE2D 回调入口
-conf.lua              窗口配置
-game.lua              游戏主控制器(协调层,~3000行)
-classic.lua           轻量 OOP 库
-assets/sphere.glsl        球面畸变 shader(世界层后处理)
-
-engine/
-  engine.lua          主循环、错误捕获、自动存档(每5分钟)
-  eventbus.lua        发布/订阅事件总线
-  registry.lua        统一数据访问(getCrop/getItem/getBlock/getTool)
-  save.lua            多存档读写(save_1~3.lua),版本17
-  camera.lua          摄像机(环形世界坐标、zoom、tileToScreen)
-  mod_loader.lua      Mod 加载、API 工厂、钩子分发
-  interface.lua       跨层接口定义 + MockGraphics(测试用)
-  audio.lua           程序化音频合成
-  sfx.lua             音效预合成与事件绑定
-  anim.lua            动画帧计时
-  pathfinding.lua     A* 寻路(环形地图)
-  particles.lua       粒子效果
-
-love_adapter/
-  graphics.lua        IGraphics → love.graphics
-  filesystem.lua      IFilesystem → love.filesystem
-  audio.lua           IAudio → love.audio
-  window.lua          IWindow → love.graphics.getWidth/Height
-
-systems/
-  state.lua           gameState 创建与操作(金币/经验/精力/天赋)
-  farm.lua            农场格子逻辑(耕/种/浇/收)
-  world_system.lua    100×100 环形地图(实现 IWorldQuery)
-  player.lua          玩家移动 + 工具操作(整合 Character + A*)
-  character.lua       角色像素坐标、动画状态机
-  inventory.lua       背包(30格 + 快捷栏6格)
-  block_system.lua    可放置方块(箱子/工作台/栅栏等)
-  tick_system.lua     物流方块定时驱动(每0.5秒)
-  time.lua            游戏时间、昼夜、节气
-  weather.lua         天气系统(晴/阴/雨/暴雨)
-  genetics.lua        作物基因系统(杂交、表现型、高产)
-  talent_stats.lua    天赋+种族+职业+装备 → stats 表
-  market.lua          动态市场价格
-  drops.lua           掉落物(吸引+自动拾取)
-  dungeon.lua         副本地图数据
-  pet.lua             宠物(跟随、离线收益)
-  achievement_system.lua  成就系统
-  consumable_system.lua   消耗品使用逻辑
-  equipment_system.lua    装备穿脱与套装效果
-  shop_system.lua         商店购买逻辑
-  workbench_system.lua    工作台合成
-  forge_system.lua        扑克工厂锻造
-  quiz_npc_system.lua     问答NPC
-  lighting_system.lua     夜晚光照贴图
-
-render/
-  world_renderer.lua      地图底层/覆盖层精灵(y-sort)
-  farm_renderer.lua       农场格子与作物生长动画
-  character_renderer.lua  玩家行走/动作动画(strip 精灵表)
-  ui_renderer.lua         HUD、商店、消息、飘字、Mod管理面板
-  inventory_renderer.lua  背包/快捷栏/装备槽/拖拽
-  block_renderer.lua      方块精灵
-  crop_renderer.lua       作物图标工具
-  pet_renderer.lua        宠物渲染与升级面板
-  talent_renderer.lua     天赋选择/查看面板
-  workbench_renderer.lua  工作台合成面板
-  forge_renderer.lua      扑克工厂锻造面板
-  dungeon_renderer.lua    副本地图渲染
-  drops_renderer.lua      掉落物渲染
-  effect_renderer.lua     粒子特效封装
-  render_pipeline.lua     渲染调度框架
-
-data/                     纯数据(return { ... },无副作用)
-  config.lua              全局配置(窗口/玩家初始值)
-  crops.lua               作物定义
-  items.lua               消耗品/可放置物品
-  blocks.lua              方块定义
-  tools.lua               工具定义
-  talents.lua             天赋定义
-  equipment.lua           装备(扑克牌+骰子)
-  equipment_sets.lua      套装效果
-  races.lua               种族定义
-  classes.lua             职业定义
-  achievements.lua        成就定义
-  recipes.lua             工作台配方
-  forge.lua               锻造链
-  levels.lua              升级经验表
-  quiz.lua                问答题库
-  solar_terms.lua         24节气
-  seasons.lua             季节定义
-  sfx.lua                 音效参数
-  music.lua               背景音乐
-  pets.lua                宠物定义
-  redeem_codes.lua        兑换码
-
-mods/
-  seasonal_trader/        内置示例 Mod(季节商人)
-
-spec/                     busted 单元测试
+cropSpeed, moveSpeed, shopSellBonus, shopBuyDiscount,
+maxStaminaBonus, staminaRegen, harvestCountMult, woodChopMult,
+lightRange, toolRange, noStaminaCost, flying, dailyInterest,
+extraEquipSlots, keepTilled, harvestKeepSeed, breedChance,
+rainChance, expGain, axeStaminaCost, offlineBonus, petUpgradeCostMult
 ```
 
 ---
 
-## 核心常量
+## render/ — 渲染层
+
+| 文件 | 职责 |
+|------|------|
+| `world_renderer.lua` | 代理 WorldSystem 接口 + 绘制底层/覆盖层精灵(y-sort) |
+| `farm_renderer.lua` | 农场格子与作物生长阶段绘制 |
+| `block_renderer.lua` | 方块精灵收集与绘制 |
+| `ui_renderer.lua` | HUD、商店、设置、消息、飘字 |
+| `inventory_renderer.lua` | 背包/快捷栏/装备槽/拖拽 |
+| `character_renderer.lua` | 玩家行走/动作动画 |
+| `pet_renderer.lua` | 宠物渲染与升级面板 |
+| `talent_renderer.lua` | 天赋选择/查看面板 |
+| `workbench_renderer.lua` | 工作台合成面板 |
+| `forge_renderer.lua` | 扑克工厂锻造面板 |
+| `dungeon_renderer.lua` | 副本地图渲染 |
+| `drops_renderer.lua` | 掉落物渲染 |
+| `crop_renderer.lua` | 作物图标工具函数 |
+| `render_pipeline.lua` | 渲染调度框架(register/draw) |
+| `effect_renderer.lua` | 粒子特效绘制封装 |
+
+**注意:** `world_renderer` 不持有地图数据,所有逻辑通过 `WorldSystem.getBaseData()` / `getOverlayData()` 读取。
+
+---
+
+## data/ — 纯数据
+
+所有文件均为 `return { ... }` 格式,无副作用。
+
+| 文件 | 内容 |
+|------|------|
+| `crops.lua` | 作物定义(id/name/growHours/sellPrice/seedPrice/color/solarMult) |
+| `items.lua` | 消耗品/可放置物品(id/name/desc/price/color/icon/placeable/blockId/action) |
+| `blocks.lua` | 方块定义(id/name/solid/interactive/action/itemId/icon/color) |
+| `tools.lua` | 工具定义 |
+| `talents.lua` | 天赋定义(id/name/desc/stat/value/maxStack) |
+| `equipment.lua` | 卡牌装备(扑克牌+骰子系列) |
+| `equipment_sets.lua` | 套装效果(同花色/同点数/素数/孪生素数) |
+| `races.lua` | 种族定义(id/name/desc/effects/startMoney/startTool) |
+| `classes.lua` | 职业定义(id/name/desc/effects/startEquip) |
+| `achievements.lua` | 成就定义(id/name/desc/icon/event/check) |
+| `recipes.lua` | 工作台合成配方(id/name/level/inputs/outputs) |
+| `forge.lua` | 锻造链定义 |
+| `config.lua` | 全局配置(窗口/地图参数) |
+| `levels.lua` | 升级经验表 |
+| `quiz.lua` | 问答题库(100题) |
+| `solar_terms.lua` | 24节气定义 |
+| `seasons.lua` | 季节定义 |
+| `sfx.lua` | 音效定义(程序化合成参数) |
+| `music.lua` | 背景音乐定义 |
+| `pets.lua` | 宠物定义 |
+| `redeem_codes.lua` | 兑换码定义 |
+
+---
+
+## game.lua — 主控制器
+
+`Game` 类整合所有系统,处理输入分发与绘制调度。
 
 ```lua
--- engine/camera.lua
-Camera.TILE_PX  = 32    -- 每格像素
-Camera.MAP_COLS = 100   -- 地图宽(格)
-Camera.MAP_ROWS = 100   -- 地图高(格)
+Game.new()           -- 创建实例,初始化所有子系统
+game:update(dt)      -- 每帧更新(农场生长/天气/玩家/摄像机/成就通知)
+game:onTap(x, y)     -- 点击事件总入口(按优先级分发)
+game:_tapTile(r, c)  -- 地图格子点击(空手/工具/种子)
+game:_onHold(x, y)   -- 长按(物品菜单/装备详情)
+game:drawWorld()     -- 绘制地图层(含光照/y-sort)
+game:drawUI()        -- 绘制 UI 层
+game:saveGame(silent)-- 保存到当前 slot
+game:loadGame(silent)-- 从当前 slot 读取
+game:_enterDungeon() / _exitDungeon()
+```
 
--- engine/save.lua
-version = 17            -- 存档版本,不兼容时提示删除旧存档
+**game 实例主要字段:**
+
+```lua
+game.gameState    -- 玩家状态(见 State)
+game.farm         -- FarmSystem
+game.player       -- PlayerSystem
+game.blocks       -- BlockSystem
+game.tick         -- TickSystem
+game.weather      -- Weather
+game.ui           -- UIRenderer
+game.invRender    -- InventoryRenderer
+game.particles    -- Particles
+game.drops        -- Drops
+game.anim         -- 动画时钟(秒)
+game.startScreen  -- true = 主菜单显示中
+game.inDungeon    -- true = 副本模式
 ```
 
 ---
 
-## EventBus 主要事件
+## EventBus 事件列表
 
 模块间通信通过 `Bus.emit(event, data)` / `Bus.on(event, fn)` 解耦。
 
 | 事件 | 触发时机 | data 字段 |
 |------|----------|-----------|
 | `tile_harvested` | 收获作物 | `cropId, row, col, count, gene, dropSeed` |
+| `tile_planted` | 播种 | `cropId, row, col, gene` |
 | `tile_tilled` | 耕地 | `row, col` |
 | `tile_watered` | 浇水 | `row, col` |
-| `tree_chopped` | 砍树 | `row, col, wood` |
+| `tile_paved/unpaved` | 铺/拆路 | `row, col` |
+| `tree_chopped` | 砍树 | `row, col, count` |
+| `bush_chopped` | 砍灌木 | `row, col, count` |
+| `mushroom_picked` | 采蘑菇 | `row, col, itemId` |
 | `gravel_mined` | 采碎石堆 | `row, col, count` |
 | `block_placed/mined` | 放置/挖掉方块 | `row, col, blockId` |
-| `block_interact` | 交互方块 | `row, col, action, blockData` |
-| `gain_exp` | 获得经验 | `amount` |
+| `block_interact` | 交互方块 | `row, col, blockId, action` |
 | `player_levelup` | 玩家升级 | `level` |
-| `sold` | 出售作物 | `amount` |
-| `day_changed` | 游戏日切换 | — |
-| `weather_changed` | 天气/节气变化 | `solarTerm` |
+| `gain_exp` | 获得经验 | `amount` |
+| `item_bought/seed_bought/tool_bought` | 购买 | `id/cropId/toolId` |
+| `sold` | 出售 | `cropId, count, earned` |
+| `craft_success` | 合成成功 | `{}` |
+| `equip_changed` | 装备变化 | `{}` |
+| `talent_picked` | 选择天赋 | `talentId` |
+| `weather_changed` | 天气变化 | `weather` |
+| `dungeon_entered` | 进入副本 | `{}` |
+| `quiz_correct/wrong` | 答题结果 | `{}` |
 | `achievement_unlocked` | 解锁成就 | `id` |
-| `show_msg` | 显示底部消息 | `text` |
-| `item_drop` | 背包满掉落 | `item, pixX, pixY` |
-
----
-
-## 测试
-
-```bash
-busted .
-```
-
-| 文件 | 覆盖内容 |
-|------|---------|
-| `spec/regression_core_spec.lua` | Genetics/Inventory/EventBus/Market/State/Save |
-| `spec/phase1~6_*_spec.lua` | 各层路径与接口验证 |
-| `spec/layered_arch/` | 属性测试(层依赖、接口契约) |
-| `spec/helpers/love_mock.lua` | love API stub,无需 LÖVE 运行时 |
+| `save_success` | 存档成功 | `{}` |
+| `show_msg` | 显示消息 | `text` |
+| `crop_ready` | 作物成熟 | `row, col, cropId` |
+| `pet_levelup` | 宠物升级 | `level` |
 
 ---
 
@@ -257,25 +339,51 @@ busted .
 
 详见 `MOD_GUIDE.md`。
 
-Mod 放在存档目录的 `user_mods/<mod_name>/mod.lua`,内置 Mod 在 `mods/` 下。主菜单有 Mod 管理面板,可按存档槽独立启用/禁用。
+**Mod 目录:**
+- 内置:`mods/<mod_name>/mod.lua`
+- 用户:`user_mods/<mod_name>/mod.lua`(存档目录下)
+
+**mod.lua 格式:**
 
 ```lua
--- mod.lua 最小结构
 return {
-    priority = 50,  -- 加载顺序,越小越先
+    priority = 50,
     init = function(api)
         -- api.registerCrop/Item/Block/Tool/Talent/Race/Class/Achievement/Recipe
         -- api.overrideCrop/Item/Block/Tool/Talent
         -- api.wrapFunction(modulePath, fnName, wrapper)
-        -- api.addConsumable / addToolAction / addDraw / addTick / addKey
+        -- api.addConsumable(itemId, fn)
+        -- api.addToolAction(toolId, fn)
+        -- api.addDraw("world"|"ui", fn)
         -- api.on(event, fn) / api.emit(event, data)
+        -- api.addTick(interval, fn) / api.addKey(key, fn)
         -- api.replaceAsset(virtualPath, modRelativePath)
-        -- 运行时(只在回调里用):getGame/getFarm/getPlayer/getGameState
-        -- api.addMoney/addExp/addStamina/addItem/showMsg
+        -- api.getGame/getFarm/getPlayer/getBlocks/getGameState/getWorld
+        -- api.addMoney/addExp/addStamina/addItem/showMsg/addFloat
     end,
 }
 ```
 
+**注意:** `init` 阶段不能调用运行时 API(`getGame()` 等),请在 `on/addTick` 回调里使用。
+
+---
+
+## 测试
+
+```bash
+busted --lua lua5.1 spec/
+```
+
+| 测试文件 | 覆盖内容 |
+|----------|---------|
+| `spec/regression_core_spec.lua` | 核心逻辑回归(Genetics/Inventory/EventBus/Market/State/Save) |
+| `spec/phase1_engine_paths_spec.lua` | engine/ 路径验证 |
+| `spec/phase2_systems_paths_spec.lua` | systems/ 路径验证 |
+| `spec/phase3_world_system_spec.lua` | WorldSystem 接口验证 |
+| `spec/phase4_game_split_spec.lua` | 各提取 system 接口验证 |
+| `spec/phase5_6_engine_render_spec.lua` | Engine/RenderPipeline 验证 |
+| `spec/helpers/love_mock.lua` | love API stub(无需 LÖVE 运行时) |
+
 ---
 
 ## 存档版本历史
@@ -284,4 +392,4 @@ return {
 |------|------|
 | 15 | 基础版本 |
 | 16 | 新增 quizDoneDay |
-| 17 | 新增 achievements、enabledMods、多存档(save_1~3.lua) |
+| 17 | 新增 achievements、enabledMods、多存档支持 |

+ 0 - 0
app/src/embed/assets/assets/VonwaonBitmap-16px.ttf → app/src/embed/assets/VonwaonBitmap-16px.ttf


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_big_cactus_02.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_big_cactus_03.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_big_cactus_04.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_big_flower_01.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Agave_Cactus_01.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Agave_Cactus_02.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Agave_Cactus_03.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Agave_Cactus_04.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Bush_01.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Bush_02.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_02.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_03.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_04.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_05.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_06.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_07.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_09.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_10.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_11.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_12.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_13.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_14.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Cactus_15.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Flower_01.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Flower_02.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Flower_03.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Desert_small_Flower_04.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_big_cypress_01.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_big_cypress_02.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_big_cypress_03.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_big_stone_01.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_big_stone_02.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_big_tree_leaf_01.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_big_tree_needle_03.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_big_tree_needle_04.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_deadBush (3).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_deadTree (1).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_deadTree (2).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_deadTree (4).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_deadbush(5).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_bush_01.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_bush_02.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_clover_01.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_clover_02.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_clover_03.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_fern_01.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_fern_02.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_flower_01.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_flower_02.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_flower_03.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_grass_01.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_grass_02.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_grass_03.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_grass_04.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_grass_05.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_grass_06.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_grass_07.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_grass_08.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_mushroom_01.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_mushroom_02.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_mushroom_03.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_mushroom_04.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_tree_log_01.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_tree_log_02.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_tree_log_03.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_tree_stump_01.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_tree_stump_02.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_Forest_small_tree_stump_03.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_bamboo (1).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_bamboo (2).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_bamboo (3).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_bamboo (4).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_bamboo (5).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_bamboo (6).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_bamboo (7).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_bamboo (8).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_desert_skull_01.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_desert_skull_02.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_desert_skull_03.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_forest_berrybush.png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_forest_bush (4).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_forest_bush (5).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_reed (1).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_reed (2).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_reed (3).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_reed (4).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_reed (5).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_reed (6).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_reed (7).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_reed (8).png


BIN
app/src/embed/assets/assets/foliage/GSS_Foliage_stone (1).png


Некоторые файлы не были показаны из-за большого количества измененных файлов