Перейти к контенту

Рекомендуемые сообщения

OFF_ender,

По мере заполнения таблиц получаю либо зависание при сохранении, либо вылет при попытке загрузки (чаще).

С большой вероятностью происходит переполнение нетпакета. Эти функции сохраняют всё в один нетпакет, скорее всего актора. Размер нетпакета - 8кб. При этом он частично заполнен другими данными, зачастую более, чем наполовину. Если твои таблицы большие, то риск переполнения вполне реальный.

Если это так, то не поможет даже переход на более продвинутые системы хранения, поскольку все они так или иначе используют нетпакеты с ограничением в 8кб. Вообще желательно избегать хранения таблиц. Почти всегда можно найти обходной путь. К примеру, если таблица хранит какие-то данные по объектам, то можно эти данные хранить в каждом объекте индивидуально, а при загрузке игры собирать в таблицу. Каждый объект, который имеет скриптовый серверный класс или биндер у клиентского класса, способен хранить свои данные у себя и не грузить нетпакет одного-единственного актора.

 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

 malandrinus, спасибо за ответ.

Немного поэкспериментировал, сначала выкинул из таблиц стринговые секции - вылеты стали реже. Потом вообще исключил подтаблицы и сделал 5 отдельных таблиц, немного save/load - пока вроде не было вылетов, но может только пока...

Вообще, нет ли каких недостатков именно у этих amk-шных функций сохранения таблиц? Может есть другие, более надежные функции, поскольку вылет, так понимаю, именно из-за переполнения 8кб ?

Спасибо.

Изменено пользователем OFF_ender
Ссылка на комментарий

OFF_ender

Если очень нужно, то именно для твоих таблиц могу дать вариант "на скорую руку". Насколько я понял таблиц будет сохраняться две. Если в каждой будет по 50 полей, то размер сохраняемой строки составит около 1кб +-. Так что если ещё актуально - прошу.

Хотя сорри. Что означает <1..65535>? кол-во символов или числа из этого диапазона?

Изменено пользователем Gun12
Ссылка на комментарий

 Gun12, <1..65535> - id об'екта, я так понимаю, он в этих пределах. В общем в таблицах важны только числовые значения. По возможности стринги можно исключить. (писал в лс - буду благодарен за твой вариант)

Изменено пользователем OFF_ender
Ссылка на комментарий

OFF_ender, "amk-шные функции" конечно же имеют некие недостатки, но те, кто их писал, все же старались учитывать их. Как минимум, к "amk-шным функциям" относится и контроль переполнения нет-пакета актора, который тобою (судя по постам) напрочь проигнорирован.

Любое использование нет-пакетов игровых объектов имеет недостаток - отсутствие контроля переполнения! Т.о. если модмейкер не контролирует свои записи (и тем самым вероятность переполнения), то только незначительные объемы "пользовательских" сохранений могут быть "безопасными".

Если есть желание не иметь головной боли с объемами сохранения своих данных (т.е. вне зависимости от их объема) - почитай и этот топик и "Язык Lua. Общие вопросы программирования" на тему "универсального хранилища", где были и наработки и варианты реализаций.

 

Gun12, запись id_a=<1..65535> вероятно означает, что ключ id_a в таблице может принимать значение из диапазона 1..65535 (и т.п.). Хотя замечу, что 65535  это уже перебор для игровых id (u16) и правильнее: 0...65534.

 

malandrinus, если контролировать размер строки (а большие таблицы сериализовать) - то резать на куски и хранить куски, а при считывании склеивать куски - поможет "более продвинутым системам хранения" обойти и этот недостаток. ;-) (но лучше не допускать больших строк /таблиц)

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Artos, спасибо. Да, как-то попадался ваш пост:

"при осваивании нет-пакетов, советую отбросить все "дурные" привычки. Нет-пакеты требуют полного понимания "что, как и зачем" и не допускают любых вольностей иль гаданий при их использовании.".

Раз уж возникла нужда в нетпакетах, то придется видимо разбираться серьезно.

Изменено пользователем OFF_ender
Ссылка на комментарий

В твоём примере я стрингов не видел.

В общем так. Я исхожу из следующих утверждений.

1. Таблицы две.

2. В каждой из этих таблиц находится массив из таблиц

3. Все таблицы из массива имеют одинаковые ключи (id_a, id_b и numb)

