Malandrinus 615 Опубликовано 8 Мая 2012 Поделиться Опубликовано 8 Мая 2012 Artos, проверка типа:if type(object) == 'userdata' and type(object.id) ~= 'nil' then ... - может привести к фатальной ошибке Если точнее, то в этой строке часть type(object) == 'userdata' ошибки не вызовет, поскольку это проверка объекта Lua и обращения к движковому объекту нет, а вот вторая часть type(object.id) ~= 'nil', или точнее вот это object.id, как раз и вызовет безголовый вылет, поскольку здесь идёт обращение к свойству id, а при этом делается попытка прочитать его из движкового объекта, которого уже нет. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
Nazgool 250 Опубликовано 11 Мая 2012 Поделиться Опубликовано 11 Мая 2012 Если движкового объекта уже нет, то проверка type(object) == 'userdata' возвратит false, поэтому до второй части - and type(object.id) ~= 'nil' - даже не дойдёт. Ссылка на комментарий
Artos 99 Опубликовано 11 Мая 2012 Поделиться Опубликовано 11 Мая 2012 (изменено) Gun12, мы тут затронули слишком ... неоднозначную и 'глубокую' тему. Конечно, в типовом случае если об'ект удален из игры - то type(object) вернет nil (кстати, а не false). Однако, в предыдущих постах говорится о случае, когда не собственно о самом об'екте идет речь, а о линках (ссылках) на него, которыми об'ект запоминается в неких таблицах/модулях/... В таких случаях, порою даже выход из игры (без выхода в ОС) и запуск ее заново иль с сохранения, не уничтожает всех об'ектов (хотя это уже о классах типа окон/менеджеров/...). Но и линки на обычные об'екты (неписи/монстры) порою не очищаются ... Но далее - только о конкретных ситуациях можно говорить, а не 'вообще'. P.S. Про false - это уже я ступил ... по невнимательности. ;-) Изменено 11 Мая 2012 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
Nazgool 250 Опубликовано 11 Мая 2012 Поделиться Опубликовано 11 Мая 2012 Artos Я как то упустил, что в этом вопросе была предыстория. И всё-таки проверка!!! if a == b возвратит false, я ведь писал не о результате работы функции type Ссылка на комментарий
Malandrinus 615 Опубликовано 11 Мая 2012 Поделиться Опубликовано 11 Мая 2012 Gun12, Если движкового объекта уже нет, то проверка type(object) == 'userdata' возвратит false, поэтому до второй части - and type(object.id) ~= 'nil' - даже не дойдёт. Ты не прав, это всё ещё 'userdata', но это именно объект Lua. В этом объекте хранится указатель на собственно движковый объект, и вот по этому указателю уже ничего нет. Проверь эту ситуацию сам. Запомни где-то ссылку скажем на серверный объект аптечки из инвентаря ГГ, потом аптечку съешь, потом проверь свойства этого объекта и что с ним можно и что нельзя делать. Кстати, я в очередной раз встречаю некоторое непонимание разницы между ссылкой и самим значением. Имя переменной (в примере выше object) - это фактически ссылка. У ссылки типа нет, тип есть у значения. Даже неинициализированная ссылка на самом деле имеет значение. Это nil. Ещё раз: nil - это с точки зрения Lua не отсутствие значения, а специальное значение, которое в частности присваивается ссылке по умолчанию. Соответственно, проверяя тип переменной, мы на самом деле проверяем тип того, на что она ссылается. Ссылается на nil - получаем строку "nil". Теперь к чему это всё. Вот ты сохранил ссылку на объект. Пока ты эту ссылку не перепишешь другим объектом, с этим объектом ничего не сделается и в том числе не изменится его тип. Lua попросту не умеет менять тип значения. Тип не меняется, просто ссылку можно переназначить на объект другого типа. Но в этом случае мы договорились, что мы ссылку не трогаем. Поэтому тип не изменится, в частности не станет nil, поскольку, как я уже сказал, для этого надо явно переписать ссылку специальным значением с типом "nil". Так что в примере выше всё будет плохо. Первая проверка сработает, на второй будет вылет. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
Nazgool 250 Опубликовано 11 Мая 2012 Поделиться Опубликовано 11 Мая 2012 (изменено) malandrinus Изначально я, признаю, выразился не совсем точно. И получилось не то, что я хотел сказать. А именно : вместо сказанного - "Если движкового объекта уже нет", мне стоило сказать - "Если объекта уже нет". Получилось как-то с уклоном на Сталкер, которого у меня ни на компе нет, ни в приоритетах интересов. Поэтому о "движковых объектах" это я уже как-то случайно загнул не по моим знаниям, т.к. занимаюсь только академическим Lua. В связи с чем твоё пояснение для меня ("в очередной раз встречаю некоторое непонимание разницы между ссылкой и самим значением"), несомненно полезное для новичков, считаю направленным несколько не по теме )) Ну если (в Lua) объекта нет, т.е. все ссылки на него равны nil, то и ... вот об этом я и писал выше. Добавлено через 50 мин.: Снова не точно. Правильно будет сказать - нет ссылок на объект. Изменено 11 Мая 2012 пользователем Gun12 Ссылка на комментарий
volazar 9 Опубликовано 12 Мая 2012 Поделиться Опубликовано 12 Мая 2012 (изменено) Всем доброй ночи Имеется функция. В ней проверяется наличие 2 разных предметов в слотах. Если предметы присутствуют, то идет вызов следующей функции. Если какого то одного предмета нет - то выводится сообщение на худ. И вот с последним загвоздка - сообщение выводится постоянно. Можно ли его сделать одноразовым? Вот сам код функции: function nano_speed() local nano_speed = db.actor:item_in_slot(1) local nano_suit = db.actor:item_in_slot(6) local gg = db.actor if nano_speed and nano_speed:section() == "nano_speed" and nano_suit and nano_suit:section() == "nano_suit" then news_manager.send_tip(gg, "%c[10,241,129,129]".."Сообщение центрального процессора:".."\\n".."%c[10,241,129,129]Инициализирован модуль "Скорость". Модуль готов к использованию.".."\n") this.nano_speed_1() -- Какой молодец. И модуль нацепил и костюм не забыл одеть. else news_manager.send_tip(gg, "%c[10,241,129,129]".."ERROR:".."\\n".."%c[10,241,129,129]Ошибка инициализации. Отсутствует подключение к центральному процессору!".."\n", nil, nil, 30000) -- А костюм где? Дубина! end end Изменено 12 Мая 2012 пользователем volazar Ссылка на комментарий
Zander_driver 10 334 Опубликовано 13 Мая 2012 Поделиться Опубликовано 13 Мая 2012 volazar Ну во первых такой код чреват вылетами. В одной строке проверяете и сам объект, и его секцию. А если никакого костюма не надето? объект = nil, и тут же произойдет попытка получить nil:section() для следующей проверки. Т.е. надо разнести эти проверки в разные места. Сначала объект, а уж потом, когда известно что он есть, выясняем его секцию. Во вторых - второе сообщение, как я понимаю, должно выводиться когда костюма нет, а блок все же есть. В том виде как сейчас, оно будет выводиться и при обратном случае - костюм есть, а блока нет. В третьих... хотя небуду больше ничего говорить, хватит. local msg1 = true local msg2 = true function nano_speed() local nano_speed = db.actor:item_in_slot(1) local nano_suit = db.actor:item_in_slot(6) local gg = db.actor if nano_speed and nano_suit then if nano_speed:section() == "nano_speed" and nano_suit:section() == "nano_suit" then if msg1 then news_manager.send_tip(gg, "%c[10,241,129,129]".."Сообщение центрального процессора:".."\\n".."%c[10,241,129,129]Инициализирован модуль "Скорость". Модуль готов к использованию.".."\n") this.nano_speed_1() -- Какой молодец. И модуль нацепил и костюм не забыл одеть. msg1 = false msg2 = true end elseif nano_speed:section() == "nano_speed" and nano_suit:section() ~= "nano_suit" then if msg2 then news_manager.send_tip(gg, "%c[10,241,129,129]".."ERROR:".."\\n".."%c[10,241,129,129]Ошибка инициализации. Отсутствует подключение к центральному процессору!".."\n", nil, nil, 30000) -- А костюм где? Дубина! msg2 = false msg1 = true end else msg1 = true msg2 = true end elseif nano_speed then if nano_speed:section() == "nano_speed" and msg2 then news_manager.send_tip(gg, "%c[10,241,129,129]".."ERROR:".."\\n".."%c[10,241,129,129]Ошибка инициализации. Отсутствует подключение к центральному процессору!".."\n", nil, nil, 30000) -- А костюм где? Дубина! msg2 = false msg1 = true end else msg1 = true msg2 = true end end Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на X-Ray) На базе модифицированного движка OGSR Engine. Бывший мододел на X-Ray / Начинающий игродел на Unreal Engine. Программист. AMD Ryzen 9 7950X (16 ядер, 32 потока, 5.75 ГГц); RTX 3080; 128 ГБ DDR5; Arctic Liquid Freezer II-420; 3 ТБ SSD PCIe 4.0; 4ТБ HDD. Ссылка на комментарий
Malandrinus 615 Опубликовано 13 Мая 2012 Поделиться Опубликовано 13 Мая 2012 Zander_driver, В одной строке проверяете и сам объект, и его секцию. А если никакого костюма не надето? объект = nil, и тут же произойдет попытка получить nil:section() для следующей проверки. Не так. По правилам языка, в конструкции if obj and obj:do_something() then ... вторая проверка будет проверяться только если сработает первая. Так кстати не во всех языках, но в большинстве. В общем-то это чаще всего самый логичный вариант, зачем делать вторую проверку, если всё выражение уже по первой части заведомо не истинно. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
Nazgool 250 Опубликовано 13 Мая 2012 Поделиться Опубликовано 13 Мая 2012 volazar Может как-то так : local old_suit_name function nano_speed() local gg = db.actor local nano_speed = gg:item_in_slot(1) local suit = gg:item_in_slot(6) if nano_speed and nano_speed:section() == "nano_speed" then local current_suit_name = suit and suit:section() if current_suit_name == old_suit_name then return end if current_suit_name == "nano_suit" then news_manager.send_tip(gg, "%c[10,241,129,129]".."Сообщение центрального процессора:".."\\n"..[[%c[10,241,129,129]Инициализирован модуль "Скорость". Модуль готов к использованию.]].."\n") else news_manager.send_tip(gg, "%c[10,241,129,129]".."ERROR:".."\\n".."%c[10,241,129,129]Ошибка инициализации. Отсутствует подключение к центральному процессору!".."\n", nil, nil, 30000) end old_suit_name = current_suit_name end end Пользуйся редакторами с подсветкой синтаксиса. У тебя ошибка в строке - "%c[10,241,129,129]Инициализирован модуль "Скорость". Модуль готов к использованию." Найдёшь? Ссылка на комментарий
Artos 99 Опубликовано 13 Мая 2012 Поделиться Опубликовано 13 Мая 2012 (изменено) Как то за разбором ошибок и псевдо-ошибок затерялся собственно ответ на вопрос: volazar: Можно ли его сделать одноразовым? Конечно можно, но для этого придется запоминать факт выдачи того или иного сообщения. Запоминать можно по разному. В простейшем случае в локальную переменную вне самой функции, которая проверяется внутри функции и соответственно выдается иль нет то или иное сообщение. Zander_driver, использовал для этого две переменные (msg1 и msg2 - по одной для каждого сообщения). Gun12 использовал одну (old_suit_name) ... хотя (ИМХО) несколько чрезмерна привязка именно к имени костюма (а если ГГ переоденет на такой же - ведь ничего не должно измениться). Вот еще один вариант реализации: local msg1 = "%c[10,241,129,129]".."Сообщение центрального процессора:".."\\n".."%c[10,241,129,129]Инициализирован модуль \"Скорость\". Модуль готов к использованию.".."\n" local msg2 = "%c[10,241,129,129]".."ERROR:".."\\n".."%c[10,241,129,129]Ошибка инициализации. Отсутствует подключение к центральному процессору!".."\n" local bSend = nil --/ переменная, хранящая факт выдачи того или иного сообщения function nano_speed() local gg = db.actor if gg then --/ а в игре ли сам актор? local nano_speed = gg:item_in_slot(1) local nano_suit = gg:item_in_slot(6) if nano_speed and nano_speed:section() == "nano_speed" and nano_suit and nano_suit:section() == "nano_suit" then if bSend ~= true then --/ еще не сообщали? news_manager.send_tip(gg, msg1) bSend = true --/ флажек о том, что сообщение-1 дано this.nano_speed_1() -- Какой молодец. И модуль нацепил и костюм не забыл одеть. end elseif bSend ~= false then --/ еще не сообщали? news_manager.send_tip(gg, msg2, nil, nil, 30000) -- А костюм где? Дубина! bSend = false --/ флажек о том, что сообщение-2 дано end end end Использована одна переменная (булева bSend). Две других - просто для удобства вынесены в них тексты ... (лучше бы в локализационные *.ltx) Ну а если потребуется запоминать более серьезно, т.е. чтобы и после запуска сэйва сообщения не спамили - потребуется запоминать состояние локальной переменной, например, в pstor актору. Изменено 13 Мая 2012 пользователем ColR_iT "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
Nazgool 250 Опубликовано 13 Мая 2012 Поделиться Опубликовано 13 Мая 2012 Artos У меня, твоя переменная bSend, называлась просто flag. После того как написал код я сделал следующее : 1. Подумал что так делалось уже очень много раз. 2. Выделил всё. 3. Удалил. 4. И решил написать немного по-другому. 5. Написал. Лично мне так...веселее что-ли? Интереснее... Ссылка на комментарий
Artos 99 Опубликовано 13 Мая 2012 Поделиться Опубликовано 13 Мая 2012 Gun12, однако ... логика с твоим флагом несколько отлична от исходной. В твоем случае, если у актора отсутствует в 1-ом слоте требуемый nano_speed (ведь он может его вынуть/выкинуть/...) - то сообщение об ошибке НЕ будет выдано. Ну а остальное - это конечно же дело вкуса и зависит от задумки модмейкера. ;-) "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
volazar 9 Опубликовано 13 Мая 2012 Поделиться Опубликовано 13 Мая 2012 (изменено) Artos, Дык это и не нужно Если одет просто костюм - сообщение не нужно выводить. Однако если костюма нету, но nano_speed вставляется в слот, тогда вывод сообщения об ошибке. ЗЫ: Функция Zander_driver у меня вылетает с ошибкой по синтаксису. Ф-ия Gun12 работает, однако не вызывается this.nano_speed_1() (если поставить ее вызов после сообщения, что все ок). Ф-ию Artos пока еще не пробовал. Изменено 13 Мая 2012 пользователем volazar Ссылка на комментарий
Nazgool 250 Опубликовано 13 Мая 2012 Поделиться Опубликовано 13 Мая 2012 (изменено) Artos Да я то изначально так и подумал, что если нет nano_speed-а, то и не фиг дёргаться )) Хотя логичнее по-твоему Изменено 13 Мая 2012 пользователем Gun12 Ссылка на комментарий
volazar 9 Опубликовано 13 Мая 2012 Поделиться Опубликовано 13 Мая 2012 (изменено) Еще 1 вопрос Взял ф-ию Gun12. Ее немножко изменил, получилось так: local old_suit_name local msg_vse_ok = тут текст сообщения local msg_vse_ne_ok = тут текст сообщения function nano_speed() local gg = db.actor local nano_speed = gg:item_in_slot(1) local suit = gg:item_in_slot(6) if nano_speed and nano_speed:section() == "nano_speed" then local current_suit_name = suit and suit:section() if current_suit_name == old_suit_name then return end if current_suit_name == "nano_suit" then news_manager.send_tip(gg, msg_vse_ok) this.nano_speed_1() else news_manager.send_tip(gg, msg_vse_ne_ok) end old_suit_name = current_suit_name end end Как уже писал выше, сообщения работают, однако нет вызова this.nano_speed_1() Если брать мой старый вариант (проверка на то, что nano_speed находится в слоте) то все работает. Изменено 13 Мая 2012 пользователем volazar Ссылка на комментарий
Nazgool 250 Опубликовано 13 Мая 2012 Поделиться Опубликовано 13 Мая 2012 (изменено) однако не вызывается this.nano_speed_1() (если поставить ее вызов после сообщения, что все ок)Ну так я просто не поставил этот вызов. Забыл там... или ещё чего-то. Не стоит копировать всё что видишь. Иногда нужно и подумать, проверить, понять. Да и не мешало бы в подробностях объяснить что, когда и как должно работать. А то каждый додумывает по-своему. Изменено 13 Мая 2012 пользователем Gun12 Ссылка на комментарий
Artos 99 Опубликовано 13 Мая 2012 Поделиться Опубликовано 13 Мая 2012 volazar, потрудись, плз, в своих вопросах обозначать цель и условия, дабы не гадать в ответах! Вариантов написания кодов может быть великое множество и захламлять топик "а вот мне не так, а эдак ... а теперь еще и это ..." - не стОит. И вопросы будут удаляться и ответы могут уже отсутствовать. Тебе дан ответ "как сделать вывод сообщений одноразовым" - вот и пиши далее, а не устраивай погадалки о некоей твоей еще одной функции (nano_speed_1), о назначении которой и условиях вызова можно только гадать. Пиши для себя вначале сам алгоритм, т.е. что за чем и при каких условиях должно поисходить, и уже потом воплощай в конкретные коды. Не получится - тогда и спрашивай. "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
volazar 9 Опубликовано 13 Мая 2012 Поделиться Опубликовано 13 Мая 2012 (изменено) Да вроде все уже воплотил. Есть функция, которая висит в апдейте. Функция проверяет наличие предмета и костюма в слотах. Если предмет находится в слоте, а костюм по каким то причинам не одет на ГГ, то выводится сообщение с ошибкой. Если же и предмет и костюм находятся в слотах, то выводится сообщение, что все ок и вызывается следующая функция (которая при условии, что в инвентаре есть нужный предмет и соблюдено условие (if gg.power > 0.4 then), юзает этот самый предмет, что приводит к восстановлению сил ГГ). Вот эта вторая вызываемая ф-ия: local fl = false local fl_1 = false local msg_sp_1 = тут текст local msg_sp_2 = тут текст function nano_speed_1() local gg = db.actor if gg.power > 0.4 then fl = false fl_1 = false return end if not fl then news_manager.send_tip(gg, msg_sp_1) end fl = true local speed = gg:object("nanobot_pow") if speed then gg:eat(speed) fl = false fl_1 = false return elseif not fl_1 then news_manager.send_tip(gg, msg_sp_2) fl_1 = true end end Вчера, я использовал ф-ию, просто проверяющую, что предмет в слоте и вызывающую след. function nano_speed() local nano_speed = db.actor:item_in_slot(1) if nano_speed and nano_speed:section() == "nano_speed" then this.nano_speed_1() end end Все работает, все прекрасно. Однако решил убрать это, дабы без костюма, ГГ не мог юзать предмет nano_speed. Затем был вчера мой пост тут, получил ответы (за что большое спасибо всем), сегодня попробовал предложенные ф-ии, остановился на ф-ии Gun12 и встретился с проблемой, которую описал выше (не работает вызов this.nano_speed_1()) Вроде бы все обьяснил... Извиняюсь за тавтологию. Используй, плз, для кодов тэг <code>, дабы сохранялось форматирование/отступы. --/Artos Изменено 13 Мая 2012 пользователем Artos Ссылка на комментарий
Artos 99 Опубликовано 13 Мая 2012 Поделиться Опубликовано 13 Мая 2012 (изменено) volazar, вот с этого и нужно было начинать: "Если предмет находится в слоте, а костюм по каким то причинам не одет на ГГ, то выводится сообщение с ошибкой". Неужели сложно в уже предложенных вариантах это осуществить, и при выдаче сообщения "что все в порядке" - вызывать и свою доп.функцию? Т.е. сделать как и задумано: "то выводится сообщение, что все ок и вызывается следующая функция" Попробуй реализовать все же самостоятельно. Ну а если запутаешься, то сравни: Все в одной функции: local msg1 = "%c[10,241,129,129]".."Сообщение центрального процессора:".."\\n".."%c[10,241,129,129]Инициализирован модуль \"Скорость\". Модуль готов к использованию.".."\n" local msg2 = "%c[10,241,129,129]".."ERROR:".."\\n".."%c[10,241,129,129]Ошибка инициализации. Отсутствует подключение к центральному процессору!".."\n" local bSend = nil --/ переменная, хранящая факт выдачи того или иного сообщения function nano_speed() local gg = db.actor if gg and gg.power <= 0.4 then then --/ актор в игре и силенок маловато? local nano_speed = gg:item_in_slot(1) --/ имеем ли мы "предмет" в 1- ом слоте if nano_speed and nano_speed:section() == "nano_speed" then local nano_suit = gg:item_in_slot(6) if nano_suit and nano_suit:section() == "nano_suit" then --/ надет ли костюм if bSend ~= true then news_manager.send_tip(gg, msg1) bSend = true --this.nano_speed_1() -- Какой молодец. И модуль нацепил и костюм не забыл одеть. end elseif bSend ~= false then news_manager.send_tip(gg, msg2, nil, nil, 30000) -- А костюм где? Дубина! bSend = false end end else --/ нет актора иль его сила достаточна ... bSend = nil end end По серьезному, если ранее не сделано, стОит еще ограничить все проверки таймером, вызывая все это, например 1 раз в секунду, дабы не перегружать апдейт актора каждые ~20 ms Изменено 13 Мая 2012 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти