news 2026/5/8 2:40:30

实战篇:基于 ET 框架实现 CDKEY 礼包

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
实战篇:基于 ET 框架实现 CDKEY 礼包

实战篇:基于 ET 框架实现 CDKEY 礼包

礼包码系统是游戏运营侧最高频的需求之一,看似简单,实际上暗坑不少。本文从为什么做、怎么设计、怎么防护三个维度展开,最后用 ET 框架落地一套伪代码实现。


一、为什么需要 CDKEY 礼包

CDKEY(兑换码)礼包是运营与玩家之间最轻量的物质连接。它不依赖支付流程,不需要玩家填写任何个人信息,只需要一串字符就能完成奖励的"从运营侧到玩家背包"这条链路。

常见的使用场景:

场景说明
新服开服活动生成一批通用码,活动页公开发放,限量 10000 次
媒体合作给每家媒体生成独立批次,通过兑换数据追踪来源
客服补偿生成单次码,点对点补偿出问题的玩家
直播活动主播在直播间公布码,限时兑换,制造紧迫感
付费礼包购买实体商品赠送的游戏内容(一码一用)

二、CDKEY 的分类

在动手写代码之前,先把类型分清楚,因为不同类型在存储结构和校验逻辑上差异很大。

CDKEY ├── 通用码(Universal Code) │ 同一个码,多个玩家可用,有总次数限制 │ 例:"GAME2026",全服限兑 5000 次 │ └── 专属码(Unique Code) 一码一人,用完即废 例:"A3X9-K7QP-2M8N",只能被一个玩家兑换

两种类型可以共存于同一套系统,通过code_type字段区分。


三、核心设计:数据库表结构

-- 礼包批次表(运营后台配置)CREATETABLEcdkey_batch(batch_idINTNOTNULLAUTO_INCREMENT,batch_nameVARCHAR(64)NOTNULLCOMMENT'批次名称,如"4月媒体合作-游侠"',code_typeTINYINTNOTNULLCOMMENT'0=通用码 1=专属码',rewards JSONNOTNULLCOMMENT'奖励列表,如 [{"item_id":1001,"count":10}]',start_atBIGINTNOTNULLCOMMENT'生效时间戳(毫秒),防提前兑换',expire_atBIGINTNOTNULLCOMMENT'过期时间戳(毫秒)',total_countINTUNSIGNEDNOTNULLCOMMENT'批次总生成码数(统计用)',statusTINYINTNOTNULLDEFAULT1COMMENT'1=有效 0=已关闭',operatorVARCHAR(32)NOTNULLCOMMENT'操作人(运营账号)',remarkVARCHAR(256)NOTNULLDEFAULT''COMMENT'备注',created_atBIGINTNOTNULLCOMMENT'创建时间戳(毫秒)',PRIMARYKEY(batch_id))ENGINE=InnoDB;-- 礼包码表CREATETABLEcdkey_code(codeVARCHAR(32)NOTNULLCOMMENT'兑换码,唯一',batch_idINTNOTNULL,code_typeTINYINTNOTNULLCOMMENT'冗余,方便查询',max_use_countINTUNSIGNEDNOTNULLDEFAULT1COMMENT'生成时固化,通用码>1,专属码=1',used_countINTUNSIGNEDNOTNULLDEFAULT0COMMENT'已兑换次数',statusTINYINTNOTNULLDEFAULT0COMMENT'0=未用 1=已用(专属码)',channelVARCHAR(32)NOTNULLDEFAULT''COMMENT'渠道标识,如"bilibili"',expire_atBIGINTNOTNULLDEFAULT0COMMENT'单码独立过期时间(0=跟随批次)',create_timeBIGINTNOTNULLCOMMENT'生成时间戳(毫秒)',PRIMARYKEY(code),INDEXidx_batch(batch_id))ENGINE=InnoDB;-- 玩家兑换记录表CREATETABLEcdkey_record(idBIGINTNOTNULLAUTO_INCREMENT,player_idBIGINTNOTNULL,codeVARCHAR(32)NOTNULL,batch_idINTNOTNULL,server_idINTNOTNULLCOMMENT'兑换时所在区服(合服兼容)',reward_statusTINYINTNOTNULLDEFAULT0COMMENT'0=待发 1=已发 2=失败',ipVARCHAR(64)NOTNULLDEFAULT''COMMENT'客户端IP(审计用)',redeemed_atBIGINTNOTNULLCOMMENT'兑换时间戳(毫秒)',PRIMARYKEY(id),-- 核心:同一玩家在同一批次只能兑换一次(无论用哪个码)UNIQUEKEYuk_player_batch(player_id,batch_id),INDEXidx_player_id(player_id),INDEXidx_redeemed_at(redeemed_at))ENGINE=InnoDB;

表设计要点

  • max_use_count放在cdkey_code表并在生成时固化,而非从cdkey_batch实时读取。运营中途修改批次配置时,不会影响已生成码的限额
  • uk_player_batch(player_id, batch_id)而非(player_id, code)——运营需求几乎都是"同一批次只能兑一次",玩家不能通过换不同专属码多次领取同批次奖励
  • 时间字段全部用BIGINT存毫秒时间戳,彻底规避时区问题
  • reward_status字段是发奖补偿幂等的关键,发奖前先查、发奖后原子更新

