Malandrinus 615 Опубликовано 14 Апреля 2013 Поделиться Опубликовано 14 Апреля 2013 OFF_ender, По мере заполнения таблиц получаю либо зависание при сохранении, либо вылет при попытке загрузки (чаще). С большой вероятностью происходит переполнение нетпакета. Эти функции сохраняют всё в один нетпакет, скорее всего актора. Размер нетпакета - 8кб. При этом он частично заполнен другими данными, зачастую более, чем наполовину. Если твои таблицы большие, то риск переполнения вполне реальный.Если это так, то не поможет даже переход на более продвинутые системы хранения, поскольку все они так или иначе используют нетпакеты с ограничением в 8кб. Вообще желательно избегать хранения таблиц. Почти всегда можно найти обходной путь. К примеру, если таблица хранит какие-то данные по объектам, то можно эти данные хранить в каждом объекте индивидуально, а при загрузке игры собирать в таблицу. Каждый объект, который имеет скриптовый серверный класс или биндер у клиентского класса, способен хранить свои данные у себя и не грузить нетпакет одного-единственного актора. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
OFF_ender 33 Опубликовано 14 Апреля 2013 Поделиться Опубликовано 14 Апреля 2013 (изменено) malandrinus, спасибо за ответ. Немного поэкспериментировал, сначала выкинул из таблиц стринговые секции - вылеты стали реже. Потом вообще исключил подтаблицы и сделал 5 отдельных таблиц, немного save/load - пока вроде не было вылетов, но может только пока... Вообще, нет ли каких недостатков именно у этих amk-шных функций сохранения таблиц? Может есть другие, более надежные функции, поскольку вылет, так понимаю, именно из-за переполнения 8кб ? Спасибо. Изменено 14 Апреля 2013 пользователем OFF_ender Ссылка на комментарий
Nazgool 250 Опубликовано 14 Апреля 2013 Поделиться Опубликовано 14 Апреля 2013 (изменено) OFF_ender Если очень нужно, то именно для твоих таблиц могу дать вариант "на скорую руку". Насколько я понял таблиц будет сохраняться две. Если в каждой будет по 50 полей, то размер сохраняемой строки составит около 1кб +-. Так что если ещё актуально - прошу. Хотя сорри. Что означает <1..65535>? кол-во символов или числа из этого диапазона? Изменено 14 Апреля 2013 пользователем Gun12 Ссылка на комментарий
OFF_ender 33 Опубликовано 14 Апреля 2013 Поделиться Опубликовано 14 Апреля 2013 (изменено) Gun12, <1..65535> - id об'екта, я так понимаю, он в этих пределах. В общем в таблицах важны только числовые значения. По возможности стринги можно исключить. (писал в лс - буду благодарен за твой вариант) Изменено 14 Апреля 2013 пользователем OFF_ender Ссылка на комментарий
Artos 99 Опубликовано 14 Апреля 2013 Поделиться Опубликовано 14 Апреля 2013 (изменено) OFF_ender, "amk-шные функции" конечно же имеют некие недостатки, но те, кто их писал, все же старались учитывать их. Как минимум, к "amk-шным функциям" относится и контроль переполнения нет-пакета актора, который тобою (судя по постам) напрочь проигнорирован. Любое использование нет-пакетов игровых объектов имеет недостаток - отсутствие контроля переполнения! Т.о. если модмейкер не контролирует свои записи (и тем самым вероятность переполнения), то только незначительные объемы "пользовательских" сохранений могут быть "безопасными". Если есть желание не иметь головной боли с объемами сохранения своих данных (т.е. вне зависимости от их объема) - почитай и этот топик и "Язык Lua. Общие вопросы программирования" на тему "универсального хранилища", где были и наработки и варианты реализаций. Gun12, запись id_a=<1..65535> вероятно означает, что ключ id_a в таблице может принимать значение из диапазона 1..65535 (и т.п.). Хотя замечу, что 65535 это уже перебор для игровых id (u16) и правильнее: 0...65534. malandrinus, если контролировать размер строки (а большие таблицы сериализовать) - то резать на куски и хранить куски, а при считывании склеивать куски - поможет "более продвинутым системам хранения" обойти и этот недостаток. ;-) (но лучше не допускать больших строк /таблиц) Изменено 14 Апреля 2013 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
OFF_ender 33 Опубликовано 14 Апреля 2013 Поделиться Опубликовано 14 Апреля 2013 (изменено) Artos, спасибо. Да, как-то попадался ваш пост: "при осваивании нет-пакетов, советую отбросить все "дурные" привычки. Нет-пакеты требуют полного понимания "что, как и зачем" и не допускают любых вольностей иль гаданий при их использовании.". Раз уж возникла нужда в нетпакетах, то придется видимо разбираться серьезно. Изменено 14 Апреля 2013 пользователем OFF_ender Ссылка на комментарий
Nazgool 250 Опубликовано 14 Апреля 2013 Поделиться Опубликовано 14 Апреля 2013 (изменено) В твоём примере я стрингов не видел. В общем так. Я исхожу из следующих утверждений. 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] Можно ещё пару сотен байт срезать Изменено 15 Апреля 2013 пользователем ColR_iT Ссылка на комментарий
OFF_ender 33 Опубликовано 15 Апреля 2013 Поделиться Опубликовано 15 Апреля 2013 (изменено) 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кб - это общий размер всех сохраняемых данных или размер каждого пакета в отдельности? Изменено 15 Апреля 2013 пользователем OFF_ender Ссылка на комментарий
Nazgool 250 Опубликовано 15 Апреля 2013 Поделиться Опубликовано 15 Апреля 2013 (изменено) В моём варианте ключи id_a, id_b, numb записываются только один раз. В сохраняемой строке они занимают всего 16 байт. Вот и весь выигрыш в пакете. Всё остальное это значения каждой из подтаблиц. После загрузки строки подтаблицы примут первоначальный вид, каждая с ключами и естественно со значениями. Так что решай что тебе нужнее - 16 байт или нормальный вид подтаблиц. Дальше. Если ты не обращался ко второй таблице, то и записывать её нет смысла. Передавай в вызове только одну s=toString(table1). ну или какую нужно. 8192 байта размер пакета Если тебе будет жалко 16-ти байт, давай подкину вариант, который экономит ещё порядка 200 (может и больше) байт (т.е. максимальный размер таблицы формата 2х50 не превысит 874 байта). А ещё другими словами - в тот же размер (1074) можно записать таблицы формата 2х62 Изменено 15 Апреля 2013 пользователем Gun12 Ссылка на комментарий
OFF_ender 33 Опубликовано 15 Апреля 2013 Поделиться Опубликовано 15 Апреля 2013 (изменено) Gun12, если тебе не сложно, я только за. Кстати, если numb [1..1000] загнать в диапазон 1..100, я так понимаю, еще по одному байту экономиться будет? Можно конечно еще извернуться, и сохранять в таблице не id об'ектов, а индексы 1,2,3,... но наверно уж слишком много вычислений будет производиться при каждом действии... Изменено 15 Апреля 2013 пользователем OFF_ender Ссылка на комментарий
Artos 99 Опубликовано 15 Апреля 2013 Поделиться Опубликовано 15 Апреля 2013 (изменено) OFF_ender и Gun12 , вы явно не в ту сторону идете... 1. 8 кб - это максимальный размер (объем) любого нет-пакета в игре , который воспринимается движком. 2. Если использовать готовые amk-функции (де)сериализации для записи в pstor(ы), то накладные расходы будут значительными. И даже более изощренный алгоритм (с компрессией) тоже страдает излишествами. 3. Прямой записью в нет-пакет(ы) можно с'экономить... Но, пакет актора уже достаточно нагружен... , а в процессе игры он еще разбухает... Если мод не остановится только на "этой парочке таблиц", т.е. будут и иные данные для сохранения, то тупик уже виден. 4. Выше, malandrinus, упомянул о способе децентрализации сохраняемых данных (размазать по множеству объектов) - следует все же его рассмотреть, хотя автор вопроса пока ничего не говорит о сути сохраняемых данных. 5. Ну а если все же не стучаться в стенку, а обратить внимание на "универсальные хранилища", то отпадет нужда думать о "каждом байте" в каждом случае... и потратить время на более полезное. ;-) Изменено 15 Апреля 2013 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
Nazgool 250 Опубликовано 15 Апреля 2013 Поделиться Опубликовано 15 Апреля 2013 (изменено) Ну это смотря как кодировать.Если использовать 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 с компа и не парить себе мозги. Вот. Изменено 15 Апреля 2013 пользователем Gun12 Ссылка на комментарий
Artos 99 Опубликовано 15 Апреля 2013 Поделиться Опубликовано 15 Апреля 2013 Gun12, я все же обращу твое внимание на то, что конечный результат не только от упражнений с Lua зависит, а точнее Lua тут только промежуточная ступень. Ты сейчас ориентирован на сериализацию таблиц и их запись строками в нет-пакет, в этом случае выбор метода сохранения (stringZ) единственен. Полезное и интересное занятие, не спорю, тем более и сам грешен. :-) В этом случае и тебе будет полезным все же посмотреть и то, что уже имеется по этой теме. Подсказка: с'экономить можно и на ключах, если таблица является индексированной, помнишь, был такой разговор в теме? Однако, как раз переполнение сэйва (пакета) этим вариантом наиболее вероятно, если в игре не только эти данные (по)требуется сохранять. Любая компрессия только отодвигает тупик. Нельзя же заранее просчитать в игре все объемы данных, которые потребуется сохранить. "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
Nazgool 250 Опубликовано 15 Апреля 2013 Поделиться Опубликовано 15 Апреля 2013 (изменено) 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' --================================================ Изменено 15 Апреля 2013 пользователем Gun12 Ссылка на комментарий
Artos 99 Опубликовано 15 Апреля 2013 Поделиться Опубликовано 15 Апреля 2013 Gun12, (тоже шепотом) ;-) Просто напомню тебе это: lua_extension в котором и твои труды были в свое время учтены. ;-) По сути это сборник, а table.compress и table.decompress имеют прямое отношение к текущему вопросу. "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
Shredder 49 Опубликовано 15 Апреля 2013 Поделиться Опубликовано 15 Апреля 2013 Поделитесь, пожалуйста, ссылкой на универсальное хранилище. Или подскажите, как его регестрировать в class_registrator.script. P.S. поиском нашёл только мёртвые ссылки. Ссылка на комментарий
Artos 99 Опубликовано 15 Апреля 2013 Поделиться Опубликовано 15 Апреля 2013 (изменено) Универсальные хранилища в контексте Сталкера имеют (мне известны) три реализации: by malandrinus, by xStream и by Artos. Последние две базируются на идее 1-ой. По последней повторю свой ответ в ЛС автору вопроса (OFF_ender): Последний вариант кодов для "публичного" использования лежит тут: se_stor_ext_120429-3 Актуальный вариант всегда в актуальной версии мода SIMBION:SHoC (скачать и взять). ну а за другими реализациями следует обратиться к их авторам и, если сочтут возможным, может и обновят ссылки (или дадут свое 'добро' на их обновление в этой теме). Изменено 15 Апреля 2013 пользователем Artos 1 "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
Nazgool 250 Опубликовано 15 Апреля 2013 Поделиться Опубликовано 15 Апреля 2013 fCloneTable и fCopyTable можно одной функцией сделать Себе так и сделал. Да и на вид по-проще. Ссылка на комментарий
OFF_ender 33 Опубликовано 15 Апреля 2013 Поделиться Опубликовано 15 Апреля 2013 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 -- получили первоначальный вид таблицы Смысл в том, чтобы после конвертации в символы расходовалось меньше байт? Ссылка на комментарий
Nazgool 250 Опубликовано 15 Апреля 2013 Поделиться Опубликовано 15 Апреля 2013 (изменено) Нет. Просто вызывай : 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] и т.д. И будут тебе твои таблицы в прежнем виде Изменено 15 Апреля 2013 пользователем Gun12 Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти