BHBoard 项目流程图 纯静态站点 · Cloudflare Pages 托管 · Upstash Redis 存储 · 无后端服务

起点/终点 处理步骤 判断分支 双人同步 数据读写

全站架构

主页是唯一的登录入口,登录后各模块直接读取本地登录态,不再重复验证。

用户访问 bhboard.pages.dev
主页:输入名字 + 密钥keycheck.js 统一校验(详见下节)
写入本地登录态localStorage: bh_user = { username }
主页菜单(5 个入口)
💬 兄弟论坛/bhb/
🔫 兄弟轮盘赌/play/
🎮 兄弟广场/square/
🎓 南外生存·单人/nfls/ → 页内可进联机版 /nfls2/
📸 兄弟照片/photos/
🛠️ 兄弟管理/manage/
🛠️ 兄弟管理 /manage/人人可看名单与对局;输入管理密码解锁操作
共享数据层:Upstash Redis所有页面直连同一个数据库,键名见最后一节

登录门禁(keycheck.js)

全站唯一的身份校验逻辑。子页面启动时先检查本地登录态,没有就直接跳回主页。

页面加载
本机 localStorage 有 bh_user 吗?
有 → 已登录
直接放行不再要求密钥
无 → 子页面
强制跳转主页location.replace('/')
无 → 主页
要求输入名字 + 密钥
密钥是通用密钥吗?通用密钥值不对外展示,向管理员索取
放行(可登任何账号)
否 → 查 bh_keys
读取密钥登记表
该密钥的状态?
未使用
绑定到该名字写入 bh_keys
放行
已绑定 = 自己
放行
已绑定 = 别人
拒绝"这个密钥已经是别的兄弟的了"
不存在
拒绝"密钥无效,请找管理员要一个"

南外生存指南(单人)

10 天校园生存模拟,撑到 9 月 10 日教师节即胜利,快乐归零即崩溃。

标题界面附完整规则书(概率与数值全部列出)
选择角色(8 选 1)陈仰正 / 王浩宇 / 侯景瑞 / 徐悠然 / 贾子辰 / 朱凌初 / 常喆 / 范书元
该角色可以自选同桌吗?
可以(陈仰正 / 徐悠然 / 王浩宇)
手动选同桌只显示同桌效果,不显示对方属性
不可以
随机分配同桌
同桌确认界面"你的同桌是 XXX,效果是 XXX"
换一个
重选 / 重随机
就这样开始
应用同桌加成,开局
进入 10 天日程循环9月1日 ~ 9月10日(含 9/5、9/6 两个周末)
今天是周末吗?
上学日
21 个步骤早晨 → 早自习 → 9×(上课 + 课间/午餐/大课间) → 晚上
周末
3 个步骤周末早晨 → 周末时光 → 晚上
每一步后检查:快乐 ≤ 0 ?
你崩溃了游戏结束,出结算
否,且已过第 10 天
撑到教师节了!胜利,出结算
否,继续
推进到下一步 / 下一天

结算面板内容

  • 存活天数、最终快乐值、颜值 / 体力 / 智力
  • 答对提问次数、蹴瓶子进球次数、崩溃次数、与同桌互动次数
  • 称号判定 + 隐藏成就(选择王浩宇或被王浩宇选为同桌 → "死气沉沉")

南外生存·联机(重点)

双人合作生存。A、B 各选一个角色互为同桌,每一步都要双方提交才结算,快的等慢的。

大厅建房 / 输入房间号加入
A:创建房间
生成 4 位房间号写入 bh_room:XXXX,A 坐 0 号位(房主)
B:输入房间号加入
校验房间状态waiting 才能加入,B 坐 1 号位
双方各自选角色(互斥)对方已选的角色变灰不可选 → 自动互为同桌
同桌效果互相作用如 A 选陈仰正 + B 选徐悠然 → 双方各触发"故意的"加成
开学:进入 10 天日程(同单人版结构)
🔁 每一步的同步循环(核心机制) A、B 各自提交选择 → 写入房间 → 双方都提交后才结算
A 已提交,B 未提交
A 的按钮锁定显示"已提交,等待 B 选择…"
双方都已提交
房主(0 号位)统一结算避免并发写入冲突
结算结果写回房间双方各自轮询读取(间隔 0.9 秒),看到同一份结果
自动步骤(上课/早晨)也要双方点"继续"确认保证两人节奏一致,不会有人被甩在后面
结算后判定:有人快乐 ≤ 0 ?
推进下一步回到上面的同步循环
两人都倒下
游戏结束"你们两个一起倒下了"
一人倒下
进入救活阶段详见下方

💗 救活同桌机制

  • 一方快乐归零 → 标记为"倒下",同桌收到救活选择
  • 选择救活:救人方的颜值 / 体力 / 智力 全部变成 5;被救方快乐恢复到上限的 50%,重新站起来
  • 选择不救:直接游戏结束
  • 每人只能被救一次:被救过的人标记 revivedOnce,第二次倒下 → 直接 game over,无法再救
  • 救活阶段同样需要双方提交确认才结算,文案按实际座位分配(倒下的是房主也不会错位)

