Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions !src-dist/ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@


# 引入自定义的打包发布模块和环境设置模块
import subprocess

from plib.publish import run


def main() -> None:
subprocess.run(["lua", "tests/team_mon_compute.lua"], check=True)
run("ci")


Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

## 未发布

* [团队监控] 支持数据定义的团队 Buff 统计与计算变量,并随状态变化更新倒计时文案
* [基础库] 修复 29.0.12 中团队面板气血刷新报错的问题

## 茗伊插件集 v29.0.12
Expand Down
129 changes: 129 additions & 0 deletions MY_TeamMon/docs/computed-countdowns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# 倒计时计算变量(提案 v1)

在现有 `tCountdown` 条目中增加可选 `tVars`,按团队 Buff 统计结果执行数据作者提供的公式,再使用原有 `{$变量名}` 模板显示结果。没有 `tVars` 的条目沿用原有行为。

插件只提供通用计算与刷新能力。Buff ID、层数条件、公式、文案、触发事件、倒计时时长及取消条件由数据作者定义。

## 示例

下面是现有数据条目中的 `tCountdown` 字段示意。1001、1002、1003 是测试 ID;差值公式仅演示语法,不能用作实战配平公式。外层地图和监控事件数据仍按现有格式填写。

```lua
tCountdown = {
{
nClass = 8, -- SKILL_BEGIN;由作者选择实际触发类型
key = 'example-computed-countdown',
nTime = 20,
nRefresh = 0,
szName = '红2×{$calc_red2};黑×{$calc_black};差值 {$calc_difference}',
tVars = {
nVersion = 1,
szUnavailable = '团队状态未完整读取',
bUpdate = true,
nDebounce = 100,
aQueries = {
{
szName = 'calc_red2',
dwBuffID = 1001,
nLevel = 0,
nStackNum = 2,
szStackOp = '==',
bAliveOnly = true,
dwExcludeBuffID = 1003,
szAggregate = 'count',
},
{
szName = 'calc_black',
dwBuffID = 1002,
bAliveOnly = true,
},
},
aValues = {
{
szName = 'calc_difference',
tExpression = { 'sub', 'calc_black', 'calc_red2' },
},
},
},
},
}
```

实际的“接圈人数”“找背人数”可放在 `aValues`,再由 `szName` 引用。原有 `{$sender}`、`{$receiver}`、`{$1}` 等变量继续可用;计算结果仅加入本次渲染上下文,不写入原始事件或 Buff 对象。

## 字段

| 位置 / 字段 | 含义 |
|---|---|
| `tVars.nVersion` | 必须为 `1` |
| `tVars.szUnavailable` | 必填非空备用文案;状态不可读或计算失败时显示 |
| `tVars.bUpdate` | 默认不持续刷新;仅 `true` 时监听后续变化 |
| `tVars.nDebounce` | 首次相关事件后的合并等待毫秒数,默认 100,范围 50–1000;后续事件不继续延长等待 |
| `tVars.aQueries` | 查询数组,最多 32 条,可省略 |
| `tVars.aValues` | 公式数组,按顺序执行,最多 32 条,可省略 |
| `szName` | 查询或公式的变量名,必须以 `calc_` 开头,后接英文字母、数字或下划线,最长 64 字节,不得重复 |
| 查询 `dwBuffID` | 必填正整数 Buff ID |
| 查询 `nLevel` | 非负整数,默认 0,沿用 `X.GetBuff` 的任意等级匹配;不汇总同 ID 的多个实例 |
| 查询 `nStackNum` / `szStackOp` | 默认 `1` / `>=`;比较符支持 `== ~= < <= > >=` |
| 查询 `bAliveOnly` | 默认包含死亡成员;设为 `true` 时仅统计存活成员 |
| 查询 `dwExcludeBuffID` | 可选;拥有此 Buff 的成员排除,等级任意 |
| 查询 `aExcludeBuffIDs` | 可选 ID 数组,最多 8 项;拥有其中任何一个 Buff 即排除。与 `dwExcludeBuffID` 二选一 |
| 查询 `szAggregate` | `count` 为满足条件的人数(默认);`sum` 为满足条件成员的 Buff 层数之和 |
| 公式 `tExpression` | 数字、已有计算变量名,或下述表达式表 |

