Перейти к контенту

Рекомендуемые сообщения

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

 

Ссылка на комментарий

Gun12, мы тут затронули слишком ... неоднозначную и 'глубокую' тему.

Конечно, в типовом случае если об'ект удален из игры - то type(object) вернет nil (кстати, а не false).

Однако, в предыдущих постах говорится о случае, когда не собственно о самом об'екте идет речь, а о линках (ссылках) на него, которыми об'ект запоминается в неких таблицах/модулях/...

В таких случаях, порою даже выход из игры (без выхода в ОС) и запуск ее заново иль с сохранения, не уничтожает всех об'ектов (хотя это уже о классах типа окон/менеджеров/...). Но и линки на обычные об'екты (неписи/монстры) порою не очищаются ... Но далее - только о конкретных ситуациях можно говорить, а не 'вообще'.

 

P.S. Про false - это уже я ступил ... по невнимательности. ;-)

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Artos

Я как то упустил, что в этом вопросе была предыстория.

И всё-таки проверка!!! if a == b возвратит false, я ведь писал не о результате работы функции type :)

Ссылка на комментарий

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

 

Ссылка на комментарий

malandrinus

Изначально я, признаю, выразился не совсем точно. И получилось не то, что я хотел сказать. А именно :

вместо сказанного - "Если движкового объекта уже нет", мне стоило сказать - "Если объекта уже нет".

Получилось как-то с уклоном на Сталкер, которого у меня ни на компе нет, ни в приоритетах интересов.

Поэтому о "движковых объектах" это я уже как-то случайно загнул не по моим знаниям, т.к. занимаюсь только академическим Lua.

В связи с чем твоё пояснение для меня ("в очередной раз встречаю некоторое непонимание разницы между ссылкой и самим значением"), несомненно полезное для новичков, считаю направленным несколько не по теме ))

Ну если (в Lua) объекта нет, т.е. все ссылки на него равны nil, то и ... вот об этом я и писал выше.

 

Добавлено через 50 мин.:

Снова не точно. Правильно будет сказать - нет ссылок на объект.

Изменено пользователем Gun12
Ссылка на комментарий

Всем доброй ночи :)

Имеется функция. В ней проверяется наличие 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

 

Изменено пользователем volazar
Ссылка на комментарий

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.

Ссылка на комментарий

Zander_driver,

В одной строке проверяете и сам объект, и его секцию. А если никакого костюма не надето? объект = nil, и тут же произойдет попытка получить nil:section() для следующей проверки.

Не так. По правилам языка, в конструкции

if obj and obj:do_something() then ...

вторая проверка будет проверяться только если сработает первая.

 

Так кстати не во всех языках, но в большинстве. В общем-то это чаще всего самый логичный вариант, зачем делать вторую проверку, если всё выражение уже по первой части заведомо не истинно.

 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

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]Инициализирован модуль "Скорость". Модуль готов к использованию."

Найдёшь?

Ссылка на комментарий

Как то за разбором ошибок и псевдо-ошибок затерялся собственно ответ на вопрос:

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 актору.

Изменено пользователем ColR_iT

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Artos

У меня, твоя переменная bSend, называлась просто flag.

После того как написал код я сделал следующее :

1. Подумал что так делалось уже очень много раз.

2. Выделил всё.

3. Удалил.

4. И решил написать немного по-другому.

5. Написал.

Лично мне так...веселее что-ли? Интереснее... :)

Ссылка на комментарий

Gun12, однако ... логика с твоим флагом несколько отлична от исходной.

В твоем случае, если у актора отсутствует в 1-ом слоте требуемый nano_speed (ведь он может его вынуть/выкинуть/...) - то сообщение об ошибке НЕ будет выдано.

Ну а остальное - это конечно же дело вкуса и зависит от задумки модмейкера. ;-)

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Artos, Дык это и не нужно :) Если одет просто костюм - сообщение не нужно выводить. Однако если костюма нету, но nano_speed вставляется в слот, тогда вывод сообщения об ошибке.

 

ЗЫ: Функция Zander_driver у меня вылетает с ошибкой по синтаксису. Ф-ия Gun12 работает, однако не вызывается this.nano_speed_1() (если поставить ее вызов после сообщения, что все ок). Ф-ию Artos пока еще не пробовал.

Изменено пользователем volazar
Ссылка на комментарий

Artos

Да я то изначально так и подумал, что если нет nano_speed-а, то и не фиг дёргаться ))

Хотя логичнее по-твоему

Изменено пользователем Gun12
Ссылка на комментарий

Еще 1 вопрос :wacko:

Взял ф-ию 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 находится в слоте) то все работает.

Изменено пользователем volazar
Ссылка на комментарий
однако не вызывается this.nano_speed_1() (если поставить ее вызов после сообщения, что все ок)
Ну так я просто не поставил этот вызов. Забыл там... или ещё чего-то. Не стоит копировать всё что видишь. Иногда нужно и подумать, проверить, понять.

Да и не мешало бы в подробностях объяснить что, когда и как должно работать.

А то каждый додумывает по-своему.

Изменено пользователем Gun12
Ссылка на комментарий

volazar, потрудись, плз, в своих вопросах обозначать цель и условия, дабы не гадать в ответах!

Вариантов написания кодов может быть великое множество и захламлять топик "а вот мне не так, а эдак ... а теперь еще и это ..." - не стОит.

И вопросы будут удаляться и ответы могут уже отсутствовать.

Тебе дан ответ "как сделать вывод сообщений одноразовым" - вот и пиши далее, а не устраивай погадалки о некоей твоей еще одной функции (nano_speed_1), о назначении которой и условиях вызова можно только гадать.

Пиши для себя вначале сам алгоритм, т.е. что за чем и при каких условиях должно поисходить, и уже потом воплощай в конкретные коды. Не получится - тогда и спрашивай.

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Да вроде все уже воплотил. Есть функция, которая висит в апдейте. Функция проверяет наличие предмета и костюма в слотах.

Если предмет находится в слоте, а костюм по каким то причинам не одет на ГГ, то выводится сообщение с ошибкой. Если же и предмет и костюм находятся в слотах, то выводится сообщение, что все ок и вызывается следующая функция (которая при условии, что в инвентаре есть нужный предмет и соблюдено условие (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

Изменено пользователем Artos
Ссылка на комментарий

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

 

 

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

Создать аккаунт

Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!

Зарегистрировать новый аккаунт

Войти

Есть аккаунт? Войти.

Войти
  • Недавно просматривали   0 пользователей

    • Ни один зарегистрированный пользователь не просматривает эту страницу.
×
×
  • Создать...