4. Каждое значение ключа - число из указанного диапазона.

Если так, то, как я уже говорил, для 50-ти полей в каждой из таблиц и максимальных значений каждого поля размер будет 1074 байта

function toString(...)    local args = {...}    local s = ''    for i = 1, #args do        local n = args[i]        if next(n) then            local keys = {}            for k in pairs(n[1]) do                keys[#keys+1] = k            end                s = s..'#@'..table.concat(keys,' ')..'@'            local values = {}            for j=1,#args[i] do                for _,v in pairs(args[i][j]) do                    values[#values+1]=string.format('%x',v)                end                s = s..'~'..table.concat(values,' ')                values = {}            end        else            s=s..'#~'        end    end    return sends=toString(table1,table2) -- сохранять строку 's'function toTable(s)    local t = {}    for w in s:gmatch('[^#]+') do        local k = {}        w = w:gsub('%@(.+)%@', function(v) for m in v:gmatch('%S+') do k[#k+1] = m end return '' end)        local t1 = {}        for v in w:gmatch('[^~]+') do            local n = 1            local t2 = {}            for m in v:gmatch('%S+') do                t2[k[n]] = tonumber(m,16)                n = n+1            end            t1[#t1+1]=t2        end        t[#t+1]=t1    end    return tendt = toTable(s) -- загружать строку 's'table1 = t[1]table2 = t[2]

 

 

 

 

 

Можно ещё пару сотен байт срезать

Изменено пользователем ColR_iT
Ссылка на комментарий

Gun12, спасибо

В твоём примере я стрингов не видел.

Я имел ввиду ключи: id_a, id_b, numb. Если их совсем исключить и сделать таблицу вида:
table1 = {[1] = <1..65534>, [2]=<1..8>, [3]=<1..65535>, [4] = <1..65534>, [5]=<1..8>, [6]=<1..65535>,...}, тогда в ней прошлая 1-я подтаблица - это элементы [1],[2],[3], следующая - [4],[5],[6] и т.д. Надёжность в таком варианте не пострадает? Всё-таки раньше обращались к конкретному ключу конкретной подтаблицы, а здесь если выпадет один элемент, то всё сместится и посыпется... А также выигрыш по размеру пакета будет существенный?
Имеет ли смысл записывать только одну таблицу, если ко второй ещё не обращались? В твоём варианте сохраняются сразу обе, или особой разницы нет?

И ещё: 8кб - это общий размер всех сохраняемых данных или размер каждого пакета в отдельности?

Изменено пользователем OFF_ender
Ссылка на комментарий

В моём варианте ключи id_a, id_b, numb записываются только один раз. В сохраняемой строке они занимают всего 16 байт. Вот и весь выигрыш в пакете. Всё остальное это значения каждой из подтаблиц. После загрузки строки подтаблицы примут первоначальный вид, каждая с ключами и естественно со значениями. Так что решай что тебе нужнее - 16 байт или нормальный вид подтаблиц.

 

Дальше. Если ты не обращался ко второй таблице, то и записывать её нет смысла. Передавай в вызове только одну s=toString(table1). ну или какую нужно.

8192 байта размер пакета



Если тебе будет жалко 16-ти байт, давай подкину вариант, который экономит ещё порядка 200 (может и больше) байт (т.е. максимальный размер таблицы формата 2х50 не превысит 874 байта). А ещё другими словами - в тот же размер (1074) можно записать таблицы формата 2х62

Изменено пользователем Gun12
Ссылка на комментарий

Gun12, если тебе не сложно, я только за.

Кстати, если numb [1..1000] загнать в диапазон 1..100, я так понимаю, еще по одному байту экономиться будет? Можно конечно еще извернуться, и сохранять в таблице не id об'ектов, а индексы 1,2,3,... но наверно уж слишком много вычислений будет производиться при каждом действии...

Изменено пользователем OFF_ender
Ссылка на комментарий

OFF_ender и Gun12 , вы явно не в ту сторону идете...

1. 8 кб - это максимальный размер (объем) любого нет-пакета в игре , который воспринимается движком.

2. Если использовать готовые amk-функции (де)сериализации для записи в pstor(ы), то накладные расходы будут значительными. И даже более изощренный алгоритм (с компрессией) тоже страдает излишествами.

