Skip to content

Releases: wm-develop/Texas

0.7.0

Choose a tag to compare

@wm-develop wm-develop released this 20 Sep 10:15

好友德州 v0.7.0

新增抽水:管理员可以按房间设置每手从底池里抽走一部分娱乐筹码,进入管理员账户。默认不抽;不开启时行为与 v0.6.2 完全一致。

数据库、服务端、客户端三处都要更新,有先后顺序,见文末「升级须知」。本版同时包含 v0.6.1、v0.6.2 的修复(那两个版本没有单独发 Release)。

抽水规则

管理员在「服务器管理 → 抽水管理」里给每个开着的房间单独设置,房主不能改。

设置项 含义
开启抽水 总开关
比例 每手按底池的百分之几抽,0%~10%,步长 0.25%
封顶筹码 比例部分最多抽多少;填 0 或留空为不封顶
翻后加抽 发出翻牌的手额外再抽一笔固定筹码,不受封顶限制,但不超过一个大盲
  • 底池按标准规则计:没人跟注而退回的筹码不算。
  • 比例部分向下取整后再封顶,翻后加抽另加,一手最多抽「封顶 + 加抽」。
  • 「发出翻牌」按手结束时公共牌不少于 3 张判断,翻牌前全下后补发的牌面也算。底池不足两个大盲的手不加抽,因此抽水永远小于底池。
  • 一手只抽一次,发两次也一样。有边池时按各池大小分摊:短码全下的人只承担主池那一份,不会替边池付抽水。
  • 修改从下一手起生效;进行中的一手(包括服务端重启后恢复出来的)按开局时的规则结算。
  • 看牌费不抽水。

向下取整不会丢筹码:守恒校验从「各人输赢之和为 0」改为「各人输赢之和 + 本手抽水 = 0」,在规则引擎、牌谱入库和钱包事务三处同时校验;抽水入管理员钱包与该手结算在同一个数据库事务里完成,管理员账户每手多一条「牌桌抽水」流水。

玩家看到什么

  • 规则一变,房间文字聊天里出现一条系统公告,写明比例、封顶、加抽与「下一手起生效」。公告伪造不了,也不受屏蔽名单影响。
  • 牌桌信息栏常驻显示当前规则;输入房间码后的带入窗口里也写明,进房间之前就能知道。
  • 每手结算写明「本手抽水 X」,「最近牌局」里同样标出。

管理员看到什么

  • 「抽水管理」页:开着的房间及各自规则,按房间的累计抽水(含已关闭的房间)与合计。可填「多少元 = 多少筹码」做换算——与房间战绩一样只在本机计算,服务端不存储也不传输任何金额。
  • 每次修改规则记入审计。
  • 管理员账号不能再创建或加入牌桌,想打牌请另注册普通账号。抽水打进最早创建的、状态正常的管理员钱包;这位管理员自己还在某个房间里时,那个房间不抽。

同时包含的修复(v0.6.1 / v0.6.2)

  • 弃牌后中途离开、或同一房间反复进出,会丢失桌上筹码。
  • 自动准备倒计时到点的瞬间有人离开,会造出「幽灵座位」,此后该房间每手结算失败、输赢不入账(表现为「点了弃牌没反应」)。现在上一手没入账就不开下一手,结算失败写 Error 日志并向全桌广播。

升级须知

  1. 升级前,管理员账号先离开所有房间。
  2. 备份后先跑数据库迁移 000012_rake,再启动新服务端。 一旦产生了抽水流水,这个迁移就不能回滚(账本不可变)。
  3. 更新服务端并重启。不开抽水时,旧客户端一切照常。
  4. 把服务器上的对账脚本换成新版:sudo cp deploy/backup/texas-verify.sql /opt/texas/bin/。旧版会把每一手抽过水的牌都报成不平衡。
  5. 分发 0.7.0 客户端。在所有人装好、并把「最低客户端版本」填成 7000 之前,不要给任何房间开抽水:旧客户端不显示「本手抽水」,也不认识系统公告。
  6. 建议先在一个自己人的房间里开抽水,按 docs/ACCEPTANCE_GUIDE.md 的 I-4 走一遍并跑一次对账,再给正式房间开。

接口与协议变化

  • 新增 GET /v1/admin/rooms、POST /v1/admin/rooms/{roomID}/rake(五个字段必须传齐)、GET /v1/admin/rake。
  • 结算 settlement 增加 rake、rakeBase(仅本手有抽水时出现);快照顶层与 GET /v1/rooms/preview 增加 rake;最近牌局每手增加 rake。
  • 聊天消息增加 kind=system,只由服务端发出。
  • 新错误码:admin_cannot_play(403)、invalid_rake_settings(400)。

已知边界

  • 抽水只打给一位管理员;多位管理员之间如何分配不在系统内处理。
  • 累计按房间汇总;更细的口径可直接查 bankroll_entries 中 reason = 'rake' 的流水。
  • 牌桌信息栏显示的是房间当前规则(下一手起适用);管理员在一手中途改规则时,以聊天公告与该手结算写明的数额为准。

完整说明见 docs/releases/v0.7.0.md,给玩家的版本见 docs/releases/v0.7.0-players.md。本 Release 仅提供源码,请使用自己的服务地址、TRTC 配置和平台签名构建。

0.6.0

Choose a tag to compare

@wm-develop wm-develop released this 17 Sep 00:44

好友德州 v0.6.0

v0.6.0 汇总了 v0.4.2 之后的全部改动,包括未在 GitHub 单独发布的 0.4.3、0.5.0 与 0.5.1。这一段的工作集中在两件事上:

  • 进行中的牌局能跨进程重启恢复;移动端被系统回收后回来直接落回原桌,不必重新登录;CI 接入真实 PostgreSQL,此前静默跳过的集成测试每次都真跑。
  • 换座和私下看牌可以在设置里整体关掉,拒绝时可以屏蔽这个人,对方给你看过牌后本手不能再问。

服务端与客户端都需要更新,并且必须先执行数据库迁移。

发布方式

本 Release 不会直接附带 Web、Windows、Android、HarmonyOS 或 iOS 安装包,仅发布 Git 标签对应的源码快照。

客户端需要写入自建游戏服务地址,语音需要部署者自己的腾讯云 TRTC 配置,Android 与 HarmonyOS 正式分发还涉及各自的平台签名,因此各平台产物应由部署者根据自己的环境构建、签名和测试。

从空服务器开始部署,请参阅自建部署指南。已有部署的版本升级流程请参阅生产环境更新手册。

升级须知

  • 必须先迁移再启动服务。 自 v0.4.2 以来新增一个迁移 000011_table_states。服务端启动时会校验迁移版本,未迁移会拒绝启动。若服务器已经部署过 v0.5.0 或 v0.5.1,这个迁移已经执行过,本次只需替换服务端二进制。
  • 服务端与客户端必须一起更新。 本版新增了 WebSocket 命令与事件:旧客户端连新服务端不会出错,只是没有新功能;新客户端连旧服务端会拿到 unsupported_message_type,拒绝范围也会被旧服务端忽略、退化成普通拒绝。
  • 所有人装好后,管理员在「服务器管理 → 最低客户端版本」填入 6000。
  • 崩溃恢复需要接入 PostgreSQL。 未接数据库的部署行为不变:崩溃后进行中的一手仍然作废。
  • 强烈建议在服务器上跑一遍真实 PostgreSQL 集成测试,步骤见更新手册对应章节。自 v0.4.2 以来新增了一张表和一批 SQL,而内存仓储的单元测试拦不住 SQL 与真实库的错配。
  • 协议变化:新增命令 table.request.preferences.set;新增只发给申请者本人的事件 table.request.declined;table.hole_cards.view.respond 与 table.seat.swap.respond 新增可选字段 scope;快照新增 requestPreferences(只发给本人)。详见协议文档。

重要改进

进行中的牌局跨进程重启恢复