离线成员跳过;在线且需要参与查询的成员对象不可读、必要状态缺失时,整组计算使用备用文案。已成功读取的对象没有指定 Buff,才按 0 层处理。查询遵守现有团队监控、地图和可见 Buff 限制,不扩展游戏允许的读取范围。

## 表达式

| 类型 | 写法 |
|---|---|
| 数值 / 引用 | `3`、`'calc_red2'` |
| 二元运算 | `{ 'add', a, b }`、`sub`、`mul`、`div`、`min`、`max` |
| 一元运算 | `{ 'floor', a }`、`ceil`、`abs` |
| 比较 | `{ 'lt', a, b }`、`le`、`eq`、`ge`、`gt`,返回布尔值 |
| 条件 | `{ 'if', 布尔表达式, 真分支, 假分支 }`,只执行选中的分支 |

`aValues` 只能引用查询结果或前面已经定义的公式变量,不能前向引用。最终变量必须是有限数字;布尔值仅用于条件。除零、无效类型或运算、非有限结果进入备用文案路径,并写入调试日志。表达式深度最多 16,单次计算最多访问 256 个表达式节点。不执行表达式字符串或配置中的 Lua 函数。

## 更新和生命周期

首次创建立即计算。开启 `bUpdate` 后,相关团队 Buff 的增加、移除、层数变化,以及成员增减、在线、生死、进出场景事件会标记待刷新;计时窗口在合并等待到期后重新读取状态。只监听查询中出现的 Buff ID 和排除 Buff ID,普通无关 Buff 不触发查询。

刷新调用原有计时条的 `SetInfo({ szContent = ... })`,仅在文案改变时写入,不改变开始时间、剩余时间、进度或重播语音。分段倒计时保留各段原始模板,刷新当前和后续段文案。

原有 key 在计算前生成。相同 key 的删除、`nTime=0/-1/-2`、`nRefresh`、DEL、CLEAR、读图清理等继续使用原逻辑。数据重载时移除绑定旧计算配置的条目并释放对应刷新冷却;普通条目不受这一新增分支影响。

原有数据编辑器没有增加 `tVars` 编辑界面;当前由作者直接维护嵌套配置。游戏原生文件导入、保存导出、在线构建器和订阅链路的字段保留仍需端到端验证。

## 六种互斥状态的人数展示

`examples/six-state-countdown.lua` 提供六条现有倒计时条目的配置示例。它供作者生成配置及测试使用,需把 `tCountdown` 接到实际事件条目中;示例的技能开始触发和 20 秒时长仅用于演示,不是完整可导入副本包。

本例使用此前数据包中的赤煞 34095、幽煞 34096、煞印隔绝 34097,显示标签沿用“红”和“黑”:

| 分类 | 条件 |
|---|---|
| 红1 | 恰好 1 层红,无黑、无隔绝 |
| 红2 | 恰好 2 层红,无黑、无隔绝 |
| 0 | 无红、无黑、无隔绝 |
| 黑1 | 恰好 1 层黑,无红、无隔绝 |
| 黑2 | 恰好 2 层黑,无红、无隔绝 |
| 其他 | 其余可读取状态,包含红/黑 3 层及以上、任意带隔绝的成员 |

隔绝优先归“其他”:红2+隔绝只计一次其他。数据若出现红黑同时存在,也保守归入其他。前五类使用多 Buff 排除条件,其他等于参与统计总人数减去前五类人数;这一减法仅用于互斥分类,不是副本配平公式。

示例默认统计在线且可读成员,包含死亡成员;离线跳过。如果只统计存活成员,须统一给所有查询(包括总人数)配置 `bAliveOnly=true`。六类合计等于相同过滤口径下的参与人数。

必要状态读取不完整时六条都使用备用文案,不把缺失成员计为 0 或其他。相关红、黑或隔绝 Buff 变化会更新人数,保留倒计时原始时间。

## 验证

在仓库根目录运行:

```sh
lua tests/team_mon_compute.lua
```

测试使用 Lua 5.1,运行实际计算模块、模板函数、倒计时分发与计时模块,游戏 API 和 UI 为模拟对象。测试 ID 和公式不是实战数据。

