Nazgool 251 Опубликовано 22 Июня 2016 (изменено) @abramcumner, Я всё это знаю, читал, и слава Богу ещё помню.Не в этом дело. Сам факт. Ну вот посчитала lua в этот раз, что #t ==3. Так уж вышло что не 1. К примеру.Пишу : t = {1,2,3} t[2]=nil По Вашему удалил я его. Совсем. И след простыл. И поверил я что так и есть (к примеру). А lua мне пишет что 3 поля. И я ей ничего не делал. Сама, гадина, решила наплевать на мой nil. Врет и не краснеет.Теперь я больше не буду ей доверять. Сказали "нет поля" - значит нет. И точка. Пусть свои тройки и дальше пишет. Плевать я хотел. Изменено 22 Июня 2016 пользователем Nazgool Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 22 Июня 2016 (изменено) Посмотри, что выдаст тебе луа Да мне всё равно что она выдаст. Вернее я знаю что. Всяких вариантов и сам могу наклепать предостаточно. Я говорю про конкретный случай. Оператор # работает с массивом.Так? А ты сам говоришь после третьего поля Т.е. если это массив (раз # так отработал - факт), то есть и второе поле. И если бы не было второго поля, то t[3] показало бы nil в массиве. А тройка была бы в t[2] Но нет. Показывает 3. Значит всё-таки массив с тремя полями. И хоть я написал t[2]=nil, никуда оно не удалилось. Зачистилось значение - да. Уже не помню где, но читал в доках, что lua до последнего старается сохранить таблицу как массив, а не как хэш. Выражения "массив" и "хэш" не совсем точно определил, но думаю понятно что я имел в виду. Изменено 22 Июня 2016 пользователем Nazgool Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 23 Июня 2016 (изменено) @Desertir, Смотри. Из-за чего всё началось. Я сказал что t=nil не удаляет поле, а изменяет его значение. Кто действительно удаляет поле, так это table.remove Мне сказали что t=nil тоже удаляет поле Вот я и пытался показать что только t=nil не перестраивает таблицу. И при итерации поля в ней никуда не деваются в отличии от table.remove. Вот тут всё прекрасно видно t = {1,2,3,4,5} for i, v in ipairs(t) do print(i,v) table.remove(t,i) end --> 1 1 --> 2 3 --> 3 5 for i, v in ipairs(t) do print(i,v) t[i]=nil end --> 1 1 --> 2 2 --> 3 3 --> 4 4 --> 5 5 Т.е. во втором случае next читает поля и дальше, как ни в чем не бывало. А значит никуда они не деваются. Просто я даю им новое значение - nil. С оператором # ещё яснее. for i = 1, #t do print(i,t[i]) table.remove(t,i) end --> bla-bla --> bad argument #1 to 'remove' (position out of bounds) for i = 1, #t do print(i,t[i]) t[i]=nil end Если t=nil отрабатывает нормально, то с table,remove ошибка - "position out of bounds". Т.е. снова. Хоть я nil и присваиваю, но поля остаются. Да, при повторном использовании полей уже не будет. lua приберет (и то не всегда. показывал уже с t={1.nil,3}).Но на этом этапе, выходит, никакого удаления полей нет. Поэтому и называю "изменение значения" а не "удаление". Изменено 23 Июня 2016 пользователем Nazgool Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 23 Июня 2016 (изменено) @abramcumner, Ты в 5.3 тестируешь что-ли? Да и не важно, пусть в 5.3 и ошибка, но поля-то она правильно удаляет. Как же мне это ещё объяснить? Во-первых моё выражение "никуда не деваются" не верное. Признаю. Правильнее сказать "не определяются". И мои примеры с ipairs этому подтверждение. Во всем остальном остаюсь на своём. Вот то, от чего я отталкиваюсь, и что уже говорил - "lua до последнего старается сохранить таблицу как массив" t = {} t[1]=1 --> #t == 1 Всё верно. lua не куда деваться, есть элемент с индексом 1 - значит есть и массив t[3]=3 --> #t == 1 Сработала неопределённость оператора #. Ну вот решила lua что не хочет добавлять это поле в массив. t[4]=4 --> #t == 4 Теперь есть три конкретных элемента и одна дырка, значит можно создать массив(подумала lua) t[6]=6 --> #t == 4 Одну поблажку сделала - пока хватит. Пусть остается как есть (опять же её мысли передаю). t[8]=8 --> #t == 8 Вот это уже снова похоже на массив. Так тому и быть. print(#t) --> 8 Фууух. Насилу собрала массив. t[1]=nil --> #t == 8 То что зачистили одно поле ещё не значит что буду валить всё то, что так тяжело строила. t[2]=nil --> #t == 8 Не легко держать массив, но ничего. Выдюжим и это. t[3]=nil --> #t == 8 Безобразие конечно, но пойду на принцип. Моё ведь. t[4]=nil --> #t == 8 Караул, грабят. Отбиваюсь как могу. t[6]=nil --> #t == 8 Ни грамма сусликам. Нажито непосильным трудом. Не отдам и всё тут. print(#t) --> 8 Победа Так вот о чем и говорю - НЕ я, сама lua определяет поле [8]=8 при "дырках" от 1-го до 7-го поля. А как она определяет что поле именно с индексом [8], а не [144] например? Не потому ли, что перед ним есть поля с индексами 1-7? Значит есть таки поля? Т.е. они определились как поля. И они (пока) не удаляются, а только зачищаются их значения. И я говорю, что записав t=nil мы только лишь изменяем значение. Нельзя сказать что я удаляю поле. Не нам это решать а lua Оно может ей пока и понадобиться, как я только что под спойлером показал. Именно об этом битый ... толкую.А остальное - это уже совсем другая история. Л.Каневский. Изменено 23 Июня 2016 пользователем Nazgool Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 23 Июня 2016 (изменено) @CRAZY_STALKER666, В крайнем случае, если стоит расширение lua, можно и самому организовать свой динамический аналог game_story_ids.И там хранить типа sid-ов объектов.Я так делал когда-то.Если интересно. Изменено 23 Июня 2016 пользователем Nazgool Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 23 Июня 2016 Этот вариант я тоже тогда рассматривал.Но если ты будешь спавнить что-то через секцию alife():create("any_section", vector():set(... и т.д. и нужно будет это позже удалять.Снова for i=1,65534 ? Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 24 Июня 2016 (изменено) @CRAZY_STALKER666, Если ты будешь спавнить все объекты, которым необходимо назначать sid через all.spawn, то тогда я ни о чем. Я о том что будет, если будешь спавнить что-то по имени секции динамически, т.е. (например) alife():create("stalker", vector():set ... bla-bla И тебе позже нужно будет найти именно этого сталкера из кучи остальных, так же заспавненных. Изменено 24 Июня 2016 пользователем Nazgool Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 24 Июня 2016 (изменено) Более не пригодиться задавать sid через скрипт Вот это и плохо. Ты сам себя ограничиваешь в тех возможностях, которые люди придумали спустя много лет использования box-версии. Вот смотри. Что такое назначение sid-а в исходном варианте? В all.spawn-е ты создаешь секцию и прописываешь в ней story_id. Кроме этого тебе нужно зарегистрировать этот sid в game_story_ids.ltx. А что такое этот game_story_ids? Это жестко фиксированное хранилище, основываясь на котором возможен поиск по alife():story_object(sid), и без которого все твои назначенные sid-ы будут до лампочки. Не знаю как это выглядит, но подозреваю что достаточно запутанно и не очень удобно. До настоящего времени люди старались, делали, и как сказал Чебурашка - "строили, строили и наконец построили". Построили так, что можно и обойтись без всего того, что ты делаешь по "старой технологии". Что же есть нового, чтобы больше не смотреть на all.spawn, как на спасательный круг в твоём случае? Как можно назначить sid "не отходя от кассы"? 1. В расширение X-Ray extensions есть метод alife():assign_story_id. 2. Есть универсальные хранилища. By Malandrinus например. 2а. Если всё то что сказано выше сложно, то есть самый простой вариант - расширение lua by RvP, о чем я и хотел тебе сказать несколько постов назад. Так вот о самом простом, последнем варианте ( и втором тоже). Есть стандартное фиксированное хранилище (game_story_ids), а есть возможность сделать такое же, но динамическое хранилище. Теперь подробнее. Например создаем сталкера: local sobj = alife():create("stalker", vector():set ... bla-bla Пока этот сталкер существует, для него остаются неизменными name и id sobj:name() sobj.id Поэтому можно "запоминать" его либо по name, либо по id. Имя для динамически заспавненных объектов составляется из имени секции и его id (Для данного варианта) sobj:name() == 'stalker' .. sobj.id Зачем такая сложность, проще запомнить его id, оно же и так уникально. И вот теперь сама фишка того, что люди и придумали. Ты можешь сохранять id так : 1 (приоритетно) . Используя хранилище Malandrinus-а local sobj = alife():create("stalker", vector():set ... bla-bla ogse_unist.set_value('my_sid_kakoj_to_stalker', sobj.id , "number") 2. Используя только расширение by RvP писать эти id в свой файл посредством библиотеки io. Пишу налету, без всяких там разборок, криво, косо, на эмоциях, но это всё равно должно работать, и для наглядности хватит. В папке gamedata\config создать файл "my_sid.ini" (например) В _g.script добавить my_sid = {} my_sid_path = getFS():update_path("$game_config$", "my_sid.ini") function load_my_sid() local sim = alife() for line in io.lines(my_sid_path) do local k,v = line:match('([%w_]+)=([%w_]+)') v = tonumber(v) if sim:object(v) then -- для очиски от несуществующих на всяк my_sid[k] = v end end end function save_my_sid() local sim = alife() local f = io.open(my_sid_path, 'w') for k, v in pairs(my_sid) do if sim:object(v) then -- для очиски от несуществующих на всяк f:write(k..'='..v..'\n') end end f:flush() f:close() end Для запуска пока достаточно и в bind_stalker.script после function actor_binder:net_spawn(data) пишешь load_my_sid() и после function actor_binder:net_destroy() добавляешь save_my_sid() И наконец само использование где-то в скриптах : local sobj = alife():create("stalker", vector():set ... bla-bla my_sid.my_sid_kakoj_to_stalker = sobj.id Теперь в любой момент, ты можешь не перебирая for i=1,65534 которое может не лагать только на мощных системах, определить id своего объекта сталкера Либо по первому варианту local id_my_stalker = ogse_unist.get_value('my_sid_kakoj_to_stalker' , 0 , "number") Либо по второму local id_my_stalker = my_sid.my_sid_kakoj_to_stalker И найти сам объект local obj = alife():object(id_my_stalker) -- по прочтённому id А теперь удаляй или что ты с ним хочешь сделать. Изменено 24 Июня 2016 пользователем Nazgool 1 4 Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 27 Июня 2016 (изменено) @Zander_driver, На самом деле всё не так уж и плохо. Оператор '#' прекрасно работает с "правильными" массивами. Осталось только нам научиться работать с массивами также правильно table.insert и table.remove сделаны специально для этого и должны помочь. А поведение оператора '#' и его будущее в других случаях до сих пор не так однозначно. В PiL3 об этом написано в разделе 3.5. Оператор длины Особенно мне "нравиться" фраза самого автора:"поэтому большую часть времени оператор длины безопасен для использования" Как тебе такое? Изменено 27 Июня 2016 пользователем Nazgool Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 27 Июня 2016 (изменено) Да, в 5.1 не хватает этого метода. Впрочем можно написать функцию типа : function table.len(t) local n = 0 for _ in ipairs(t) do n = n + 1 end return n end А заодно не хватает __pairs и __ipairs. Да и goto, при аккуратном использовании, помогает крепко сокращать код Изменено 27 Июня 2016 пользователем Nazgool Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 6 Июля 2016 (изменено) Почему при спавне НПЦ скриптом в его имени к основному добавляются какие-то рандомные цифры? Вот почему, извините начальство форума за не очень пристойное слово, хочется {игнорировать} всякие призывы о помощи, и не тратить силы на распинания по сути. CRAZY_STALKER666 ты же поставил "Спасибо" к моему посту http://www.amk-team.ru/forum/topic/6185-skriptovanie/?p=1020661, т.е. ты должно быть его прочитал. А если это так, то ты не мог не заметить, что я в этом посте рассказывал про "цифры" в имени объекта. В то время, когда я начинал моддить, не было столько исчерпывающей информации как сейчас. Цеплялись за любые намеки. А тут... "Абыдно, да?" ("Кавказская пленница") "Начальство" в специально отведенном месте постоянно рыдает по тому же самому поводу. Не успевает жилетки менять. dc Изменено 6 Июля 2016 пользователем Dennis_Chikin Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 18 Августа 2016 (изменено) @FonSwong, Таблицы, функции, потоки и пользовательские данные (userdata) - это объекты: переменные фактически не содержат их значений, только ссылки на них. Присвоение, передача параметров и возврат из функций всегда манипулируют ссылками на эти значения; эти операции не подразумевают никакого типа копирования. Вот тут: ignore_tbl[back_level] = point_tblты создаешь ещё одну ссылку(имя) на таблицу(объект) с именем point_tbl.Таких ссылок(имен) может быть множество, а объект один и тот же. Изменено 18 Августа 2016 пользователем Nazgool 1 Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 20 Августа 2016 (изменено) как мне сделать дубликат Как тебе уже сказали - именно перебирать и переписывать каждое вложение. Есть не мало вариантов функций сделать это. Но при условии, что у тебя достаточно простая таблица. Сделать полное копирование сложной таблицы (реально полное) проблематично. (По крайней мере необходимости в этом не было, поэтому не делал. Да и не буду) Поясню что я подразумеваю под простой сложной таблицей и почему проблематично. Всё дело в ключах таблицы. Если ключи НЕ объекты - то всё нормально. Вот вариант копирования простой таблицы, в котором ключи не объекты, а строки или числа. Если значением ключа будет таблица, то создается копия этой таблицы. И так рекурсивно для всех степеней вложенности : function table.copy (tab) assert(type(tab) == 'table' , [[bad argument #1 to 'table.copy' => table expected, got ]] .. type(tab)) local function tcopy(src) if type(src) ~= 'table' then return src end local new = {} for k, v in pairs(src) do new[k] = tcopy(v) end return new end return tcopy(tab) end Вот сложнее вариант. Если значением есть таблица, для которой установлена метатаблица, то нужно скопировать эту метатаблицу. Поэтому немного расширенный вариант будет выглядеть так : function table.copy (tab, meta) assert(type(tab) == 'table' , [[bad argument #1 to 'table.copy' => table expected, got ]] .. type(tab)) local function tcopy(src, meta) if type(src) ~= 'table' then return src end local new = {} for k, v in pairs(src) do new[k] = tcopy(v, meta) end if meta then setmetatable(new, tcopy(getmetatable(src), meta)) end return new end return tcopy(tab, meta) end И вот теперь про самый сложный вариант и про "проблематично". А если ключем будет таблица (не буду брать функции, потоки и тем более userdat-у). По аналогии нужно копировать и эту таблицу-ключ. Для этого нужно изменить : new[k] = tcopy(v, meta) -- на new[tcopy(k, meta)] = tcopy(v, meta) НО. При этом будет создана новая ключ-таблица, для которой не назначено никакого идентефикатора. Т.е. она будет анонимна. Я вот о чем : Например есть такой код : t = {b=3} x = {a=1, [t]=2} y = table.copy(x) Вариант с кодом - new[k] = tcopy(v) В "new[k]" будет использована ссылка на таблицу с именем "t". Поэтому можно увидеть : print(y[t]) --> 2 Но если использовать вариант с - new[tcopy(k, meta)] = tcopy(v, meta), то : print(y[t]) --> nil Обращаясь y[t] мы обращаемся к полю таблицы, именем которого является объект!!! с именем "t" . Но в ключе была создана новая таблица(объект) - new[tcopy(k, meta)] - которая уже не является таблицей с именем "t". Поэтому print(y[t]) --> nil - Действительно, ключ был переписан новым безымянным объектом. Т.е. такое копирование ограничивает функционал, т.к. теперь нет поля y[t], к которому можно было просто обратиться. И можно ли назвать подобное копирование копированием? А если таких ключей множество, то при переборе for k, v in pairs как определить что этот ключ-таблица "k" именно то что нам нужно, если они все безымянны? В функции копирования создавать сопоставления? Теоретически можно. А практически нужно? Изменено 20 Августа 2016 пользователем Nazgool 1 1 Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 23 Августа 2016 @FonSwong, Ну если массив, то почему не ipairs ? Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 24 Августа 2016 (изменено) @Kirgudu, Про оператор "#" я не так давно уже рассказывал. Это не надежно. Поэтому всё-таки стоит пользоваться специально созданными для этого функциями ipairs и table.insert(remove) Напомню local t = {nil,nil,3} for i = 1, #t do print(t[i]) end --> nil --> nil --> 3 for i, v in ipairs(t) do print(i,v) --> ничего не печатает end И хотя я считаю что работа оператора # более правильная, чем ipairs (как ни крути, но это массив. есть ключи 1.2.3 и есть соответствующее им lua-значения), он не гарантирует всегда правильной работы. Но разработчики считают что nil не должен быть значением, поэтому пусть так и будет.А в специальных случаях (как то мой пример выше) никто не запретит пользоваться # Изменено 24 Августа 2016 пользователем Nazgool Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 25 Августа 2016 (изменено) @Serge!, она просто рассчитана на неассоциированный массив без вложений Т.е. копируем массив всё-таки.И если до копирования работать с массивом правильно, посредством функции table.remove и др., то у Вас в массиве никогда не будет полей со значением nil.Поэтому и копирование с помощью irairs создаст точную копию такого массива. И оператор # работает с таким правильным массивом тоже совершенно правильно.И будет работать правильно, пока как мы своими неправильными действиями не испортим массив, и не начнутся казусы с этим оператором. Поэтому в очередной раз настаиваю на использовании, уже мною упомянутых, специально предназначенных для этого функций стандартной библиотеки. Изменено 25 Августа 2016 пользователем Nazgool Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 25 Августа 2016 (изменено) @Malandrinus, Абсолютно согласен с тем, что массивы с nil-ами это зло. А необходимость копирования таблиц (с nil-ами или без них) можно определить только после того, как будут известны общие цели и задачи скрипта. Но в это мы не посвящены, поэтому принимаем задачу как есть - т.е. нужно копировать. И насчет того, чтобы "вообще убрать такой массив" я уже неоднократно говорил. Если работать с массивами правильно, то такой необходимости не возникнет в принципе. @Kirgudu, Хоть в сталкере используется lua 5.1.4, но компилируется код с помощью luajit 1.1.5 (или ошибаюсь?) И если у тебя есть возможность протестировать оба варианта (for i=1,#t и ipairs) в luajit, то заметной разницы в скорости выполнения ты не увидишь. Изменено 25 Августа 2016 пользователем Nazgool Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 25 Августа 2016 (изменено) @Serge!, Ну обсуждалось же уже. Ладно. Вот случай, описанный тобой. Есть массив, похожий на тот, что ты упоминал : local t = {nil,2} 1-я проблема. Определять поля нужно сразу local t = {} t[1]=nil t[2]=2 Так уже не работает! В этом массиве опрелено только одно поле по индексу [2]. В процессе (например) нужно сначала добавить поле с индексом [3] 2-я проблема. local t = {nil,2,nil} - третий nil как ты говоришь "должен присутствовать", но валит весь массив. И ты не сможешь его перебирать, т.е. и уже определенное значение в поле [2] пропадает. Поэтому нужно оставлять в таком виде для целостности массива local t = {nil,2} и теперь нужно добавиить поле [3], как у тебя "позже в процессе инициализации" t[3]='a' 3-я проблема. Массив валиться с этим добавлением. Пока хватит. И так проблема на проблеме. Кому это нужно? И да. При использовании функций-итераторов выполняются некоторые дополнительные инструкции, но в контексте luajit время их выполнения минимизируется по сравнению с (как уже выяснилось) не 100%-но надежным оператором #. Но в контексте надежности кода, использование стандартных методов намного предпочтительнее, чем гонка за сомнительной прибавкой в скорости. Тем более, как ты сам сказал, при работе с небольшими таблицами сталкера. Изменено 26 Августа 2016 пользователем HellRatz Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 26 Августа 2016 (изменено) в чём проблема? Вот в чем. Если почитать описание функции pairs, она использует как итератор функцию next. А для функции next записано : Порядок следования индексов неопределен, даже для числовых индексов. (Для прохождения по таблице в числовом порядке, используйте числовой for или функцию ipairs.) Т.е. разрабы и сами не уверены, что pairs верно распарсит правильный массив. Да и когда кто-то будет читать твой код, то увидев ipairs сразу поймет что парсится массив, а не всё подряд. Изменено 26 Августа 2016 пользователем Nazgool Поделиться этим сообщением Ссылка на сообщение
Nazgool 251 Опубликовано 26 Августа 2016 (изменено) @abramcumner, Изначально речь шла о копировании массива. Правильно индексированного, без "дырок" списка. В функции использовался pairs. Как можно копировать такой массив с помощью pairs если: Порядок следования индексов неопределен, даже для числовых индексов !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! И разрабы и сами не уверены, что pairs верно распарсит правильный массив. Я ни слова не сказал о том, что он не обойдет всю таблицу. Обойдет, конечно же обойдет. Но как? Обойдет как написано в первой цитате. Т.е. а кто его знает как. И что же мы скопируем? Поэтому - ipairs Кому не нравиться - тому _G.ipairs А кому и это не нравиться, тогда local kak_ni_kruti_vse_ravno_ipairs = ipairs Изменено 26 Августа 2016 пользователем Nazgool 1 Поделиться этим сообщением Ссылка на сообщение