在此之前,服务异常退出会让进行中的那一手作废:底池退回上一手结算后的状态,玩家的决策全部白费。优雅停机会等牌局打完,但崩溃、OOM 和宿主机重启不会等,而这几种情况恰恰无法预告。

每次引擎推进后,牌桌的完整状态(底牌、未发的牌堆、底池、行动位、加时卡、观战者看牌权、动作记录)写入新表 table_states,手结束即删除。进程重启后,第一个回到该房间的人触发恢复,那一手照原样继续。

三个关键决定:

  • 写库放到后台。 保存发生在持有牌桌锁的路径上,同步写会让数据库一慢就把整桌人卡住——这是恢复功能引入的新故障模式,之前牌局根本不碰数据库。改成每房间只保留最新一次待写的异步写入,顺序天然正确;优雅停机时会等它刷完。
  • 恢复从严,宁可作废。 状态版本对不上、内容自相矛盾(牌重复、筹码为负、轮到空座位)、或停机期间房间盲注被改过,一律放弃并清除记录,退回旧行为。拿一个不确定的状态继续发牌,比作废一手严重得多。
  • 行动倒计时从恢复时刻重新起算,不沿用崩溃前的截止时间。玩家在服务端停摆期间无法行动,一上来就判他超时弃牌,是替服务端的故障惩罚玩家。

客户端跟着改了一处:原来一看到服务端进程标识变化就提示「本手作废」,现在要等重连后的第一条快照——手号还在就是恢复成功,不再冤枉服务端。

引擎侧有一条按字段数量比对的守卫测试:以后给 holdem.Table 加字段却忘了同步状态序列化,会被它拦住。

登录态持久化(移动端)

移动设备上应用挂后台十几秒就可能被系统回收,而登录态此前只存在内存里:出去回条微信,回来就要重新输账号密码。牌局本身已经能跨重启续上,客户端却因为这一处停在登录页。

刷新令牌存到设备上,启动时自动换会话。牌桌路由本就是「有房间就进牌桌」,因此回来会直接落在原来那一桌。

这项功能的难点不在存取,而在超时不等于取消:

  • 恢复串了三个请求,每个能等 30 秒,因此加了 8 秒总超时——不设上限时服务端挂起会让玩家对着一个没有出口的转圈等一分半,而此前登录页是立刻出现的。
  • 但 Future.timeout 不会中止底层请求。用代次标记让迟到的结果不再落地,否则十几秒后界面会自己跳走,甚至把玩家手动登录的账号覆盖掉。「正在进行中」的标记改由真正执行者释放,避免两次拿同一个令牌去换会话——服务端刷新时会删掉旧会话,后一次必然被拒还会清空存储。
  • 只有服务端明确拒绝令牌才清除;没网、超时、版本过旧一律保留,否则信号不好的地方启动一次就得重新登录。临时失败后回到前台静默重试,不切回等待界面:切界面会把玩家正在填的登录表单连输入框一起卸载。
  • 轮换出来的新令牌一律等写入落盘再继续。服务端刷新时旧会话已被删除,写入没落盘就被系统回收等于丢掉登录态,而那正是本功能要应对的场景。

Web 端刻意不持久化。 那里的存储落在 localStorage,而浏览器常常是公用的:下一个打开页面的人会直接进入上一个人的账号。移动端的设备通常属于一个人,风险完全不同。Web 的第一帧仍是登录页,行为与从前一致。

存储用应用私有的 shared_preferences,内容明文。这是权衡:本项目是熟人私人牌局、不涉真钱,应用私有目录在未 root 的设备上其他应用读不到;而更严格的安全存储在 HarmonyOS 上没有可用适配。过期时间按 UTC 存,避免玩家换时区后有效令牌被误判。

换座与私下看牌的申请偏好和拒绝范围

换座和私下看牌此前只有「同意」和「拒绝」两个选项,同一个人可以一直申请下去,被申请的人只能一次次地关弹窗。现在有三层控制,粒度从粗到细:

  • 设置里整体关闭(房间级)。「允许其他玩家向我申请换座」「允许其他玩家申请私下看我的牌」,关掉后申请在服务端当场被拒,本人不会看到弹窗,已经排队的申请一并撤掉。偏好只在本房间有效,离开房间即恢复为允许——这是刻意的:这类设置多半是针对当下这一桌的某个人,带到下一个房间去反而意外。
  • 拒绝时屏蔽这个人。换座的屏蔽在被申请者离开房间前一直有效,申请者自己退出再进来不会清除它(否则屏蔽形同虚设);看牌的屏蔽只在本手内有效,因为看牌申请本身就只在一手之内有意义。
  • 拒绝所有人(仅看牌,本手)。牌局里被两三个弃牌的人轮流申请时,一次点掉。

还加了一条小规则:对方同意过一次后,本手不能再向同一人申请。牌已经在自己的玩家框里了,再申请只会让对方再被弹一次窗。客户端直接不发这条申请,服务端也有兜底校验。

拒绝范围的选项没有挤进弹窗底部的按钮行:四个按钮在横屏手机开大字号时会折成参差的两行,看不出哪个是「拒绝」哪个是「同意」。范围选项改成整行按钮放在正文里,底部只留「拒绝 / 同意」。

申请被拒的提示只有申请者看到

被拒的提示区分四种情况(这次拒绝 / 不再接受你 / 不接受任何人 / 对方关掉了申请),并且带上对方昵称。

这条提示走的是只发给一个人的定向事件,不进房间事件缓冲。牌桌的事件缓冲是为断线补发准备的,进了缓冲的事件会在别人重连时一并送出——「谁拒绝了谁」如果进了缓冲,等于过一会儿全桌都知道。定向事件不占序号,客户端把序号 0 当作带外消息接受,因此也不会打乱断线补发的序号连续性检查。

CI 接入真实 PostgreSQL

集成测试在缺少 TEST_DATABASE_URL 时会静默跳过——没人跑就等于没有。列数错配那次 P0、观战者的满员计数、以及一条自 000007 起就已过期的迁移测试,都是这么漏掉的。

  • Go 作业加了 postgres 服务容器并设置 TEST_DATABASE_URL,集成测试每次推送都真跑。
  • 新增跳过检测:显式跑一遍 Postgres 用例并检查输出里没有 SKIP,容器或环境变量坏掉时直接失败,而不是继续全绿。
  • 传输层用例连跑 5 轮,钉出只在慢机器上偶发的竞态。
  • history 包此前没有任何集成测试,生产走的那条 SQL 路径上的手牌裁剪从未在真实库验证过;现已补上并纳入 CI。

手牌历史的可见性契约

存下来的每手牌带着所有参与者的底牌(复盘与纠纷裁定需要),而发给玩家的必须裁剪:只有自己的牌和那手真的亮过的牌。两个 Store 实现一直都做了这件事,但这条契约没有任何测试盯着它——新增实现或重构时漏掉不会有任何征兆,而漏掉就等于公开对手从未亮过的底牌。

契约现已写进接口文档,并有一条可复用的契约测试在内存与 Postgres 两个实现上验证。

界面调整与修复

  • 最近牌局补上按街的动作过程。服务端一直在记录每个动作,客户端此前整个丢掉了,复盘时最想知道的「谁在什么时候下了多少」反而看不到。对手盖着牌结束时那一栏原来是一片空白,看着像加载失败,现在写明「未亮牌」。牌面改为复用牌桌的四色与自绘花色。
  • 本房间战绩不再虚高(0.5.1)。服务端的「桌上筹码」取自成员表,只在结算时更新,牌局中途仍含着已经推进底池的那部分。没弃牌时那笔钱归属未定,照常算在桌上;一旦弃牌它就已经输掉了,再算成自己的筹码会让净胜负虚高一截。现在弃牌后战绩里会单列一行扣掉它。
  • 鸿蒙手机上设置弹窗滚不到最后一项(0.4.3):房主看不到「房间管理」,管理员看不到「打开服务器管理」。内容区此前按屏幕高度的 70% 限高,上游 Flutter 会把它压到弹窗真实剩余空间,OpenHarmony 那版不会,于是滚动范围按错误的高度算。新增 DialogScrollArea 按真实可用空间计算,设置、房间管理、房间名单三个弹窗统一使用。
  • 花色符号没有跟着四色染色(0.4.3):♠♥♦♣ 在 Android / HarmonyOS 上被系统彩色 emoji 字体接管,文字颜色对它不起作用。花色改为自绘图形,公共牌与玩家框同一套,四端一致。
  • 玩家框小牌「10」错位(0.4.3):一行放不下时折成两行。小牌改为一律点数在上、花色在下居中。
  • 快照尚未到达时,房主判断退回房间信息里的房主,避免「房间管理」入口短暂缺失(0.4.3)。
  • 房间管理里的看牌费输入框改为与补码弹窗同款的整行带标签输入。

