模块:MaterialReaction/PreData

来自Noita Wiki
跳到导航 跳到搜索

此模块的文档可以在模块:MaterialReaction/PreData/doc创建

--完成了,用于预处理材料反应数据,以此提升性能
local result = {}

local IDtoTable = {}                                                         --材料ID转数据表
for _, v in pairs(mw.loadData("Module:DataQuery/Materials")["Materials"]) do --初始化id对应表
    IDtoTable[v.herd] = v
end

--- 移除前后空格,换行
local function strip(s)
    if s == nil then
        return ''
    end
    return s:gsub("^%s+", ""):gsub("%s+$", ""):gsub("%c", "")
end

--构造一个用于判断的表
local function split(s, delim)
    if string.find(s, delim) == nil then
        return {
            strip(s)
        }
    end
    local result = {}
    for ct in string.gmatch(s, '([^' .. delim .. ']+)') do
        ct = "[" .. strip(ct) .. "]"
        result[ct] = true
    end
    return result
end

local raw_data = require("Module:MaterialReaction/data")

for i, v1 in pairs(raw_data.children) do --遍历元素
    --获得材料输入和输出
    local tempInputT = { nil, nil, nil } --nil用于占位,提供一个合适的数组大小,避免hash操作带来的性能损失
    local tempOutputT = { nil, nil, nil } --nil用于占位,提供一个合适的数组大小,避免hash操作带来的性能损失
    local HasMaterialT = {}              --此表用于标记已写入材料

    local k = 1                          --用于遍历元素的属性
    local cmpStr = "input_cell" .. tostring(k)
    while (v1.attr[cmpStr] ~= nil) do    --解析输入材料
        tempInputT[k] = v1.attr[cmpStr]
        k = k + 1
        cmpStr = "input_cell" .. tostring(k)
    end
    k = 1
    local cmpStr = "output_cell" .. tostring(k)
    while (v1.attr[cmpStr] ~= nil) do --解析输出材料
        tempOutputT[k] = v1.attr[cmpStr]
        k = k + 1
        cmpStr = "output_cell" .. tostring(k)
    end
    
    --构建返回值的表的函数 可能没问题 谁知道呢()
    local function SetResult(InputTable)
        for j = 1, #InputTable do
            local this = InputTable[j]
            if not HasMaterialT[this] then           --如果没被标记过
                local continue = true                --牛魔5.1没有goto,真麻烦啊
                if string.byte(this, 1, 1) ~= 91 then --91为[ 如果等于则是tag,正常保存,是id要判断,这里是为了避免在MaterialReaction中加载重复反应
                    local hasTags = split(IDtoTable[this].tags, ",") --分割出来判断表
                    local has = false                --判断变量
                    local iTag = 1
                    while (not has) and iTag <= #tempInputT do --遍历判断是不是存在此tag
                        has = hasTags[tempInputT[iTag]]
                        iTag = iTag + 1
                    end
                    iTag = 1
                    while (not has) and iTag <= #tempOutputT do --遍历判断是不是存在此tag
                        has = hasTags[tempOutputT[iTag]]
                        iTag = iTag + 1
                    end
                    if has then
                        continue = false
                    end
                end
                if continue then
                    if not result[this] then     --如果不存在id索引或tag索引
                        --第一个表中元素和第二个表中元素同一个下标索引则为同一反应
                        result[this] = { {}, {}, { "0" }, { "0" } } --数组第一个表为输入材料,第二个为输出材料,第三个表为速率,第四个表为快速反应
                        --这里直接插入输入和输出的内容和速率,快速反应
                        table.insert(result[this][1], tempInputT)
                        table.insert(result[this][2], tempOutputT)

                        result[this][3][1] = v1.attr.probability --反应速率
                        if v1.attr.fast_reaction ~= nil then --解析反应是否快速
                            if v1.attr.fast_reaction == "1" then
                                result[this][4][1] = "是"
                            else
                                result[this][4][1] = "否"
                            end
                        else
                            result[this][4][1] = "否"
                        end
                    else --反之如果存在
                        --这里直接构建输入和输出的内容和速率,快速反应
                        --插入表
                        table.insert(result[this][1], tempInputT)
                        table.insert(result[this][2], tempOutputT)

                        table.insert(result[this][3], v1.attr.probability) --反应速率
                        if v1.attr.fast_reaction ~= nil then --解析反应是否快速
                            if v1.attr.fast_reaction == "1" then
                                table.insert(result[this][4], "是")
                            else
                                table.insert(result[this][4], "否")
                            end
                        else
                            table.insert(result[this][4], "否")
                        end
                    end
                end
                HasMaterialT[this] = true --标记这个材料被记录过
            end
        end
    end
    --输入表格
    SetResult(tempInputT)
    SetResult(tempOutputT)
end

--继承反应实现
for i, matT in pairs(IDtoTable) do
    local tempMat = matT
    while tempMat ~= nil and tempMat.parent ~= "" and tempMat.inheritsReactions == "1" do --看看有没有材料,然后判断是否有父类和是否有继承反应
        local tempReaction = result[tempMat.parent]

        if tempReaction ~= nil then     --如果有反应
            local hasTags = split(matT.tags, ",") --分割出来判断表
            for t_i = 1, #tempReaction[1] do --解析反应数据,并进行适当的深/浅拷贝
                --四个数组等长,只需要知道一个长度即可
                local hasReaction = false
                local Input = { nil, nil, nil }
                local Output = { nil, nil, nil }
                local ReactionMat = {}
                local has = false --用于判断当前材料是否参与了它有的tag的反应
                for _, str in pairs(tempReaction[1][t_i]) do
                    has = hasTags[str]
                    if str == tempMat.parent then
                        hasReaction = true
                        table.insert(Input, i)
                        ReactionMat[i] = true
                    else
                        table.insert(Input, str)
                        ReactionMat[str] = true
                    end
                end
                if hasReaction then
                    if result[i] == nil then
                        result[i] = { { nil }, { nil }, { nil }, { nil } }
                    end
                    for _, str in pairs(tempReaction[2][t_i]) do
                        has = hasTags[str]
                        if str == tempMat.parent then
                            table.insert(Output, i)
                            ReactionMat[i] = true
                        else
                            table.insert(Output, str)
                            ReactionMat[str] = true
                        end
                    end
                    if has then --如果当前材料参与了它有的tag的反应,那么就把当前材料从添加表移除,防止重复
                        ReactionMat[i] = nil
                    end
                    for ID, _ in pairs(ReactionMat) do --添加表
                        table.insert(result[ID][1], Input)
                        table.insert(result[ID][2], Output)
                        table.insert(result[ID][3], tempReaction[3][t_i])
                        table.insert(result[ID][4], tempReaction[4][t_i])
                    end
                end
            end
        end
        tempMat = IDtoTable[tempMat.parent] --更新父类
    end
end

return result