Dennis_Chikin 3 658 Опубликовано 4 Января 2015 Поделиться Опубликовано 4 Января 2015 (изменено) С чего начинать и где взять. Установка Lua:http://www.amk-team.ru/forum/index.php?showtopic=11584&p=629106 Руководство «Программирование на языке Lua», третье издание:http://www.amk-team.ru/forum/index.php?showtopic=11584&p=905308 Изменено 2 Марта 2015 пользователем Kirgudu Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Nazgool 250 Опубликовано 17 Сентября 2012 Поделиться Опубликовано 17 Сентября 2012 (изменено) *Shoker* Неявная передача возможна при вызове метода, т.е. посредством двоеточия. При этом неявной переменной self будет соответствовать значение типа таблица или юзердата. В чистом lua это делается просто. В таблице _G всегда есть поля с загруженными модулями (файлами). Из этих полей можно "выдрать" название модуля. (если интересно, то могу показать) А вот в Сталкере...лень искать. Возможно есть что-то похожее на _M. Ну там this._NAME что-ли :-) Artos Но тут ведь школа...И тем более по lua. Так что есть смысл изучать серьёзнее. Изменено 17 Сентября 2012 пользователем Gun12 Ссылка на комментарий
Malandrinus 615 Опубликовано 17 Сентября 2012 Автор Поделиться Опубликовано 17 Сентября 2012 Shoker А в Lua случаем нету возможности неявно передать в функцию название скрипта, откуда она была вызвана? Вопрос задан неоднозначно. Из скрипта ничего не вызывается, вызывается из функции. Поэтому непонятно, что такое "скрипт, откуда вызвана функция". Ты имеешь в виду файл, где находится функция, или имеешь в виду именно функцию, откуда вызвана текущая? Если нужен файл, содержащий данную функцию, то в сталкере имеется функция script_name(), которая возвращает имя текущего файла без расширения. Если же нужно имя вызвавшей функции, то это в общем случае может быть не выполнимо, поскольку у функции может и не быть имени вообще, как например в случае, если вызов был прямо из движка, или функция была определена только своим телом без имени или вообще была скомпилена на лету с использованием loadstring. Если уж совсем надо, то нужны отладочные возможности из debug, как советовал Artos. Однако использовать отладочные возможности в неотладочных целях - порочная практика: ненадёжно, ресурсоёмко, делает код малопереносимым и малопонятным. Типичный пример индусского подхода. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
Desertir 202 Опубликовано 18 Сентября 2012 Поделиться Опубликовано 18 Сентября 2012 Пожалуйста, обновите ссылку на скрипты из этого поста или дайте новую. malandrinus, пытался отправить тебе ЛС, не вышло, ящик забит? ТЧ 1.0004. SAP и Trans mod github Ссылка на комментарий
7.9 174 Опубликовано 18 Сентября 2012 Поделиться Опубликовано 18 Сентября 2012 (изменено) А вот для нетпектов "простых обёрток для управления параметрами объектов в процедурно-ориентированном стиле", что-то до сих пор и нету... И вообще!.. Изменено 18 Сентября 2012 пользователем 7.9 всё легко Ссылка на комментарий
Shredder 49 Опубликовано 18 Сентября 2012 Поделиться Опубликовано 18 Сентября 2012 Есть ли в Lua возможность пропустить шаг в цикле? Приведу пример из php foreach ($array as $k => $v ) { ... if (...) { continue // код ниже не будет выполнятся для текущей пары k,v } ... } Надеюсь, понятно объяснил Ссылка на комментарий
ColR_iT 171 Опубликовано 18 Сентября 2012 Поделиться Опубликовано 18 Сентября 2012 (изменено) Shredder, конкретного оператора нет, но это можно с имитировать. for i=1, 3 do if i ~= 2 then print (i) end end Результат понятен - пропускается цикл со значением счётчика равному двум. Конечно, это далеко не универсальный вариант, но он работает. Изменено 18 Сентября 2012 пользователем ColR_iT Ссылка на комментарий
Shredder 49 Опубликовано 18 Сентября 2012 Поделиться Опубликовано 18 Сентября 2012 Да это понятно. Только как раз наличие такого оператора дало бы возможность уменьшить вложенность, как ранний return в функции. Эх, жаль конечно. Я тут недавно наткнулся на интересный вариант итерации таблиц table.foreach(table, function(k,v) ... end). Если пользоваться таким способом, то тут ранний return решает проблему вложенности. А вот как со скоростью по сравнению с pairs (ipairs)? Есть ли какие-нибудь подводные камни? Ссылка на комментарий
ColR_iT 171 Опубликовано 18 Сентября 2012 Поделиться Опубликовано 18 Сентября 2012 (изменено) Shredder Дык, а table.foreach ничем не отличается от того же итератора pairs. Для foreach передается два параметра: первый таблица, второй - функция, в функцию же автоматом передаётся два значения: ключ и значение этого ключа. И так происходит для всей таблицы, т.е. в функцию передаётся поочерёдно все ключи указанной таблицы. Абсолютно тоже самое происходит и с конструкцией вида: for key, value pairs(table) do -- здесь по сути тело функции, которая передавалась вторым параметром для foreach. end Всё также пробегаемся по всем ключам таблицы и если ничего не вернули (отсутствует оператор break), то перебирать будем всю таблицу. P.S. А к стати table.foreach в игре осталась? Вроде как её и table.foreachi нет с какой-то версии lua. Сейчас глянул в 5.0 ещё были, в 5.1 уже исключили из стандартного набора. В игре какая версия используется? Ещё заглянул в _G в 1.0006. Там функция foreach ещё есть. Но в любом случае - не вижу смысла её использовать... Изменено 18 Сентября 2012 пользователем ColR_iT Ссылка на комментарий
Shredder 49 Опубликовано 18 Сентября 2012 Поделиться Опубликовано 18 Сентября 2012 (изменено) В ЗП эта функция есть, и раз нет ничего такого, чтобы мешало её использовать, отныне буду все итерации таблиц делать с её применением, чтобы код выглядел более читабельным. Дабы не разводить чат в теме пишу в твоём же посте (эх, служебное положение). Не соглашусь с тем, что функция итератор foreach выглядит более читабельно нежели pairs. Но, раз тебе нравится - пожалуйста, никто собственно и не возражает... ColR_iT Изменено 18 Сентября 2012 пользователем ColR_iT Ссылка на комментарий
Nazgool 250 Опубликовано 18 Сентября 2012 Поделиться Опубликовано 18 Сентября 2012 (изменено) В lua таблицы построены настолько правильно, что скорость их обработки, естественно при использовании стандартных методов, так велика, что не имеет решающего значения. Ну если бы я был автором этого языка, то неужели написал бы на С заведомо медленную функцию? В среднем foreach и pairs работают одинаково быстро. Остальное зависит от... платформы, процессора.. и Бог его знает чего ещё. Например у меня foreach работает на пару десятых(сотых) долей секунды быстрее (при десятимилионном цикле). Тем не менее логичнее и понятнее, для меня, использовать pairs. Но тут уж каждому своё. Изменено 18 Сентября 2012 пользователем Gun12 1 Ссылка на комментарий
Artos 99 Опубликовано 18 Сентября 2012 Поделиться Опубликовано 18 Сентября 2012 (изменено) Кину и свои 5 копеек ;-) Не знаю где нашли ColR_iT и Shredder в кодах игры применение table.foreach иль table.foreachi, но в оригинальных кодах их нет ни в какой версии релизов ТЧ/ЧН/ЗП и ни в каком патче ТЧ. Если создатели Lua при обновлении версии -> 5.1 и далее посчитали нужным изъять (заменить) данные методы, то наверное не из косметических соображений. И на вкус и цвет конечно же товарисЧей нет, но читабельность кода зависит и от того, 'знакомы' ли встречающиеся по тексту функции/методы иль это экзотика. Если основная масса скриптов в приложении постоена на использовании (i)pairs, то врядли повысится читабельность от навязывания устаревших foreach(i). Каждый язык имеет свой синтаксис и свою "читабельность", и попытки читать/писать как на другом, привычном кому-то языке - это просто напросто субъективизм. Изменено 18 Сентября 2012 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
Nazgool 250 Опубликовано 18 Сентября 2012 Поделиться Опубликовано 18 Сентября 2012 (изменено) 7.9 Согласен. Например меня, занимаясь wxLua, всегда напрягала необходимость обязательного указания всех необходимых аргументов (а их список может быть не самый короткий). И кроме всего того - в определённом порядке. Когда мне это всё надоело, я и создал обёртку с использованием ООП для классов wxLua. Теперь красота. Вызвал конструктор с необходимым(и) полем(и)-параметром(и), а остальные добавляются автоматом. Изменено 18 Сентября 2012 пользователем Gun12 Ссылка на комментарий
Malandrinus 615 Опубликовано 18 Сентября 2012 Автор Поделиться Опубликовано 18 Сентября 2012 (изменено) Shredder, Есть ли в Lua возможность пропустить шаг в цикле? В версии 5.2 добавили goto, который решает эту задачу. Ну а в сталкере придётся извращаться. К примеру так (не претендую на оптимальность, просто как вариант): for i = 1,7 do (function() -- ... if i == 3 then return end -- ... end)() end Данный вариант более-менее имитирует семантику continue в том смысле, что так можно сделать проверку на выход именно внутри, в точке выхода. Присутствуют накладные расходы на вызов функции (только вызов, компиляция происходит один раз), что в зависимости от ситуации может и не быть критично. Изменено 18 Сентября 2012 пользователем malandrinus Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
Shredder 49 Опубликовано 19 Сентября 2012 Поделиться Опубликовано 19 Сентября 2012 Приведу пример, что для меня значит "читабельность" кода. Фрагмент из treasure_manager.script (ТЧ) for k,v in pairs(self.treasure_info) do if v.done == false then local treasure_prob = xr_logic.pick_section_from_condlist(db.actor, npc, v.condlist) if treasure_prob == "" or treasure_prob == nil then treasure_prob = 0 end if tonumber(treasure_prob) >= 0 and v.community[npc:character_community()] == true and v.active == false then if tonumber(treasure_prob) == 100 then self:give_treasure(k) else table.insert(avail, {k = k, prob = treasure_prob}) tr_sum = tr_sum + treasure_prob end end end end table.foreach(self.treasure_info, function(k,v) if v.done then return end local treasure_prob = xr_logic.pick_section_from_condlist(db.actor, npc, v.condlist) if treasure_prob == "" or treasure_prob == nil then treasure_prob = 0 end if tonumber(treasure_prob) == 0 or not v.community[npc:character_community()] or v.active then return end if tonumber(treasure_prob) == 100 then self:give_treasure(k) else table.insert(avail, {k = k, prob = treasure_prob}) tr_sum = tr_sum + treasure_prob end end) P.S. Использование функции table.foreach случайно обнаружил в файле .script распакованной геймдаты ТЧ Ссылка на комментарий
Artos 99 Опубликовано 19 Сентября 2012 Поделиться Опубликовано 19 Сентября 2012 Приведу пример, в котором может быть "читабельность" кого-то не устраивает, но с точки зрения корректности и оптимальности - повыше чем приведенные выше варианты: for name,v in pairs(self.treasures) do if not (v.done and v.active) and v.community[npc:character_community()] then local treasure_prob = tonumber(xr_logic.pick_section_from_condlist(db.actor, npc, v.cond)) or 0 if treasure_prob > 0 then --/ тайник может быть выдан if treasure_prob < 100 then --/ заносим в таблицу возможных для выдачи table.insert(avail, {k=name, prob=treasure_prob}) tr_sum = tr_sum + treasure_prob else --/ безусловная выдача тайника self:give_treasure(name, npc) return --/> выходим из функции, т.к. выдаем только один раз! end end end end - примечание: код может быть еще немного оптимизирован, но это уже на любителя и конкретика для модов. Немного об оригинальном и "читабельном" вариантах: 1. if treasure_prob == "" or treasure_prob == nil then - не кажется странным, вначале сравнивать переменную со строкою, а уж затем проверять на 'nil'? Логика и безопасность диктуют иной порядок... 2. Оперировать с tonumber(treasure_prob), а в таблицу 'avail' заносить без преобразования. Уж или-или, т.е. если допускать что treasure_prob может не быть числом - то зачем же в дальнейшем для 'нечисла' допускать выполнение подобного: tr_sum = tr_sum + treasure_prob? Ведь очевидно же что будет ошибка в математике! 3. При 100%-ой вероятности - выдавать тайник ( self:give_treasure(k) ) и продолжать итерацию и дальнейшие проверки? Как будто с одного непися может быть получено более одного тайника?! Ну и можно о других мелочах поговорить и посетовать, но и этого достаточно, чтобы не стОль на читабельность обращать внимание, как больше внимания уделять корректности и оптимальности кода. ИМХО "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
Shredder 49 Опубликовано 19 Сентября 2012 Поделиться Опубликовано 19 Сентября 2012 (изменено) Как раз в приведённых мною примерах я вообще не уделил внимание корректности и оптимальности, а только показал, как с помощью table.foreach можно избавиться от вложенности. Что конкретно происходит внутри цикла - я даже не вникал. Так что по пунктам 1,2 и 3 - это к GSC Изменено 19 Сентября 2012 пользователем ColR_iT Ссылка на комментарий
ColR_iT 171 Опубликовано 19 Сентября 2012 Поделиться Опубликовано 19 Сентября 2012 (изменено) Ложка дёгтя в бочку мёда... Попытался вычислить время работы обоих итераторов в игре (ТЧ 1.0006 + X-Ray extension), вот результаты работы: tbl = { ["a"] = 1, ["b"] = 2, ["c"] = 3, ["d"] = 4, ["e"] = 5, } tbl2 = {} tbl3 = {} local timer = profile_timer() timer:start() for i = 1, 1000000 do for k,v in pairs(tbl) do if k~="b" then tbl2.k = v end end end timer:stop() log1("##Time is "..timer:time()) --# 0.6806496875 sec timer:start() for i = 1, 1000000 do table.foreach (tbl, function (k,v) if k == "b" then return end tbl3.k = v end) end timer:stop() log1("##Time is "..timer:time()) --# 1.581734375 sec Как видно pairs выигрывает более чем в два раза. P.S. Поправил результаты. profile_timer считает время в микросекундах, а я делил результат на 105. Изменено 19 Сентября 2012 пользователем ColR_iT Ссылка на комментарий
Shredder 49 Опубликовано 19 Сентября 2012 Поделиться Опубликовано 19 Сентября 2012 Проверил для ЗП 1.6.2 + X-Ray extension, результаты: pairs: 0.162835 sec foreach: 0.698536 sec Достаточно убедительный довод, чтобы впредь не использовать foreach. Жаль конечно Ссылка на комментарий
ColR_iT 171 Опубликовано 19 Сентября 2012 Поделиться Опубликовано 19 Сентября 2012 Эх, будет мне наукою... Как оказалось метод start() класса profile_timer не обнуляет значение, а продолжает считать. Вот ПРАВИЛЬНЫЕ результаты эксперимента: --#------------------------------------------------------------ tbl = { ["a"] = 1, ["b"] = 2, ["c"] = 3, ["d"] = 4, ["e"] = 5, } tbl2 = {} tbl3 = {} tbl4 = {} --#------------------------------------------------------------ local timer1 = profile_timer() timer1:start() for i = 1, 1000000 do for k,v in pairs(tbl) do if k~="b" then tbl2.k = v end end end timer1:stop() log1("##Time is "..timer1:time()) --# 0.684159375 sec --#------------------------------------------------------------ local timer2 = profile_timer() timer2:start() for i = 1, 1000000 do table.foreach (tbl, function (k,v) if k == "b" then return end tbl3.k = v end) end timer2:stop() log1("##Time is "..timer2:time()) --# 0.9012660625 sec --#------------------------------------------------------------ local function f(k,v) if k == "b" then return end tbl4.k = v end local timer3 = profile_timer() timer3:start() for i = 1, 1000000 do table.foreach (tbl, f) end timer3:stop() log1("##Time is "..timer3:time()) --# 0.7032258125 sec --#------------------------------------------------------------ И как видно, в эксперименте появился третий вариант (спасибо Charsi). Результаты на лицо. Так что Shredder - приношу свои извинения за дезинформацию. Ссылка на комментарий
Shredder 49 Опубликовано 19 Сентября 2012 Поделиться Опубликовано 19 Сентября 2012 (изменено) Когда я первый раз запускал эксперимент, то подумал об этом, и создавал три разных "счётчика", поэтому у меня результаты не изменились: ##time is 162232.109375 ##time is 731144.5 ##time is 566500.8125 PS: Результаты сильно разнятся, интересно, с чем это связано? У меня процессор Intel Core Duo T8100 2.10Ghz. А может из-за версии игры? Изменено 19 Сентября 2012 пользователем Shredder Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти