8.3 KiB
Coin Madness 开发与接入说明
本次已实现的规则
- 同一账号每期仅能购买一次;一次支付解锁整期任务,没有付费档位,也没有购买即送金币。
- 付费确认前不计数、不追溯历史通关。 从服务端确认付款之后开始记录主线新关胜利。
- 阶段独立计数:例如 2、3、5 关,需要分别完成 2、再 3、再 5 关。
- 达标后暂停计数,领取后才进入下一阶段。 等待领取期间的胜利不会带入下一段。
- 只接入正常主线胜利结算。登录同步、重复结算、无限关不增加进度;一次跳过多个关卡的同步也不追溯。
- 统一使用服务端毫秒时间,
startsAt <= now < endsAt。截止后不再购买或增加进度。 - 到期仅补发已付费、当前阶段已达标但未领取的金币。未达标部分失效。玩家回到首页或打开活动时执行补发,离线期间保留待处理状态。
客户端目录与内存
assets/coin_madness/ 是独立 Asset Bundle,名称 coin_madness。微信、字节跳动构建采用 subpackage;当前付费能力只接入微信原生道具直购。
CoinMadness.prefab:活动根预制体,无对其他活动图集、场景或预制体的依赖。CoinMadnessPanel.ts:橙色活动面板、倒计时、付费入口、滚动任务列表、状态与领取交互。当前使用系统字体和矢量金币,后续美术资源应放在同一个 Bundle 中。assets/Script/CoinMadnessHost.ts:必要的常驻小桥接层,只负责首页入口、JSON 请求、奖励同步及 Bundle 生命周期;不静态导入活动 UI 类。- 首次展示前不调用
loadBundle。点击入口后依次loadBundle('coin_madness')、bundle.load('CoinMadness', cc.Prefab)。 - 关闭时销毁节点;等待 Cocos 延迟销毁完成,再调用
bundle.releaseAll()和cc.assetManager.removeBundle(bundle)。移除定时回调、显示事件监听及 UI 引用,不缓存预制体。 - 对重复点击、场景切换时迟到的加载回调及正在释放时重新打开做了保护。刷新列表先销毁旧节点,避免仅移除父节点造成泄漏。
- 小游戏平台已经执行的 JS 模块和磁盘下载缓存不能保证通过 Cocos API 从进程/设备中卸载。这里释放的是界面实例、图形/文字资源和 Bundle 缓存,不承诺删除平台脚本缓存。
释放方式依据:Cocos Creator 2.4 Asset Bundle 文档。
原有代码改动范围
| 文件 | 必要接入 |
|---|---|
assets/Script/JiaZai.ts |
首页挂载 Host,未改原有场景和活动预制体 |
assets/Script/GameManager.ts |
登录时恢复未确认的金币奖励回执,只处理该活动的金币 |
assets/Script/module/Pay/Utils.ts |
通关上传增加可选的活动胜利标记,其他调用默认不计数 |
assets/Script/module/Tool/GameTool.ts |
正常主线胜利结算时传入标记 |
functions/userLevel.ts |
原有通关保存成功后更新独立活动进度,异常不阻塞原有通关 |
functions/userCoin.ts |
有待确认回执时暂停旧金币快照覆盖;钱包版本比较避免并发旧快照覆盖新奖励 |
functions/wx/orderPaySig.ts、iosorderPaySig.ts |
仅对 coin_madness 新增期次/资格校验、服务端价格和订单复用 |
functions/wx/payCallBack.ts |
已验签且匹配的活动订单解锁,不直接发金币;重复通知不重复解锁 |
functions/wx/getOrderReward.ts |
禁止通用发奖接口提前消费此活动订单 |
functions/wx/KeFuInfo.ts |
拒绝通过旧客服通道绕过本活动订单校验 |
服务端配置
云函数 coinMadness 与共享模块 coinMadnessModel 都需要同步到 Laf;同时同步表中修改的云函数。没有部署操作包含在本次本地开发中。
环境变量 COIN_MADNESS_CONFIG 内容为 coinMadness.config.example.json 的完整 JSON。默认关闭,没有默认售价、7 天有效期或正式奖励值。enabled 和 approved 均为 true 且所有字段校验通过时才开放。
| 字段 | 策划/运营填写 |
|---|---|
periodId |
唯一期次编号,1–64 位字母、数字、下划线或横线;已用期次不得复用 |
startsAt / endsAt |
统一起止时间,Unix 毫秒,结束大于开始 |
minLevel |
已完成主线关卡数门槛,非负整数 |
priceCents |
微信人民币分,正整数;注册商品 ID 固定为 coin_madness |
stages |
1–50 个 { "wins": 正整数, "coins": 正整数 } |
title |
活动名称,1–40 字符 |
活动首次建立时保存配置快照,避免调整配置影响已产生的任务或订单。修改正式数值应使用新期次;已付费的旧快照即使当前配置关闭,仍可正常领取/到期结算。新期次不继承旧期进度或购买权益,上一期结算/回执处理完成后再创建新期。
本地预览中的价格和任务表仅为测试数据,不写入正式服务端配置。
支付与奖励恢复
- Android 和支持
requestMidasPaymentGameItem的 iOS 使用现有微信签名通道,商品金额、数量由服务端决定。 - 用户每期保留同一个待支付订单号;取消、网络失败或切换设备后重试不会生成第二个可付款订单。数据库订单
_id使用该订单号,阻止并发重复插入。 - 旧 iOS 客服付款不支持此新商品;客户端会说明当前平台不支持,服务端也阻止绕过。正式上线前需确认目标客户端支持原生道具直购。
- 服务端确认晚于截止的付款不解锁新期,订单写入
coinMadnessReviewReason=confirmed_after_deadline,需要客服核对并退款。不自动退款。这一异常流程应在活动上线前落实运营处理人。 users.coinMadnessState:期次快照、购买状态、当前阶段和进度、通关高水位。users.coinMadnessPending:持久化待确认奖励回执,和阶段状态、金币余额在同一条件更新内保存。users.coinMadnessWalletRevision:防止领取前发出的旧金币上传在领取后覆盖奖励。- 客户端将金币与回执号一起落盘,然后确认;响应丢失可以重读/重试。登录有未确认回执时采用其服务端金币余额,避免再次加币。
- 金币上传继续遵循原游戏客户端快照体系,本次未改为全游戏服务端权威钱包。验证范围是本活动重复请求与并发旧快照防护;全游戏其他活动之间的跨设备资源冲突仍需整体经济系统联调。
验证命令与结果
需要 Node.js 24 及项目 TypeScript 依赖。
node --import ./server/laf-cloud/tests/register-typescript.mjs --test server/laf-cloud/tests/coin-madness.test.mjs
16 项新测试通过,覆盖未付费计数、独立阶段、领取前暂停、重复结算、期限、配置与鉴权、服务端定价、订单复用、签名通知、重复/并发领取、回执重试、到期补发、跨期重置和旧金币上传竞争。
本地 Cocos 组件预览(无真实支付、无线上请求):
node tools/coin-madness/preview.cjs
# 在另一终端执行;可用 PLAYWRIGHT_MODULE 指定已安装的 Playwright 模块路径
node tools/coin-madness/check-preview.cjs
预览使用本机 Cocos Creator 2.4.15 引擎、项目导入缓存、实际 Host 和实际预制体,经真实 Asset Bundle 加载。可通过 COCOS_CREATOR_PATH 指定编辑器目录。首次需要用 Creator 导入本项目,生成 library/imports 中的内建资源。默认使用 Edge 无头模式,可用 BROWSER_CHANNEL 调整。
已验证:文字显示、未购买/可领取/下一阶段状态、双击只领取一次、列表刷新不增加文字节点、连续开关 10 次后 Bundle 不存在且活动节点为 0,资源缓存回到打开前数量;Host 销毁后迟到的预制体加载同样释放资源。
旧支付/丛林活动回归共 38 项,其中 31 项通过、7 项失败;对照修改前 HEAD 后失败项完全一致,未顺带修改旧活动规则。整个仓库 TypeScript 检查受原有 drawHead.ts 语法错误阻断;客户端独立检查也有原有声明/类型错误,新增代码未新增诊断。完整 Creator 命令行构建停在资源导入阶段,尚未取得整包构建成功证据。仍需在微信真机和测试支付环境完成最终验收。