3. Прямой записью в нет-пакет(ы) можно с'экономить... Но, пакет актора уже достаточно нагружен... , а в процессе игры он еще разбухает... Если мод не остановится только на "этой парочке таблиц", т.е. будут и иные данные для сохранения, то тупик уже виден.

4. Выше, malandrinus, упомянул о способе децентрализации сохраняемых данных (размазать по множеству объектов) - следует все же его рассмотреть, хотя автор вопроса пока ничего не говорит о сути сохраняемых данных.

5. Ну а если все же не стучаться в стенку, а обратить внимание на "универсальные хранилища", то отпадет нужда думать о "каждом байте" в каждом случае... и потратить время на более полезное. ;-)

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Ну это смотря как кодировать.
Если использовать HEX вариант то да, один байт экономиться. Т.е. число 1000 переводиться в 3-х значное hex-число, число 100 в 2-х значное
Это значит что числа диапазона 256-4095 кодируются 3-мя символами(байтам),  4096-65535 4-мя байтами и т.д.
Я использую кодирования с основанием 100
Поэтому диапазоны такие : 99-9999 кодируются 2-мя байтами), 10000-999999 - 3-мя, 1000000-99999999 4-мя и т.д.
Так что, как видишь, для этой системы кодирования всё-равно что 100, что 1000. Кодироваться всё равно будет 2-мя байтами в отличии от HEX

Насчёт индексов 1,2,3 или ключей стрингов. Функциям по барабану. Количество строки байтов увеличится на длину строк всех ключей - 3
Ну будет лишний десяток байт. Если не критично, то можешь писать стринги.

Artos, мне хорошо известно в какую сторону иду я.
Не знаю как для тебя, но для меня упражнения в lua дело очень даже полезное.
Так что всем спасибо за предупреждения. Приняли. Подумаем на досуге... как-то...

Ты же уже давно знаешь меня, и пора привыкнуть что для меня получить готовый результат не самоцель.

Ну возьму я хранилища. Нет. Чего мелочиться. Качать готовые моды паком, удалить на фиг lua с компа и не парить себе мозги. Вот.

Изменено пользователем Gun12
Ссылка на комментарий

Gun12, я все же обращу твое внимание на то, что конечный результат не только от упражнений с Lua зависит, а точнее Lua тут только промежуточная ступень.

Ты сейчас ориентирован на сериализацию таблиц и их запись строками в нет-пакет, в этом случае выбор метода сохранения (stringZ)  единственен. Полезное и интересное занятие, не спорю, тем более и сам грешен. :-) В этом случае и тебе будет полезным все же посмотреть и то, что уже имеется по этой теме. Подсказка: с'экономить можно и на ключах, если таблица является индексированной, помнишь, был такой разговор в теме?

Однако, как раз переполнение сэйва (пакета) этим вариантом наиболее вероятно, если в игре не только эти данные (по)требуется сохранять. Любая компрессия только отодвигает тупик. Нельзя же заранее просчитать в игре все объемы данных, которые потребуется сохранить.

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Artos,

 

 

тут понимаешь в чём загвоздка ? (не у меня :))

Не в обиду игре, я шепотом, - мне глубоко плевать на Сталкера с его нет-пакетами и прочими прибамбасами, портящими lua.

Я занялся этим вопросом потому, что он сейчас как раз пересекается с моими интересами в работе над одним .. в общем не важно

И мне хотелось бы кое-чего попаковать. Вот на что я ориентирован.

 

А лично мне переполнение не грозит. Есть lua. Есть io.write

 

 



OFF_ender, пробуй :

 

--===============================================
-- Составление таблицы соответсвий число -> символ
local char = string.char
local t10, t100 = {}, {}

