参考 › 函数参考 › Functions

Functions.forecast.calculate

公共

调用方式

Functions.forecast.calculate(platform, history, window, noheals, nodmg, now)

将其记录为名为 Functions.forecast.calculate 的依赖项(接受自动补全即可完成),然后按该名称调用。

作用

使用显式的有限时间窗口和时钟,计算经过检查的生命值历史速率。保留有序加权、逐行实时规范舍入、被跳过的数据流、数组空洞、小数键以及最终访问时的时长。固定的 4096 单位预算涵盖两个数据流中被访问的行和累加区间;超出预算或无效的已消耗运算会返回不可用,绝不返回部分估算或截断值。这个新 API 有其自己的源码身份;历史趋势函数保持不变。

参数

名称类型作用
platformRMPlatform所使用值的可读性判定依据。
historytable由时间/数值行组成的伤害/治疗数组;只会使用所选的数据流。
windownumber显式的有限加权窗口;不会回退到配置文件或截断。
nohealsboolean为 true 时跳过对治疗数据流的所有访问。
nodmgboolean为 true 时跳过对伤害数据流的所有访问。
nownumber显式的有限时钟快照;带符号和小数值仍然有效。

返回值

1number | nil有限的带符号合并速率;计算不可用时为 nil。
2number | nil有限的最终数据流时长;不可用时为 nil。
3string | 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

依赖项

源码

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

返回函数参考