规则文档理清楚,开始代码层面对比和校对

This commit is contained in:
2026-07-04 09:52:49 +08:00
parent 911cc9cc23
commit 96372d713c
18 changed files with 4624 additions and 67 deletions
@@ -0,0 +1,431 @@
# 二七王协议包列表
说明:`data` 均为发送方与接收方之间约定的 JSON 内容;成败判定只看推送包里的 `data.success`。
---
## 1. 发牌(fapai)
发包者:服务器 收包者:游戏 app:youle route:erqiwang rpc:fapai
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| asetidx | 整数 | 当前局数 |
| asetcount | 整数 | 总局数 |
| cards | 数组 | 自己得到的牌id列表 |
| seat | 整数 | 当前等待叫分者的位置 |
| countdown | 整数 | 叫分倒计时 |
---
## 2. 叫分或不叫(jiaofen,客户端→服务器)
发包者:游戏 收包者:服务器 app:youle route:erqiwang rpc:jiaofen
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| agentid | 字符 | 代理id |
| playerid | 整数 | 玩家id |
| gameid | 字符 | 游戏id |
| roomcode | 整数 | 房间号 |
| seat | 整数 | 叫分者的位置序号 |
| call | 整数 | 分数,0表示不叫 |
---
## 3. 叫分或不叫(jiaofen,服务器→客户端)
发包者:服务器 收包者:游戏 app:youle route:erqiwang rpc:jiaofen
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| seat | 整数 | 叫分者的位置序号 |
| call | 整数 | 分数,0表示不叫 |
| currcall | 整数 | 当前叫到的分数 |
| multiple | 整数 | 倍数 |
| nextseat | 整数 | 下一个叫分者的位置序号 |
| countdown | 整数 | 叫分倒计时 |
---
## 4. 上庄(shangzhuang)
发包者:服务器 收包者:游戏 app:youle route:erqiwang rpc:shangzhuang
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| seat | 整数 | 叫分者的位置序号 |
| call | 整数 | 分数,0表示不叫 |
| banker | 整数 | 庄家的位置序号 |
| grade | 整数 | 庄家的叫分 |
| multiple | 整数 | 倍数 |
| bottomcards | 数组 | 底牌 |
| cards | 数组 | 拿了底牌后手上的牌,包括底牌,庄家才有此属性,闲家没有该属性 |
| countdown | 整数 | 选主倒计时 |
| touxiang | 整数 | 是否允许投降 0:不允许 1:允许 |
---
## 5. 投降(touxiang,客户端→服务器)
发包者:游戏 收包者:服务器 app:youle route:erqiwang rpc:touxiang
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| agentid | 字符 | 代理id |
| playerid | 整数 | 玩家id |
| gameid | 字符 | 游戏id |
| roomcode | 整数 | 房间号 |
| seat | 整数 | 庄家的位置序号(`mod.js` 中校验 `o_paiju.banker != seat`,只有庄家能投降;选主/埋牌/投降阶段均可发起) |
---
## 6. 选主(xuanzhu,客户端→服务器)
发包者:游戏 收包者:服务器 app:youle route:erqiwang rpc:xuanzhu
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| agentid | 字符 | 代理id |
| playerid | 整数 | 玩家id |
| gameid | 字符 | 游戏id |
| roomcode | 整数 | 房间号 |
| seat | 整数 | 选主者的位置序号 |
| flower | 整数 | 花色 1方块 2梅花 3红心 4黑桃 |
---
## 7. 选主(xuanzhu,服务器→客户端)
发包者:服务器 收包者:游戏 app:youle route:erqiwang rpc:xuanzhu
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| banker | 整数 | 庄家的位置序号 |
| flower | 整数 | 花色 1方块 2梅花 3红心 4黑桃 |
| countdown | 整数 | 埋牌倒计时 |
| cards | 数组 | 选主后自己手上的牌id列表 |
---
## 8. 埋牌(maipai,客户端→服务器)
发包者:游戏 收包者:服务器 app:youle route:erqiwang rpc:maipai
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| agentid | 字符 | 代理id |
| playerid | 整数 | 玩家id |
| gameid | 字符 | 游戏id |
| roomcode | 整数 | 房间号 |
| seat | 整数 | 埋牌者的位置序号 |
| cards | 数组 | 埋牌的id列表 |
---
## 9. 埋牌(maipai,服务器→客户端)
发包者:服务器 收包者:游戏 app:youle route:erqiwang rpc:maipai
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| cards | 数组 | 埋牌后手上的牌,去掉了埋牌,庄家才有此属性,闲家没有该属性 |
| bottomcards | 数组 | 埋的牌,庄家才有此属性,闲家没有该属性 |
| seat | 整数 | 出牌者的位置序号 |
| countdown | 整数 | 出牌倒计时 |
---
## 10. 出牌(chupai,客户端→服务器)
发包者:游戏 收包者:服务器 app:youle route:erqiwang rpc:chupai
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| agentid | 字符 | 代理id |
| playerid | 整数 | 玩家id |
| gameid | 字符 | 游戏id |
| roomcode | 整数 | 房间号 |
| seat | 整数 | 出牌者的位置序号 |
| cards | 数组 | 出牌的id列表 |
---
## 11. 第一个玩家出牌(chupai1)
发包者:服务器 收包者:游戏 app:youle route:erqiwang rpc:chupai1
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| seat | 整数 | 出牌者的位置序号 |
| cards | 数组 | 出的牌id列表 |
| info | 数组 | 出牌者的座位牌况 `o_paiju.seatlist[seat]`,5 元素数组:前 4 个对应花色1~4 的 `[无该花色标志, 该花色无对标志]`(0/1),第 5 个为报副情况 `[剩余主牌数, 剩余主对数]`(初始 `[-1,-1]`,报无主后为实际数量) |
| count | 整数 | 出牌数量 |
| flower | 整数 | 出牌花色 |
| cardtype | 整数 | 出牌牌型 |
| nextseat | 整数 | 下一个出牌者的位置序号 |
| countdown | 整数 | 下一个出牌者的出牌倒计时 |
| baozhu | 整数 | 是否已有玩家报无主(主牌出空)0否 1是;对应服务端 `have_baofu()`(任一玩家 `seatlist[seat][4][0]==0` 即为 1),供客户端在可查牌模式下展示他家主牌数量/对子结构 |
| cardsinhand | 数组 | 出牌者出牌后手上剩下的牌id列表,只有出牌者才有此属性 |
---
## 12. 第二个玩家出牌(chupai2)
发包者:服务器 收包者:游戏 app:youle route:erqiwang rpc:chupai2
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| seat | 整数 | 出牌者的位置序号 |
| cards | 数组 | 出的牌id列表 |
| info | 数组 | 出牌者的座位牌况 `o_paiju.seatlist[seat]`,5 元素数组:前 4 个对应花色1~4 的 `[无该花色标志, 该花色无对标志]`(0/1),第 5 个为报副情况 `[剩余主牌数, 剩余主对数]`(初始 `[-1,-1]`,报无主后为实际数量) |
| nextseat | 整数 | 下一个出牌者的位置序号 |
| countdown | 整数 | 出牌倒计时 |
| baozhu | 整数 | 是否已有玩家报无主(主牌出空)0否 1是;对应服务端 `have_baofu()`(任一玩家 `seatlist[seat][4][0]==0` 即为 1),供客户端在可查牌模式下展示他家主牌数量/对子结构 |
| cardsinhand | 数组 | 出牌后出牌者手上剩下的牌id列表,只有出牌者才有此属性 |
---
## 13. 第三个玩家出牌(chupai3)
发包者:服务器 收包者:游戏 app:youle route:erqiwang rpc:chupai3
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| seat | 整数 | 出牌者的位置序号 |
| cards | 数组 | 出的牌id列表 |
| info | 数组 | 出牌者的座位牌况 `o_paiju.seatlist[seat]`,5 元素数组:前 4 个对应花色1~4 的 `[无该花色标志, 该花色无对标志]`(0/1),第 5 个为报副情况 `[剩余主牌数, 剩余主对数]`(初始 `[-1,-1]`,报无主后为实际数量) |
| nextseat | 整数 | 下一个出牌者的位置序号 |
| countdown | 整数 | 出牌倒计时 |
| baozhu | 整数 | 是否已有玩家报无主(主牌出空)0否 1是;对应服务端 `have_baofu()`(任一玩家 `seatlist[seat][4][0]==0` 即为 1),供客户端在可查牌模式下展示他家主牌数量/对子结构 |
| cardsinhand | 数组 | 出牌后出牌者手上剩下的牌id列表,只有出牌者才有此属性 |
| maxseat | 整数 | 本轮出牌谁最大,只有本轮最后一个玩家出牌后才有此属性 |
| grade | 整数 | 本轮闲家得分,只有本轮最后一个玩家出牌后且闲家有得分才有此属性 |
---
## 14. 结算(jiesuan)
发包者:服务器 收包者:游戏 app:youle route:erqiwang rpc:jiesuan
结算包由以下几个子结构拼装而成。三种结算来源的组成不同:
- **正常出牌结算**(`mod.chupai` 中最后一张牌出完,`get_paiju_account(0, ...)`):含 `chupai` + `bottom` + `aset`(末局再加 `account`)。
- **投降结算**(`mod.touxiang`,`get_paiju_account(1, ...)`):只含 `aset`(末局再加 `account`),无 `chupai`、无 `bottom`。
- **解散结算**(`export.get_disbandRoom`,`get_paiju_account(2, ...)`):只含 `aset` + `account`,无 `chupai`、无 `bottom`。
**chupai(出牌包,仅正常出牌结算存在)**
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| seat | 整数 | 出牌者的位置序号,投降和解散无此属性 |
| cards | 数组 | 出的牌id列表,投降和解散无此属性 |
| maxseat | 整数 | 本轮出牌谁最大,投降和解散无此属性 |
| grade | 整数 | 本轮闲家得分,投降和解散无此属性 |
| gradecards | 数组 | 本轮闲家得分分牌列表,投降和解散无此属性。**注意:当前源码中赋值语句被注释(`class.paiju.js`/`mod.js` 中相关行均被注释掉),该字段实际永远不会出现在下发的包里,属于失效字段** |
**bottom(抠底包,仅正常出牌结算存在;`cards` 恒有,其余仅闲家抠底时有)**
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| cards | 数组 | 底牌,投降和解散无此属性 |
| multiple | 整数 | 闲家抠底倍数,闲家没抠底无此属性,投降和解散无此属性 |
| grade1 | 整数 | 底牌分数,闲家没抠底无此属性,投降和解散无此属性 |
| grade2 | 整数 | 闲家抠底得分,闲家没抠底无此属性,投降和解散无此属性 |
**aset(单局结算包)**
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| banker | 整数 | 庄家的位置序号,-1:无庄 |
| call | 整数 | 庄家叫分,-1:无叫分 |
| multiple | 整数 | 叫分倍数 `get_multiple_bycall(call)`:call>60→1,call>40→2,call>0→4;无叫分(call≤0)→0 |
| flower | 整数 | 主牌花色,-1:无主牌花色 |
| grade | 整数 | 闲家得分 |
| upgrade | 整数 | 升级级数:0中途解散 1过庄 2小光 4大光 -1倒庄 <-1升几级 -99投降 |
| seatlist | 数组 | 玩家列表,元素结构见下 |
`seatlist` 数组元素结构:
```json
{
"cards": [], // 王牌或冲关牌列表
"obsolete": 0, // 冲关作废标志 0不作废 1作废
"chongguan": 0, // 冲关数
"grade_cg": 0, // 冲关得分
"grade_w": 0, // 傍王得分
"grade_jf": 0, // 捡分得分
"grade": 0, // 本局总分
"score": 0 // 累计得分
}
```
**account(大局结算包)**
> 仅当打到最后一局(`o_paiju.idx >= o_room.asetcount`)或房间中途解散(解散结算)时,`jiesuan` 包才会带上此分组;普通的中间局结算包没有 `account` 字段(`class.paiju.js` `get_paiju_account`)。
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| account | 数组 | 玩家列表,第一位为累积得分,第二位为每局得分,结构见下 |
```json
[
[0, []],
[0, []],
[0, []]
]
```
---
## 15. 准备(zhunbei,客户端→服务器)
发包者:游戏 收包者:服务器 app:youle route:erqiwang rpc:zhunbei
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| agentid | 字符 | 代理id |
| playerid | 整数 | 玩家id |
| gameid | 字符 | 游戏id |
| roomcode | 整数 | 房间号 |
| seat | 整数 | 位置序号 |
---
## 16. 准备(zhunbei,服务器→客户端)
发包者:服务器 收包者:游戏 app:youle route:erqiwang rpc:zhunbei
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| seat | 整数 | 位置序号 |
---
## 断线重连(deskinfo)
> 由平台在玩家进入房间/断线重连时回调 `youle_erqiwang.export.get_deskinfo(o_room, seat)` 生成并下发(服务器→客户端);下发的 app/route/rpc 由平台的进房/重连流程决定,不在本子游戏代码内固定。下列字段即该函数返回的 `deskinfo` 对象结构,按当前 `paiju.step` 只带对应阶段的分组。
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| count | 整数 | 总局数 |
| idx | 整数 | 当前局数 |
| PlayerInfo | 数组 | 三个玩家目前的总积分 `[0,0,0]` |
| step | 整数 | 牌桌状态:1发完牌叫分 2选主 3埋牌 4投降 5出牌 6结算 |
| MyCards | 数组 | 自己手上的牌 |
**CallRun(不在叫分阶段无此属性)**
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| seat | 整数 | 当前叫分位置 |
| countdown | 整数 | 叫分倒计时 |
| nowcall | 整数 | 当前叫分 |
| multiple | 整数 | 倍数 |
| call | 数组 | 三家叫分 `[null,0,65]`,null还未叫分,0不叫,>0叫了多少分 |
**ChooseMain(不在选主阶段无此属性)**
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| banker | 整数 | 庄家 |
| call | 整数 | 叫分 |
| multiple | 整数 | 倍数 |
| countdown | 整数 | 选主倒计时 |
| bottomcards | 数组 | 底牌 |
| touxiang | 整数 | 是否允许投降 0:不允许 1:允许 |
**BuryCards(不在埋牌阶段无此属性)**
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| banker | 整数 | 庄家 |
| call | 整数 | 叫分 |
| multiple | 整数 | 倍数 |
| flower | 整数 | 主牌花色 |
| countdown | 整数 | 埋牌倒计时 |
| bottomcards | 数组 | 底牌 |
| touxiang | 整数 | 是否允许投降 0:不允许 1:允许 |
**Surrender(不在投降阶段无此属性)**
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| banker | 整数 | 庄家 |
| call | 整数 | 叫分 |
| multiple | 整数 | 倍数 |
| flower | 整数 | 主牌花色 |
| countdown | 整数 | 出牌倒计时 |
| bottomcards | 数组 | 埋的牌,只有庄家有此属性 |
| touxiang | 整数 | 是否允许投降 0:不允许 1:允许 |
**PushCards(不在出牌阶段无此属性)**
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| banker | 整数 | 庄家 |
| call | 整数 | 叫分 |
| multiple | 整数 | 倍数 |
| flower | 整数 | 主牌花色 |
| countdown | 整数 | 出牌倒计时 |
| bottomcards | 数组 | 埋的牌,只有庄家有此属性 |
| grade | 整数 | 当前的捡分分数 |
| gradecards | 数组 | 当前的捡分分牌,只有闲家有此属性 |
| playproc | json | 当前出牌情况 `o_paiju.playproc`:`round` 第几轮、`start` 本轮首出位置、`currseat` 当前出牌位置、`startcount` 首出张数、`startflower` 首出花色、`starttype` 首出牌型、`maxseat` 本轮最大者位置、`maxcard` 最大牌编码、`cards` 本轮三家各自出的牌(数组下标=位置序号) |
| seatlist | 数组 | 三家座位牌况,元素结构同上文 chupai 包的 `info`(每个玩家一个 5 元素数组:4 个花色的 `[无该花色,无对]` + 报副 `[剩余主牌数,剩余主对数]`) |
| pushlist | 数组 | 出牌历史 `[[[], [], []], [[], [], []], ...]`,外层下标=轮次,内层 3 个数组按位置序号存该轮各家出的牌id(已按大小排序) |
**Balance(不在结算阶段无此属性)**
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| readystate | 数组 | 所有玩家的准备状态 |
| aset | json | 单局结算包,同上面结算包中的 `aset`,只有当自己的准备状态为0时才有此属性 |
---
## 战绩(大局列表)gameinfo1
> 非客户端收发包:大局结束/解散时由 `class.desk.js` `get_desk_account` 组装,经 `import.save_grade(o_room, o_gameinfo1, o_gameinfo2, 1)` 传给平台战绩服务持久化(服务器→平台)。
| 参数名 | 类型 | 说明 |
| --- | --- | --- |
| roomcode | 整数 | 房号 |
| asetcount | 整数 | 实际局数 |
| createtime | 字符 | 开房时间 |
| makewartime | 字符 | 开战时间 |
| players | 数组 | 玩家列表,元素结构见下 |
`players` 数组元素结构:
```json
{
"seat": 0, // 座位
"playerid": 100001, // 玩家ID
"name": "", // 昵称
"avatar": "", // 头像
"score": 0 // 成绩
}
```
---
## 战绩(大局)gameinfo2
> 非客户端收发包:与 gameinfo1 同批,由 `import.save_grade` 的第 3 个参数传给平台战绩服务(服务器→平台)。
牌局列表,数组元素结构:
```json
{
"starttime": "", // 开始时间
"endtime": "", // 结束时间
"seatlist": [6, -6, 0], // 玩家成绩
"callproc": [], // 叫分过程,详情见代码中的注释
"banker": 0, // 庄
"call": 0, // 叫分
"flower": 0, // 主牌花色
"result": 0, // 牌局结果
"cards": [] // 发牌出牌情况,详情见代码中的注释
}
```