顺手修掉的既有缺陷

申请偏好功能引出的三轮代码审查,在周边既有代码里查出两处问题,一并修了:

  • 行动超时后的状态落盘在解锁之后才执行。那里用的是 defer,函数返回时牌桌锁已经放开,序列化牌桌状态会与其他协程对同一批数据的写入并发。改为解锁前显式落盘。
  • 结束一手的路径有四条,只有一条清理了本手的看牌状态。发牌次数选择、行动超时、选择超时三条路径都漏了,导致结算展示期里还挂着上一手的私下看牌。现在四条路径共用同一个清理函数。

测试

  • 服务端新增:引擎状态往返与恢复用例(含字段数量守卫)、牌桌管理层的重启恢复与降级用例、状态存储用例、手牌裁剪的契约测试;申请偏好的作用范围、离房重置、申请者进出不清屏蔽、拒绝范围校验、本手结束清理、跨重启保留;传输层端到端用例覆盖定向事件只发申请者且不占序号、旁观者拿不到被看的牌、当场拒绝的各个错误码、偏好字段必填。Postgres 集成测试补上牌桌状态往返与级联删除、手牌历史。
  • 客户端新增:登录态持久化 18 项(存储往返与轮换覆盖、UTC 序列化、Web 空操作、恢复成功进大厅、令牌被拒后清除、网络失败后保留、迟到结果不覆盖当前会话、登录表单不被冲掉);申请偏好 24 项(偏好解析、七种提示文案、定向事件去重、答复弹窗的四种决定、断线时不拨开关也不弹申请、拒绝后本地撤回排队申请、跨手边界不误撤、横屏大字号下的弹窗布局);另有最近牌局的动作解析、四色牌、弹窗滚动高度等用例。
  • 客户端 351 项、服务端全量与 go vet 通过,传输层与牌桌管理层各连跑 5 轮稳定;本标签对应提交的 CI(含竞态检测与真实 PostgreSQL 集成测试)全部通过。

已知限制

  • 仍是单游戏服务实例。恢复解决的是「崩溃后那一手不作废」,不是多实例高可用;多实例已在 ADR-002 中评估并决定暂不实施。
  • 恢复是尽力而为:最后一次状态写入未落盘就崩溃,恢复的是稍早的状态或直接作废。这是设计内的降级。
  • 手间重启(包括正常发版)会把所有人的申请偏好与换座屏蔽重置为默认。这两样跟着「进行中的牌桌状态」走,而手间本来就没有牌桌状态行。牌局进行中崩溃恢复能保留。要跨发版保留,需要把偏好挪进房间成员表(新迁移),本版没有做。
  • 被顺带撤回申请的人收不到提示。关掉偏好、或选「本手不再接受任何人」时,其他人已排队的申请会被静默撤掉,他们要等到再次申请时才知道。
  • 偏好弹窗开着时若正好有别的快照到达,开关可能闪一下再回到正确位置,窗口约一个网络往返。
  • 回到前台自动重试登录态无法写自动化测试:生命周期回调在本项目的 Flutter OpenHarmony 分支上无法在测试里驱动,只能真机验证。
  • 观战者的语音限制只能由客户端配合执行;改过的客户端可以绕过。牌局进行中没有「进入观战」入口(需求定义在准备区)。
  • 24 小时稳定性观测与弱网验收仍未实跑。
  • iOS 不在验收范围。

0.4.2

Choose a tag to compare

@wm-develop wm-develop released this 06 Sep 10:09

好友德州 v0.4.2

服务端与客户端都需要更新,并且必须先执行数据库迁移。

发布方式

本 Release 不会直接附带 Web、Windows、Android、HarmonyOS 或 iOS 安装包,仅发布 Git 标签对应的源码快照。

客户端需要写入自建游戏服务地址,语音需要部署者自己的腾讯云 TRTC 配置,Android 与 HarmonyOS 正式分发还涉及各自的平台签名,因此各平台产物应由部署者根据自己的环境构建、签名和测试。

从空服务器开始部署,请参阅自建部署指南。已有部署的版本升级流程请参阅生产环境更新手册。

升级须知

  • 必须先迁移再启动服务:本次新增迁移 000010_spectators,为 rooms 增加观战位设置四列,为 room_members 增加 spectating,座位号允许为 0,座位唯一约束改为只对真实座位生效。服务端启动时会校验迁移版本,未迁移会拒绝启动。
  • 服务端与客户端必须一起更新:本版新增了 WebSocket 命令(table.spectate.enter、table.seat.take、table.spectator.settings.set)与快照字段(spectators、spectatorSettings、spectatorFee、spectatorFees、spectating、座位上的 holeCards 与 pendingSpectate)。
  • Web 端部署者请检查反向代理:如果 nginx 层自行处理 CORS,Access-Control-Allow-Headers 必须包含 X-Client-Version,且 OPTIONS 预检要放行;否则 Web 端会显示「无法连接游戏服务」。服务端自带的 CORS 已修复。
  • 版本门槛请在所有人装好 0.4.2 之后再设为 4002。0.4.1 及更早的客户端不给语音凭证请求带版本头,门槛一开语音就连不上(见下文)。已开启门槛的部署,在客户端更新完成前请先把门槛填回 0。
  • 强烈建议在服务器上跑一遍真实 PostgreSQL 集成测试。本版改动了 room_members 的约束与索引,内存仓储的单元测试拦不住这类问题。更新手册的对应章节已重写:测试环境文件只需 TEST_DATABASE_URL 一个变量,指向单独的测试库;先只跑 Postgres 用例,再跑全量。

新增功能

观战位(OB)

房间成员可以不占座位地留在房间里观战,最多 10 人,与座位数无关。

  • 切换:手间的准备区有「进入观战」,观战面板有「上桌」;手间立即生效,牌局进行中只记录意向、本手结算后应用。座位满时立即拒绝,不排队;上桌必须有筹码。
  • 看牌费:观战者付费后能看到本手所有参与者的手牌。费用 = 房主设置的大盲倍数 × 大盲,默认 10 个大盲,可设 0~100,0 为免费。费用在全员准备完成、发牌之前收取,平分给即将参与本手的上桌玩家,余数从庄位起顺时针逐枚。余额不足的观战者本手不收费也不给看牌,补码后下一手恢复。
  • 看牌权按手发放,免费模式也不例外:开局时在观战位的人才能看本手;手间进入看不到刚结束那手的盖牌,牌局中途进入看不到进行中的这手。
  • 可见性:服务端按接收者裁剪,普通玩家的快照里永远没有别人的手牌。
  • 权限:房主可在「房间管理」里分别关闭观战者的语音、文字与赞赏/嘲讽,默认全部允许,服务端校验。语音的实际推流在客户端,服务端只能拒绝状态广播,由客户端配合关麦。
  • 其他:观战者可补码、不能准备、不能换座、不能私下申请看牌、不能成为表情目标;房主可随时移出观战者(包括牌局进行中);右上角「X/N(OB: Y)」点开房间名单;观战者不画在牌桌上。

收费放在发牌前是因为引擎在 StartHand 里记下每人的起始筹码作为结算守恒校验的基线,发牌后再加钱会让 Σ(结束 − 起始) ≠ 0。看牌费只在观战者与上桌玩家之间转移,牌桌筹码总量不变,持久化走与结算相同的事务与幂等保证。