房间生命周期

  • 每人每天最多创建 10 个房间(独立额度,不与轮盘赌共用)
  • 房间存储 TTL 1 天,等待中超过 1 小时无人加入 → 自动清除
  • 任何房间闲置超过 30 分钟 → 自动清除(懒清理:有人读取时顺带检查)
  • 意外关闭页面 → 重新打开会自动恢复到原进度(本地存了房间号与座位)

兄弟轮盘赌

双人在线回合制,三局两胜。也支持人机模式。

大厅建房 / 输房间号加入 / 从对局列表加入 / 人机模式
房间人满了吗?
未满
加入对战
已满 / 已结束
进入观战模式只能看,所有操作按钮禁用
装弹:5 发,其中 1~4 发实弹随机排列双方各 4 点生命,各发 2 个道具
轮到你:先用道具,再开枪一回合可用多个道具
🔍 放大镜
偷看当前弹结果只显示在自己屏幕
🚬 香烟
回复 1 点生命满血时拒绝使用
🔗 手铐
对手跳过下回合
🍺 啤酒
退掉当前弹显示退掉的是实弹还是空包
🔪 手锯
本回合伤害 +1开枪后失效
开枪:打谁?
打对方
轮到对方行动
打自己 · 空包
自己继续行动白赚一枪
打自己 · 实弹
自己扣血,轮到对方
子弹打光?是 → 自动换弹 + 各发 2 道具
有人生命归零?
是,且未达 2 胜
本局结束,开下一局
是,且已 2 胜
比赛结束,出胜负可"再来一场"

其他模块

💬 兄弟论坛 /bhb/

  • 聊天式滚动:留言区固定高度(约 5 条),标题和输入框不滚动
  • 消息时间正序,越往下越新,最新的贴着输入框,发完自动滚到底
  • 发言存入 bh_messages,双存储备份防丢

🎮 兄弟广场 /square/

  • 名字池 9 人随机进出:RRRory、我是WHY、chenyz、丙寅、CZ、李知行07、Felixxx、徐悠然、朱凌初
  • 访客在广场待 30~60 秒后离开,离开后 6~10 秒有新访客进来,场上最多 5 个访客
  • 操作:走动(方向键/WASD)、说话(头顶气泡)、出拳(空格/J)、求婚(K)
  • 求婚命中 → 50% 概率同意 → 立刻在两人中间生一个小孩,名字为"XXX与XXX的小孩"
  • 小孩出生 10 秒后长大成人,可打架、可被求婚、会说话;永不退出广场

📸 兄弟照片 /photos/

  • 上传流程:选图 → 校验(必须是图片、≤1MB)→ 前端压缩到 500KB 以内(最长边 900px)→ 存库
  • 每人每天最多 10 张;照片墙总量上限 40 张,超出自动删最旧的
  • 缩略图(200px)单独存储 → 照片墙秒开,点大图才加载原图
  • 管理员解锁后可删除任意照片

🛠️ 兄弟管理 /manage/

  • 人人可看:成员列表(绿点在线 / 灰点离线)、全部对局列表(状态、比分、观战入口),每 3 秒刷新
  • 输入管理密码解锁后多出:注销账号、清空论坛留言、删除对局、生成 / 删除注册密钥
  • 在线判定:各页面每 30 秒上报心跳,90 秒内无心跳视为离线;谁来过都登记进持久成员表

数据层(Upstash Redis 键名)

全站直连同一个数据库,无后端服务。所有页面共用下面这些键。

键名用途说明
bh_messages论坛留言全部留言数组,双存储备份防丢
bh_pending待处理消息论坛发言的备份队列
bh_keys密钥登记表密钥 → { owner, usedAt },记录绑定给谁、何时首次使用
bh_members持久成员表谁来过就登记,管理页列名单用(离线也保留)
bh_member:名字在线心跳值为时间戳,TTL 90 秒,过期即视为离线
bh_room:房号轮盘赌房间TTL 7 天,闲置 30 分钟懒清理
bh_nfls2:房号联机生存房间TTL 1 天,闲置 30 分钟懒清理(与轮盘赌分开)
bh_registry对局总列表开局页与管理页共用的房间索引
bh_room_creates轮盘赌建房计数按"名字 + 日期"记录,每人每天限建 10 个
bh_nfls2_creates联机生存建房计数独立的每日 10 个额度,不与轮盘赌共用
bh_photos照片索引含缩略图,照片墙直接读这一个键
bh_photo:ID单张照片完整数据,点大图时才加载
bh_music音乐索引数组,含外链曲目与上传曲目的元数据(名称 / 上传者 / 日期 / 类型)
bh_music:ID单首上传音频压缩后的 base64 数据,播放时才加载;受单条约 1.2MB 限制,只能存短片段

技术要点

  • 纯静态部署:Cloudflare Pages,无服务端函数(api/ 与 vercel.json 是早期 Vercel 遗留,实际未使用)
  • 写入格式:必须用路径式 /set/键/值/ex/秒数,JSON 请求体会被原样存成字符串(曾导致房间状态读取失败的 bug)
  • 单条容量上限:实测 800KB 可写、1.2MB 报错,因此照片压缩目标定 500KB
  • 原子计数:数据库支持 INCRBY,用于并发安全的计数场景
  • 联机同步:无 WebSocket,靠双方各自轮询(0.9 秒)+ 房主单点结算避免写冲突
  • 离线版:南外生存另有一份单机副本,移除了 keycheck、心跳、登录跳转,双击即可玩