
一、功能简介
玩法
- 常驻公共大地图:没有「建房 / 加入房间」这一步 —— 进来就在同一张地图上。 人多时自动分片(
PUBLIC→PUBLIC2…PUBLIC999),玩家被分到当前人少的那片。 - 一碰即死:
instant = true,被别人的刀碰到立即出局,没有血条拉锯。 - 捡刀 + 合成升阶:地上散落飞刀,5 把同阶合 1 阶,最高 8 阶(铁刃 → 精钢 → 寒锋 → 幽紫 → 青铜 → 魅影 → 血纹 → 玄铁)。 阶数越高,刀越长、伤害越高。
- 宝箱:打碎宝箱掉刀。
- 增益道具:疾旋(转速 ×1.5 / 12 秒)、疾行(移速 ×1.45 / 5 秒)、长臂(攻击距离 ×1.35 / 12 秒)、防护罩(6 秒)。
- 战力分档决定移速:战力越高基础移速越慢(120% → 91% → 76% → 66%), 避免高战力玩家滚雪球。
- 电脑玩家:默认 10 个(可配 3 ~ 24),名字可自定义。 ⚠️ 它们是各客户端本地模拟的,不进服务器快照 —— 所以别人看不到你屏幕上的电脑玩家。
- 复活续战:死亡后点「再来一局」原地复活,再交一次入场费;公共大地图不因某人死亡而结束。
观战
两条路,都可用:
| 路径 | 数据源 | 说明 |
|---|---|---|
| 入口页「只看不打」 | 服务端 watch_sync |
纯观战者,不参与战斗、不扣费、不记战绩 |
| 死亡卡片上点「观战」 | 本地继续 room_sync |
死了之后看别人打,随时可退出回死亡卡片 |
观战条提供:上一位 / 下一位、点名字直接挑人、退出。 (2026-09-29 修复:死亡后点观战不再导致画面卡死。)
积分与经济
- 入场费
entry_fee(默认 0):每次进场 / 每次复活各扣一次。 - 击杀奖励
kill_reward(默认 1 积分 / 杀):结算时一次性发放,不是实时到账。 - 每日奖励上限
daily_cap(默认 100):当天累计发满即停发,第二天自动重置。 - 余额不足时免费玩,但不发奖励(
free_when_broke = true)—— 不会把人挡在门外。 - 头像商店:游戏内头像共 20 个(槽 0 ~ 19),前 3 个默认拥有,其余每个 300 积分。 也可以直接切回论坛头像。
⚠️ 奖励只按服务端记录的击杀数发放,浏览器上报的快照不参与计算; 并有合理性校验(
5 + 存活秒数 × 1的击杀上限、分数上限、刀数上限),防刷分。
排行榜
- 前台排行榜按 最高战力 降序、其次总击杀,取前 10;
- 后台另有一份只读战力榜(前 10),方便核对积分发放是否正常。
入口
- 前台:侧边栏「应用」下拉里的「飞刀大乱斗」→
/feidao(需登录) - 后台:
/admin/feidao
二、一局的完整流程
① 进页面 /feidao
└─ 顶栏显示「在线人数」「我的积分」
② 点开始 → POST /feidao/api?action=join
├─ 复用判定:本人在这张地图上还活着且未结算 → 直接续用,不重复扣费
├─ 否则:扣入场费 → 选分片 → 写 feidao_room_players(status = playing)
└─ 返回战场快照(roomPayload)
③ 战斗循环:客户端每拍 POST action=room_sync
├─ 上报自己的位置/角度/刀阶 + 攒下的命中事件
└─ 取回全量快照(含别人的状态与击杀播报)
④ 死亡 → POST action=room_finish(结算这条命)
├─ 按服务端记录的击杀数发奖励(受每日上限约束)
├─ 更新 feidao_stats / feidao_daily
└─ 弹死亡卡片:击杀数 / 最高战力 / 存活时长 / 本次奖励
⑤ 死亡卡片上二选一
├─「再来一局」→ action=restart(再扣一次入场费,原地复活)
└─「观战」→ 本地继续同步,看别人打;退出即回死亡卡片
每条「生命」对应一行
feidao_runs,结算幂等(settled_at置位后重复请求原样返回)。
三、路由与接口
前台
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /feidao |
游戏页(需登录) |
| POST | /feidao/api |
全部业务动作(需登录 + CSRF) |
| GET | /feidao/asset |
原版客户端静态资源直通 |
/feidao/asset 是必要的中间层:WASM / WebP / MP3 需要正确的 Content-Type, 交给 Web 服务器按扩展名猜会在 IIS 上出错。内部走 realpath() + 前缀比对,防目录穿越。
后台
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /admin/feidao |
设置页 + 战场看板 + 战力榜 |
| POST | /admin/feidao/save |
保存设置(CSRF + 白名单区间校验) |
| POST | /admin/feidao/reset-names |
恢复默认电脑玩家名字 |
API 动作(POST /feidao/api,参数 action=)
| 分类 | 动作 |
|---|---|
| 只读(免登录也可) | init、rank |
| 对战 | join、room_sync、room_finish、restart、settle、game |
| 观战 | watch、watch_sync |
| 头像 | pick_avatar、buy_avatar、use_forum_avatar |
| 弹幕 | danmaku ⚠️ 当前是空壳,见注意事项 |
四、后台可配项
| 设置项 | 默认 | 范围 | 说明 |
|---|---|---|---|
入场费 entry_fee |
0 |
0 ~ 1000000 | 每次进场 / 复活扣的积分 |
击杀奖励 kill_reward |
1 |
0 ~ 1000000 | 每击杀发多少积分 |
每日上限 daily_cap |
100 |
0 ~ 100000000 | 每人每天最多发多少奖励积分(0 = 不限) |
电脑玩家数量 bot_count |
10 |
3 ~ 24 | |
电脑玩家名字 bot_names |
内置 12 个 | 每行一个,最多 48 个 | 留空 = 用内置默认名 |
改了规则后战场
rules_rev会变化,已开局的客户端会收到「请刷新」提示并重开 —— 这是有意行为。
后台看板:战场数 / 在线人数 / 累计玩家 / 累计击杀 / 今日已发奖励。
五、数据表
插件独立库:plugins/feidao/data/feidao.sqlite
| 表 | 用途 |
|---|---|
feidao_rooms |
战场(公共地图 PUBLIC 及其分片) |
feidao_room_players |
场内玩家(player_token / run_token / status / state_json / last_seen) |
feidao_runs |
单条生命的结算记录(击杀 / 战力 / 已发奖励 / settled_at 幂等标记) |
feidao_stats |
用户累计战绩(总击杀 / 局数 / 最高战力 / 最高刀数) |
feidao_daily |
每日奖励额度(user_id + day_key) |
feidao_avatars |
头像拥有与选择 |
保留期:对局记录 7 天,单条生命结算窗口 3 小时,惰性清理节流 5 分钟。
六、目录结构
plugins/feidao/
├── plugin.json # 清单(4 个钩子;admin_url = /admin/feidao)
├── Plugin.php # 主类:配置、建表、对战规则、结算、排行、头像、生命周期
├── FrontController.php # 前台:页面壳 / API 分发 / 静态资源直通
├── AdminController.php # 后台:设置保存 / 看板统计 / 恢复默认名
├── FeidaoException.php # 面向玩家的业务异常
├── hook/
│ ├── init_after.php # 幂等建表(内容门控,标记 protected/.feidao_table_cache)
│ ├── route_register.php # 前台路由(/feidao、/feidao/api、/feidao/asset)
│ ├── admin_route_register.php # 后台路由(/admin group 内,路径不写 /admin 前缀)
│ └── nav_plugin_links.php # 侧边栏「应用」下拉入口
├── views/
│ ├── index.php # 游戏页外壳(data-* 契约 + 顶栏)
│ └── admin.php # 后台设置页
├── assets/
│ ├── script.js # 站点适配层(由原版 adapter.js 改写)
│ ├── style.css # 外壳与顶栏样式
│ ├── vendor/remixicon/ # 图标字体
│ └── original/ # 原版客户端(移植,尽量不改)
│ ├── view.html # 首页 / 商店 / 排行 / 死亡卡片(全部由它渲染)
│ ├── module.js # 主入口:装配各部件、主循环、掉线守望
│ ├── adapter.js # 原版适配器(本站实际用的是 assets/script.js)
│ ├── module.css # 客户端样式
│ ├── sim.wasm # ⚠️ 遗留未使用,见注意事项
│ ├── module/ # 13 个部件
│ │ ├── art.js # 美术与常量(刀表 / 尺寸 / 配色)
│ │ ├── net.js # 帧、输入、预测、同步(**核心逻辑**)
│ │ ├── render.js # 画面渲染与镜头
│ │ ├── board.js # 榜单与小地图
│ │ ├── hud.js # 血量 / 刀阶 / 道具条
│ │ ├── buffs.js # 增益道具
│ │ ├── input.js # 键鼠 / 摇杆
│ │ ├── overlay.js # 倒计时 / 掉线幕布 / 加入播报
│ │ ├── spectate.js # 观战条
│ │ ├── sheet.js # 商店面板
│ │ ├── danmaku.js # 弹幕(当前未接)
│ │ ├── store.js # 本地状态门面
│ │ └── audio.js # 音效
│ ├── img/ # chest / faces / buffs(webp)
│ └── audio/ # clash / countdown / death(mp3)
├── data/ # feidao.sqlite + .htaccess / web.config
└── lang/ # zh.php / en.php / zh_tw.php(各 46 键,三语零差异)