调用方式
Functions.forecast.calculate(platform, history, window, noheals, nodmg, now)
将其记录为名为 Functions.forecast.calculate 的依赖项(接受自动补全即可完成),然后按该名称调用。
作用
使用显式的有限时间窗口和时钟,计算经过检查的生命值历史速率。保留有序加权、逐行实时规范舍入、被跳过的数据流、数组空洞、小数键以及最终访问时的时长。固定的 4096 单位预算涵盖两个数据流中被访问的行和累加区间;超出预算或无效的已消耗运算会返回不可用,绝不返回部分估算或截断值。这个新 API 有其自己的源码身份;历史趋势函数保持不变。
参数
| 名称 | 类型 | 作用 |
|---|---|---|
platform | RMPlatform | 所使用值的可读性判定依据。 |
history | table | 由时间/数值行组成的伤害/治疗数组;只会使用所选的数据流。 |
window | number | 显式的有限加权窗口;不会回退到配置文件或截断。 |
noheals | boolean | 为 true 时跳过对治疗数据流的所有访问。 |
nodmg | boolean | 为 true 时跳过对伤害数据流的所有访问。 |
now | number | 显式的有限时钟快照;带符号和小数值仍然有效。 |
返回值
| 1 | number | nil | 有限的带符号合并速率;计算不可用时为 nil。 |
|---|---|---|
| 2 | number | nil | 有限的最终数据流时长;不可用时为 nil。 |
| 3 | string | nil | 速率/时长为 nil 时的工作量上限、数据或运算可用性原因。 |
版本
内置辅助函数在每个版本上都会注册。不同的是它们读取的游戏 API;某个 API 缺失时,辅助函数会改用后备方案,或返回 nil 并附上原因。
它不直接读取任何游戏 API。
秘密值(正式服和永久服)
在正式服和永久服上,游戏交给插件的是秘密值。此辅助函数会检查它读取的内容(addon.Platform:CanReadValue),遇到无法比较的秘密值时返回 nil 并附上原因(例如 restricted-value),而不是返回该秘密值。请将 nil 视为不可用,而不是假。
示例
local guid = UnitGUID("player")
local history = guid and addon.damageHistory[guid]
if not history then return nil, "no-history" end
local rate, age, reason = Functions.forecast.calculate(addon.Platform, history, 5, false, false, GetTime())
if rate == nil then return nil, reason end
return age >= 2 and rate < 0依赖项
finite→Functions.forecast.finitereadField→Functions.forecast.readField
源码
Functions/forecast.lua,第 61 行。在游戏中为只读;“复制”会生成一份可编辑的副本。
Functions.forecast.calculate(platform, history, window, noheals, nodmg, now)
if type(platform)~='table' or type(platform.CanReadValue)~='function' then return nil,nil,'invalid-forecast-platform' end
if not platform:CanReadValue(history) or not platform:CanReadValue(noheals) or not platform:CanReadValue(nodmg) then return nil,nil,'restricted-value' end
if type(history)~='table' then return nil,nil,'invalid-forecast-history' end
if type(noheals)~='boolean' or type(nodmg)~='boolean' then return nil,nil,'invalid-forecast-mode' end
local valid,reason=finite(platform,window)
if not valid then return nil,nil,reason end
valid,reason=finite(platform,now)
if not valid then return nil,nil,reason end
local work=0
local function scan(name,skip)
if skip then return 0,0,0 end
local rows,why=readField(platform,history,name)
if why then return nil,nil,nil,why end
if type(rows)~='table' then return nil,nil,nil,'invalid-forecast-stream' end
local maxoffs,data=0,{}
for _,row in ipairs(rows) do
work=work+1
if work>4096 then return nil,nil,nil,'forecast-work-budget' end
local time,problem=readField(platform,row,'time')
if problem then return nil,nil,nil,problem end
local good,numberReason=finite(platform,time)
if not good then return nil,nil,nil,numberReason end
local diff=now-time
good,numberReason=finite(platform,diff)
if not good then return nil,nil,nil,numberReason end
local scale=window-diff
local functions,namespaceReason=readField(platform,addon,'Functions')
if namespaceReason then return nil,nil,nil,namespaceReason end
if type(functions)~='table' then return nil,nil,nil,'forecast-round-unavailable' end
local values
values,namespaceReason=readField(platform,functions,'values')
if namespaceReason then return nil,nil,nil,namespaceReason end
if type(values)~='table' then return nil,nil,nil,'forecast-round-unavailable' end
local round
round,namespaceReason=readField(platform,values,'round')
if namespaceReason then return nil,nil,nil,namespaceReason end
if type(round)~='function' then return nil,nil,nil,'forecast-round-unavailable' end
local ok,rounded=pcall(round,diff)
if not ok then return nil,nil,nil,'forecast-round-error' end
good,numberReason=finite(platform,rounded)
if not good then return nil,nil,nil,numberReason end
maxoffs=rounded
if maxoffs>window then break end
local amount,amountReason=readField(platform,row,'value')
if amountReason then return nil,nil,nil,amountReason end
if amount~=nil and amount~=false then
good,numberReason=finite(platform,amount)
if not good then return nil,nil,nil,numberReason end
good,numberReason=finite(platform,scale)
if not good then return nil,nil,nil,numberReason end
local product=amount*scale
good,numberReason=finite(platform,product)
if not good then return nil,nil,nil,numberReason end
local value=(data[maxoffs] or 0)+product
good,numberReason=finite(platform,value)
if not good then return nil,nil,nil,numberReason end
data[maxoffs]=value
end
end
local bins=maxoffs<0 and 0 or math.floor(maxoffs)+1
if bins>4096-work then return nil,nil,nil,'forecast-work-budget' end
work=work+bins
local total,count=0,0
for i=0,maxoffs do
total=total+(data[i] or 0)
local good,numberReason=finite(platform,total)
if not good then return nil,nil,nil,numberReason end
local scale=window-i
good,numberReason=finite(platform,scale)
if not good then return nil,nil,nil,numberReason end
count=count+scale
good,numberReason=finite(platform,count)
if not good then return nil,nil,nil,numberReason end
end
return total,count,maxoffs
end
local damageTotal,damageCount,damageSeconds,damageReason=scan('damage',nodmg)
if damageReason then return nil,nil,damageReason end
local healTotal,healCount,healSeconds,healReason=scan('heals',noheals)
if healReason then return nil,nil,healReason end
local damageRate=damageCount>0 and -damageTotal/damageCount or 0
valid,reason=finite(platform,damageRate)
if not valid then return nil,nil,reason end
local healRate=healCount>0 and healTotal/healCount or 0
valid,reason=finite(platform,healRate)
if not valid then return nil,nil,reason end
local rate=damageRate+healRate
valid,reason=finite(platform,rate)
if not valid then return nil,nil,reason end
return rate,damageSeconds>healSeconds and damageSeconds or healSeconds