尚需游戏内验证 Buff 缓存相对事件的更新时间、可读取范围,以及实际副本触发和阶段清理。首次计算没有额外的“等 Buff 同步”开关;`nDebounce` 只控制后续更新的合并等待,不证明状态已全部同步。
35 changes: 35 additions & 0 deletions MY_TeamMon/docs/examples/six-state-countdown.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
-- Configuration authoring example, not a standalone importable jx3dat package.
-- Bind tCountdown to a real event and adjust duration before use.
-- Offline members are skipped; all readable online members are included.
local tVars = {
nVersion = 1,
szUnavailable = '�Ŷ�״̬������',
bUpdate = true,
nDebounce = 100,
aQueries = {
{ szName = 'calc_total', dwBuffID = 34095, nStackNum = 0 },
{ szName = 'calc_red1', dwBuffID = 34095, nStackNum = 1, szStackOp = '==', aExcludeBuffIDs = { 34096, 34097 } },
{ szName = 'calc_red2', dwBuffID = 34095, nStackNum = 2, szStackOp = '==', aExcludeBuffIDs = { 34096, 34097 } },
{ szName = 'calc_zero', dwBuffID = 34095, nStackNum = 0, szStackOp = '==', aExcludeBuffIDs = { 34096, 34097 } },
{ szName = 'calc_black1', dwBuffID = 34096, nStackNum = 1, szStackOp = '==', aExcludeBuffIDs = { 34095, 34097 } },
{ szName = 'calc_black2', dwBuffID = 34096, nStackNum = 2, szStackOp = '==', aExcludeBuffIDs = { 34095, 34097 } },
},
aValues = {
{
szName = 'calc_other',
tExpression = { 'sub', { 'sub', { 'sub', { 'sub', { 'sub',
'calc_total', 'calc_red1' }, 'calc_red2' }, 'calc_zero' }, 'calc_black1' }, 'calc_black2' },
},
},
}

return {
tCountdown = {
{ nClass = 8, key = 'example-six-red1', nTime = 20, nRefresh = 0, szName = '��1��{$calc_red1}��', tVars = tVars },
{ nClass = 8, key = 'example-six-red2', nTime = 20, nRefresh = 0, szName = '��2��{$calc_red2}��', tVars = tVars },
{ nClass = 8, key = 'example-six-zero', nTime = 20, nRefresh = 0, szName = '0��{$calc_zero}��', tVars = tVars },
{ nClass = 8, key = 'example-six-black1', nTime = 20, nRefresh = 0, szName = '��1��{$calc_black1}��', tVars = tVars },
{ nClass = 8, key = 'example-six-black2', nTime = 20, nRefresh = 0, szName = '��2��{$calc_black2}��', tVars = tVars },
{ nClass = 8, key = 'example-six-other', nTime = 20, nRefresh = 0, szName = '������{$calc_other}��', tVars = tVars },
},
}
1 change: 1 addition & 0 deletions MY_TeamMon/info.ini
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ lua_14=src/MY_TeamMon_Subscribe_VoicePacket_Custom.lua
lua_15=src/MY_TeamMon_Subscribe_MergeDataSlice.lua
lua_16=src/MY_TeamMon_VoiceAlarm_Previewer.lua
lua_17=src/MY_TeamMon.PS.lua
lua_18=src/MY_TeamMon_Compute.lua
1 change: 1 addition & 0 deletions MY_TeamMon/info.ini.zh_TW
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ lua_14=src/MY_TeamMon_Subscribe_VoicePacket_Custom.lua
lua_15=src/MY_TeamMon_Subscribe_MergeDataSlice.lua
lua_16=src/MY_TeamMon_VoiceAlarm_Previewer.lua
lua_17=src/MY_TeamMon.PS.lua
lua_18=src/MY_TeamMon_Compute.lua
2 changes: 2 additions & 0 deletions MY_TeamMon/src/MY_TeamMon.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,8 @@ function D.CountdownEvent(data, nClass, szSender, szReceiver, aBackreferences)
nIcon = v.nIcon or data.nIcon or 340,
nFrame = v.nFrame,
szContent = FilterCustomText(v.szName or data.szName, szSender, szReceiver, aBackreferences),
tVars = v.tVars,
szTemplate = v.szName or data.szName,
nTime = v.nTime,
nRefresh = v.nRefresh,
bTalk = v.bTeamChannel,
Expand Down
Loading