调整dps插件对仇恨的估算方式

优化dps插件
This commit is contained in:
rucky
2026-03-25 00:57:35 +08:00
parent 5c3f2243c4
commit 12c8c55159
16 changed files with 2454 additions and 165 deletions

View File

@@ -0,0 +1,221 @@
# Nanami-Plates 仇恨系统对接需求文档
## 概述
Nanami-DPS 已完成仇恨监控系统的全面重做采用自适应双轨混合架构TWThreat API 服务端直读 + 本地战斗日志推演)。本文档定义 Nanami-Plates 姓名板插件需要对接的数据接口、渲染要求和交互规范。
---
## 一、数据接口
### 1.1 全局引用
```lua
local TE = NanamiDPS.ThreatEngine -- 仇恨引擎实例
local TC = NanamiDPS.ThreatCoefficients -- 系数常量
```
### 1.2 核心 API 函数
| 函数签名 | 返回值 | 说明 |
|----------|--------|------|
| `TE:GetActiveTargetKey()` | `string``nil` | 获取当前激活目标的唯一键优先API目标键回退到本地目标 |
| `TE:GetCurrentTargetKey()` | `string``nil` | 获取玩家当前 target 的唯一键 |
| `TE.GetTargetKey(unitID)` | `string``nil` | 根据 unitID 计算目标唯一键(格式: `G:GUID` / `I:RaidIcon` / `V:Name:MaxHP` |
| `TE:GetThreatList(targetKey)` | `table` | 返回按仇恨降序排列的列表,每项包含 `{name, threat, tps, perc, isTanking, isMelee, relativePercent}` |
| `TE:GetOTStatus(targetKey)` | `table` | 返回当前玩家的 OT 分析: `{safe, pct, threshold, otPoint, buffer, myThreat, tankThreat, tankName, isMelee}` |
| `TE:IsAPIActiveForTarget(targetKey)` | `boolean` | 判断该目标是否使用服务端 API 数据(精确模式) |
| `TE.IsEliteOrBoss(unitID)` | `boolean` | 判断目标是否为精英/Boss |
| `TE.IsInGroup()` | `boolean` | 判断玩家是否在小队/团队中 |
### 1.3 状态字段(只读)
| 字段 | 类型 | 说明 |
|------|------|------|
| `TE.inCombat` | `boolean` | 当前是否在战斗中 |
| `TE.apiActive` | `boolean` | API 直读引擎是否激活 |
| `TE.playerName` | `string` | 当前玩家名称 |
| `TE.playerClass` | `string` | 当前玩家职业 token大写 |
| `TE.targets` | `table` | 三维数据表,结构见下文 |
### 1.4 三维数据结构
```
TE.targets[targetKey] = {
players = {
[playerName] = {
threat = number, -- 绝对仇恨值
tps = number, -- 每秒仇恨制造率
isTanking = boolean, -- 是否持有仇恨
isMelee = boolean, -- 是否在近战范围
perc = number, -- 相对百分比 (0-100)
history = table, -- TPS 计算用历史数据
lastThreatTime = number, -- 最后一次仇恨更新时间
},
...
},
tankName = string, -- 当前坦克名称
tankThreat = number, -- 坦克仇恨值
lastUpdate = number, -- 最后更新时间戳
source = string, -- "api" | "api_tm" | "local"
}
```
### 1.5 回调注册
```lua
-- 仇恨数据更新时触发API 报文到达或本地计算完成)
NanamiDPS:RegisterCallback("threat_update", "NanamiPlates", function()
-- 在此刷新姓名板仇恨显示
end)
```
### 1.6 OT 阈值常量
```lua
TC.OT_MELEE_THRESHOLD = 1.10 -- 近战 110%
TC.OT_RANGED_THRESHOLD = 1.30 -- 远程 130%
```
---
## 二、姓名板渲染要求
### 2.1 仇恨百分比指示器
**位置**: 锚定在每个敌方姓名板的名称文字正上方或正下方
**格式**: `XX%` 数字文本,字号 10-12
**更新频率**: 跟随 `threat_update` 回调,约 0.5 秒一次
### 2.2 颜色渐变规则
根据玩家在当前目标上的仇恨百分比(相对于 OT 阈值)分级着色:
| 百分比区间 | 颜色 | 含义 |
|-----------|------|------|
| 0% - 49% | 绿色 `(0.2, 1.0, 0.2)` | 安全 |
| 50% - 79% | 黄色 `(1.0, 1.0, 0.0)` | 警戒 |
| 80% - 100%+ | 红色 `(1.0, 0.2, 0.0)` | 危险,即将 OT |
### 2.3 仇恨条背景色
为已持有仇恨(`isTanking = true`)的目标姓名板生命条添加边框高亮:
- 坦克视角: 正在坦克的怪物边框为**绿色**
- DPS/治疗视角: 自己正在被攻击的怪物边框为**红色**
### 2.4 数据来源标识(可选)
在仇恨百分比旁边显示小图标区分数据来源:
- API 数据: 小圆点 (绿色) — 表示服务端精确数据
- 本地推算: 小圆点 (灰色) — 表示基于战斗日志估算
---
## 三、Tank Mode 姓名板增强
当玩家为坦克角色(防御姿态/巨熊形态)时:
### 3.1 多目标仇恨概览
在每个姓名板上显示**仇恨排名第二**的玩家名称和百分比,格式:
```
[怪物名称]
██████████████ 100% ← 仇恨条(自己)
紧随: Mage_A 85% ← 第二名信息
```
### 3.2 松动目标高亮
如果某个怪物上的第二名仇恨超过坦克仇恨的 80%(接近 110% OT 线),该姓名板整体加红色闪烁边框,提示坦克需要立即补仇恨技能。
### 3.3 快速目标切换SuperWoW 依赖)
如果检测到 SuperWoW/SuperAPI 可用:
- 姓名板上的仇恨区域可点击
- 点击后调用 `TargetUnit``SetTarget` 切换到该怪物
- 方便坦克无需 TAB 键即可快速切换目标
---
## 四、Healer Mode 姓名板增强
当玩家为治疗角色时:
### 4.1 主坦锁定
允许设置一个"主坦克焦点"(通过 `/nanami mt [name]` 或右键团队框架)
### 4.2 未稳固目标标记
在姓名板上对**主坦克仇恨不是最高**的怪物添加特殊标记(橙色感叹号),提示治疗者该怪物仇恨不稳定,可能随时转向治疗者。
---
## 五、性能要求
| 项目 | 要求 |
|------|------|
| 姓名板遍历频率 | 最大 0.5 秒一次(跟随 `threat_update` 回调) |
| 内存开销 | 单个姓名板附加元素不超过 3 个 FontString + 1 个 Texture |
| 不可见姓名板 | 必须隐藏对应的仇恨指示器,避免孤立 UI 元素 |
| 战斗外 | 所有仇恨指示器隐藏,不做任何查询 |
| 数据清理 | 离开战斗后清除所有姓名板附加元素 |
---
## 六、对接代码示例
```lua
-- Nanami-Plates 中的对接示例
local TE = NanamiDPS and NanamiDPS.ThreatEngine
local TC = NanamiDPS and NanamiDPS.ThreatCoefficients
-- 获取某个 nameplate 对应怪物的玩家仇恨百分比
local function GetMyThreatPct(unitID)
if not TE or not TE.inCombat then return nil end
local targetKey = TE.GetTargetKey(unitID)
if not targetKey then return nil end
local td = TE.targets[targetKey]
if not td then return nil end
local pd = td.players[TE.playerName]
if not pd then return nil end
return pd.perc, pd.isTanking, pd.isMelee
end
-- 获取该怪物仇恨第二名
local function GetSecondThreat(unitID)
if not TE or not TE.inCombat then return nil end
local targetKey = TE.GetTargetKey(unitID)
if not targetKey then return nil end
local list = TE:GetThreatList(targetKey)
if list and list[2] then
return list[2].name, list[2].perc, list[2].threat
end
return nil
end
-- 注册回调
if NanamiDPS then
NanamiDPS:RegisterCallback("threat_update", "NanamiPlates_Threat", function()
-- 遍历所有可见姓名板,刷新仇恨数据
NanamiPlates:RefreshAllThreatIndicators()
end)
end
```
---
## 七、版本兼容性
- **必须依赖**: Nanami-DPS >= 1.0.0(含 ThreatEngine 模块)
- **可选依赖**: SuperWoW / SuperAPI用于姓名板高级交互
- **WoW 客户端**: 1.12.x (Turtle WoW)
- **Lua 环境**: 不支持现代 Lua 特性(使用 `table.getn` 代替 `#``pairs` 代替 `next`