牌桌调整

  • 弃牌确认:轮到自己且可以过牌时点「弃牌」先弹窗确认;需要跟注时直接提交。弹窗期间若已超时轮到别人,确认也不会把弃牌打到别人的回合上。
  • 赞赏/嘲讽气泡从玩家框底部向上飘,全程留在玩家框的竖向范围内;此前从框中心上方起飘,顶排座位的气泡一出现就在画布外被裁掉。
  • 四色牌:黑桃黑、红桃红、方块蓝、梅花绿,公共牌与玩家框小牌同一套;玩家框小牌从 27×34、10 号字放大到 30×36、12 号字。试玩反馈小牌里黑桃与梅花分不清,靠颜色区分才是根本解法,尺寸受玩家框高度限制只能放大一档。
  • 玩家框不再显示行动倒计时:轮到谁由高亮边框表示,倒计时只在公共牌区显示一处。

重要修复

Web 端无法连接游戏服务

v0.3.0 加 X-Client-Version 请求头后,服务端 CORS 的 Access-Control-Allow-Headers 没有声明它,浏览器预检失败,前端只看到一句笼统的连接失败;原生客户端不走 CORS,全都正常。现已放行,预检 OPTIONS 也绕过版本门禁。

开启版本门槛后语音提示「获取语音凭证失败」

客户端有两个 HTTP 客户端:所有接口走 GameApiClient 并带版本头,唯独语音凭证走独立的 TrtcCredentialClient,没带头。版本门禁包在整个服务外层,不带头的请求一律 426,客户端把任何非 200 都显示成凭证失败。这是 v0.3.0 的遗留问题,门槛首次开启才触发。0.4.2 补上请求头并增加断言测试。

观战位审查修复(0.4.1)

服务端:

  • 0 筹码的观战者上桌会被持久化成「已入座却不在引擎里」,此后全桌人的准备、重连、快照全部失败。现在上桌必须有筹码,手结束时被看牌费掏空的人的上桌意向自动放弃。
  • 免费模式此前只要在观战位就能看牌:输了的人手间进观战就能看到对手刚盖掉的牌再坐回去。改为看牌权同样只在开局时发放。
  • Postgres 的满员计数把观战者算了进去,5 人上桌加 5 人观战就把新人挡在门外。
  • 换座可能牵扯观战者:0 号位会匹配到第一个观战者,交换后写库撞约束。
  • 看牌费幂等键在运行时第一手不再用空串,避免重启后账本静默漏记。
  • 房主可在牌局进行中移出观战者;唯一没准备的人进观战后,其余人已全准备时立即开局。

客户端:

  • 观战者点「补码」此前静默无效(页面只在座位里找自己)。
  • 房间管理的移出列表此前不含观战者。
  • 付费后看别人的座位被整个换成「本人座位」样式,昵称、断线、全下全没了;改为只翻牌,其他信息照旧。
  • 「本手看不到牌」被当成「筹码不足」:看牌权是开局时发放的,手间与中途进入的观战者 canSeeHoleCards 必然为 false。快照新增 spectatorFee,只有筹码真的低于看牌费才提示补码。
  • 看牌费输入框改用平台数字面板(HarmonyOS 横屏约定);观战者点座位不再弹换位申请;同一错误连续出现按序号提示;房主设置未连接时不假装成功;头部与名单分母用房间最大人数;补齐错误码文案;屏蔽列表里观战者显示昵称。

只在真实 Postgres 上跑的两条用例

迁移升降级用例写死了 6 个版本,自 000007 起就已过期;改为以嵌入目录的版本数为准。集成测试里的「2 人房」并不存在(创建时会强制 10 人),满员判断从未被触发;改为直接把库里的 max_players 改成 2 再验证。两处都是测试本身的问题。

断线重连用例的竞态

TestWebSocketReconnectRestoresCurrentHandAndPrivateCards 在关掉客人的连接后只读房主连接上的下一条快照就断言客人已断线;房主连接上可能还排着开局前后的几条快照,断线通知在它们之后,CI 的慢机器上会随机撞上旧快照而误判。改为一直读到「客人显示为断线」为止。服务端逻辑没有问题,也没有改动。

测试

服务端新增约 40 项观战用例,覆盖房间、牌桌管理、传输三层:费用平分与守恒(含真实账本)、按手计费、中途切换、离开与断线、自动准备、权限与范围、0 筹码上桌、免费模式不漏牌、换座隔离、牌局中移出观战者、进观战触发开局。客户端新增约 30 项:观战面板三态、名单、设置、拦截、弃牌确认、气泡轨迹、补码筹码来源、错误序号、语音凭证版本头。Postgres 集成测试新增观战者持久化、两名观战者共用 0 号位、观战设置往返、满员只数上桌。

已知限制

  • 仍是单游戏服务实例,进程异常时该实例上进行中的那一手会作废。
  • 观战者的语音限制只能由客户端配合执行;改过的客户端可以绕过。
  • 牌局进行中没有「进入观战」入口(需求定义在准备区),服务端支持的中途意向目前只会由「上桌」产生。
  • 看牌费流程、名单、鸿蒙数字面板尚未在真机完整验证;HarmonyOS 原生代码无法在本机编译。
  • iOS 不在验收范围。

0.3.0

Choose a tag to compare

@wm-develop wm-develop released this 03 Sep 08:04

好友德州 v0.3.0

服务端与客户端都需要更新,并且必须先执行数据库迁移。

发布方式

本 Release 不会直接附带 Web、Windows、Android、HarmonyOS 或 iOS 安装包,仅发布 Git 标签对应的源码快照。

客户端需要写入自建游戏服务地址,语音需要部署者自己的腾讯云 TRTC 配置,Android 与 HarmonyOS 正式分发还涉及各自的平台签名,因此各平台产物应由部署者根据自己的环境构建、签名和测试。

从空服务器开始部署,请参阅自建部署指南。已有部署的版本升级流程请参阅生产环境更新手册。

升级须知

  • 必须先迁移再启动服务:本次新增两组迁移 000008_room_join_lock 与 000009_client_version_gate。服务端启动时会校验迁移版本,未迁移会拒绝启动。
  • 服务端与客户端必须一起更新:本版修改了 WebSocket 关闭码语义(新增 4001 / 4002)、结算报文(payouts[].displayName)与底池分层规则。只更新一端会出现提示错乱或边池显示不一致。
  • 客户端版本门禁默认关闭,升级后行为不变。需要强制朋友更新时,管理员在客户端「服务器管理 → 最低客户端版本」填入版本号即可,不需要改环境变量或重建容器。
  • 上一版短暂引入过的 MINIMUM_CLIENT_VERSION 环境变量已移除,改存数据库。
  • 版本门禁对 v0.3.0 之前的客户端只能拒绝,无法提示。0.2.x 的客户端不认识这套机制:它们能登录(登录路径是管理员的逃生通道),但加入房间与连接牌桌都会被 426 拒绝,界面上只会显示「操作失败(client_too_old)」或反复重连。因此请先确认所有人都装好 0.3.0 再设置门槛;从 0.3.0 起,未更新的客户端才会看到干净的阻断页。
  • 设置门槛不会踢掉已经连在牌桌上的旧客户端——版本检查发生在 WebSocket 握手时,已建立的连接不回头重查,他们能把当前这手打完。

重要修复

房间读取全面失败(P0)

v0.2.1 之后的开发中,为房间增加 join_locked 列时,loadRoom 的 SELECT 语句带 r. 前缀未被批量替换命中,而 Scan 目标多了一个,导致所有房间读取以 expected 12 destination arguments in Scan, not 13 失败。表现为创建房间后立刻被踢回大厅提示创建失败,之后任何房间操作一律 internal_error。

单元测试走内存仓储发现不了,Postgres 集成测试需要 TEST_DATABASE_URL,未配置时跳过。现已把列清单与 Scan 目标放在一起,并增加不依赖数据库的列数守卫测试。

