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
Например, я пробовал вот так обращаться к объектам. Но вроде это не лучше.
Короче, решено: самая оптимальная работа на луа со строками через саб. Быстрее и дешевле нет ничего. Прямое обращение саб к подстроке и все. Без локальных переменных и кэширований.