NovaSDK 开发文档

NovaSDK 开发文档
MeteorCat最近接触到公司游戏聚合的项目, 突然想结合之前公司开发经验来考虑自己应该怎么从而完善设计, 从而方便其他人借鉴处理
首先这里介绍下具体的字段参考表, 需要明确规则: 传递字段必须有默认值, 不允许为 null 值
| 类型 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|
string |
‘’ | - | 字符串类型, 默认只允许为空字符串, 一般从数据库性能考虑建议字符串控制在 varchar(255) 之中 |
boolean |
0 / 1 | - | 布尔类型, 一般来说建议采用数值1和0来区分(数据库采用 tinyint(1) 类型), 主要部分数据清洗或者转化成字符串, 也就是 true 和 "true" 的问题 |
number |
0 | int64 | 数值类型, 数值方面建议安装 int64 范围取值(数据库采用 bigint 类型), 部分开发语言最大值需要特定 BigInt 类型 |
time |
0 | int64 | 时间戳类型, 推荐采用 bigint 类型保存 UTC 时间的毫秒时间戳, 因为基于0时区开始的时间戳方便直接做全球化跨时区换算, 所有开发语言都内置支持 |
country |
‘CN’ | - | 字符串类型, 全球化的来源地区码(数据库采用 char(2) 类型, 入库必须强制转大写), 基于 ISO 3166-1 的地区统一标准码, 海外部分支付渠道需要支付的地区来源标识 |
currency |
‘CNY’ | - | 字符串类型, 全球化的地区货币码(数据库采用 char(3) 类型, 入库必须强制转大写), 基于 ISO 4217 的地区货币标准码, 海外部分支付渠道需要支付的地区货币标识 |
scale |
2 | uint8 | 数值类型, 全球币种小数位(数据库采用 unsigned tinyint 类型), 大部分国家采用以 分 为货币单位, 而部分海外国家是没有 分 单位(日本/韩国最小单位为 日元/韩元), 可以通过计算换算最小货币金额 |
日常规范差不多是这样, 实际上可以日常动态调整部分需求
-
有的业务系统喜欢直接采用
秒级时间戳从而节省性能, 但是后续面向全球化还是要扩展发起的地区时区字段 -
有的业务系统不需要货币和地区码, 可能单一国家业务不需要通过美元/日元/韩元结算金额
应用表设计
注意: 我习惯将游戏统统归为
应用(app), 而不会直接将其受限于游戏(game), 主要应对支持除游戏等所有应用对接方式
这部分没有什么具体定式, 都是可以按照各自业务需求来动态调整, 接下来就是表结构设计(这里是 MariaDB(MYSQL Fork的分支))
1 |
|
这就是游戏应用主体表设计, 注意: 一个游戏是关联多个渠道(也包含官方服), 渠道游戏唯一关联标识 = ({渠道ID} + {游戏ID})
1 | # 聚合渠道部分也是共享表, 可以放在统一的数据库 |
至此就获得自定义的 {APP_ID = {10000}, CHANNEL_IDENT = {novagame}} 的渠道专服游戏, 现在就是做进一步规划设计
接口设计
聚合的游戏应用常采用类似链路设计如下
https://{API_URL}/business/{3RD_CHANNEL}/{METHOD}/{APP_ID}/{CHANNEL_IDENT}
-
{API_URL}: 对外开放的API服务域名 -
{3RD_CHANNEL}: 对接的第三方渠道SDK, 比如QQ腾讯大厅/QuickSDK/果盘游戏SDK/百度等对接渠道 -
{METHOD}: 调用第三方渠道 SDK 方法, 主要对接应用初始化/验证授权/发起支付/支付回调/信息上报 -
{APP_ID}: 渠道对应的游戏应用ID, 也就是聚合系统内部的游戏ID -
{CHANNEL_IDENT}: 聚合系统当中自己划分的特殊渠道标识
聚合系统主要目标就是对接
QQ腾讯大厅/QuickSDK/果盘游戏SDK/百度等 SDK 从而集成到自己的系统
这里提供 QuickSDK/果盘游戏SDK 文档, 可以先行查看对接流程
可以对照两者SDK对接时候接入方法不同, 所以请求和响应参数不一样, 这里以 果盘SDK 对接文档来扩展
-
请求地址:
https://{API_URL}/business/guopan/{METHOD}/{APP_ID}/{CHANNEL_IDENT}
请求 {METHOD} 的取值如下, 其实内部就是涵盖大部分应用的 生命周期 流程
| 方法名称 | 路径地址 | 说明 |
|---|---|---|
init |
/business/guopan/init/{APP_ID}/{CHANNEL_IDENT} | 下发第三方SDK的配置参数, 比如果盘SDK要求客户端需要通过 AppId/ClientKey 参数签名, QuickSQK 是需要通过 ProductCode/ProductKey, 通过接口可以下发游戏这部分信息提供初始化SDK |
login |
/business/guopan/login/{APP_ID}/{CHANNEL_IDENT} | 第三方SDK唤起登录授权接受提交给我们聚合SDK的二次验证的接口, 比如果盘游戏SDK验证正确会响应 uid/token, 客户端需要再次将这部分信息提交给我们聚合SDK接口验证, 验证通过同步数据库创建用户实体 |
pay |
/business/guopan/pay/{APP_ID}/{CHANNEL_IDENT} | 游戏应用内部预下单功能, 必须先提交到我们聚合SDK生成数据库中等待支付的订单, 然后按照第三方SDK的支付参数返回给客户端, 最后客户端再次去对应第三方SDK发起支付请求 |
notify |
/business/guopan/notify/{APP_ID}/{CHANNEL_IDENT} | 游戏应用返回的回调入口, 大部分情况是配置在第三方后台支付回调或者配置这部分回调地址 |
order |
/business/guopan/order/{APP_ID}/{CHANNEL_IDENT} | 游戏应用查询后台订单的接口, 并不是必须要实现的接口, 一般用于支付订单的二次检查查询 |
report |
/business/guopan/report/{APP_ID}/{CHANNEL_IDENT} | 游戏应用内部数据上报功能, 实际上流程也也是和发起订单差不多, 必须先提交到我们聚合SDK上报日志, 然后聚合SDK生成对应第三方SDK参数再由客户端提交过去 |
quit |
/business/guopan/quit/{APP_ID}/{CHANNEL_IDENT} | 游戏应用注销会话退出功能, 部分 H5 游戏可能不需要(可以不去实现), 主要是用于玩家用户手动退出注销, 有的系统需要用到记录玩家手动退出时间和IP |
这里用在我们在自己内聚系统当中创建应用来说明, 架设目前我们有款游戏要接入果盘SDK游戏渠道:
-
APP_ID: 10000
-
CHANNEL_IDENT: novagame
-
3RD_CHANNEL: guopan
那么这里的对应的渠道游戏应用请求方法如下, 这里以 CURL 来做模拟:
1 | - 应用初始化, 从聚合SDK拉取第三方参数 |
目前开发部分测试 demo 的 接口,可以通过请求以下地址来查看具体接口配置:
-
QuickSDK 初始化: https://dev-sdk.meteorcat.me/business/quick/10000/novagame
-
GuoPanSDK 初始化: https://dev-sdk.meteorcat.me/business/guo-pan/10000/novagame
对照内部的 params 参数就是下发给第三方SDK的配置参数, 后续流程基本上就是拿这些客户端参数按照常规对接
因为这部分方案这是我个人开发服务器, 这个服务器国内可能会抽风所以直接附带参考的响应数据:
1 | 目前支持 GET 和 POST 参数混合提交 |
这就是聚合SDK响应给第三方 SDK 所需初始化的参数, 接下来就是关于用户相关的结构设计
用户结构
注意: 对于多应用来说单表已经很难支撑这部分的数据量, 所以需要采用数据分表处理(需要做全局ID, 后续复制数据合并到其他表)
这里的表推荐做好分表处理(时候分库看后续需求, 但是如果用户量大的情况分表是必须的), 表结构如下
1 | # 这里需要做数据库分表, 以 游戏应用ID 做区分 |
关于分表有个注意点, 就是目前主流如果玩家信息分表都有两种处理方式:
-
直接标识: 之前创建的游戏应用{APP_ID = 10000}, 这部分数据直接将用户分表命名为nova_user_10000 -
取模标识: 通过将{APP_ID = 10000}按照APP_ID % 10 = {TABLE_ID}计算出散列在nova_user_{0-9}之中
其实比较推荐采用 取模分表 算法, 主要是如果游戏应用比较多的话会导致单库当中散列大量的数据表
后续聚合应用的规模上来, 有时候打开数据库刷出上万个游戏数据分表也不好检索和处理
所以这里采用取模算法, 将之前得出的 {APP_ID = 10000} 散布在 {10000} % {10} = nova_user_{0}
只是日常使用的时候, 需要每次都额外加上 where app_id=10000, 但是这部分可以加个单独索引即可, 问题也不是那么严重
处理完用户信息的数据库表设计之后, 现在就是准备接口方面设计, 也就是需要以上面第三方对接的上报授权请求之后的请求和响应:
-
QuickSDK授权认证:
https://dev-sdk.meteorcat.me/business/quick/login/10000/novagame -
果盘SDK授权认证:
https://dev-sdk.meteorcat.me/business/guo-pan/login/10000/novagame
这里客户端把对应渠道参数请求上报给我们的聚合SDK, 服务器内部和远程第三方SDK验证授权正确之后就响应 聚合系统数据库的玩家实体对象
也就是统一响应核心的数据结构必须包含以下内容:
1 | { |
无论授权验证响应的数据结构再怎么变, 最后核心关键依旧还是提供以上这些参数
注销登录这部分就没什么好说的, 直接提供单一的登出接口就行了, 所以跳过这部分说明
数据上报
目前数据上报的格式经过多年演变基本上固定成型了, 大致的表结构设计只需要提供特定的字段即可
1 | # 这里需要做数据库分表, 以 游戏应用ID 做取模分表 |
应用上报也是通过将 {APP_ID = 10000} 按照 APP_ID % 10 = {TABLE_ID} 计算出散列在 nova_report_{0-9} 之中
一般情况下只需要关注以下声明周期来做上报提交, 可以自行按照 action 字段来调度不同上报行为
-
选择服务器: 部分应用/游戏是单账号多服务器, 在授权完成之后就需要选择服务器的情况, 需要上报周期进度 -
创建角色: 部分应用/游戏支持单账号多角色, 也就是进入游戏之后会经历选择服务器 → 选择角色 → 进入游戏过程 -
进入应用: 也就是应用/游戏选中之后就执行上报, 留意好创建角色说明时候的 '进入游戏的过程(选择服务器 → 选择角色 → 进入游戏)' -
等级升级: 在游戏当中涉及等级提升的时候做出上报行为 -
退出游戏: 在游戏当中涉及用户退出应用/游戏的时候做出上报行为
这里上报格式一般是发送到我们聚合系统都是统一格式, 比如下方示例(这里采用 JSON 演示, 实际环境可以用 form 提交)
1 | { |
这部分统一的结构将会上报我们标准聚合SDK接口, 之后将会按照哪部分第三方SDK来下发特定的数据结构:
-
QuickSDK上报行为:
https://dev-sdk.meteorcat.me/business/quick/report/10000/novagame -
果盘SDK上报行为 :
https://dev-sdk.meteorcat.me/business/guo-pan/report/10000/novagame
上报之后数据保存在数据库之后, 可以按照第三方SDK渠道参数来返回客户端, 比如下面的格式
1 | // QuickSDK角色上报需要以下数据格式 |
这些都是请求到聚合系统之后响应回来, 由客户端再次调用第三方SDK同步推送过去即可
支付系统
支付系统其实涉及到以下方面流程, 具体可以在脑中试着模拟这部分调用和执行链路:
-
预下单: 应用/游戏研发方在自己服务器生成订单, 并将系统订单信息发送给聚合SDK响应聚合自己的订单数据, 响应给客户端第三方SDK支付参数调用
-
支付回调: 第三方支付完成异步通知第三方SDK, 第三方SDK再回调到聚合SDK系统, 聚合系统则再次回调给应用游戏内部回调接口
-
二次验证: 聚合SDK回调给游戏应用方会对参数做参数签名用于验证, 但还是推荐采用提供查询订单接口用于更加细致的订单查询功能
数据库订单表其实设计都大差不差, 但是如果是面向海外的时候情况就比较复杂, 因为海外对接支付方式和国内有很大差别
而且订单表支付表不太适合设计成分表, 因为面向支付订单这部分需要做大量统计, 所以还是推荐单表处理配合读写分离处理
但是预下单机制也是有很大弊端, 如果不做限制会疯狂生成大量待支付订单, 不过如果考虑到支付成功的转化率其实也是可以接受
毕竟能够成交的订单也就不在意这点数据库空间, 几百条数据对于云数据库来说可能就几块钱, 但是成功支付的收益大部分能够覆盖其成本
另外还需要区分发起订单的类型:
-
官方渠道: 自身对接的应用/游戏(不走第三方渠道直接官方下载运行), 主体聚合SDK自己就是官方渠道 -
第三方渠道: 比较典型的就是上面说的QuickSDK/果盘SDK/腾讯游戏大厅等, 这部分具体支付通道由第三方控制
结合上面提出的, 最终的数据库表设计如下
1 | # 基础应用表数据, 不推荐设计为分表, 整合单表才方便后续统计, 否则要核算整体付费用户还得去分表内部分开统计最后整合 |
这样差不多可以搞定支付业务的情况, 这里需要科普下国际最小单位的情况(这种最小单位算法比较简单且泛用)
-
scale=2: 货币最小单位为分(分/美分) -
scale=0: 货币最小单位为元(日元/韩元) -
scale=3: 极其冷门特殊的货币单位(科威特第纳尔), 单位为科威特第纳尔
接下来提供几个具体的复杂聚合查询, 这里在创建表之后会插入几条实验数据用来做模拟测试
1 | # 生成测试数据 |
然后就开始提供一些日常比较常用的数据聚合查询:
1 | -- 这里后续会用到核心换算公式: ROUND(item_price * item_total / POW(10, scale), 2) |
这里的关键核心就是最小货币算法: ROUND(SUM(item_price * item_total) / POW(10, scale), 2)
以此得出的就是我们日常使用的
元单位, 一般日常使用不会以分作为衡量单位
对于后台系统来说, 这样查询出来的值可以直接显示给运营查看, 避免还要不同金额换算处理





