Files
farm_service/docs/catalogue.md
T

6.9 KiB
Raw Blame History

作物目录独立维护与发布

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;发布脚本不安装依赖、不访问网络或玩家数据库。 从本仓库根目录运行:

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 只读核对源与当前最新发布版本,源已修改时会拒绝,且不会生成 目录或替换清单。变更后先运行测试,再显式生成:

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。 字体保持独立发布,不纳入四文件目录版本。