二七王:补齐 data.success 成败标志与失败回包
此前全仓(除协议文档开头一句说明外)没有任何下发包携带 data.success,且所有失败路径一律裸 return、不回任何包:前端点了 没反应,只能干等倒计时,同时违反 server dev-guide「成败标志唯一 是 data.success,主动推送的 data 必须自带 success」与 client dev-guide「发包只请求、收包才表现」两条硬红线。 本次: - 成功包一律补 data.success=true:fapai、zhunbei(class.desk.js)、 jiaofen、shangzhuang、xuanzhu、maipai、chupai1/2/3、mingpai、 tishi(mod.js),jiesuan 在 get_paiju_account 统一注入(覆盖 正常/投降/解散三种结算来源)。 - 新增 youle_erqiwang.ERR 失败码表与 do_sendfail 统一回包封装: PLAYER/NODESK/STEP/SEAT/PARAM/RULE,失败只回发给请求者 (conmode/fromid 取自请求包),data.success=false + errcode。 - 每个 handler 的每条失败分支都改为「回失败包 + return」,含 check_player 不通过(平台侧只返回 null、不回包,前端会干等)。 tishi 成功时仍按 design §11 只转发给对家、不给发送者回执(该包不 含对局状态,属 fire-and-forget 提示),失败才回给发送者。 test_rpc 中原先以「不发包」表示被拒的断言,同步改为断言「恰好回 1 个 success=false 且 errcode 正确的包」——是随行为修正而加强, 不是软化。新增 test_success.js 29 项覆盖成功包 success 字段与各 handler 失败回包。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,32 @@ youle_erqiwang.import = null;
|
||||
//对内的输出接口类(提供给外部使用的接口)
|
||||
youle_erqiwang.export = null;
|
||||
|
||||
//失败码(协议层约定,非 design 玩法规则;详见 docs/protocol/packet_protocol.md)
|
||||
//前端一律只看 data.success 判成败,errcode 仅用于区分失败原因、给出对应提示
|
||||
youle_erqiwang.ERR = {
|
||||
PLAYER: 1, //玩家/房间/座位校验不通过
|
||||
NODESK: 2, //牌桌或牌局不存在
|
||||
STEP: 3, //当前阶段不允许该操作
|
||||
SEAT: 4, //位置不符,或还没轮到该玩家操作
|
||||
PARAM: 5, //参数非法(类型/范围/张数/牌不在手上)
|
||||
RULE: 6 //规则不允许(叫分未更低、出牌不合法、投降条件不满足、房间模式禁止等)
|
||||
};
|
||||
|
||||
//失败回包:只回发给请求者,data.success=false
|
||||
//(dev-guide server 03 §4/§5:成败标志唯一是 data.success,主动推送的 data 必须自带 success)
|
||||
youle_erqiwang.do_sendfail = function(pack, rpc, errcode){
|
||||
var msg = {};
|
||||
msg.app = "youle";
|
||||
msg.route = "erqiwang";
|
||||
msg.rpc = rpc;
|
||||
msg.data = {};
|
||||
msg.data.success = false;
|
||||
msg.data.errcode = errcode;
|
||||
msg.conmode = pack.conmode;
|
||||
msg.fromid = pack.fromid;
|
||||
youle_erqiwang.app.SendPack(msg);
|
||||
}
|
||||
|
||||
//叫分或不叫
|
||||
youle_erqiwang.jiaofen = function(pack){
|
||||
var agentid = pack.data.agentid;
|
||||
@@ -43,37 +69,45 @@ youle_erqiwang.jiaofen = function(pack){
|
||||
//检查玩家的位置是否正确
|
||||
var o_room = youle_erqiwang.import.check_player(agentid, gameid, roomcode, seat, playerid, pack.conmode, pack.fromid);
|
||||
if (!o_room){
|
||||
youle_erqiwang.do_sendfail(pack, "jiaofen", youle_erqiwang.ERR.PLAYER);
|
||||
return;
|
||||
}
|
||||
//牌桌
|
||||
var o_desk = o_room.o_desk;
|
||||
if (!o_desk){
|
||||
youle_erqiwang.do_sendfail(pack, "jiaofen", youle_erqiwang.ERR.NODESK);
|
||||
return;
|
||||
}
|
||||
//牌局
|
||||
var o_paiju = o_desk.method.curr_paiju();
|
||||
if (!o_paiju){
|
||||
youle_erqiwang.do_sendfail(pack, "jiaofen", youle_erqiwang.ERR.NODESK);
|
||||
return;
|
||||
}
|
||||
//检查当前的游戏阶段是否是叫分阶段
|
||||
if (o_paiju.step != 1){
|
||||
youle_erqiwang.do_sendfail(pack, "jiaofen", youle_erqiwang.ERR.STEP);
|
||||
return;
|
||||
}
|
||||
//检查当前的叫分位置
|
||||
if (o_paiju.method.get_callgrade_seat() != seat){
|
||||
youle_erqiwang.do_sendfail(pack, "jiaofen", youle_erqiwang.ERR.SEAT);
|
||||
return;
|
||||
}
|
||||
//检查叫分:0(不叫)或 5~70 且为 5 的整数倍(design §4)
|
||||
if (call < 0 || call > 70 || call % 5 != 0){
|
||||
youle_erqiwang.do_sendfail(pack, "jiaofen", youle_erqiwang.ERR.PARAM);
|
||||
return;
|
||||
}
|
||||
var curr_call = o_paiju.method.get_callgrade_value();
|
||||
//第一家不能不叫分
|
||||
if (curr_call == 0 && call == 0){
|
||||
youle_erqiwang.do_sendfail(pack, "jiaofen", youle_erqiwang.ERR.RULE);
|
||||
return;
|
||||
}
|
||||
//叫分必须小于之前的叫分
|
||||
if (curr_call != 0 && call >= curr_call){
|
||||
youle_erqiwang.do_sendfail(pack, "jiaofen", youle_erqiwang.ERR.RULE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -88,10 +122,11 @@ youle_erqiwang.jiaofen = function(pack){
|
||||
msg.route = "erqiwang";
|
||||
msg.rpc = "jiaofen";
|
||||
msg.data = {};
|
||||
msg.data.success = true;
|
||||
msg.data.seat = seat;
|
||||
msg.data.call = call;
|
||||
msg.data.currcall = o_paiju.method.get_callgrade_value();
|
||||
msg.data.multiple = cls_youle_erqiwang_arith.get_multiple_bycall(msg.data.currcall);
|
||||
msg.data.multiple = cls_youle_erqiwang_arith.get_multiple_bycall(msg.data.currcall);
|
||||
msg.data.nextseat = o_paiju.method.get_callgrade_seat();
|
||||
msg.data.countdown = o_desk.method.get_countdown_jiaofen();
|
||||
o_room.method.sendpack_toother(msg, -1);
|
||||
@@ -104,6 +139,7 @@ youle_erqiwang.jiaofen = function(pack){
|
||||
msg.route = "erqiwang";
|
||||
msg.rpc = "shangzhuang";
|
||||
msg.data = {};
|
||||
msg.data.success = true;
|
||||
msg.data.seat = seat;
|
||||
msg.data.call = call;
|
||||
msg.data.banker = o_paiju.banker;
|
||||
@@ -140,7 +176,7 @@ youle_erqiwang.jiaofen = function(pack){
|
||||
youle_erqiwang.app.SendPack(msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//选主
|
||||
@@ -154,30 +190,36 @@ youle_erqiwang.xuanzhu = function(pack){
|
||||
//检查玩家的位置是否正确
|
||||
var o_room = youle_erqiwang.import.check_player(agentid, gameid, roomcode, seat, playerid, pack.conmode, pack.fromid);
|
||||
if (!o_room){
|
||||
youle_erqiwang.do_sendfail(pack, "xuanzhu", youle_erqiwang.ERR.PLAYER);
|
||||
return;
|
||||
}
|
||||
//牌桌
|
||||
var o_desk = o_room.o_desk;
|
||||
if (!o_desk){
|
||||
youle_erqiwang.do_sendfail(pack, "xuanzhu", youle_erqiwang.ERR.NODESK);
|
||||
return;
|
||||
}
|
||||
//牌局
|
||||
var o_paiju = o_desk.method.curr_paiju();
|
||||
if (!o_paiju){
|
||||
youle_erqiwang.do_sendfail(pack, "xuanzhu", youle_erqiwang.ERR.NODESK);
|
||||
return;
|
||||
}
|
||||
//检查当前的游戏阶段是否是选主阶段
|
||||
if (o_paiju.step != 2){
|
||||
youle_erqiwang.do_sendfail(pack, "xuanzhu", youle_erqiwang.ERR.STEP);
|
||||
return;
|
||||
}
|
||||
//检查庄家位置
|
||||
if (o_paiju.banker != seat){
|
||||
youle_erqiwang.do_sendfail(pack, "xuanzhu", youle_erqiwang.ERR.SEAT);
|
||||
return;
|
||||
}
|
||||
//检查花色
|
||||
if (flower != 1 && flower != 2 && flower != 3 && flower != 4){
|
||||
youle_erqiwang.do_sendfail(pack, "xuanzhu", youle_erqiwang.ERR.PARAM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//选主成功
|
||||
o_paiju.method.do_choiceflower(flower);
|
||||
@@ -188,6 +230,7 @@ youle_erqiwang.xuanzhu = function(pack){
|
||||
msg.route = "erqiwang";
|
||||
msg.rpc = "xuanzhu";
|
||||
msg.data = {};
|
||||
msg.data.success = true;
|
||||
msg.data.banker = o_paiju.banker;
|
||||
msg.data.flower = flower;
|
||||
msg.data.countdown = o_desk.method.get_countdown_maipai();
|
||||
@@ -210,36 +253,44 @@ youle_erqiwang.maipai = function(pack){
|
||||
//检查玩家的位置是否正确
|
||||
var o_room = youle_erqiwang.import.check_player(agentid, gameid, roomcode, seat, playerid, pack.conmode, pack.fromid);
|
||||
if (!o_room){
|
||||
youle_erqiwang.do_sendfail(pack, "maipai", youle_erqiwang.ERR.PLAYER);
|
||||
return;
|
||||
}
|
||||
//牌桌
|
||||
var o_desk = o_room.o_desk;
|
||||
if (!o_desk){
|
||||
youle_erqiwang.do_sendfail(pack, "maipai", youle_erqiwang.ERR.NODESK);
|
||||
return;
|
||||
}
|
||||
//牌局
|
||||
var o_paiju = o_desk.method.curr_paiju();
|
||||
if (!o_paiju){
|
||||
youle_erqiwang.do_sendfail(pack, "maipai", youle_erqiwang.ERR.NODESK);
|
||||
return;
|
||||
}
|
||||
//检查当前的游戏阶段是否是埋牌阶段
|
||||
if (o_paiju.step != 3){
|
||||
youle_erqiwang.do_sendfail(pack, "maipai", youle_erqiwang.ERR.STEP);
|
||||
return;
|
||||
}
|
||||
//检查庄家位置
|
||||
if (o_paiju.banker != seat){
|
||||
youle_erqiwang.do_sendfail(pack, "maipai", youle_erqiwang.ERR.SEAT);
|
||||
return;
|
||||
}
|
||||
//检查埋牌入参本身是否合法(数组/整数牌id/范围/无重复),须先于 length 判断
|
||||
if (!o_paiju.method.check_cards_valid(cards)){
|
||||
youle_erqiwang.do_sendfail(pack, "maipai", youle_erqiwang.ERR.PARAM);
|
||||
return;
|
||||
}
|
||||
//检查埋牌是否是8张
|
||||
if (cards.length != 8){
|
||||
youle_erqiwang.do_sendfail(pack, "maipai", youle_erqiwang.ERR.PARAM);
|
||||
return;
|
||||
}
|
||||
//检查埋牌是否都在庄家手上
|
||||
if (!o_paiju.method.check_cards_inhand(cards, seat)){
|
||||
youle_erqiwang.do_sendfail(pack, "maipai", youle_erqiwang.ERR.PARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -259,6 +310,7 @@ youle_erqiwang.maipai = function(pack){
|
||||
msg.route = "erqiwang";
|
||||
msg.rpc = "maipai";
|
||||
msg.data = {};
|
||||
msg.data.success = true;
|
||||
msg.data.seat = o_paiju.playproc.currseat;
|
||||
msg.data.countdown = o_desk.method.get_countdown_chupai();
|
||||
for (var i = 0; i < o_room.seatlist.length; i++) {
|
||||
@@ -292,28 +344,34 @@ youle_erqiwang.touxiang = function(pack){
|
||||
//检查玩家的位置是否正确
|
||||
var o_room = youle_erqiwang.import.check_player(agentid, gameid, roomcode, seat, playerid, pack.conmode, pack.fromid);
|
||||
if (!o_room){
|
||||
youle_erqiwang.do_sendfail(pack, "touxiang", youle_erqiwang.ERR.PLAYER);
|
||||
return;
|
||||
}
|
||||
//牌桌
|
||||
var o_desk = o_room.o_desk;
|
||||
if (!o_desk){
|
||||
youle_erqiwang.do_sendfail(pack, "touxiang", youle_erqiwang.ERR.NODESK);
|
||||
return;
|
||||
}
|
||||
//牌局
|
||||
var o_paiju = o_desk.method.curr_paiju();
|
||||
if (!o_paiju){
|
||||
youle_erqiwang.do_sendfail(pack, "touxiang", youle_erqiwang.ERR.NODESK);
|
||||
return;
|
||||
}
|
||||
//投降是选主阶段(step 2)与选主互斥的选择:点投降直接结算,不选主、不埋牌(design §4)
|
||||
if (o_paiju.step != 2){
|
||||
youle_erqiwang.do_sendfail(pack, "touxiang", youle_erqiwang.ERR.STEP);
|
||||
return;
|
||||
}
|
||||
//检查庄家位置
|
||||
if (o_paiju.banker != seat){
|
||||
youle_erqiwang.do_sendfail(pack, "touxiang", youle_erqiwang.ERR.SEAT);
|
||||
return;
|
||||
}
|
||||
//仅 70 分坐庄可投降(design §4 / §7.1)
|
||||
if (o_paiju.call != 70){
|
||||
youle_erqiwang.do_sendfail(pack, "touxiang", youle_erqiwang.ERR.RULE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -339,38 +397,46 @@ youle_erqiwang.chupai = function(pack){
|
||||
//检查玩家的位置是否正确
|
||||
var o_room = youle_erqiwang.import.check_player(agentid, gameid, roomcode, seat, playerid, pack.conmode, pack.fromid);
|
||||
if (!o_room){
|
||||
youle_erqiwang.do_sendfail(pack, "chupai", youle_erqiwang.ERR.PLAYER);
|
||||
return;
|
||||
}
|
||||
//牌桌
|
||||
var o_desk = o_room.o_desk;
|
||||
if (!o_desk){
|
||||
youle_erqiwang.do_sendfail(pack, "chupai", youle_erqiwang.ERR.NODESK);
|
||||
return;
|
||||
}
|
||||
//牌局
|
||||
var o_paiju = o_desk.method.curr_paiju();
|
||||
if (!o_paiju){
|
||||
youle_erqiwang.do_sendfail(pack, "chupai", youle_erqiwang.ERR.NODESK);
|
||||
return;
|
||||
}
|
||||
//检查当前的游戏阶段是否是出牌阶段
|
||||
if (o_paiju.step != 5){
|
||||
youle_erqiwang.do_sendfail(pack, "chupai", youle_erqiwang.ERR.STEP);
|
||||
return;
|
||||
}
|
||||
//检查出牌位置
|
||||
if (seat != o_paiju.playproc.currseat){
|
||||
youle_erqiwang.do_sendfail(pack, "chupai", youle_erqiwang.ERR.SEAT);
|
||||
return;
|
||||
}
|
||||
//检查出牌入参本身是否合法(数组/整数牌id/范围/无重复,含非空)
|
||||
if (!o_paiju.method.check_cards_valid(cards)){
|
||||
youle_erqiwang.do_sendfail(pack, "chupai", youle_erqiwang.ERR.PARAM);
|
||||
return;
|
||||
}
|
||||
//检查出牌是否都在玩家手上
|
||||
if (!o_paiju.method.check_cards_inhand(cards, seat)){
|
||||
youle_erqiwang.do_sendfail(pack, "chupai", youle_erqiwang.ERR.PARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
//检查选中的牌是否可出,并出牌
|
||||
var re = o_paiju.method.do_playcard(cards);
|
||||
if (!re.result){
|
||||
youle_erqiwang.do_sendfail(pack, "chupai", youle_erqiwang.ERR.RULE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -382,6 +448,7 @@ youle_erqiwang.chupai = function(pack){
|
||||
msg.app = "youle";
|
||||
msg.route = "erqiwang";
|
||||
msg.data = {};
|
||||
msg.data.success = true;
|
||||
msg.data.seat = seat;
|
||||
msg.data.cards = re.cards ? re.cards : cards; //实际打出的牌(甩错时为单张)
|
||||
if (!_cfg.nocheck){
|
||||
@@ -473,29 +540,35 @@ youle_erqiwang.mingpai = function(pack){
|
||||
//检查玩家的位置是否正确
|
||||
var o_room = youle_erqiwang.import.check_player(agentid, gameid, roomcode, seat, playerid, pack.conmode, pack.fromid);
|
||||
if (!o_room){
|
||||
youle_erqiwang.do_sendfail(pack, "mingpai", youle_erqiwang.ERR.PLAYER);
|
||||
return;
|
||||
}
|
||||
//牌桌
|
||||
var o_desk = o_room.o_desk;
|
||||
if (!o_desk){
|
||||
youle_erqiwang.do_sendfail(pack, "mingpai", youle_erqiwang.ERR.NODESK);
|
||||
return;
|
||||
}
|
||||
//牌局
|
||||
var o_paiju = o_desk.method.curr_paiju();
|
||||
if (!o_paiju){
|
||||
youle_erqiwang.do_sendfail(pack, "mingpai", youle_erqiwang.ERR.NODESK);
|
||||
return;
|
||||
}
|
||||
//只在出牌阶段
|
||||
if (o_paiju.step != 5){
|
||||
youle_erqiwang.do_sendfail(pack, "mingpai", youle_erqiwang.ERR.STEP);
|
||||
return;
|
||||
}
|
||||
//不查牌模式禁止明牌
|
||||
var cfg = cls_youle_erqiwang_config.parse(o_room.roomtype);
|
||||
if (cfg.nocheck){
|
||||
youle_erqiwang.do_sendfail(pack, "mingpai", youle_erqiwang.ERR.RULE);
|
||||
return;
|
||||
}
|
||||
//必须已有玩家报无主才允许明牌
|
||||
if (!o_paiju.method.have_baofu()){
|
||||
youle_erqiwang.do_sendfail(pack, "mingpai", youle_erqiwang.ERR.RULE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -505,6 +578,7 @@ youle_erqiwang.mingpai = function(pack){
|
||||
msg.route = "erqiwang";
|
||||
msg.rpc = "mingpai";
|
||||
msg.data = {};
|
||||
msg.data.success = true;
|
||||
msg.data.seat = seat;
|
||||
msg.data.others = [];
|
||||
for (var i = 0; i < 3; i++){
|
||||
@@ -532,28 +606,34 @@ youle_erqiwang.tishi = function(pack){
|
||||
//检查玩家的位置是否正确
|
||||
var o_room = youle_erqiwang.import.check_player(agentid, gameid, roomcode, seat, playerid, pack.conmode, pack.fromid);
|
||||
if (!o_room){
|
||||
youle_erqiwang.do_sendfail(pack, "tishi", youle_erqiwang.ERR.PLAYER);
|
||||
return;
|
||||
}
|
||||
//牌桌
|
||||
var o_desk = o_room.o_desk;
|
||||
if (!o_desk){
|
||||
youle_erqiwang.do_sendfail(pack, "tishi", youle_erqiwang.ERR.NODESK);
|
||||
return;
|
||||
}
|
||||
//牌局
|
||||
var o_paiju = o_desk.method.curr_paiju();
|
||||
if (!o_paiju){
|
||||
youle_erqiwang.do_sendfail(pack, "tishi", youle_erqiwang.ERR.NODESK);
|
||||
return;
|
||||
}
|
||||
//只在出牌阶段(step5)任意时刻可发
|
||||
if (o_paiju.step != 5){
|
||||
youle_erqiwang.do_sendfail(pack, "tishi", youle_erqiwang.ERR.STEP);
|
||||
return;
|
||||
}
|
||||
//只有闲家可发提示,庄家无对家、不参与
|
||||
if (seat == o_paiju.banker){
|
||||
youle_erqiwang.do_sendfail(pack, "tishi", youle_erqiwang.ERR.RULE);
|
||||
return;
|
||||
}
|
||||
//提示类型:1=踩 2=没分 3=有分
|
||||
if (tip != 1 && tip != 2 && tip != 3){
|
||||
youle_erqiwang.do_sendfail(pack, "tishi", youle_erqiwang.ERR.PARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -566,6 +646,7 @@ youle_erqiwang.tishi = function(pack){
|
||||
msg.route = "erqiwang";
|
||||
msg.rpc = "tishi";
|
||||
msg.data = {};
|
||||
msg.data.success = true;
|
||||
msg.data.seat = seat; //发出提示的闲家
|
||||
msg.data.tip = tip;
|
||||
msg.conmode = o_room.seatlist[partner].conmode;
|
||||
@@ -583,24 +664,29 @@ youle_erqiwang.zhunbei = function(pack){
|
||||
//检查玩家的位置是否正确
|
||||
var o_room = youle_erqiwang.import.check_player(agentid, gameid, roomcode, seat, playerid, pack.conmode, pack.fromid);
|
||||
if (!o_room){
|
||||
youle_erqiwang.do_sendfail(pack, "zhunbei", youle_erqiwang.ERR.PLAYER);
|
||||
return;
|
||||
}
|
||||
//牌桌
|
||||
var o_desk = o_room.o_desk;
|
||||
if (!o_desk){
|
||||
youle_erqiwang.do_sendfail(pack, "zhunbei", youle_erqiwang.ERR.NODESK);
|
||||
return;
|
||||
}
|
||||
}
|
||||
//牌局
|
||||
var o_paiju = o_desk.method.curr_paiju();
|
||||
if (!o_paiju){
|
||||
youle_erqiwang.do_sendfail(pack, "zhunbei", youle_erqiwang.ERR.NODESK);
|
||||
return;
|
||||
}
|
||||
//检查当前的游戏阶段是否是结算阶段
|
||||
if (o_paiju.step != 6){
|
||||
youle_erqiwang.do_sendfail(pack, "zhunbei", youle_erqiwang.ERR.STEP);
|
||||
return;
|
||||
}
|
||||
//检查当前局数小于总局数
|
||||
if (o_desk.paiju_list.length >= o_room.asetcount){
|
||||
youle_erqiwang.do_sendfail(pack, "zhunbei", youle_erqiwang.ERR.RULE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -611,4 +697,4 @@ youle_erqiwang.zhunbei = function(pack){
|
||||
//Node(本地/单元测试)导出模块对象;友乐/浏览器无 module 时跳过(dev-guide 01 §1)
|
||||
if (typeof module !== "undefined"){
|
||||
module.exports = youle_erqiwang;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user