Kirgudu 1 260 Опубликовано 19 Июня 2012 Колебался между этой темой и "общими вопросами программирования", решил запостить вопрос сюда; если ошибся, прошу перенести. При работе над HARDWARMOD (CS) я столкнулся вот с какой штукой. Имеем таблицу вида local t = { Alpha = {a=3,b=13}, Bravo = {a=1,b=12}, Charlie = {a=5,b=11}, Delta = {a=9,b=17}, Echo = {a=7,b=16} } содержащую динамически генерируемые данные. В зависимости от некоторых условий мне нужно отсортировать эту таблицу по тому или иному полю таблиц, содержащихся в значениях. До поры до времени прекрасно работал стандартный для Lua метод: table.sort(t, function(v1,v2) return v1.b < v2.b end) но в какой-то момент перестал это делать. Проверял даже на самых несложных примерах, без вложенных таблиц - сортировка даже по простым значениям стала возвращать исходную таблицу (либо далее используемый pairs перебирал элементы таблицы раньше в правильном порядке, хоть это и не гарантируется, а теперь перестал это делать). Между двумя этими моментами, работы и не работы сортировки, я внедрил модуль универсального хранилища Artos-а и, пожалуй, всё, по крайней мере ничего особо значимого больше не делал. Из положения я вышел: написал собственную функцию для получения упорядоченной как мне надо таблицы: -- Выборка из таблицы с сортировкой по value (быстрая сортировка с разбивкой на две части). -- Работает также в случае если value - тоже таблица (простая). -- Выводимая таблица представляет собой простой массив, индекс исходной таблицы перемещается в поле "__key". -- t - исходная таблица -- s - значение, по которому должна произойти сортировка. Может принимать вид: -- "", nil или без параметра - для случаев, когда vаlue представляет собой простое значение. Пример: -- t = {3,7,1,9,4}; вызов сортировки: t2 = sort_table_by_value(t, "") -- "key" - для случаев, когда value представляет собой таблицу, указывается название поля этой таблицы для сортировки по нему. Пример: -- t = {{a=3,b=7,c=1},{a=8,b=2,c=5}}; вызов сортировки: t2 = sort_table_by_value(t, "b") function sort_table_by_value(t, s) local function quick_sort(t, s, low, high) local i, j, x = low, high, t[math.floor((low+high)/2)] while (i <= j) do if s == "" then while (t[i] < x) do i = i + 1 end while (t[j] > x) do j = j - 1 end else while (t[i][s] < x[s]) do i = i + 1 end while (t[j][s] > x[s]) do j = j - 1 end end if (i <= j) then local temp = t[i] t[i] = t[j] t[j] = temp i, j = i + 1, j - 1 end end if (low < j) then quick_sort(t, s, low, j) end if (i < high) then quick_sort(t, s, i, high) end end s = s or "" if not t or type(t) ~= "table" then return nil, "sort_table_by_value: wrong source" end if type(s) ~= "string" then return nil, "sort_table_by_value: wrong sort parameter" end if t.__key then return nil, "sort_table_by_value: source table already has '__key' field" end local t1, t2, low, high = deepcopy(t), {}, 1, 0 for k,v in pairs(t1) do high = high + 1 v.__key = k table.insert(t2, v) end if high <= 1 then return t2, nil end quick_sort(t2, s, low, high) return t2, nil end -- Полное копирование переменной любого типа, включая таблицу, по значению function deepcopy(object) local lookup_table = {} local function _copy(object) if type(object) ~= "table" then return object elseif lookup_table[object] then return lookup_table[object] end local new_table = {} lookup_table[object] = new_table for index, value in pairs(object) do new_table[_copy(index)] = _copy(value) end return setmetatable(new_table, _copy(getmetatable(object))) end return _copy(object) end однако вопрос остался открытым: что и каким образом могло так подействать, что перестал работать встроенный метод? Может быть, он изначально не должен был работать - но ведь работал же. И ещё, раз у меня зашла речь об универсальном хранилище, хочу уточнить один момент. Возможно, в неявном виде он обсуждался здесь раньше, однако я об этом не знал; может быть, кому-нибудь тоже эта информация пригодится. Из se_stor вызываются методы расширения для таблиц clone, serialize и другие, описанные в m_helpers.script. Но в момент регистрации se_stor файл m_helpers.script ещё не обработан движком, поэтому вызов тех методов приводит к вылету. Чтобы этого не происходило, я добавил в функцию se_custom_storage:on_register() проверку на то, что m_helpers.script существует, после чего вылеты прекратились. Вот модифицированная функция регистрации: function se_custom_storage:on_register() cse_alife_dynamic_object.on_register(self) --/#+# загрузка: чтение tail-пакета в хранилище (из объекта хранения загруженного из сэйва) -- printf("se_custom_storage:on_register:ID=[%s]:sid=[%s]%s", self.id, self.m_story_id, "") --/#~# if self.m_story_id ~= 4294967296 then --/ элемент ext-modules tStorPks[self.m_story_id] = self.tail_pk --/ запоминаем нет-пакет для 'отложенного прочтения' alife():release(self,true) --/ clear (удаляем объект 'загруженный из сэйва') else --/ элемент общего хранилища? if not m_helpers then return end -- <-- добавил тут local sini = self:spawn_ini() if sini:section_exist("metka") then --/ элемент загружен из сэйва local build = (sini:line_exist("metka","d") and sini:r_s32("metka","d")) or nil --/метка-дата local f_nocompress = sini:line_exist("metka","s") --/ флаг несжатия данных read_tail_packet( self.tail_pk, tonumber(build), f_nocompress ) --/ чтение в общую таблицу db.storehouse alife():release(self,true) --/ clear (удаляем 'прочитанный' объект) else --/ создан новый элемент table.insert(tStorIDs,self.id) --/ запоминаем в списке IDs end end end Возможно, это решение не идеально, но какое есть. Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 26 Июня 2012 (изменено) Вампир35, можно попробовать в xml-конфиг окна с этими подсказками добавить элемент hint_wnd с атрибутом complex_mode="1". Примерно так: <w> <!-- остальное содержимое --> <hint_wnd x="0" y="0" width="210" height="100"> <background x="0" y="0" width="210" height="100" border="10"> <texture a="100">ui_temp_frame</texture> </background> <text x="20" y="20" width="190" height="100"> <text font="letterica16" color="ui_6" complex_mode="1" align="l" vert_align="t"/> </text> </hint_wnd> </w> А дальше пробовать "\n" и "\\n". Изменено 26 Июня 2012 пользователем Kirgudu Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 29 Июня 2012 (изменено) Возник очередной вопрос по универсальному хранилищу, в этот раз весьма насущный. Дело в том, что я столкнулся с пропаданием одного из custom_storage объектов при загрузке, соответственно, не загружается и его нет-пакет, что приводит к пропаже части сохраняемых данных. Причём до поры до времени всё в порядке, сохраняются и загружаются все данные, никаких ошибок нет. Я могу даже ничего не делать, просто стоять на одном месте и жать F5-F9 в цикле. Но в какой-то момент... Вот небольшая иллюстрация из лога сбойного цикла записи-загрузки. Тут записывается 7 custom_storage объектов, по которым оказались распределены данные из хранилища: ! Cannot find saved game ~:create_storage_element:id=[25778],sid=[9901]:cnt=[1]+ ! Cannot find saved game ~:create_storage_element:id=[25779],sid=[nil]:cnt=[2]+ ! Cannot find saved game ~:create_storage_element:id=[25780],sid=[nil]:cnt=[3]+ ! Cannot find saved game ~:create_storage_element:id=[25781],sid=[nil]:cnt=[4]+ ! Cannot find saved game ~:create_storage_element:id=[25782],sid=[nil]:cnt=[5]+ ! Cannot find saved game ~:create_storage_element:id=[25783],sid=[nil]:cnt=[6]+ ! Cannot find saved game ~:create_storage_element:id=[25784],sid=[nil]:cnt=[7]+ А тут читается только 6 таких объектов, седьмой (второй по id) пропущен. ! Cannot find saved game ~:se_custom_storage:on_register:id=[25778]:sid=[9901] ! Cannot find saved game ~:se_custom_storage:on_register:id=[25780]:sid=[4294967296] ! Cannot find saved game ~:se_custom_storage:on_register:id=[25781]:sid=[4294967296] ! Cannot find saved game ~:se_custom_storage:on_register:id=[25782]:sid=[4294967296] ! Cannot find saved game ~:se_custom_storage:on_register:id=[25783]:sid=[4294967296] ! Cannot find saved game ~:se_custom_storage:on_register:id=[25784]:sid=[4294967296] В чём может быть причина? Очень надеюсь, что кто-нибудь, кто "в теме", сможет мне помочь. К сожалению, автор используемого мной универсального хранилища, Artos, уже 2 недели не появляется на форуме. Изменено 29 Июня 2012 пользователем Kirgudu Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 23 Июля 2012 Непросто ответить в отрыве от применяемого контекста конкретного мода, тем более приведены логи только по созданию и чтению элементов хранилища. Честно говоря, меня несколько удивляет об'ем записи (6х8kB) и не является ли факт "пропажи" сбоем при записи некорректных данных. Даже не знаю, как показать контекст. Вот архив с модулями, в которые я внедрил хранилище (все файлы, которые к нему относятся) https://dl.dropbox.com/u/56394435/HWM/HWM_plus_store.7z Данные в хранилище пишутся в модулях ogsm_notepad.script, ogsm_rare_items_manager и ogsm_rt_manager, остальное - часть комплекта хранилища или его подключение. Но в отрыве от мода запустить их вряд ли получится, если только код посмотреть. Могу архивнуть и выложить мод целиком. Логи я привёл только как иллюстрацию пропажи объекта, а не для показа конкретной ошибки. Ошибки-то я как раз и не обнаружил, о чём ниже. Что же касается объёма записи, то ничего удивительного тут нет. Он, кстати, даже больше - 6x16kB, - ведь речь идёт о моде для CS. Просто в хранилище должны были сохраняться изменяемые данные статей экспериментального КПК - дата создания и изменения, статус, всяческие примечания, заметки игрока. Особенно заметки игрока, уж очень их игроки просили. Пока пришлось отказаться. Если такая ситуация возникает (с чем еще ни разу не сталкивался), то следует вывести в лог и строки собственно функции записи в создаваемые элементы, их очистки/удаления элементов хранилица, и их спавна при загрузке сэйва и анализировать. Это было первое, что я сделал. Поставил вывод в лог во всех возможных закоулках как в se_stor и m_helpers, так и в bind_stalker, а также в модулях, где использовал хранилище. Всё чисто, никаких ошибок, некорректных данных нет (я специально оптимизировал сохраняемые таблицы так, чтобы в них были только простые типы данных или, максимум, вложенные таблицы с простыми типами собственных данных). Потом, при сужении области поиска, как раз и обнаружил, что пропадает custom объект вместе со своим tail пакетом, причём именно при чтении, а при записи по всем фронтам вроде бы порядок... И уточни версию скриптов универсального хранилища, т.к. вполне может быть что используешь устаревшую. Комплект хранилища брал отсюда: http://www.amk-team.ru/forum/index.php?sho...st&p=695329 Внедрял в мод с небольшой модификацией, описанной здесь (в конце поста): http://www.amk-team.ru/forum/index.php?s=&...st&p=707932 На вопрос о прекращении табличной сортировки штатным методом, могу только сказать, что если в скриптах этот метод не затрагивается (а в m_helpers.script этого как раз нет), то причины изменения функционирования следует искать в ином месте. У меня и у других метод table.sort работает вполне корректно. Возможно используешь "странные таблицы", менял/добавлял динамические библиотеки (движек) или используешь какой-то лаунчер для запуска игры ... В скриптах метод не затрагивается, расширений движка не делалось, лаунчер не используется, но штатный метод больше не работает. Впрочем, вопрос этот больше риторический, так как написанная мной функция прекрасно взяла на себя обязанности штатного метода. Может, кому-нибудь она тоже пригодится. А что в Lua подразумевается под "странными таблицами"? Вложенные таблицы, индексы, отличные от последовательной нумерации, метатаблицы, что-то ещё? Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 23 Июля 2012 Shredder, да-да, точно такая сортировка, по одному из полей значений, и у меня перестала работать, но при этом без понятных (мне) внешних причин. В изначальном посте, где я про сортировку спрашивал, всё есть. И описание, и сама функция (с доп. функцией поддержки), и примеры использования. Вот здесь: http://www.amk-team.ru/forum/index.php?s=&...st&p=707932 Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 13 Ноября 2012 Viнt@rь, там проблема не с сохранением и последующим чтением имени доп. файла, а с тем, как определить это имя. Есть 2 категории сэйвов, для которых сделать это затруднительно - квиксэйвы пользователя и автосэйвы, которые происходят при переходе на другую локацию (после диалога "вы уверены, что хотите перейти?.."). Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 14 Ноября 2012 Artos, небольшая проблема всё-таки есть, так как при использовании эксклюзивных автогенерируемых имён для доп. файлов автосэйва и квиксэйва будет затруднительно передать кому-то нужный сэйв, да и, как совершенно справедливо было замечено, кол-во файлов будет расти очень быстро. Впрочем, действительно, раз нет решения, то и обсуждать нечего. Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 8 Сентября 2013 (изменено) @boryan67, просто в данном комплекте в модуле m_helpers.script не хватает реализации глобальной функции size пространства имён table.Добавь где-нибудь в модуле (например, в разделе expansion classes functionality) следующее: function fGetSizeTable(tTbl) if type(tTbl) == 'table' then --/ не таблица? if next(tTbl) then --/ не пустая? local iCnt = 0 for _,_ in pairs(tTbl) do iCnt = iCnt +1 end return iCnt --/> end else printf("fGetSizeTable:arg(%s)=[%s]~NOT_table:<%s>", type(tTbl), tTbl, "Warning!") end return 0 --/> end if not table.size then table.size = this.fGetSizeTable end Изменено 8 Сентября 2013 пользователем Kirgudu 2 Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 16 Мая 2014 Artos в октябре выкладывал этот комплект: m_netpk Потом почему-то удалил (не исключено, что из-за ошибок, но об этом ничего не известно). Тем не менее, это самая свежая версия, которая есть в наличии. 1 Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 10 Июля 2014 И вот здесь меня мучат сомнения: допустим, кровососы убиты в порядке 4,2,1,3, будет ли в таком случае k = 4? Разумеется. Поскольку в функции sosyci_proverka() нет преждевременных возвратов после каждой проверки, результат будет накапливаться. В итоге получишь правильную сумму вне зависимости от порядка. Вообще, это больше относится к азам программирования, чем к скриптам конкретно Сталкера. Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 18 Июля 2014 (изменено) function give_esc_art(first_speaker, second_speaker) if db.actor:object("af_vyvert") ~= nil then dialogs.relocate_item_section(second_speaker, "af_vyvert", "out") elseif db.actor:object("af_gravi") ~= nil then dialogs.relocate_item_section(second_speaker, "af_gravi", "out") else return end dialogs.relocate_money(second_speaker, 1500, "in") end Изменено 18 Июля 2014 пользователем Kirgudu Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 18 Июля 2014 local news_relocate_item -- вывод сообщения о потере/получении предмета Здесь стоит добавить для тех, кто не в теме, что news_relocate_item - функция или ссылка на функцию. Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 21 Июля 2014 @demon96, не надо её применять. Надо внутри этой функции сделать проверку, а тот ли это obj, что тебе нужен, и если тот - выдать инфопорцию. Чтобы не загромождать исходный код, лучше всего проверку и выдачу оформить как новую функцию, а здесь её вызвать, передав в качестве аргумента объект. Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 22 Августа 2014 , или так: function round(num, idx) local coeff = 10^(idx or 0) return math.floor(num*coeff+0.5)/coeff end где num - округляемое число, idx - порядковый номер знака после запятой, до которого следует округлить, включая 0 для округления до целого.Но если необходимо предусмотреть округление в том числе и до какого-либо старшего знака в целой части, тогда нужна доработка. 1 1 Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 6 Сентября 2014 (изменено) @Хемуль36рус, немного дополню ответ @naxac. Тут ещё важно, для какой версии игры тебе надо реализовать смену группировки. Подозреваю, что для ТЧ, но если для ЧН (а вдруг), необходимо ещё сделать цикл по всем заданиям, выданным не целевой группировкой (именно группировкой, а не отдельными НПС), и отменить их. Это, как правило, задания на захват точек, оборону и т. д. Изменено 6 Сентября 2014 пользователем Kirgudu 1 Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 8 Сентября 2014 @Хемуль36рус, не могу сейчас посмотреть, как в ТЧ, но в ЧН в модуле dialogs.script есть такая функция: function who_is_npc(first_speaker, second_speaker) local npc = second_speaker if db.actor:id() == npc:id() then npc = first_speaker end return npc end которая возвращает НПС при любом порядке подачи аргументов. Можно обратить условие и получить функцию возврата актора. В любом случае, используя эти функции, ты всегда будешь уверен в том, что применяешь последующие действия к нужному тебе объекту. Для твоего примера как-то так: function npc_set_killer(actor, npc) local npc = who_is_npc(actor, npc) printf("NPC [%s] NOW IN KILLER COMMUNITY", npc:name()) npc:set_character_community("killer", 0, 0) end Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 16 Октября 2014 @kalmah(13), судя по тому коду, который ты привёл, познания в языках программирования вообще и Lua в частности у тебя минимальные. В этих условиях обучение написанию скриптов с нуля становится слишком обширной задачей, на что тут вряд ли кто-то способен просто из-за недостатка свободного времени. Так что, имхо, пока надо самостоятельно разбирать примеры, запоминать, пробовать применить и т. д.Впрочем, если найдётся кто-то, кто сможет предложить тебе помощь в обучении - буду только рад. Если же говорить конкретно, тебе для начала следует запомнить базовые конструкции языка, такие как function ... end, if ... then ... end, if ... then ... else ... end, for ... do ... end и другие. В частности, в твоих функциях вида function dump_world_rain() if level.get_weather() == "sect_default_weather_rain" then get_console():execute("r2_gloss_factor 6") end ты функцию объявляешь, открываешь условие, что-то делаешь, затем закрываешь только условие - а функция остаётся открытой. В то время как в конце обязательно должен стоять ещё один end: function dump_world_rain() if level.get_weather() == "sect_default_weather_rain" then get_console():execute("r2_gloss_factor 6") end end иначе весь модуль будет невалидным. 1 Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 16 Октября 2014 @Barmolini, ... weathers[level.get_weather()] and weathers[level.get_weather()] or ... в этом есть какая-то великая сермяжная правда? 1 1 Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 10 Ноября 2014 (изменено) Для тех, кто пользуется модулем m_netpk от Artos.В прошлогодней (последней, выложенной автором здесь на форуме) версии модуля обнаружена и исправлена ошибка, которая приводила к вылету во время работы с абстрактной частью нет-пакета, а именно при срабатывании коллбэка, читающего абстрактную часть в момент её доступности.Кроме того, было уточнено название одного из флагов фонаря, но это на общую функциональность модуля не влияет. Ссылка на скачивание исправленной версии:https://yadi.sk/d/qVBvicSdQPHra За обнаружение ошибки и помощь в её исправлении спасибо @Charsi. Изменено 10 Ноября 2014 пользователем Kirgudu 3 4 Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 260 Опубликовано 12 Ноября 2014 Снова для тех, кто пользуется модулями от Artos. На этот раз под прицел попали: скрипт «Общие функции» (m_helper) от 28.09.2013 из этого поста; модуль «Универсальные таймеры» (m_timers) от 23.09.2013 из этого поста. В обоих модулях (в m_timers постольку, поскольку этот модуль содержит в себе m_helper) обнаружена и исправлена ошибка, приводившая к вылету при попытке определения типа патронов в стволе и режима стрельбы из подствольника. Какие-либо другие изменения авторского кода не производились. Ссылки на скачивание архивов с исправленной ошибкой: https://yadi.sk/d/HYBcS9iccfWMV - «Общие функции» https://yadi.sk/d/DPa6ZiGscfWeY - «Универсальные таймеры» 2 1 1 Инструмент Поделиться этим сообщением Ссылка на сообщение