mirror of
https://github.com/Shu-Ying/farm_service.git
synced 2026-11-02 18:50:01 +08:00
add # 新增对资源文件的维护
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
# 作物目录独立维护与发布
|
||||
|
||||
`catalogue/source/` 是日常维护的正式来源,不再读取 Farm 仓库或旧作物库。
|
||||
首次迁出保留 202 条作物的全部业务字段、768 张图片的原始字节及现有布局。
|
||||
原 `assets.zip` 和小型 `land-soils.zip` 字节不变,旧迁移基线保持原样。
|
||||
|
||||
## 源目录
|
||||
|
||||
- `plants.json`:根对象仅含 `schema: 1` 和 `plants` 数组。
|
||||
- `metadata.json`:维护画布、布局、定位、panel 等绘图配置;发布工具重建
|
||||
`plants` 和 `images`,不要手工修改这两个生成字段。
|
||||
- `images/<原 ZIP 路径>`:PNG/JPEG 等原始图片,每个文件对应同名 ZIP 成员。
|
||||
- `land-soils.zip`:精确包含 `soil/红土地.png`、`soil/黑土地.png`、
|
||||
`soil/金土地.png` 三张可解码图片。
|
||||
|
||||
作物 `id` 为永久编号,不能重排、复用、删除或更名。名称唯一且不超过
|
||||
128 字符,不能为 `.`、`..` 或包含 `/`、`\`。数值仅允许 64 位有符号
|
||||
范围内非负整数,`id`、`time`、`crop`、
|
||||
`harvest` 必须为正;`time` 为小时,转换为秒仍须在范围内。
|
||||
`level/buy/vipBuy/experience/price` 分别控制等级、种子普通币价格、点券价格、
|
||||
经验和收获物售价。`isVip`、`isBuy` 和可选 `enabled` 仅允许 0 或 1;
|
||||
可选 `crop_type` 默认为 1,只有类型 1 可新种植。
|
||||
|
||||
`phase` 为逗号分隔的正整数秒值,按首次出现去重后须严格递增且至少两项;
|
||||
它与 `general/offsetH/offsetW/offsetX/offsetY` 一并生成展示元数据。
|
||||
其他已有字段原样保留。图片原有缺图占位行为保留,但不能删除已经发布的
|
||||
图片路径;新增作物应同时补充所需阶段图片。
|
||||
|
||||
发布工具独立校验完整展示契约:30 个地块位置、schema 4 作物放置、
|
||||
面板字段及贴图、虫动画、六主题装饰、画布与图片尺寸,以及所有必需
|
||||
背景和通用图片引用。schema 不接受布尔值,坐标不接受布尔值或非有限数。
|
||||
|
||||
## 编辑、检查、生成
|
||||
|
||||
需要 Python 3.10+ 和 Pillow;发布脚本不安装依赖、不访问网络或玩家数据库。
|
||||
从本仓库根目录运行:
|
||||
|
||||
```text
|
||||
python scripts/prepare_catalogue.py --source catalogue/source --output catalogue --version catalogue-20261026-1 --check
|
||||
python -m unittest discover -s tests -p test_prepare_catalogue.py
|
||||
```
|
||||
|
||||
`--check` 只读核对源与当前最新发布版本,源已修改时会拒绝,且不会生成
|
||||
目录或替换清单。变更后先运行测试,再显式生成:
|
||||
|
||||
```text
|
||||
python scripts/prepare_catalogue.py --source catalogue/source --output catalogue --version catalogue-20261027-1
|
||||
python scripts/prepare_catalogue.py --source catalogue/source --output catalogue --version catalogue-20261027-1 --check
|
||||
```
|
||||
|
||||
例如把已有条目的 `price` 改为新售价,或新增从未使用过的 ID;不要把
|
||||
旧 ID 改成另一个作物。`isBuy=0` 表示禁售,`enabled=0` 禁止新购买和新播种。
|
||||
生成时对照当前已校验版本,拒绝删除/更名旧 ID 或丢失已有图片路径。
|
||||
|
||||
产物位于 `catalogue/releases/<release>/`,包含清单和精确四个文件:
|
||||
`plants.json`、`metadata.json`、`assets.zip`、`land-soils.zip`。
|
||||
生成完整目录后,最后原子替换 `catalogue/manifest.json` 发现入口;失败
|
||||
不会切换最新版本。已存在版本必须逐字节相同,不能原地覆盖。相同内容
|
||||
重复生成须沿用相同版本标签;仅更换标签不能覆盖相同内容的历史清单。
|
||||
已经发布的标签也不能用于内容不同的新版本,修改内容时必须使用新标签。
|
||||
|
||||
发布操作按输出目录同时使用进程内线程锁和系统文件锁,锁覆盖读取最新
|
||||
版本、兼容性检查与最终替换,防止并发旧发布删除刚新增的 ID。系统锁在
|
||||
进程退出时自动释放;`.publish.lock` 是应保留的空状态锁文件,不应删除,
|
||||
仓库已忽略它。`--check` 保持只读,不创建或修改锁文件。
|
||||
|
||||
ZIP 使用固定成员顺序、2020-01-01 时间、Unix 0644 文件权限和 STORED 格式,
|
||||
保留图片原始字节。输出不依赖文件修改时间或 Farm 相邻工作区。
|
||||
临时 `.prepare-*` 目录不是有效发布版本,可在确认没有发布进程后清理。
|
||||
|
||||
## 清单协议与 HTTP
|
||||
|
||||
清单严格包含 `schema/version/release/files`:schema 固定 1;version 为
|
||||
1~64 个字母数字或 `._-`;files 精确对应四文件,每项仅含正整数
|
||||
`size_bytes` 和 64 位小写 `sha256`。release 为 files 对象经键排序、紧凑
|
||||
UTF-8 JSON 序列化后的 SHA256,不接受 URL 或自定义路径。
|
||||
|
||||
清单最大 16 KiB;plants 2 MiB;metadata 4 MiB;各 ZIP 64 MiB;两个 ZIP
|
||||
解压后图片总量不超过 256 MiB。源发布工具校验业务数据与图片,Rust 服务
|
||||
启动校验各历史清单关系、文件大小和摘要;客户端也校验完整版本。
|
||||
这些摘要检测不一致和损坏,不构成发布账号被接管时的真实性保证。
|
||||
|
||||
设置 `FARM_CATALOGUE_DIR=./catalogue` 后,服务启动加载最新清单及所有
|
||||
历史版本为不可变内存快照:
|
||||
|
||||
| 接口 | 行为 |
|
||||
|---|---|
|
||||
| `GET /v1/catalogue/manifest.json` | 最新清单,`no-cache`,支持 ETag |
|
||||
| `GET /v1/catalogue/releases/{release}/{file}` | 精确白名单四文件和该版本 `manifest.json`;一年 immutable 缓存,支持 ETag |
|
||||
|
||||
接口公开只读,不需要用户资料接口令牌。未配置目录时返回 503;未知版本
|
||||
和文件返回 404;无效目录或摘要导致启动失败,并写入既有日志。
|
||||
运行中不重读磁盘,发布后须重启 Service。旧素材/字体接口及用户资料鉴权
|
||||
保持独立。所有历史版本都会驻留内存,部署前须按版本数量规划内存。
|
||||
|
||||
GitHub/Gitea 同样从本仓库 raw 根路径的 `catalogue/manifest.json` 和
|
||||
`catalogue/releases/<release>/<file>` 获取相同字节。应先发布完整版本目录,
|
||||
最后发布发现入口,保留历史版本;本工具仅准备本地文件,不执行提交、
|
||||
推送或部署。真实远端下载与生产重启需在发布后另行验证。
|
||||
|
||||
## 重启生效与兼容回滚
|
||||
|
||||
机器人仅在启动时检查一次更新,同一次运行使用一个完整版本,失败优先
|
||||
回退已校验缓存,再回退插件初始版本。若选定版本无法覆盖玩家已持有或
|
||||
已种植的 ID,应拒绝业务初始化,恢复兼容版本后再启动,不能清空玩家数据。
|
||||
|
||||
新播种使用本次启动目录;已经播种的地块继续使用原结算快照。出售使用
|
||||
当前目录售价,调价也会影响旧库存。回滚应从当前源发布一个新兼容版本:
|
||||
恢复旧数值,但保留期间新增的全部 ID、名称及图片,需要下架时使用禁售/
|
||||
禁播字段。不能把最新清单直接退回缺少新 ID 的老版本。
|
||||
|
||||
Farm 随包的轻量 bootstrap 由显式同步工具从本地完整 release 刷新,日常
|
||||
Service 发布不要求同时改 Farm;三个机器人分发包继续不捆绑大型素材 ZIP。
|
||||
字体保持独立发布,不纳入四文件目录版本。
|
||||
@@ -0,0 +1,126 @@
|
||||
# 作物数据与素材独立维护设计
|
||||
|
||||
日期:2026-10-26。状态:用户已确认,实施中;本地完成后记录验证证据。
|
||||
|
||||
## 目标与已确认决定
|
||||
|
||||
- 作物数值及可维护素材的正式来源迁入 `farm_service`,不再从农场插件的
|
||||
`legacy` 基线生成日常发布数据。
|
||||
- 用户已明确选择:机器人仅在启动时检查更新。运行中不定时更新,
|
||||
本次启动选定的版本持续使用到关闭。
|
||||
- 真寻、NoneBot、AstrBot 共用同一加载实现,沿用已有 Github、Gitea、
|
||||
farm_service 资源源选择与独立的服务基础地址配置。
|
||||
- 保留玩家数据库、地块中保存的作物结算快照及旧迁移基线。
|
||||
- 本轮只完成本地实现、验证和维护说明;提交、推送、部署及安装另行授权。
|
||||
|
||||
## 方案取舍
|
||||
|
||||
1. 启动时检查完整资源版本:用户最终选择。可以独立发布作物更新,
|
||||
同一次机器人运行期间不切换规则,生命周期与缓存管理较简单。
|
||||
2. 运行中定时更新:用户已改为不采用。需要额外处理交易和渲染任务
|
||||
跨版本切换、任务取消与长期更新调度。
|
||||
3. 只迁移维护源、插件固定版本:不采用。更新数值仍需重新发插件。
|
||||
|
||||
## 正式来源与发布产物
|
||||
|
||||
- Service 仓库保存可编辑的作物目录、图片源和绘图配置。旧目录中的
|
||||
202 条作物及现有图片仅作为首次迁出的来源;迁出后不修改旧基线。
|
||||
- 作物保留有业务意义的字段;移除将旧数据库摘要当成日常维护来源
|
||||
的依赖。新增数据协议说明、字段校验和维护示例。
|
||||
- 发布工具由上述来源可复现生成 `plants.json`、`metadata.json` 和
|
||||
`assets.zip`、`land-soils.zip`,以及绑定四者的发布清单。字体继续单独维护。
|
||||
- 清单包含协议版本、发布版本和各文件的大小、SHA256;下载路径固定,
|
||||
不接受玩家输入路径。每个发布版本存于不可变版本目录,最新清单
|
||||
仅作为版本发现入口,保留历史版本供旧客户端和回滚使用。
|
||||
- GitHub/Gitea 从 Service 仓库读取公开文件;Service 提供等价的公开
|
||||
只读清单及版本文件接口,不复用用户资料接口令牌。
|
||||
- 发布工具先生成并校验完整版本,最后才更新最新版本指针。
|
||||
发布后的版本目录不得原地覆盖;修正内容应生成新版本。
|
||||
|
||||
## 插件启动与失败处理
|
||||
|
||||
1. 日志初始化后、玩家数据库迁移和业务服务初始化前,读取本地当前版本。
|
||||
2. 在线检查所选资源源的最新清单,限制大小、超时及 HTTPS 地址格式;
|
||||
不自动跨源下载,不请求占位 Service 地址。
|
||||
3. 若版本未变化,复核并复用本地内容;否则下载缺少文件至独立临时目录。
|
||||
4. 校验协议、大小、SHA256、作物业务字段、唯一编号及名称、展示配置
|
||||
与目录对应关系、ZIP 成员集合和图片内容。任何一项失败都不切换版本。
|
||||
5. 校验全部通过后,以不可变目录保存候选版本,原子更新本地当前版本
|
||||
指针。业务目录、绘图元数据和图片始终取自同一完整版本。
|
||||
6. 在线检查或下载失败时使用当前已验证缓存;缓存缺失或损坏时使用
|
||||
随插件生成的初始作物目录与匹配展示配置。初始版本图片仍按已有
|
||||
外部资源策略加载;完全离线且没有图片缓存时提供文字功能。
|
||||
7. 本次运行不再次切换目录,不创建更新定时任务。网络操作在后台线程
|
||||
执行;超时、拒绝原因、采用版本和回退来源写入日志,不记录凭据。
|
||||
|
||||
启动前须确认选定目录覆盖现有玩家库使用的作物 ID。若缓存损坏且
|
||||
初始目录不包含玩家已持有的新作物,应明确拒绝业务初始化并提示恢复
|
||||
兼容版本;不得清除库存、替换 ID 或伪装成正常启动。空数据目录仍可
|
||||
通过初始目录离线启动。读取玩家库仅用于兼容性检查,不导出真实数据。
|
||||
|
||||
最新清单通过已有发布方 HTTPS 地址获取,摘要用于一致性和损坏检测,
|
||||
不宣称其可防御发布账号或源站被接管。未知协议版本必须拒绝并回退。
|
||||
|
||||
## 存量兼容与字段约束
|
||||
|
||||
- 作物 ID 永不重排、复用或更换含义。新增作物使用从未使用过的新 ID。
|
||||
- 本轮不支持删除或更名已有作物;发布工具对照前一版本拒绝这类操作。
|
||||
下架用 `isBuy=0`,禁止新购买和新播种用 `enabled=0`,保留旧库存结算。
|
||||
- 已播种地块继续使用数据库中的不可变作物定义,更新不重写成熟时间、
|
||||
产量、经验、季数和再生长规则;新播种使用本次启动加载的目录。
|
||||
- 出售使用当前目录价格,包含更新前已存在的库存。这沿用现有行为,
|
||||
必须在维护说明中提示调价影响。
|
||||
- 新版本应保留已有作物的展示资源引用及存量绘制所需阶段图片;
|
||||
原有缺图占位行为保留,不要求首次迁移凭空补齐历史缺图。
|
||||
- 回滚采用“发布新的兼容版本恢复旧数值”,保留期间新增的全部 ID
|
||||
及其图片,必要时禁售或禁播。不能将最新指针直接退回缺少新增作物
|
||||
的历史版本。客户端对照本地已验证版本拒绝删除和更名,避免旧库存
|
||||
无法查询或出售。这是实现者根据稳定 ID 约束提出的回滚方案。
|
||||
- 不执行玩家数据清理、重置、隐式批量迁移或远程管理写入。
|
||||
|
||||
## 代码和 CI 调整
|
||||
|
||||
- Service 实现发布文件校验、公开只读分发与可重复构建工具;提供独立
|
||||
源目录和更新步骤,日常维护不要求旁边存在 Farm 开发仓库。
|
||||
- Farm 核心继续只处理已校验的离线目录,不增加网络或 Pillow 依赖。
|
||||
- 共享适配层负责启动下载、完整版本选择和故障回退;渲染器支持传入
|
||||
同版本元数据,避免继续强制读取插件内固定 `metadata.json`。
|
||||
- Farm 保留一套可复现的初始数据产物,提供显式刷新初始版本的工具;
|
||||
CI 校验该版本自身一致性,不访问生产最新数据,不要求相邻 Service
|
||||
仓库,也不再要求日常目录与旧 `plant.db` 字节导出一致。
|
||||
- 旧基线完整性与迁移测试继续独立运行;不能通过刷新基线哈希来放行
|
||||
新作物。三个框架打包包含共享加载模块及必要初始数据,继续不捆绑
|
||||
大型 `assets.zip` 或字体 ZIP。
|
||||
|
||||
## 验收场景
|
||||
|
||||
1. 首次迁出作物数值、图片与现有版本一致,旧基线保持原样。
|
||||
2. 在 Service 正式来源新增作物或调整数值,发布工具生成有效新版本;
|
||||
不修改 Farm 业务源码或旧基线,重启测试运行实例即可加载。
|
||||
3. 一次启动只采用一个完整版本;文件混用、摘要错误、非法字段、未知
|
||||
协议、删除/复用旧 ID 等情况被拒绝,当前缓存不受损。
|
||||
4. 网络超时、404、资源源不可用时优先复用已验证缓存;无缓存时初始
|
||||
目录仍能提供文字业务,图片不可用有明确日志。
|
||||
5. 旧种植快照结算不变,新播种使用新规则,旧库存按当前价格出售。
|
||||
更新后新增作物已进入库存时,缺少该 ID 的回滚版本会被拒绝;
|
||||
兼容回滚保留该 ID。缓存丢失且初始目录不兼容时拒绝业务初始化。
|
||||
6. Service 与 GitHub/Gitea 使用同样的发布内容;历史版本可读取,未知
|
||||
路径和版本拒绝,用户资料鉴权及字体分发行为保持有效。
|
||||
7. 三框架包与离线 CI 通过,不依赖真实远端或相邻开发仓库;提供
|
||||
“编辑—检查—生成—发布—重启生效—回滚”的维护说明。
|
||||
|
||||
## 实施与验证边界
|
||||
|
||||
使用 Python 标准库为主的共享下载与缓存,沿用 Rust/Axum 服务结构。
|
||||
开发测试使用临时目录和人工测试数据,不访问真实玩家库或启动机器人。
|
||||
覆盖发布生成、HTTP 路由、异常缓存、并发写入、规则快照及三端打包;
|
||||
Rust 执行格式、测试和静态检查,Python 执行针对性与最终离线检查。
|
||||
真实 GitHub/Gitea 发布、生产下载、Service 部署及宿主消息验证不作为
|
||||
本地通过的结论,单独列出尚未执行事项。
|
||||
|
||||
## 实施决定
|
||||
|
||||
- 用户已确认本设计作为实施与验收依据,采用当前工作区,不提交、合并或推送。
|
||||
- 实施前重新查询 Comet,返回无可恢复的 active change,未强建额外工作流。
|
||||
- Service 已迁出独立源并生成初始四文件版本,提供启动校验和公开只读分发;
|
||||
维护步骤见 `catalogue.md`。跨端最终验证由实施计划统一记录。
|
||||
Reference in New Issue
Block a user