在线玩家被标为断线、自动准备失效、下注按钮卡死

试玩中最恶劣的一类问题,根因有三处,互相叠加:

  • 旧连接关闭把在线玩家标为断线。手机切换网络后新连接先加入,旧的死连接要等 TCP 超时才被察觉;此前它的关闭会无条件把玩家标为断线并在手间取消准备。服务端自动准备跳过断线者,客户端又只提交一次——这就是「倒计时走完却不准备」。现在服务端记录每个用户当前生效的连接,新连接加入时以关闭码 4001 主动关掉旧的;旧连接的关闭不再改动牌桌状态。
  • 牌局中途加入者结算后一律以断线入座。他在结算前没有引擎座位,加入时的 SetConnected 落空,入座时写死 connected=false 且此后无人置回。现按真实在线状态入座。
  • 动作被拒后要不回快照。动作因 stale_revision 被拒后客户端请求快照,序号已追平时服务端只回一个空的 replay.completed,客户端手里的 tableRevision 依旧过期,再点什么都被拒——表现为下注按钮怎么点都没反应。现在显式请求一律返回完整快照。

客户端另加三道保险:system.error 也视为动作未生效并放开按钮、动作回执 5 秒看门狗、自动准备 3 秒后重试。发牌动画改用单调时钟,避免手机校时回拨导致动画永远播不完、按钮一直禁用。

无人 all in 时不该出现边池

边池的意义是「部分玩家无权争夺」,只有 all in 造成投入档位差异时才会产生。此前按投入额分层,弃牌者投得少同样会切出一层,而那一层与下一层的候选人集合完全相同——于是没人 all in 的牌局里也会显示「边池 1」。

现在候选人相同的相邻层合并为一个池:同一批人比同样的牌,赢家必然相同,合并后余数也只分一次,与真实牌桌一致。客户端相应地在只有一个池时称「底池」,有边池时才区分「主池 / 边池 N」。

结算文案显示用户 ID、底池金额对不上

同一个根因:赢家常常赢完这手就立刻离开房间。此后房间成员表和引擎座位里都没有他,靠座位反查昵称只能退化成显示 usr_...,而 totalPot(按在座玩家投入累加)也会小于结算金额。

现在服务端在结算时固化昵称并随 potAwards 下发;结算展示期间 totalPot 改用各池金额之和——发两次时每个池均分到各块牌面,所有 award 之和仍等于本手总底池。

被踢出房间提示「操作失败 permission_denied」

此前服务端用通用的 policy violation 关闭连接,客户端只能靠随后重连时 table.join 被拒来推断。现在用专门的关闭码 4002,关闭原因为 removed_by_owner 或 removed_by_administrator,客户端据此不再重连,回到大厅弹窗说明是谁移出的、筹码已退回钱包。

HarmonyOS:语音与提示音并存

开麦后过几秒就听不到其他玩家说话,系统音量条从话筒(通话音量)变为喇叭(媒体音量)。排查走了四轮,前三轮的方案都被真机否定,记录在此供参考:

尝试 结果
改用音频通话场景、不切换角色 无效
语音进行中放弃提示音 有效,但鸿蒙语音里没有提示音
交给 TRTC startPlayMusic 走通话流 不掐语音,但音量偏小、有延迟断续——那条链路是给背景音乐用的
并发模式改为 CONCURRENCY_MIX_WITH_OTHERS 无效

真因是牌局提示音,不是 TRTC。鸿蒙的音频焦点是应用级的:audioplayers 每次播放前调用 setAudioSessionScene(AUDIO_SESSION_SCENE_MEDIA) 并以 CONCURRENCY_DEFAULT 激活音频会话,该模式独占物理输出通道并压制应用内其他音频流。第四轮证明改并发模式无效,说明致命的是会话切换本身。

最终改为鸿蒙原生 SoundPool 通道:系统专为短音效提供的低时延通道,完全不经过 AudioSessionManager。已真机验证通过,语音与提示音并存,音量和及时性正常。

四种应对方式保留为 HarmonyVoiceSoundStrategy,每种的真机结论写在枚举注释里,改一个默认值即可切换对比。

新增功能

本房间战绩与换算

牌桌顶部新增按钮,显示本人在当前房间的净胜负,并按自定比例(默认 10 元 = 2000 筹码)换算金额。

净胜负 = 离桌返还 + 桌上筹码 − 累计带入。把桌上筹码计入是因为玩家通常在牌局中途查看,此时盈亏还没有通过离桌返还落回钱包。换算只在客户端本地进行,服务端不存储也不传输任何金额,产品仍不接入支付。

房主的房间管理

设置面板内新增「房间管理」,只对房主显示:

  • 移出玩家:复用玩家自己离桌的同一条路径,筹码照常退回钱包。只在手间允许——牌局进行中把人踢走会牵扯底池归属与行动顺序。管理员不可被房主移出:房主是房间内的角色,管理员是服务器级角色,需要能进入任何房间处理纠纷。
  • 关闭房间入口:只挡新加入者,房内成员不受影响。

客户端版本门禁

开发期服务端改动频繁,旧客户端连上新服务端会出各种难以定位的问题,而参与试玩的朋友常常忘记更新。

  • 最低版本存在数据库,管理员在「服务器管理」页调整,立即生效且不需要改环境变量或重建容器——只更新客户端的发布不必登服务器。
  • 版本号统一为 major*1000000 + minor*1000 + patch 编码(0.2.1 → 2001),四端与鸿蒙 versionCode 同一套。此前 pubspec 的 +3 让 Android 的 versionCode 是 3 而鸿蒙是 2001,两套编码无法比较。
  • 客户端每次请求带 X-Client-Version(WebSocket 走查询参数,浏览器不允许设自定义头)。门禁包在整个 mux 外层,WebSocket 升级一并覆盖——只挡登录接口的话,已经登录的旧客户端还能继续连牌桌。
  • 过旧返回 426,客户端进入不可跳过的阻断页。Web 端提示刷新页面而不是重新安装。
  • 登录、刷新令牌与「调整门槛」三条路径豁免门禁,作为逃生通道:否则门槛设得比管理员自己的客户端还高时会把自己锁死。
  • 新增 dart tool/set_version.dart <版本号>,一次改完三处版本号并拦住版本倒退。

界面调整

  • 牌桌吃满可用宽度:此前被固定上限 1040 卡住,平板与宽窗口可用宽度有 1300 以上,左侧白白空出一大片。改为按 1.95 的宽高比约束,只有超宽画布才会被限制。2~10 人的座位互不重叠、不遮挡公共牌区、不侵入两栏的测试全部在新宽度下重跑通过。
  • 平板横屏右栏按钮被裁掉且点不动:右栏高度不足时下注区被直接裁掉,改为贴底可滚动;系统手势导航条压在屏幕底部、那片区域触摸归系统,原生避让区查询在挖孔之外补上导航条(HarmonyOS TYPE_NAVIGATION_INDICATOR、Android navigationBars()),Flutter 侧再用 viewPadding/systemGestureInsets 兜底。
  • 顶部控件让开屏幕圆角:安卓手机上右上角的聊天按钮被屏幕圆角切掉一角。圆角既不属于挖孔也不属于系统栏,两套 inset 都不包含它,只能单独问系统要——Android 用 WindowInsets.getRoundedCorner(API 31+)上报四角半径,顶部两栏据此下移,已被安全区推开的那部分不重复计。选择下移而不是左移,是因为左移会挤到玩家框。鸿蒙没有对应接口,实测也正常。
  • HarmonyOS 平板显式全屏:应用此前一直顶着系统状态栏。代码注释称「FlutterAbility 管理全屏」,实际上并没有——鸿蒙手机恰好默认全屏才没暴露。现在在 onWindowStageCreate 里做沉浸式布局并隐藏状态栏。只隐藏状态栏、保留手势导航指示器:把它一起隐藏后系统仍占着屏幕底部那条手势区,但避让区接口会返回 0,界面不再让开,落在那里的按钮又会变得点不动。
  • 聊天入口按端分层:手机保持右栏里的独立大按钮;大屏做成信息栏右上角的大图标,不与那排小按钮并列,省出的竖向空间留给下注区。
  • 手机三个大下注按钮由 44 加高到 56,试玩反馈原高度容易误触。
  • 注码尺度按钮去掉「全下」:它不是「几分之几底池」那一类的尺度,混在里面容易误触。要全下把滑块推到最右或直接输入额度即可。
  • 大屏的房间信息与语音控件并入右栏顶部:玩家框现在会伸出桌沿,5~7 人时左右上角的座位会压到原先放在画布四角的控件。
  • 设置面板限高并可滚动:手机横屏可用高度很小,新增条目后一屏放不下。

