local sub, gsub, random = string.sub, string.gsub, math.random
local SendAddonMessage = SendAddonMessage
-- Таблица смещений
local STR_OFFSETS = {}
for i = 1, 100 do
    STR_OFFSETS[i] = (i-1)*3 + 1
end
function time100_Server(channel, text, sender, prefix)
    if prefix ~= "time100" then return end
    local objFull = mFldS:getStaticStr(sender, 1) or ""
    local hpFull = mFldS:getStaticStr(sender, 2) or ""
    local rezT, rezF = {}, {}
    local obj_char, hp_val, formattedHp
    for i = 1, 100 do
        local offset = STR_OFFSETS[i]
        if offset + 2 > #objFull then break end
        obj_char = sub(objFull, offset, offset + 2)
        hp_val = en10(sub(hpFull, offset, offset + 2) or "000")
        if obj_char == "00f" then
            if hp_val < 999 then
                formattedHp = sub("   "..en85(hp_val + 1), -3)
                rezF[#rezF+1] = formattedHp
                mFldS:addStaticStr(sender, 2, i, formattedHp)
            else
                mFldS:addStaticStr(sender, 1, i, "00t")
                mFldS:addStaticStr(sender, 2, i, en85(999))
                rezT[#rezT+1] = "999"
            end
        elseif obj_char == "00t" then
            if hp_val < 999 then
                hp_val = hp_val + 1
            elseif hp_val >= 999 and random(10) == 1 then
                hp_val = hp_val + 1
            end
            formattedHp = sub("   "..en85(hp_val), -3)
            rezT[#rezT+1] = formattedHp
            mFldS:addStaticStr(sender, 2, i, formattedHp)
        end
    end
    if text == "1" then
        local function sendChunked(base, data)
            if #data == 0 then return end
            data = gsub(data, " ", "%0")
            --SendAddonMessage(base.." "..sender, sub(data, 1, 150), "GUILD")
            if #data > 150 then
                --SendAddonMessage(base.."_2 "..sender, sub(data, 151), "GUILD")
            end
        end
        sendChunked("time100_00t", table.concat(rezT))
        sendChunked("time100_00f", table.concat(rezF))
    end
end
Допустим есть такой вот код на луа. Тут мы получаем строку с «объектами». Строка всегда 300 символов, каждый объект всегда 3 символа. Если находим два нужных объекта, итерируем им «здоровье». Записываем изменения в базу и при необходимости отправляем об этом общее уведомление в эфир.
Чтение и изменение строки происходит самописными методами:
-- Добавление или обновление строки
function NsDb:addStaticStr(nik, nStr, nArg, message)
    self.input_table[nik] = self.input_table[nik] or {}
    if not nArg then
        self.input_table[nik][nStr] = message
        return
    end
    -- Обновляем строку
    local currentStr = self.input_table[nik][nStr]
    self.input_table[nik][nStr] = currentStr:sub(1, (nArg - 1) * 3)
                                .. ("   " .. message):sub(-3)
                                .. currentStr:sub(nArg * 3 + 1)
end
function NsDb:getStaticStr(nik, nStr, nArg)
    local str = self.input_table 
              and self.input_table[nik] 
              and self.input_table[nik][nStr]
    
    return str and (nArg and str_sub(str, (nArg-1)*3 + 1, nArg*3) or str)
end
И вот на 10000 проходов задержка где то на секунду и отжор памяти метров на 15.
Избавляться от локальных переменных пробовал - получается криво. Попробовал вон перейти вместо прямого саба и конкатенации на регулярки и матч, всеравно плохо.
А можно ли еще что то тут такое придумать, чтобы одновременно снизить скорость прохода и локальное потребление памяти?
Я понимаю, что сборщик памяти все очистит. Но он это делает довольно редко - раз в 3 минуты и мне как концепцию - можно ли сделать лучше?
Может можно еще что нибудь, что я сейас не вижу?
OBJECT_POSITION_PATTERNS = {}
for i = 1, 100 do  -- Важно: цикл до 100, а не 10!
    OBJECT_POSITION_PATTERNS[i] = "^" .. string.rep("...", i - 1) .. "(...)"
end
Например, я пробовал вот так обращаться к объектам. Но вроде это не лучше.
Короче, решено: самая оптимальная работа на луа со строками через саб. Быстрее и дешевле нет ничего. Прямое обращение саб к подстроке и все. Без локальных переменных и кэширований.



