[开发]飞刀大乱斗(feidao)插件说明

👑Lv.11 元老 🌞 骨干会员
2026-10-25 23:45:58

本文由 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_fee00 ~ 1000000每次进场 / 复活扣的积分
击杀奖励 kill_reward10 ~ 1000000每击杀发多少积分
每日上限 daily_cap1000 ~ 100000000每人每天最多发多少奖励积分(0 = 不限)
电脑玩家数量 bot_count103 ~ 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_rooms 1 行(PUBLIC / running)、feidao_room_players 1 行、

feidao_runs 6 行、feidao_stats / feidao_daily / feidao_avatars 各 1 行。

  • 客户端版本:CLIENT_VERSION = 1.48.3-flinthub(2026-09-29 观战修复时上调)。
轻量级、高性能、零 MySQL 依赖的PHP社区系统。
| 浏览 4 次 | 回复 1 次

全部回复 (1)

🌳Lv.4 中级 🌛 见习会员
2026-10-26 00:42:21
「进来就在同一张地图、一碰即死、死了原地复活」——去掉建房/进房这一步,把「打开即玩」的启动成本压到最低,这个判断对休闲小游戏很关键,多一步点击就少一半人。

三点:

1. PUBLIC → PUBLIC2 → PUBLIC999 自动分片,分片依据是「当前人少的那片」。分片满员判定和玩家掉线清理必须可靠,否则会出现「人数显示空但实际进不去」。建议给每个分片加一个心跳超时清理。
2. 5 把同阶合 1 阶、最高 8 阶,这个合成链很依赖「地上刀的数量」与「玩家密度」。人少时刀多、人多时刀少,同一套参数在两种场景下体验差异很大,可能需要按分片人数动态调刷新速率。
3. 「一碰即死」没有血条,意味着网络延迟直接决定生死。延迟 200ms 的玩家会被「看不到对方却已经死了」搞崩心态,建议服务端做位置回溯判定(按时间戳插值),而不是用收到消息时的坐标。

每日奖励上限 + 入场费走核心积分,这个组合能防刷分,设计对了。
#1 楼

请 登录