已知限制

  • 仍是单游戏服务实例,进程异常时该实例上进行中的那一手会作废。
  • 24 小时稳定性观测与弱网验收的工具和清单已就绪,但仍未实跑。
  • 平板的系统手势导航条让开、屏幕圆角让开与 HarmonyOS 全屏尚未在真机确认。三者的实现依据都是各平台的系统接口(避让区、getRoundedCorner、window 全屏),本地无法验证。
  • HarmonyOS 原生 SoundPool 通道与 EntryAbility 的代码无法在本机编译验证(无 DevEco 工具链)。SoundPool 已真机验证运行行为正常,全屏改动尚未验证。
  • 本次发现的 P0(房间读取列数错配)说明:改动 *postgres_repository.go 时,仅靠内存仓储的单元测试不足以发现 SQL 与 Scan 的错配。有条件时应配置 TEST_DATABASE_URL 跑集成测试。
  • iOS 不在验收范围。

0.2.1

Choose a tag to compare

@wm-develop wm-develop released this 02 Sep 09:38

好友德州 v0.2.1

v0.2.1 汇总了 v0.2.0 之后的全部改动:单实例生产保障(备份、CI、限流、指标、告警)、账号注销与隐私说明、管理审计查询、优雅停机、下注区重做、牌桌布局修复和发牌动画。

本次修复了三个只在特定人数或特定屏幕下才会出现的牌桌遮挡缺陷,其中两个此前被写错的测试掩盖着。已部署环境建议升级;服务端与客户端都需要更新,并且必须先执行数据库迁移。

发布方式

本 Release 不会直接附带 Web、Windows、Android、HarmonyOS 或 iOS 安装包,仅发布 Git 标签对应的源码快照。

客户端需要写入自建游戏服务地址,语音需要部署者自己的腾讯云 TRTC 配置,Android 与 HarmonyOS 正式分发还涉及各自的平台签名,因此各平台产物应由部署者根据自己的环境构建、签名和测试。

从空服务器开始部署,请参阅自建部署指南。已有部署的版本升级流程请参阅生产环境更新手册。

升级须知

  • 必须先迁移再启动服务:本次新增迁移 000007_account_deletion,扩展了账本 reason 约束。服务端启动时会校验迁移版本,未迁移会拒绝启动。
  • docker stop 必须给足宽限期:游戏服务现在会等所有牌桌打完当前手再退出(默认最多 120 秒)。请使用 docker stop -t 150 texas-game-server;Docker 默认只等 10 秒就强制杀进程,正在进行的那一手会作废。
  • 服务端与客户端建议一起更新:只更新服务端不会出错,但账号注销与审计查询没有入口,加注档标签也仍显示旧文案。
  • 新增可选环境变量 SHUTDOWN_DRAIN_TIMEOUT_SECONDS(默认 120)。不配置即使用默认值。

重要修复

玩家框遮挡:三个此前未被发现的缺陷

牌桌的座位/公共牌不重叠测试自己按「alignment × 半宽」另算了一份座位位置,而 Flutter Align 的真实语义是按 可用空隙 = 桌宽 - 框宽 插值。两者相差一个框宽,真实的玩家框比测试以为的更靠近中心,因此测试在"会不会压住公共牌"这件事上是偏松的。按真实语义复算后暴露出:

  • 紧凑布局 4 人桌:侧边玩家框实际压进公共牌区 67 像素。
  • 桌面端 3 人桌:桌面使用纯椭圆分布,会把斜角座位放在靠近中心处,同样压住公共牌区。现已与手机统一为沿桌沿的周边分布。
  • 10 人桌玩家框互相遮挡:按角度投影的分布并不均匀,底边会挤下三个玩家框,相邻两框中心只差 159 像素而框宽 216,直接重叠 57 像素。现改为沿座位中心矩形的周长等距分布。

修复方式不是调整断言数字,而是由布局统一提供 seatRect,实现与测试共用同一套换算,杜绝两处各算各的。现在校验覆盖 8 种画布 × 2~10 人 × 三类检查:玩家框彼此不重叠、不遮挡公共牌区、不侵入聊天框与下注框,另加不被画布裁切。

玩家框位置与桌面空间

玩家框此前整个压在桌面之内,桌内被占的面积远大于桌外空白,中间的公共牌区和下注筹码反而局促。现在玩家框约 1/3 落在桌内、2/3 落在桌外的空白区。

修正过程中还发现:可见的绿色桌面比布局用的 tableRect 四周内缩 54/70 像素,早先按 tableRect 计算落位,结果玩家框整个悬在桌外还差 15 像素才碰到桌沿。现已统一以桌沿为基准。

加注档按钮标签与实际额度不符

底池远大于剩余筹码时,多个比例档会同时超过上限被压到最大加注额,但标签没有跟着改。界面上会出现一个写着「1/2 池」、实际却是你能加的最大额的按钮,旁边还有一个额度几乎相同的「全下」。

现在能全下时直接丢弃这些档位(服务端的 maxRaiseTo 就是全下额度向下取整的结果,两者相差不到一个小盲,全下已经覆盖);不能全下时保留但改名为「最大加注」。

左上角房间信息与连接状态重叠

此前用固定偏移量猜测标题高度,标题实际更高时两行文字叠在一起。现改为同一列排布,间距由内容决定。

下注区重做

参考成熟线上平台的做法重做了下注区,交互全平台统一,摆放按屏幕分层。

  • 固定三个大按钮:弃牌任何时候都合法;能过牌时第三个键是下注,不能过牌时是跟注加加注。全下不再单独占一个按钮。
  • 额度与提交分成两步:预设档、滑块、直接输入都只改额度,按钮上的数字同步变化,再点按钮才提交。此前点预设档会立即下注。
  • 全下靠把额度推到最右。这里有一处容易出错的细节:服务端的 maxRaiseTo 是向下取整到小盲倍数的,剩余筹码不是整数倍时它小于真实全下额度。若滑块右端取 maxRaiseTo 就永远滑不出全下,若把全下额度当作加注提交则会被服务端以 invalid_amount 拒绝。现在滑块右端是真实全下额度,且只有该点提交 all_in。
  • 按钮配色:弃牌与跟注原先用低饱和深色,与面板底色对比不足,看起来像不可点击的禁用键。现在三个可用态都明显亮于底色,禁用态单独用一个低彩度暗色。

摆放:手机上下注区移到牌桌右侧竖排,牌桌下方腾出的空间让给玩家框和公共牌区,牌桌纵向增加约 10%。大屏改为左侧聊天、右侧竖排下注区,与手机位置一致,换端不需要重新适应。

画布宽度不足以同时容纳「聊天 + 牌桌 + 下注区」时,聊天自动改为弹窗,与手机一致。

发牌动画

所有发牌一律「逐张背面落桌 → 停顿 → 一起翻开」。

  • 底牌:从小盲开始一张一张轮流发,本人的两张随后翻开,别人的牌背在翻牌阶段淡出,不常驻玩家框。
  • 公共牌:翻牌 3 张逐张落下后一起翻开;转牌与河牌同理。
  • 全下:服务端在全下后一次性发完剩余公共牌,客户端仍逐张演出。
  • 发两次:第一块牌面同样有发牌演出;第二块牌面不再瞬间替换第一块,而是第一次的牌收起为顶部点数条、第二次的牌自上而下滑入并淡进。第一块牌面的展示时间也改为从它翻开之后才开始计。

