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 Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Карлан 1 049 Опубликовано 6 Мая 2015 Поделиться Опубликовано 6 Мая 2015 @Nazgool, прочитал, понял, но времени пока нет самому применить и посмотреть, поэтому и не отвечаю. Ссылка на комментарий
Xdlic 9 Опубликовано 6 Мая 2015 Поделиться Опубликовано 6 Мая 2015 (изменено) Внезапно рухнула сеть, поэтому не отписывался.Описание теста: платформа ТЧ 1.0006(топология), встроено расширение луа от артоса(by RvP), вернул родной xrLua - результаты теста теже. (Заодно проверил на 4 патче(+от солянки) с чистой геймдатой) - также вставляет не в 1ю позицию.) local tt = {1,2,3,4,5,6,7,8,9,10,11} -- таблица local s my_print_table("начинаем тест", tt) table.insert(tt, "test1") -- первое обращение к таблице, счетчик создан for i = 1, #tt do tt[i] = nil end -- удалили поля -- table.remove(tt, 1) my_print_table("пустая таблица", tt) -- видим пустую таблицу table.insert(tt, "test2") -- вставили поля, у меня они встают в 11, 12 ячейке соотв. table.insert(tt, "test22") -- table.remove(tt, 1) my_print_table("добавили 2 поля", tt) table.insert(tt, "test3") table.remove(tt, 1) my_print_table("еще одно поле, сместили все поля", tt) -- все поля встают где-то в районе 9-14 индекса table.remove(tt, 1) my_print_table("еще сместили все поля", tt) -- for i = 5, 11 do tt[i] = i end table.remove(tt, 1) table.remove(tt, 1) my_print_table("fase 7", tt) -- for i = 1, 11 do tt[i] = nil end -- for i = 1, 11 do tt[i] = i end table.insert(tt, 4, "index") -- table.insert(tt, "index2") my_print_table("добавляем поле в середину таблицы, конец теста", tt)Функция вывода таблицыfunction my_print_table(text, tt) qqq(text) s = "parse tt= " for i = 1, 20 do s = s..string.format("[%i]=%s, ", i, tostring(tt[i])) end qqq(s) end Урезанный лог, удалил nil-ы до интересующих ячеек и после начинаем тест parse tt= [1]=1, [2]=2, [3]=3, [4]=4, [5]=5, [6]=6, [7]=7, [8]=8, [9]=9, [10]=10, [11]=11, [12]=nil пустая таблица parse tt= [9]=nil, [10]=nil, [11]=nil, [12]=nil, [13]=nil, [14]=nil, добавили 2 поля parse tt= [9]=nil, [10]=nil, [11]=nil, [12]=nil, [13]=test2, [14]=test22, еще одно поле, сместили все поля parse tt= [9]=nil, [10]=nil, [11]=nil, [12]=test2, [13]=test22, [14]=test3, еще сместили все поля parse tt= [9]=nil, [10]=nil, [11]=test2, [12]=test22, [13]=test3, [14]=nil, fase 7 parse tt= [9]=test2, [10]=test22, [11]=test3, [12]=nil, [13]=nil, [14]=nil, добавляем поле в середину таблицы, конец теста parse tt= [4]=index, [5]=nil, [6]=nil, [7]=nil, [8]=nil, [9]=nil, [10]=test2, [11]=test22, [12]=test3 test_4 started from 11311.940429688 Как видим - или у меня такой особый сталкер, или повторные table.insert/remove напрочь игнорируют изменения таблицы. Напоминаю - таблица была занилена после первого их использования. как это игнорируют? Нормально они работают, в т.ч. и на 6 патче, все обновляется, и оператор, и значения. Возможно я не так выразился, имеется ввиду, что позиция по умолчанию для table.insert/remove в сталкере не обновляется, если ранее они были вызваны для заполненной индексом таблицы. Т.е. берем массив, что-то делаем с ним через вставку/удаление, разрушаем массив nil-ми.. следующие вставки/удаления проходят по старой позиции, хотя перед ней может быть и 100500 пустых. Фактически, я не вижу в своем тесте, чтобы каждая новая вставка/удаление учитывали текущую длину массива. Изменено 6 Мая 2015 пользователем Xdlic Ссылка на комментарий
Charsi 440 Опубликовано 7 Мая 2015 Поделиться Опубликовано 7 Мая 2015 При работе с таблицей следует придерживаться одного из двух стилей: - только как с обычным массивом, используя table.insert\remove и т.д. - только как с ассоциативным массивом, используя оператор индексации. Смешивать их не стоит. В SciTE с Lua 5.1 проблемы нет. А современный Lua - версии 5.3 - ругается на вставку элемента с помощью table.insert за пределы границ - bad argument #2 to 'insert' (position out of bounds). Lua и LuaJIT плагины для Notepad++ SciTE-RU 3.5.5 плагины для MilkShape3D Ссылка на комментарий
Nazgool 250 Опубликовано 7 Мая 2015 Поделиться Опубликовано 7 Мая 2015 (изменено) @Xdlic, Да, иногда в сталкере стандартные действия Lua ведут себя совсем не так. Когда то меня чуть не предали анафеме за мои высказывания в сторону ненормальности сталкеровского Lua. Но уже который раз это подтверждается Что там сделали с Lua я не знаю, но ... Значение "nil" хоть и обозначает отсутствие значения, всё-таки это одно из значений Lua, в отличии от отсутствия вообще какого-либо значения. Возьми к примеру функции : function f() return end и function f() return nil end Первая не возвращает ничего, а вторая возвращает значение. nil ведь тоже значение. Видимо в сталкере разрабы как-то акцентировали на этом внимание, поэтому такие результаты. В любом случае этот вопрос решается просто. Ты используешь : for i = 1, #tt do tt[i] = nil end На самом деле ты присваиваешь полям значения (nil). А нужно удалять поля : for i = #tt, 1, -1 do table.remove(tt, i) end Изменено 7 Мая 2015 пользователем Nazgool 2 Ссылка на комментарий
_Призрак_ 11 Опубликовано 7 Мая 2015 Поделиться Опубликовано 7 Мая 2015 Значение "nil" хоть и обозначает отсутствие значения, всё-таки это одно из значений Lua, в отличии от отсутствия вообще какого-либо значения. Прости? Очень интересно высказывание, почему ты так решил? Freedom Ссылка на комментарий
Nazgool 250 Опубликовано 7 Мая 2015 Поделиться Опубликовано 7 Мая 2015 (изменено) @_Призрак_, function f() return end print(f()) --> ничего print(type(f())) --> bad argument #1 to 'type' (value expected) т.е. Lua значения нет function f() return nil end print(f()) --> nil print(type(f())) --> nil -- а тут значение есть. nil ведь одно из 8-ми значений Lua Изменено 7 Мая 2015 пользователем Nazgool Ссылка на комментарий
Xdlic 9 Опубликовано 7 Мая 2015 Поделиться Опубликовано 7 Мая 2015 (изменено) А нужно удалять поля Давайте оставим этот момент в стороне. По отношению к индексным массива в сталкере вообще никак иначе обращаться категорически не рекомендую(как раз из за необновляющегося счетчика). Собственно я отправил свое сообщение с мыслью, что получается в движке сталкера функции добавки/удаления реагируют на изменения таблицы совсем не так, как функция #t. Вопрос имел целью узнать, как влиять на выбор текущей позиции в этих самых table.insert/remove. Если, допустим, сделать простую обертку, которая предварительно будет определять конец индексного массива, то сами эти функции будут обрабатывать перестановку nil из одной ячейки в другую до сгенерировавшегося при первом вызове внутри них счетчика. Это конечно не особо сказывается на производительности, но сам факт имеет место быть. Пример обертки, которая корректирует значение позиции текущего конца индекса function insert_two(tab, pos_or_val, val) if val then table.insert(tab, pos_or_val, val) else table.insert(tab, #tab+1, val) end end Но это не отменяет того факта, что выйдя за пределы первоначального диапазона мы получим результат, когда начало таблицы наползает на ее конец Изменено 7 Мая 2015 пользователем Xdlic Ссылка на комментарий
Nazgool 250 Опубликовано 7 Мая 2015 Поделиться Опубликовано 7 Мая 2015 (изменено) @Xdlic, Зачем обертка? Вставлять стандартным способом, только принудительно указывать место вставки table.insert(tt, #tt+1, "value") #tt как раз и определит длину массива, а +1 поставит значение в конец. А если делать обертку, то так, чтобы не навредить вызовам table.insert в других скриптах do local old_insert = table.insert function table.insert(t,p,v) old_insert(t, v and p or #t+1, v or p) end end Изменено 7 Мая 2015 пользователем Nazgool Ссылка на комментарий
abramcumner 1 146 Опубликовано 7 Мая 2015 Поделиться Опубликовано 7 Мая 2015 Собственно я отправил свое сообщение с мыслью, что получается в движке сталкера функции добавки/удаления реагируют на изменения таблицы совсем не так, как функция #t.А почему они должны реагировать так же, как #t? Ссылка на комментарий
Xdlic 9 Опубликовано 7 Мая 2015 Поделиться Опубликовано 7 Мая 2015 (изменено) А почему они должны реагировать так же, как #t? Хотя бы затем, что имено если бы они реагировали также как #t, то это позволяло бы работать в сталкере с концом строки по упрощенному варианту t[#t+1] = val и t[#t] = nil вместо вызовов функций. В чистом луа как раз это и работает. Никто не исследовал вопрос, где хранятся эти созданные счетчики? В недоступной части таблиц или где-то внутри движка Lua/Сталкера? Upd: insert работает абсолютно так же. Не также, в сталкере инсерт обрабатывают таблицу ровно до той позиции, которая хранится в счетчике, который кроме как в этих двух функциях, нигде недоступен. Ну хорошо, раз в сталкере нельзя работать с индексами по упрощенному варианту, значит будем каждый раз вызывать соответстующие функции... а если одновременно нужно этими инсертами забить 100500 значений в таблицу, которые заранее нельзя задать? Мы получим ощутимый нагруз от этих 100500 вызовов функции table.insert(ну ладно, пусть еще можно ссылку хранить локально). Или в этом случае полностью придется отказаться от индексных массивов и получать случайный перебор элементов из pairs(). Upd2: И да, смысла в предложенной обертке меньше, чем 0. Чтобы она работала, нужно в ней получать доступ к счетчику и вручную его менять. Upd3: Внезапно работает. Видимо я и вправду не умеею внятно изъяснять свои мысли/идеи. Твой вариант уже не будет работать совместно с table.insert/remove. Стоит их один раз вызвать и счетчик перестает зависеть от структуры таблицы. Про индексный массив с 100500 строк, тогда уж проще сделать обертку не вокруг самих функций, а вокруг метода. Т.е. реализуем свои table.insert_new/remove_new function table_insert_new(t, pos_or_val, val) local end_pos = #t if val then if pos_or_val < end_pos then for i = end_pos, pos_or_val, -1 do t[i] = t[i-1] end else t[pos_or_val] = val end else t[end_pos+1] = val end end И подобное для remove, вроде алгоритм правильно описал В результате не будет этого статического счетчика позиции для добавления/удаления, который я вижу в сталкере. А самое главное - можно будет спокойно работать как с t[#t+1] = val, так и с новой версией вставки значений в СЕРЕДИНУ индексного массива. Изменено 7 Мая 2015 пользователем Xdlic Ссылка на комментарий
Карлан 1 049 Опубликовано 7 Мая 2015 Поделиться Опубликовано 7 Мая 2015 (изменено) @Xdlic, воистину ты занимаешься фигней, insert вставляет значение в nil или в конец, а #t получает количество элементов в таблице тоже по своим условиям, в зависимости есть nil в конце или нет, в итоге мы видим что твоя обертка вообще не несет никакой смысловой нагрузки, если на конце будет nil, то твоя обертка вставит значение вместо первого попавшегося nil, insert работает абсолютно так же. это позволяло бы работать в сталкере с концом строки по упрощенному варианту t[#t+1] = val и t[#t] = nil вместо вызовов функций Внезапно работает. local a = {}a[#a+1] = 1log(a[1]) нигде недоступен можешь рубить последний элемент, потом работать, потом его назад вставлять. я у себя с этим боролся с помощью pairs, вполне нормально выглядит. Изменено 7 Мая 2015 пользователем Карлан Ссылка на комментарий
Xdlic 9 Опубликовано 7 Мая 2015 Поделиться Опубликовано 7 Мая 2015 @Xdlic, воистину ты занимаешься фигней. Будет время - посмотрю, что там внутри этих таблиц, вдруг счетчик хранится в метаданных самой таблицы. Ладно, оставим в покое этот болезненный вопрос урезанного сталкерского Lua, интересно, какие еще особенности языка ПЫСы сумели сломать к релизу? Ссылка на комментарий
abramcumner 1 146 Опубликовано 7 Мая 2015 Поделиться Опубликовано 7 Мая 2015 Хотя бы затем, что имено если бы они реагировали также как #t, то это позволяло бы работать в сталкере с концом строки по упрощенному варианту t[#t+1] = val и t[#t] = nil вместо вызовов функций.Ну и работай так сейчас. Что мешает? В чистом луа как раз это и работает.Что такое чистое луа? @Xdlic, попробуй для получения "внутреннего счетчика" использовать table.getn(t). 1 Ссылка на комментарий
Xdlic 9 Опубликовано 8 Мая 2015 Поделиться Опубликовано 8 Мая 2015 попробуй для получения "внутреннего счетчика" использовать table.getn(t). Не обратил ранее на эту функцию внимания, считая ее аналогичной #. Проверил заодно и table.setn - да, эти функции как раз и позволяют получать и задавать "счетчик" с которым работают функции вставки/удаления. Можно ручками забивать строки через t[#t+1] = val, а затем обновлять его table.setn(t, #t) и стандартные insert/remove будут "видеть", что с таблицей что-то случилось .. и соответственно будут обрабатывать также и новые данные. Но... зачем-то их ведь удалили из стандартного набора Lua-функций. В SciTe-ru пишет: 'setn' is obsolete. P.S. Споры о том, можно ли так делать или это "моветон" пропущу мимо ушей. Ссылка на комментарий
abramcumner 1 146 Опубликовано 8 Мая 2015 Поделиться Опубликовано 8 Мая 2015 Но... зачем-то их ведь удалили из стандартного набора Lua-функций. В SciTe-ru пишет: 'setn' is obsolete.Потому что table.insert/remove стали работать через #t. Но оператор решетка не всегда был в Луа. Ссылка на комментарий
Xdlic 9 Опубликовано 12 Июня 2015 Поделиться Опубликовано 12 Июня 2015 Столкнулся с необходимостью сравнить две переменные типа userdata (копаю gui классы из луа и там возникла в этом потребность) . Но меня ждал Великий Облом в виде ошибки: LUA error: No such operator definedВ начале вылетел при проверке на неравенство, потом та же ошибка и при проверке на равенство... Выдержка из руководства: "...и не имеет предопределенных операций в Lua, за исключением присваивания и проверки на равенство." Вот так, в иных сборках это ошибки не вызывает, а в сталкере похоже метаметода сравнения двух объектов нет. По крайней мере rawequal выдает вменяемые данные, придется или пользоваться им или делать сравнение по меткам. Ссылка на комментарий
RayTwitty 492 Опубликовано 16 Июня 2015 Поделиться Опубликовано 16 Июня 2015 (изменено) Столкнулся с необходимостью сравнить две переменные типа userdataВ сталкере юзердаты так нельзя сравнивать. копаю gui классы из луа и там возникла в этом потребностьНе уверен, что именно это тебе нужно, но попробуй нечто вроде tostring(CUIStatic) == tostring(CUIStatic). Изменено 16 Июня 2015 пользователем Shadows Ссылка на комментарий
Nazgool 250 Опубликовано 17 Июня 2015 Поделиться Опубликовано 17 Июня 2015 (изменено) @Xdlic, Действительно, стандартное сравнение пользовательских данных в сталкере не работает. Но это легко изменить, используя расширение lua. Прежде всего стоит определить утверждения, касающиеся lua в игре, которые и помогут в решении. 1. Для типа 'userdata' установлена единая метатаблица. P.S. Категорично утверждать не буду, не все проверял, но например для UI окон и для Волка она едина. Это позволяет предположить, что если для таких различных объектов метатаблица едина, то она едина и для всех остальных. 2. Метаметод '__eq' вызывается только при сравнении двух юзердат (тот, что не работает). Сравнение 'userdata' == 'другой тип данных' обрабатывается обычным образом. 3. Поскольку при сравнении двух типов 'userdata' вызывается метаметод '__eq', то результат сравнения нужно произвести без вызова метаметода. Функция 'rawequal' именно это и делает. Отсюда следует, что можно переопределить метаметод '__eq', даже не сохраняя ссылку на прежний, т.к. этот метод больше ни для чего не нужен, и ничего не затрагивает. local userdata_mt = debug.getmetatable(CUIStatic()) function userdata_mt.__eq (a, return rawequal(a, end Вместо "CUIStatic()" можно использовать любое получение 'userdata'. Ну и наконец вызов этого кода необходимо поставить на 'net_spawn', т.к. после каждой загрузки новые данные поля 'userdata_mt.__eq' будут зачищаться. Изменено 17 Июня 2015 пользователем Nazgool Ссылка на комментарий
Xdlic 9 Опубликовано 18 Июня 2015 Поделиться Опубликовано 18 Июня 2015 (изменено) Отсюда следует, что можно переопределить метаметод '__eq', даже не сохраняя ссылку на прежний, т.к. этот метод больше ни для чего не нужен, и ничего не затрагивает. В результате код станет зависимым от этой правки. Метаметоды - неизбежное зло, и от важности их применения они не становятся менее злыми. В Lua нет инлайна, а следовательно каждая новая функция-обертка это неоправданное увеличение накладных расходов на один шаг алгоритма. Взять те же классы - это просто ужас, индексация к внутренним переменным класса на порядок медленнее, чем к глобальным переменным/табличным индексам. И основная доля этой издержки лежит на инициализации вызова метаметода взятия индекса. Lua 9/10 времени занимается передачей управления внутрь метаметода и 1/10 - подстановка значения в выражение. Скажу одно - создание в сталкере классов "что было объектно-ориентированым" неразумно. К примеру тот же менеджер событий OGSE - получение экземляра обернуто в дополнительную функцию.. лишь для того, чтобы не плодить новые экземпляры. Ну так сделали бы на базе таблицы: интерфейс "как у класса", а что таблица - все равно в обертку завернуто. Классы здесь, как чесать правое ухо левой пяткой. Повторюсь, без мало-мальской реализации автоподстановки кода классы еще хуже создания пользовательских метаметодов - производительность работы с данными падает в десятки раз. Меня окончательно добило, когда. цикл обхода значений внутри класса по производительности оказался в 50-60 раз медленнее, чем из глобальной таблицы. Проще взять за практику сравнивать юзердаты raw'вом, чем что-то прикручивать на локальном уровне. Оба поста скорее констатация факта, но разумная критика приветствуется. И да, сравнение юзердат оказалось несколько излишним. При достаточной синхронизации учасков кода оно совершенно не нужно. Upd пропустил пост Не уверен, что именно это тебе нужно, но попробуй нечто вроде tostring(CUIStatic) == tostring(CUIStatic). И будет внутридвижковое нефатальное исключение, по просту зависнет. У меня tostring nil'ы жрет, а юзердатами давится Изменено 18 Июня 2015 пользователем Xdlic 1 Ссылка на комментарий
Nazgool 250 Опубликовано 18 Июня 2015 Поделиться Опубликовано 18 Июня 2015 (изменено) @Xdlic, Вы наверное не полностью поняли о чем я писал. Во-первых скажу, что если Вы ничего не будете делать, т.е. оставите всё как есть, то это не отменит вызова стандартного метаметода при сравнении двух юзердат )) Во-вторых вызов этого метаметода не приводит к результату. Вернее приводит к результату печальному. В-третьих. Раз метаметод вызывается, то предположительно внутри что-то присходит. И на это затрачивается некое кол-во шагов алгоритма. Так почему не сделать правильно, т.е. выбросить прежние "накладные расходы", как Вы говорите, и не заменить своими. Вы должны были заметить, что это не обертка для прежнего "__eq", это новый метод "__eq". В-четвертых, каким образом код станет зависимым от этой правки, если этот метаметод, повторю, вызывается только! при сравнении двух юзердат, и более того - результат его работы плачевен. Что мы теряем? Ну и в-пятых пользуемся привычным сравнением "==" "~=" не задумываясь, - "А не юзердаты ли сравниваемые переменные?" Изменено 18 Июня 2015 пользователем Nazgool Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти