本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:WWW/plugins/feidao/说明.md。
飞刀大乱斗(feidao)插件说明
版本:1.0.0 | 作者:FlintHub | 状态:✅ 已启用
功能:常驻公共大地图的联机对战 —— 全员同场厮杀、一碰即死,死亡后原地复活续战;
入场费与击杀奖励走站点积分,支持每日奖励上限、头像商店与战力排行榜。
一、功能简介
玩法
- 常驻公共大地图:没有「建房 / 加入房间」这一步 —— 进来就在同一张地图上。
人多时自动分片(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 积分。
也可以直接切回论坛头像。
⚠️ 两套击杀口径,不要混淆(2026-09-29 改造):
- 积分只按服务端确认的真人击杀(
feidao_runs.kills)发放 —— 浏览器上报的快照不参与计算;- 排行榜统计用客户端上报值(
feidao_runs.reported_kills/reported_score,含本地电脑玩家),写入前按
5 + 存活秒数 × 1收敛击杀上限,分数上限 = 收敛后击杀数 × 160(客户端每杀 100 + 刀数×3,刀数 ≤ 20);结算时再校验一次,超限判「战绩校验失败」。
- 这样单人打电脑玩家也能上排行榜,但刷不到积分。
排行榜
- 前台排行榜按 最高战力 降序、其次总击杀,取前 10;
数据源 = feidao_stats,由客户端上报值驱动(含本地电脑玩家)→ 单人玩也有数据。
- 后台另有一份只读战力榜(前 10),方便核对积分发放是否正常。
- ⚠️ 后台看板的「累计击杀」=
SUM(feidao_runs.reported_kills),与排行榜同口径(不是发奖口径)。
入口
- 前台:侧边栏「应用」下拉里的「飞刀大乱斗」→
/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 | 单条生命的结算记录。kills / score = 服务端真人击杀(发奖口径);reported_kills / reported_score = 客户端上报(排行榜口径);另有已发奖励 / settled_at 幂等标记 |
feidao_stats | 用户累计战绩(总击杀 / 局数 / 最高战力 / 最高刀数) |
feidao_daily | 每日奖励额度(user_id + day_key) |
feidao_avatars | 头像拥有与选择 |
保留期:对局记录 7 天,单条生命结算窗口 3 小时,惰性清理节流 5 分钟。
⚠️ 改表结构必须走两步,漏一步就静默失效:
① 改
ddlStatements()里的CREATE TABLE(只管新装库);② 在
ensureColumnPatches()加ALTER TABLE … ADD COLUMN(管存量库)——
CREATE TABLE IF NOT EXISTS对已存在的表完全无效,只改 ① 会让老站点的新列静默不存在。改完必须上调
Plugin::SCHEMA_VERSION,否则hook/init_after.php的建表缓存命中、② 根本不执行。
六、目录结构
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 键,三语零差异)七、注意事项
- ⚠️ 必须登录:游客访问
/feidao会被重定向到登录页。 - ⚠️ 一碰即死是刻意设计,不是血条 bug。
max_hp = 100只是保留字段,实际不参与判定。 - ⚠️ 只有公共大地图:
room_create/room_join/room_status/room_start/room_leave
在 FrontController::ROOM_ONLY_ACTIONS 里被显式排除,房间玩法不在本插件范围内。
- ⚠️ 弹幕当前是死功能:
danmaku_on = false、danmaku_cost = 0,
且 api 的 danmaku 动作是空壳(return ['ok' => true])—— 前端点了没反应。
按「不留点了没反应的控件」的原则,应接上或删掉。
- ⚠️ 后台看板「战场」当前恒为 0:查询写的是
status IN ('waiting','playing'),
而实际状态取值是 waiting / running / finished —— 应为 ('waiting','running')。(已知缺陷,未修)
- ⚠️ 卸载不清核心设置:
uninstall()只删 6 张表,
核心 settings 里的 feidao_entry_fee / feidao_kill_reward / feidao_daily_cap /
feidao_bot_count / feidao_bot_names 会残留。(已知缺陷,未修)
- ⚠️⚠️ 改
assets/original/下任何 JS / CSS,必须同步上调Plugin::CLIENT_VERSION**:
资源响应头是 Cache-Control: public, max-age=31536000, immutable,
?v= 是唯一的破缓存手段 —— 不 bump 等于没上,且不报错、无日志。
- ⚠️ 改表结构 = 两步 + 一次版本号上调(详见上方「数据表」小节的说明):
① 新装库改 ddlStatements();② 存量库在 ensureColumnPatches() 加 ALTER TABLE … ADD COLUMN;
③ 上调 SCHEMA_VERSION(建表走内容门控,标记 protected/.feidao_table_cache)。
少任一步,老站点的新表 / 新列都静默建不出来。
- ⚠️
sim.wasm(约 199 KB)是遗留未使用的文件:module.js仍会调
net.loadSim('sim.wasm?v=…'),但 net.js 里的 loadSim() 是空实现(直接 resolve()),
原版的 WASM 模拟器已由 JS 重写替代 —— 该文件不会被下载,可择机清理。
- ⚠️ 观战期间仍占一个在线名额:死者继续
room_sync→last_seen保持新鲜,
因此在「在线人数」与分片容量口径里继续算一个人(改前是冻结 15 秒后自动让位)。
- ⚠️ 在线口径:15 秒内没有同步的玩家视为离线(
ROOM_PLAYER_STALE_SECONDS = 15)。 - 已知遗留:电脑玩家只在本地模拟,因此「死者观战」与「纯观战」两条路看到的场面不同
(前者能看到自己那份本地电脑玩家,后者看不到)。
八、当前状态
- 插件已启用(
plugin.json→activated: true)。 - 数据:
feidao_rooms1 行(PUBLIC/running)、feidao_room_players1 行、
feidao_runs 6 行、feidao_stats / feidao_daily / feidao_avatars 各 1 行。
- 客户端版本:
CLIENT_VERSION = 1.48.3-flinthub(2026-09-29 观战修复时上调)。