演出期间禁用行动输入,避免玩家在牌还没翻开时就做决定。牌局进行中加入的待入座观战者不在发牌顺序里,不会闪出牌背。断线重连后拿到的第一份快照里牌已经在桌上,不会补一段发牌动画。

已知取舍:服务端的行动倒计时在演出期间不会暂停,因此翻前第一个行动的玩家会少约一秒决策时间。经权衡未在服务端引入补偿逻辑。

账号注销、隐私与审计

  • 用户可自行注销账号:需输入当前密码确认,必须不在房间内;钱包中剩余的娱乐筹码整体转入创建时间最早的在用管理员,双方各记一条 account_deletion 流水且注明来源;注销后原用户名可以被重新注册;管理员不能自行注销,避免服务器失去管理入口。
  • 隐私说明:注册页与个人信息页内置说明对话框,正文与 PRIVACY_NOTICE.md 同源。
  • 管理审计查询:管理员可在客户端按类别、用户或房间查询管理操作、账号变更与语音进出记录。
  • 语音加入/退出元数据:以审计事件持久化,含房间与离开原因,不含任何音频内容。
  • 举报功能经评估后不做——熟人私人牌局的定位下,它解决不了实际问题。

生产保障

  • 数据库备份与恢复:定时备份、归档校验、异地复制(腾讯云 COS)、恢复演练,以及针对备份脚本静默失败的巡检——这是最危险的情况,能在 36 小时内发现。
  • 分层限流:登录/注册/刷新按 IP、密码错误按用户名、房间与钱包操作按用户、TRTC 凭证按用户、单 IP WebSocket 并发上限,配合 TRUSTED_PROXIES 可信代理解析。
  • 可观测性:令牌保护的 /metrics,新增 texas_goroutines、texas_memory_heap_bytes、texas_process_start_time_seconds 与 texas_draining;账本对账定时任务;健康巡检与钉钉/企业微信告警。
  • 24 小时稳定性观测脚本:判定协程泄漏、内存增长与静默重启,并在服务端指标改名时立即失败而不是静默记 0。
  • 优雅停机:收到停止信号后停开新局、取消自动准备并广播原因,等所有牌桌打完当前手再退出。客户端凭 session.authenticated 的 serverInstanceId 识别服务端重启,并明确提示上一手作废。
  • CI:服务端 gofmt/vet/test 与 -race、客户端 analyze/test、shellcheck 与仓库卫生检查。

工程与文档

  • 牌桌页从 3180 行降至约 805 行,语音状态与自动行为判定抽成不接触 BuildContext 的控制器,此前无法测试的规则现在有了直接覆盖。
  • 清理协议中五个从无发送点的常量,以及恒不命中的 revisionFromError。该分支比较的错误码与规则引擎实际产生的不一致,两个分支都返回 0。协议报文无变化。
  • 文档按「什么时候需要读它」重新组织:六份历史阶段清单合并进开发历程后移除,产品与架构规划由 792 行精简至 226 行,只保留别处没有的决策背景。
  • 新增 ADR-002:多实例与 Redis 暂不实施,并写明若要实施必须满足的约束与重新评估的触发条件。
  • 新增 验收指南:24 小时稳定性观测、9 个弱网与断线场景、四端冒烟清单,附可直接填写的记录模板。

已知限制

  • 仍是单游戏服务实例,进程异常时该实例上进行中的那一手会作废。
  • 24 小时稳定性观测与弱网验收的工具和清单已就绪,但尚未实跑。
  • 牌桌几何的自动化校验覆盖布局计算;子组件内容溢出(例如超长昵称)仍需真机冒烟。
  • iOS 不在验收范围。

0.2.0

Choose a tag to compare

@wm-develop wm-develop released this 01 Sep 07:51

好友德州 v0.2.0

v0.2.0 汇总了 v0.1.0 之后的全部改动,包含 v0.1.1 的手机牌桌重构,以及本次新增的服务端稳定性修复、牌桌交互完善、Android 发布签名支持和文档体系重建。

本次修复了一个会导致整桌卡死的服务端缺陷,建议所有已部署环境升级。

发布方式

本 Release 不会直接附带 Web、Windows、Android、HarmonyOS 或 iOS 安装包,仅发布 Git 标签对应的源码快照。

客户端需要写入自建游戏服务地址,语音需要部署者自己的腾讯云 TRTC 配置,Android 与 HarmonyOS 正式分发还涉及各自的平台签名,因此各平台产物应由部署者根据自己的环境构建、签名和测试。

从空服务器开始部署,请参阅自建部署指南。已有部署的版本升级流程请参阅生产环境更新手册。

重要修复

牌局进行中有玩家加入会导致全桌卡死

这是本次最关键的修复。此前玩家在一手牌进行中加入房间时,服务端会因无法为其分配牌桌座位而使所有玩家的状态快照生成失败,表现为全桌无法操作、无法离桌,只能等加时卡耗尽并由管理员将玩家逐出。

现在中途加入的玩家以“待入座”状态观战:对全桌可见、不参与本手、收不到任何底牌,本手结算后自动获得正式座位并从下一手开始参与。

已弃牌玩家可以随时离桌

此前任何玩家都必须等本手结束才能离桌。现在已弃牌或本手未参局的玩家可以随时离开,仍在争夺底池的玩家依旧不能中途离桌。

弃牌者已投入底池的筹码留在池中,剩余牌桌筹码在本手结算完成后幂等返还账户钱包,不会提前返还或重复返还,筹码守恒不变。

HarmonyOS 开麦后听不到其他人

HarmonyOS 在本地麦克风启动后会把播放路由切换到听筒,表现为开麦数秒后远端声音消失、关麦后恢复。现在进房和每次开关麦后都会重新固定扬声器路由。Android 与 Windows 的既有行为未改动。

登录页与大厅页键盘弹出后布局抽搐

登录页和大厅页此前按实时窗口高度切换布局档位,软键盘弹出压缩高度后会触发布局重排,导致输入框失焦、键盘立刻收回,在 Android 与 HarmonyOS 平板上形成无法输入的循环。现在布局档位改用不随键盘变化的窗口尺寸判定。

牌桌页同时改为按设备类别锁定布局族(手机、平板各自固定),并使用不受键盘影响的稳定视口尺寸。

牌桌与交互改进

发两次展示

  • 第一块牌面完整展示 5 秒后,第一次发出的牌收起为顶部点数条,第二次发出的牌叠放其下覆盖主体,两次结果可同时读取。
  • 全下前已经在场的公共牌保持原样,不参与切换。
  • 发两次结算的自动准备倒计时从 10 秒延长到 15 秒,留足两块牌面先后展示的时间;普通结算仍为 10 秒。

换位

  • 取消“选择空座位”弹窗。由于牌桌座位数始终等于房间人数,不存在可选空位。
  • 现在只保留一种操作:两手之间点击其他玩家,发起需要对方确认的换位申请。
  • 服务端不再要求牌桌坐满才能发起换位申请。

私下看牌

  • 弃牌玩家现在可以向本手发过底牌的任意其他玩家发起私下看牌申请,包括其他已弃牌的玩家。
  • 查看结果的牌型标签由内部枚举 private_view 改为中文“私下查看”。

文字聊天

  • 修复自己发送的消息必须关闭并重新打开聊天面板才显示的问题。
  • 消息列表固定在最新一条,新消息到达无需手动向下滚动。

Android 发布签名

此前 Release 构建复用调试签名,而调试密钥库由 Android SDK 在每台机器上随机生成,导致不同电脑构建的安装包无法在同一台设备上互相覆盖,且密钥口令公开、重装系统即丢失。

现在 Release 签名通过 apps/poker_client/android/key.properties 配置:

  • 存在该文件时使用维护者自己的发布密钥库签名;
  • 不存在时回退调试签名,并在构建日志中打印警告,提示该包不可分发。