四、要做哪些防护

4.1 防暴力枚举

CDKEY 如果太短、太规律,攻击者可以写脚本遍历尝试。防护措施:

  1. 码的格式设计:用加密安全随机数(RandomNumberGenerator,不能用普通Random),Base32 字符集严格去掉易混淆的0/O/I/L。专属码推荐 16 位有效字符(32^16 ≈ 10^24,暴力枚举不可行),通用码可短至 8 位但必须配严格频率限制
  2. 多层频率限制:单玩家每日 ≤ 10 次、单 IP 每分钟 ≤ 5 次、单设备每日 ≤ 20 次、全局 QPS 限流保护 DB
  3. Redis 计数器必须用Lua 脚本原子执行INCR + EXPIRE,分两步执行有竞态风险

4.2 防并发重复兑换

正确的顺序是:先消耗码,再插入兑换记录

  • 先消耗码(原子 UPDATE),成功后再 INSERT 记录
  • INSERT 时uk_player_batch唯一索引兜底,若玩家已有该批次记录则抛异常,回滚码的消耗
  • ET Actor 单线程串行,消除单玩家级别的并发;跨进程/跨服并发靠 DB 事务 + 唯一索引

❌ 错误顺序:先查"玩家是否兑换过" → 再消耗码。高并发下两个请求会同时通过查询,都消耗成功,同一玩家兑换两次。

4.3 防通用码超发

-- 原子递增,同时检查是否超限(max_use_count 已在生成时固化在 cdkey_code 表)UPDATEcdkey_codeSETused_count=used_count+1WHEREcode=?ANDused_count<max_use_count;-- 影响行数 = 0 → 已超限,拒绝

4.4 防过期码与批次未生效

兑换入口同时校验start_at(未到生效时间)和expire_at(已过期),两种情况都直接拒绝。

4.5 奖励发放幂等

发奖与兑换必须解耦,且发奖操作必须幂等:

1. 事务内:消耗码 + 写 cdkey_record(reward_status=0) 2. 事务提交成功 → 异步发奖 3. 发奖前查 reward_status,仅 0(待发)状态才执行 4. 发奖成功 → 原子 UPDATE reward_status = 1 5. 发奖失败 → reward_status 保持 0,定时任务重试(最多 5 次后置 2=失败,人工介入)

五、ET 框架伪代码实现

5.1 消息定义

// 客户端 → 服务端[Message(OuterMessage.C2G_CdkeyRedeemReq)]publicclassC2G_CdkeyRedeemReq:IRequest{publicintRpcId{
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/8 2:38:59

BepInEx终极指南:从零开始掌握游戏插件框架的完整秘籍

BepInEx终极指南&#xff1a;从零开始掌握游戏插件框架的完整秘籍 【免费下载链接】BepInEx Unity / XNA game patcher and plugin framework 项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx 想象一下&#xff0c;你正玩着一款心爱的游戏&#xff0c;突然灵…

作者头像 李华
网站建设 2026/5/8 2:25:29

2026年,昆明性价比高且技术强的代运营公司究竟哪家值得推荐?

在竞争激烈的商业环境中&#xff0c;选择一家靠谱的代运营公司对于企业的发展至关重要。特别是在2026年的昆明&#xff0c;市场上各类代运营公司层出不穷&#xff0c;如何挑选出性价比高且技术强的公司成为了众多企业关注的焦点。今天&#xff0c;就为大家重点推荐云南古汶传媒…

作者头像 李华
网站建设 2026/5/8 2:22:28

【一图看懂】Docker容器是什么(二) | 服务器篇2

Docker容器化如今已是企业云端部署、业务上线的主流标配&#xff0c;但动态启停、秒级销毁、分层存储、内核共享这些特性&#xff0c;也让传统物理机、虚拟机取证办法直接失效。上篇Docker容器是什么&#xff08;一&#xff09; | 服务器篇我们讲清了Docker基础架构&#xff0c…

作者头像 李华
网站建设 2026/5/8 2:20:07

高通MSM7200基带处理器:双核异构架构与多媒体处理技术

1. 高通MSM7200基带处理器技术解析作为2007年前后智能手机SoC领域的标杆产品&#xff0c;高通MSM7200基带处理器在移动通信发展史上具有里程碑意义。这款芯片采用了当时最先进的65nm工艺制程&#xff0c;将应用处理器、基带调制解调器和多媒体加速器集成在单颗芯片上&#xff0…

作者头像 李华
网站建设 2026/5/8 2:18:29

Windows系统secur32.dll文件丢失无法启动解决

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

作者头像 李华
网站建设 2026/5/8 2:17:27

避坑指南!IDEA + WSL 2 + Java 8 环境配置的四大终极深坑

## 避坑指南&#xff01;IDEA WSL 2 Java 8 环境配置的四大终极深坑这确实是一个非常值得总结的“血泪史”。在 WSL 2 环境下折腾 IntelliJ IDEA 和 Java 8&#xff0c;很多坑都是由于 JetBrains 尝试重构远程开发架构导致的。 为了方便你发文章&#xff0c;我把这几天的“排…

作者头像 李华