local t = {}
for i = 65, 255 do t[#t+1] = string.char(i) end
local s = table.concat(t) -- строка символов win1251

local n=10
for c in s:gmatch('[A-Za-zА-е]') do
    t100[tostring(n)] = c
    n=n+1
end

for i = 0, 10 do
    t100['0'..i] = char(240+i)
end

-- Составление таблицы соответсвий символ -> число
for k,v in pairs(t100) do
    t10[v]=k
end

--===============================================
-- функция конвертации числа в строку
function to100(n)
    return tostring(n):gsub('%d%d', function(w) return t100[w] end)
end

-- функция конвертации строки в чмсло
function to10(s)
    return s:gsub('%D', function (c) return t10[c] end)
end

--================================================
-- table to string
function toString(...)
    local args = {...}
    local s = ''
    for i = 1, #args do
        local n = args[i]
        if next(n) then
            local keys = {}
            for k in pairs(n[1]) do
                keys[#keys+1] = k
            end
    
            s = s..'#@'..table.concat(keys,' ')..'@'
            local values = {}

            for j=1,#args[i] do
                for _,v in pairs(args[i][j]) do
                    values[#values+1]=to100(v)
                end
                s = s..'~'..table.concat(values,' ')
                values = {}
            end
        else
            s=s..'#~'
        end
    end
    return s
end

-- string to table
function toTable(s)
    local t = {}
    for w in s:gmatch('[^#]+') do
        local k = {}
        w = w:gsub('%@(.+)%@', function(v) for m in v:gmatch('%S+') do k[#k+1] = m end return '' end)
        local t1 = {}
        for v in w:gmatch('[^~]+') do
            local n = 1
            local t2 = {}
            for m in v:gmatch('%S+') do
                t2[k[n]] = to10(m)
                n = n+1
            end
            t1[#t1+1]=t2
        end
        t[#t+1]=t1
    end
    return t
end

local str = toString(table1, table2) -- строку 'str' сохраняешь
local num = toTable(str)            -- таблица с таблицами 'table1' и 'table2'
--================================================

 

 

 

Изменено пользователем Gun12
Ссылка на комментарий

Gun12, (тоже шепотом) ;-)

Просто напомню тебе это: lua_extension в котором и твои труды были в свое время учтены. ;-)

По сути это сборник, а table.compress и table.decompress имеют прямое отношение к текущему вопросу.

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Поделитесь, пожалуйста, ссылкой на универсальное хранилище. Или подскажите, как его регестрировать в class_registrator.script.

P.S. поиском нашёл только мёртвые ссылки.

Ссылка на комментарий

Универсальные хранилища в контексте Сталкера имеют (мне известны) три реализации: by malandrinus,  by xStream и by Artos.

Последние две базируются на идее 1-ой.

По последней повторю свой ответ в ЛС автору вопроса (OFF_ender):

Последний вариант кодов для "публичного" использования лежит тут: se_stor_ext_120429-3

Актуальный вариант всегда в актуальной версии мода SIMBION:SHoC (скачать и взять).

ну а за другими реализациями следует обратиться к их авторам и, если сочтут возможным, может и обновят ссылки (или дадут свое 'добро' на их обновление в этой теме).

Изменено пользователем Artos
  • Нравится 1

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Gun12, может я что-то недопонял...

Есть table1 с несколькими элемнентами
-- производим нужные действия с элементами. дальше:
for i=1,#table1 do
	table1[i].id_a = to100(table1[i].id_a)
	table1[i].numb = to100(table1[i].id_numb)
	table1[i].id_b = to100(table1[i].id_
end
s = toString(table1)
-- сохраняем строку каким-то образом в нет-пакет
...
-- читаем из нет-пакета строку s
table1 = toTable(s)[1]
for i=1,#table1 do
	table1[i].id_a = to10(table1[i].id_a)
	table1[i].numb = to10(table1[i].id_numb)
	table1[i].id_b = to10(table1[i].id_
end
-- получили первоначальный вид таблицы

Смысл в том, чтобы после конвертации в символы расходовалось меньше байт?

 

 

Ссылка на комментарий

Нет. Просто вызывай :

s = toString(table1)

Таблица полностью запишется в строку. Вот эту строку и сохраняй

Если будет несколько таблиц, то так и пиши :

s = toString(table1,table2,table3,table4) -- и т.д.

Все эти таблицы запишутся в одну строку.

 

При загрузке получай из пакета строку и вызывай :

tab = toTable(s) - s это полученная строка, tab - таблица с восстановленными таблицами table1, и т.д.

 

Затем пишешь :

table1 = tab[1]

 

А если сохранял несколько, то :

table1 = tab[1]

table2 = tab[2]

table3 = tab[3]

и т.д.

 

И будут тебе твои таблицы в прежнем виде

Изменено пользователем Gun12
Ссылка на комментарий

Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

Создать аккаунт

Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!

Зарегистрировать новый аккаунт

Войти

Есть аккаунт? Войти.

Войти
  • Недавно просматривали   1 пользователь

×
×
  • Создать...