配置步骤参阅Android 发布签名配置指南。密钥库与 key.properties 均已被 Git 忽略,不会进入版本库。

手机端牌桌重构(来自 v0.1.1)

  • 重构 Android 和 HarmonyOS 手机横屏牌桌,房间信息、连接状态和语音控制移至侧边。
  • 移除独立的“你的手牌”区域,本人手牌与所有摊牌直接显示在对应玩家框内。
  • 2–10 人座位沿牌桌周边重新排列,明确图层顺序:公共牌背景 < 玩家框 < 本轮下注筹码 < 赞赏/嘲讽气泡。
  • HarmonyOS 重做横屏数字输入面板,0–9、清空、退格和确定一次性完整显示。
  • Android 通过 WindowInsets.displayCutout、HarmonyOS 通过 Window.getWindowAvoidArea(AvoidAreaType.TYPE_CUTOUT) 获取真实挖孔安全区,不再使用固定像素猜测。

完整说明见 v0.1.1 发布说明。

文档

  • 新增项目现状、项目交接文档和开发历程。
  • 按实际源码重写 WebSocket 协议文档:协议为快照驱动模型,早期设计中的细粒度手牌事件从未实现,文档此前与实现存在分叉。
  • 规则文档校正合法动作与快捷金额的下发方式,并补充中途加入、弃牌离桌、换位和私下看牌的新规则。
  • 新增 Android 发布签名配置指南。
  • 生产更新手册与交接文档改用路径变量和占位符,移除原维护者的本机绝对路径。

版本号

本次统一了各端版本号,此前 v0.1.0 与 v0.1.1 的客户端均停留在 0.1.0+1。

位置 值
pubspec.yaml 0.2.0+2
Android versionName / versionCode 0.2.0 / 2(自动取自 pubspec)
Windows 文件与产品版本 0.2.0(自动取自 pubspec)
HarmonyOS versionName / versionCode 0.2.0 / 2000(需在 ohos/AppScope/app.json5 手动同步)

HarmonyOS 不读取 pubspec.yaml,版本需在 ohos/AppScope/app.json5 中手动同步。versionCode 按 major*1000000 + minor*1000 + patch 编码与 versionName 一一对应(0.2.0 对应 2000),后续版本据此递增。

该编码低于此前模板默认的 1000000,因此 HarmonyOS 设备上的旧版本需要卸载后重新安装,此后按新编码正常覆盖升级。

升级说明

  • 本次没有数据库结构变化,不需要执行数据库迁移。 按手册执行 migrate up 会正常空跑。
  • 服务端必须更新:中途加入、弃牌离桌和换位条件的修复都在服务端。
  • 四端客户端都需要重新构建:本次修复覆盖全部平台。
  • 升级顺序为先服务端、后客户端。新客户端在未坐满时会发起换位申请,旧服务端会拒绝;反之旧客户端配新服务端不受影响。
  • 协议没有新增消息类型,也没有删除或改变字段含义。唯一的快照变化是牌局中可能出现 participating 为 false 的待入座座位,新旧客户端均可解析。
  • Android 首次使用发布签名时,所有测试设备必须先卸载旧版本再安装,否则会因签名变化被系统拒绝。此后升级不再需要卸载。
  • HarmonyOS 需要卸载旧版本后重新安装,原因见上一节的 versionCode 说明。
  • HarmonyOS 建议重点验证开麦后能否持续听到其他人,以及登录页在平板上的键盘输入。

获取源码

git clone https://github.com/wm-develop/Texas.git
cd Texas
git checkout v0.2.0

首次部署前请完整阅读自建部署指南,不要把数据库密码、TRTC 密钥、生产域名配置或平台签名提交到仓库。

0.1.0

Choose a tag to compare

@wm-develop wm-develop released this 31 Aug 07:57

好友德州 v0.1.0

这是“好友德州”的首次源码发布,面向希望自行搭建服务、快速和朋友组织私人牌局的熟人玩家及开发者。项目不提供公共运营服务,也不面向互联网公开传播。

发布方式

本 Release 不会直接附带 Web、Windows、Android、HarmonyOS 安装包,仅发布 Git 标签对应的源码快照。

客户端需要写入自建游戏服务地址,语音需要部署者自己的腾讯云 TRTC 配置,Android 与 HarmonyOS 正式分发还涉及各自的平台签名,因此各平台产物应由部署者根据自己的环境构建、签名和测试。

从空服务器开始部署,请参阅自建部署指南。已有部署的版本升级流程请参阅生产环境更新手册。

首发功能

跨平台客户端

  • 基于 Flutter OH 的统一客户端代码。
  • 已完成 Web、Windows、Android 和 HarmonyOS 构建验证。
  • HarmonyOS 声明支持手机、平板和 PC/二合一设备。
  • 横屏牌桌、全屏移动端体验和多尺寸窗口自适应。

好友房与完整牌局

  • 房间码和可选房间密码,牌桌人数随朋友加入动态扩展,最多 10 人。
  • 房主标识与离桌后的自动房主转移。
  • 服务端权威的德州扑克流程、位置、盲注、主池、边池、摊牌和结算。
  • 自定义盲注、最大带入、玩家自主带入、手间补码和输光自动补码。
  • 1/4 池、1/3 池、1/2 池、2/3 池、满池、1.2 倍超池、全下及按小盲整数倍自定义下注。
  • 普通行动 30 秒;仅剩两名未弃牌玩家时为 60 秒;每人每手两张 30 秒加时卡。
  • 每手结束 10 秒自动准备,并可主动取消。
  • 空桌位换座与满桌双方确认换位。
  • 满足全下与无需后续行动条件时协商发一次或发两次,双方同意后运行两块公共牌并分别结算。
  • 弃牌状态、赢家特效、中文牌型、主动亮牌及经对方同意的私下看牌。

牌桌交流

  • 牌桌文字聊天、快捷语和表情,收起状态提供未读提醒。
  • 本地屏蔽与管理员持久化文字禁言。
  • TRTC 牌桌自由麦、成员与说话状态、播放音量和逐玩家语音屏蔽。
  • 点击玩家头像发送带全桌动画和音效的赞赏或嘲讽。
  • 下注、全下、过牌和弃牌独立音效。

账户、筹码和管理

  • 注册、登录、短期 Access Token 与轮换式 Refresh Token。
  • 无支付接口的娱乐虚拟筹码充值、钱包流水、牌局记录与结算历史。
  • 用户可修改登录用户名、牌桌昵称和密码。
  • 一次性首管理员初始化入口及服务端权限校验。
  • 管理员可管理账号、在线状态、筹码、所在房间、密码、注册开关和文字禁言,并可强制玩家离房。
  • 批量创建、停用、恢复和软删除账号,关键操作保留审计记录。

服务端与数据

  • Go 权威游戏服务,REST API 与 WebSocket 实时协议。
  • WebSocket 事件序列、请求幂等、断线补发和私人快照恢复。
  • PostgreSQL 持久化账户、会话、钱包、房间、牌局、聊天、结算账本和管理审计。
  • 版本化数据库迁移、迁移校验和与并发迁移锁。
  • Docker 多阶段构建及健康/就绪检查。
  • 已完成真实 PostgreSQL 集成测试,以及 10 个独立 WebSocket 客户端连续 100 手的筹码守恒验收。

当前限制

  • 项目定位为熟人封闭牌局,不包含真实货币、支付或提现功能。
  • 当前生产架构为单游戏服务实例;Redis 多实例协调、自动故障恢复和完整备份演练仍在后续计划中。
  • 语音功能依赖部署者自行申请和配置腾讯云 TRTC。
  • iOS 尚未作为 v0.1.0 的正式构建交付目标。
  • 各平台安装包需由部署者自行构建、签名并在目标设备上验证。

获取源码

git clone https://github.com/wm-develop/Texas.git
cd Texas
git checkout v0.1.0

首次部署前请完整阅读自建部署指南,不要把数据库密码、TRTC 密钥、生产域名配置或平台签名提交到仓库。