Kirgudu 1 248 Опубликовано 27 Октября 2015 Поделиться Опубликовано 27 Октября 2015 @Romz, зависит от того, что происходит раньше (вот тут не помню), первый апдейт или исполнение логики (UI при заходе на Янов отключается в ней). Если первое - вполне можно не заморачиваться, а однократно сбрасывать инфопорцию при каждой загрузке. Можно даже не на апдейт сброс повесить, а, например, на спавн актора. 1 Инструмент Ссылка на комментарий
Romz 142 Опубликовано 27 Октября 2015 Поделиться Опубликовано 27 Октября 2015 @Kirgudu, В принципе, да. В скрипте, где этот инфопоршень проверяется, помимо него ещё проверки есть, так что, думаю, не критично будет. Рекомендую, кстати, глянуть доработанный se_stor, который я выложил вчера в «сборочном цехе».Да, я видел уже, и себе уволок. 1 Шаман - СисАдмин Всяко-разно: для ЧН Ссылка на комментарий
Serge! 127 Опубликовано 27 Октября 2015 Поделиться Опубликовано 27 Октября 2015 (изменено) Оболочки сделаны для более удобного вызова, так как в них сразу проверки на пустоту и тд.Вот что я думаю по этому поводу Про « сделаны для более удобного вызова».Вам придётся написать ещё пару страниц, чтобы убедить меня, что настучать на клавиатуре «get_substr_since_space_to_end (line)» мне удобнее, чем набрать знакомое «line:match('(%S+)%s?')», которое и короче самого имени и заодно сразу решает проблему. Это может бы быть не единственным примером. Про «так как в них сразу проверки на пустоту». Да нет там таких проверок. Все «If», которые там присутствуют, в лучшем случае просто дублируют последующие системные вызовы, а в большинстве просто бессмысленны. Но уж «пустоту» они точно не проверяют и не контролируют. Про «и тд.». Вот это «и тд.» есть самое опасное и тревожное. Посмотрите сами, некоторые Ваши функции/методы/оболочки (назовите, как хотите) порой вызывают простой системный метод через цепочку 3-4 вызовов промежуточных функций. А ведь ничего в этом мире не даётся просто так. Каждый вызов функции это ресурсные траты на очень многие скрытые от прямого взгляда вещи. Оправданы эти траты в данном конкретном случае? Однозначно нет. И никакое сомнительное удобство их не компенсирует. Ну и теперь, чтобы не быть голословным покажу, как бы я решал те же проблемы. Это не истина в последней инстанции, «я ведь не волшебник, а только учусь» и спасибо Charsi, который в шутейной беседе здорово подтянул меня в этой области «кодоблудия». Весьма благодарен ему за это. FonSwong, привожу только Ваше описание функции и мой вариант решения (везде line – строка, substring – подстрока, как они определении в оригинале текста) Функция возвращает подстроку с 1 символа и до ближайшего пробела, не включая его local var = line:match('(%S+)%s?') Примечание: вот здесь проверка не нужна, т.к. любой конец строки (по определению, но не всегда по реализации) считается пробельным символом, и поэтому получите то, что заказали. Функция возвращает подстроку с пробела (первого) и до конца local var = (line:find(' ')) and line:gsub('%w*%s?','',1) or '' Примечание: здесь проверка на наличие хоть одного пробела требуется по ТЗ А это мой бонус. Как получить любое слово из строки с пробелами в качестве разделителя? Да вот так. Кстати, можно задать любой разделитель, но речь, сейчас, не об этом. local word = 0 -- индекс слова, которое надо получить. Начинается с 0, а не с 1 local var = line: gsub('%w*%s?*','',word):match('(%S*)') Вычисление длины строки local var = line and line:len() Примечание: здесь просто проверка на «дурака», чтобы избежать вылета. Выделение подстроки по индексам Примечание: простое дублирование системного метода. Проверки естественно лишние, т.к. проверяются дефолтные значения. Находит первое вхождение в строку второго аргумента, возвращается не только первое вхождение, но и индекс, на котором вхождение заканчивается. Примечание: здесь простое дублирование системного метода. Эквивалентно следующему: local var1, var2 = line:find(substring) Содержит ли строка данную подстроку.Примечание: простое дублирование системного метода. Все проверки просто бессмысленны, т.к. реализуются системой. Эквивалентно следующему: local var = (line:find(substr)) and true or false Заменяет первое вхождение old в строке line на new local var = line:gsub(old,new,1) or line Заменяет все вхождения old в строке line на new local var = line:gsub(old,new) or line Проверяет, начинается ли строка с данной подстроки local var = line:sub(1,substring:len()) == substring Проверяет, заканчивается ли срока line последовательностью substring local var = line:sub(-substring:len()) == substring Проверяет, является ли строка пустой. true, если пустая, false иначе. local var = line:len() == 0Всё остальное не требует ни цитирования, ни комментариев, ни даже внимания, т.к. является простым дублированием системных методов, которые просто втихую съедают ресурсы. Вот такое моё мнение про этот пакет «Служебные функции для удобной работы со строками» Изменено 29 Октября 2015 пользователем Kirgudu Ссылка на комментарий
Romz 142 Опубликовано 28 Октября 2015 Поделиться Опубликовано 28 Октября 2015 Да я, собственно, переделываю скрипт Vergas-a, который должен будить ГГ перед выбросом.Вернусь к этой теме. Сразу добавлю, что у меня ещё AtmosFear 3 прикручен. В процессе тестирования получившейся функции выяснилось, что промежуток между выбросами может динамически меняться, почему-то. Этот самый промежуток вычисляется и хранится в surge_manager в переменной self._delta.А вычисляется он в функцях CSurgeManager:initialize, CSurgeManager:new_surge_time, CSurgeManager:update плюс ещё сохраняется и считывается из сохранения. В CSurgeManager:initialize и CSurgeManager:new_surge_time Всё понятно и прозрачно. А вот в CSurgeManager:update есть интересный кусок, назначение которого я не очень хорошо понимаю. if(self.time_forwarded) then local diff = math.abs(self._delta - g_time:diffSec(self.last_surge_time)) if(diff<3600) then self._delta = 3*3600+g_time:diffSec(self.last_surge_time) end self.time_forwarded = false end Этот код, в точно таком же виде, есть и в оригинале ЗП, только там ещё и вывод в лог кой какой инфы идёт. То есть, если время время переводится и до выброса остаётся меньше часа, то промежуток между выбросами устанавливается равным 3 часа + прошедшее с последнего выброса время... Зачем??? В общем, обошёл этот момент, путём закомменчивания в ui_sleep_dialog в функции dream_callback строчки surge_manager.get_surge_manager().time_forwarded = true. Да, теперь выброс вполне может случиться сразу после того, как ГГ проснётся. Надо бы что-то подобное и для пси-выброса теперь замутить. Вот такая конструкция получилась function dream_calculation() local delta_surge = surge_manager.get_delta() local past_seconds_su = surge_manager.get_last_surge_time() local delta_su = delta_surge - past_seconds_su local delta_psi_storm = psi_storm_manager.get_delta() local past_seconds_ps = psi_storm_manager.get_last_psi_storm_time() local delta_ps = delta_psi_storm - past_seconds_ps if delta_ps < delta_su then local delta = delta_ps else local delta = delta_su end local delta_h = math.floor(delta/3600) local delta_m = math.floor(math.fmod(delta,3600)/60) return delta_h, delta_m end Добавил в psi_storm_manager по аналогии с surge_manager переменную и функции. А эта функция должна выдать оставшееся до выброса или пси-выброса, если он ближе, время в часах и минутах. 1 Шаман - СисАдмин Всяко-разно: для ЧН Ссылка на комментарий
Kirgudu 1 248 Опубликовано 28 Октября 2015 Поделиться Опубликовано 28 Октября 2015 @Romz, я правильно понимаю, что здесь ты вычисляешь время, оставшееся до ближайшего из двух типов выброса? В целом нормально, но оптимизировать есть куда. Например: function dream_calculation() local delta_su = surge_manager.get_delta() - surge_manager.get_last_surge_time() local delta_ps = psi_storm_manager.get_delta() - psi_storm_manager.get_last_psi_storm_time() local delta_h, delta_m = math.modf(math.min(delta_ps, delta_su)/3600) delta_m = math.floor(delta_m*60) return delta_h, delta_m endНу и отсюда очевидно, что лучше не дёргать 2 раза подряд один и тот же менеджер, а вычислять соотв. дельту прямо в нём, в дополнительной функции, передавая наружу уже результат. 1 Инструмент Ссылка на комментарий
Romz 142 Опубликовано 28 Октября 2015 Поделиться Опубликовано 28 Октября 2015 я правильно понимаю, что здесь ты вычисляешь время, оставшееся до ближайшего из двух типов выброса?Совершенно верно. лучше не дёргать 2 раза подряд один и тот же менеджер, а вычислять соотв. дельту прямо в нёмНу если написать таким образом, как у тебя, то да, весьма наглядно.А вот math.modf, он разве не целую и десятичную часть возвращает? Потому что десятичная часть - это же миллисекунды, вроде. И тогда их на 3600 умножать надо, чтоб минуты получились. Мож ошибаюсь, конечно. Математика - не мой конёк совершенно... Шаман - СисАдмин Всяко-разно: для ЧН Ссылка на комментарий
abramcumner 1 167 Опубликовано 28 Октября 2015 Поделиться Опубликовано 28 Октября 2015 @Romz, странная функция dream_calculation. По идее же так должно быть: function dream_calculation() local now = level.get_game_time() local next_surge = surge_manager.get_last_surge_time() + surge_manager.get_delta() local next_psi = psi_storm_manager.get_last_psi_storm_time() + psi_storm_manager.get_delta() local delta = min(next_surge:diffSec(now), next_psi:diffSec(now)) return delta... end 1 1 Ссылка на комментарий
Kirgudu 1 248 Опубликовано 28 Октября 2015 Поделиться Опубликовано 28 Октября 2015 @abramcumner, вот кстати да. Но и в твоём примере не всё гладко. Если get_last_surge_time возвращает объект CTime, а get_delta - секунды, то... Инструмент Ссылка на комментарий
Romz 142 Опубликовано 28 Октября 2015 Поделиться Опубликовано 28 Октября 2015 (изменено) get_last_surge_time Не, я переписал функцию, она время в секундах возвращает. странная функция dream_calculation. Ну это функция от @Vergas-а. Я её и переписываю, в меру своих познаний. Возвращает целую и дробную части, но уже после деления на 3600 А, точно. Торможу Изменено 28 Октября 2015 пользователем Romz Шаман - СисАдмин Всяко-разно: для ЧН Ссылка на комментарий
Kirgudu 1 248 Опубликовано 28 Октября 2015 Поделиться Опубликовано 28 Октября 2015 А вот math.modf, он разве не целую и десятичную часть возвращает? Потому что десятичная часть - это же миллисекунды, вроде. И тогда их на 3600 умножать надо, чтоб минуты получились. Возвращает целую и дробную части, но уже после деления на 3600, то есть и то и другое - в часах. Поэтому для получения минут дробную часть надо умножать на 60. Не, я переписал функцию, она время в секундах возвращает. Тогда бери мой пример. Вариант @abramcumner относится к CTime. 1 Инструмент Ссылка на комментарий
Romz 142 Опубликовано 28 Октября 2015 Поделиться Опубликовано 28 Октября 2015 (изменено) @abramcumner, А почему складываем время, прошедшее с последнего выброса, с временем между выбросами? И как из этого получилось время до следующего выброса? Вариант abramcumner относится к CTime.Ааа, понятно тогда Изменено 28 Октября 2015 пользователем Romz Шаман - СисАдмин Всяко-разно: для ЧН Ссылка на комментарий
Kirgudu 1 248 Опубликовано 28 Октября 2015 Поделиться Опубликовано 28 Октября 2015 @abramcumner, можно я отвечу? @Romz, где ты такое увидел? Сначала сложением вычисляется время следующего выброса (двух), потом разница между ними и текущим временем (next_surge:diffSec(now)), потом берётся минимальная разница. Она и возвращается, как оставшееся время до ближайшего выброса. Инструмент Ссылка на комментарий
Romz 142 Опубликовано 28 Октября 2015 Поделиться Опубликовано 28 Октября 2015 (изменено) @Kirgudu, Не, ну из приведённых мной кусков кода, может быть, конечно, не очень понятно, что и как, но у меня get_last_*_time возвращает, в секундах, время, прошедшее со времени окончания предыдущего выброса. А get_delta - возвращает текущий промежуток между выбросами. Тоже в секундах. @Kirgudu, С секундами проще. Промежуток между выбросами - максимум четверо суток (игровых). CTime для моих задач, ИМХО, черезмерно. Изменено 28 Октября 2015 пользователем Romz Шаман - СисАдмин Всяко-разно: для ЧН Ссылка на комментарий
Kirgudu 1 248 Опубликовано 28 Октября 2015 Поделиться Опубликовано 28 Октября 2015 (изменено) @Romz, ну тогда сам смотри, с какого конца подходить. Если тебе проще оперировать секундами - используй свою функцию, в оптимизированном или нет виде. Либо, если делать через CTime, у тебя уже есть время последнего выброса (self.last_surge_time)), а время до следующего можно получить так (при учёте того, что self._delta - в минутах): local delta_ctime = game.CTime() delta_ctime:setHMS(0,self._delta,0) И тогда, вернув оба объекта, можно воспользоваться функцией, которую привёл @abramcumner. Только потом не забудь перевести его результат delta (который тоже CTime) в часы и минуты: return delta:timeToString(game.CTime.TimeToMinutes) И получишь сразу строку вида "hh:mm". Изменено 28 Октября 2015 пользователем Kirgudu 1 Инструмент Ссылка на комментарий
abramcumner 1 167 Опубликовано 28 Октября 2015 Поделиться Опубликовано 28 Октября 2015 (изменено) Не обращайте внимания на мой пост - только запутал.В ЗП CSurgeManager self.last_surge_time - это CTime, вот я и подумал, что get_last_surge_time() возвращает его же. Однако такого метода в ЗП нет. И он похоже возвращает совсем не CTime Изменено 28 Октября 2015 пользователем abramcumner Ссылка на комментарий
Romz 142 Опубликовано 28 Октября 2015 Поделиться Опубликовано 28 Октября 2015 Не обращайте внимания на мой пост - только запутал.Не, почему же. В свете того, что работает с CTime, может кому-то ещё пригодится. Шаман - СисАдмин Всяко-разно: для ЧН Ссылка на комментарий
sergej5500 0 Опубликовано 28 Октября 2015 Поделиться Опубликовано 28 Октября 2015 Добрый вечер. Я пытаюсь добавить в Зов Припяти мины, которые мог бы устанавливать игрок. Мины должны реагировать на монстров и сталкеров. Базовый элемент мины - объект класса inventory_box. Спавнится объект под ногами игрока при юзании бустера (мины) в инвентаре ГГ. Логика мины [logic]active = ph_idle [ph_idle]nonscript_usable = falseon_info = {=dist_to_actor_ge(45)}ph_idle@1 [ph_idle@1]nonscript_usable = falseon_game_timer = 30 | ph_idle@2 [ph_idle@2]nonscript_usable = falseon_info = ph_idle@1%=mine_control% Функция подрыва function mine_control(obj1,obj)for i = 1,65534 do local obj1 =alife():object(i) if obj1 then if (obj1==IsStalker orobj1==IsMonster) then if distance_between(obj1,obj)<15then alife():create("remote_explosive_bomb_1",vector():set(obj:position()),obj:level_vertex_id(),obj:game_vertex_id()) level.add_call( function() ifget_story_object("remote_explosive_bomb_1") ~= nilthen returntrue end end, function() expl_obj =get_story_object("remote_explosive_bomb_1") expl_obj:explode(0) end ) local sobj =alife():object(obj:id()) if sobjthen alife():release(sobj,true) end end end endendend Функция подрыва должна проверить, не находится ли ближе 15 метров к мине монстр или сталкер. Если ближе есть живой объект, то заспавнить заряд взрывчатки и взорвать его. Функция не срабатывает. Где я допустил ошибку? Ссылка на комментарий
Zander_driver 10 342 Опубликовано 29 Октября 2015 Поделиться Опубликовано 29 Октября 2015 Еще в ТЧ разрабы "зачем-то" делали мины на классе аномалий. а не ящиков... for i = 1,65534 do в функции, которая должна вызываться на апдейте чтоб давать нормальный результат - отбивает всякое желание разбираться, почему она не вызывается. Не вызывается, и слава богу К знатокам созрел вопрос... Собственно что я делаю: спавню инвентарный объект (оружие или комбез) в координаты максимально близкие, но не совпадающие, с координатами актора. Получается серверный объект. Беру из него нетпакет, переписываю там некоторые параметры, записываю нетпакет объекту, затем уже пускаю объект в онлайн и передаю актору. И периодически при вот этой операции, а именно - при записи измененного нетпакета в объект, происходил краш игры. т.е. так называемый "безлоговый" вылет. Замечу что происходило это не всегда. А достаточно редко. Путем раскопок выяснил следующее: если в подтаблице upd нетпакета, есть подтаблица quaternion - то любая попытка записи этого нетпакета тому же объекту, с которого он получен, приводит к вылету, даже если в пакете вообще ничего не меняли. Если в прочитанном пакете upd.quaternion отсутствует, то все работает нормально. Я соорудил такую конструкцию: local spawn_ex_settings = {} function spawn_ex_transfer(sect, keys_packet) local f_name = "spawn_ex_transfer" local args = {sect, keys_packet} log_tool(f_name, args) spawn_ex_settings["active"] = true spawn_ex_settings["attempt"] = 0 spawn_ex_settings["keys_packet"] = keys_packet local coords = mag_ref_support.get_access_position() local sobj = alife():create(sect, coords[1], coords[2], coords[3]) bind_slot_item.add_to_wait(sobj.id) --local pc = m_net_utils.Get_NetPacket(sobj, 2) spawn_ex_settings["id"] = sobj.id -- spawn_ex_settings.pc = pc alife():set_switch_online(sobj.id, false) alife():set_switch_offline(sobj.id, true) log_tool(f_name, "running") mag_ref_support.ExSpawning_process() end function ExSpawning_process() if spawn_ex_settings["active"] ~= true then return true end spawn_ex_settings["attempt"] = spawn_ex_settings["attempt"] + 1 log_tool("ExSpawning in progress:", spawn_ex_settings) local sobj = alife():object(spawn_ex_settings["id"]) if not sobj then abort("mag_ref_support.script: ExSpawning_process ~~~ Error") end local pc = m_net_utils.Get_NetPacket(sobj, 2) if not pc then return true end --- повторим после if pc.upd and pc.upd.quaternion then return true end --- повторим после for k, v in pairs(spawn_ex_settings["keys_packet"]) do pc[k] = v if pc.upd ~= nil and pc.upd[k] ~= nil then if k == 'condition' then pc.upd[k] = round(v * 255) else pc.upd[k] = v end end end m_net_utils.Set_NetPacket(sobj, pc) bind_slot_item.add_to_wait(sobj.id) alife():set_switch_online(sobj.id, true) alife():set_switch_offline(sobj.id, false) spawn_ex_settings["active"] = false spawn_ex_settings["keys_packet"] = nil spawn_ex_settings["id"] = nil spawn_ex_settings["attempt"] = nil log_tool("ExSpawning_process", "complete!") end Запуск механизма происходит в функции spawn_ex_transfer, в нее собственно передается секция, что надо заспавнить, и таблица с набором ключей-значений, что в пакете объекта надлежит изменить. Объект сажается в оффлайн, а функция ExSpawning_process проверяет его нетпакет, если есть кватернион - ждать до следующего апдейта, если нету - записываем в него что требовалось и пускаем в онлайн, миссия выполнена. Ну так вот, по моим наблюдениям - либо все срабатывает с первого раза, объект получает все нужное себе в пакет, и висение ExSpawning_process на апдейте в таком случае совершенно не требуется. Либо же, ExSpawning_process находит в пакете кватернион, находит его на следующем апдейте-тоже, и т.д. до бесконечности, т.е. если он есть, то и при повторных попытках получить пакет все так же остается. В итоге весь этот механизм оказался полезен лишь тем, что дал мне всю вышеизложенную информацию, но совершенно не выполняет поставленной задачи. Если в пакете есть кватернион, то объект так и остается висеть в оффлайне, а ExSpawning_process на апдейте теребит его пакет, пытаясь сделать то что очевидно сделать не получается. Что собственно такое этот кватернион применительно к объектам сталкера? для чего он нужен и почему блокирует запись нетпакета. Как эту проблему обойти? Поиск дал лишь пару упоминаний на этом форуме - Скриптование, страница 147, и справочник по функциям и классам, страницы 16/17. Из находящихся там постов явно видно, что есть люди разбирающиеся в данном вопросе, но совершенно не ясно как решить поставленную проблему. 1 Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на 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. Ссылка на комментарий
Kirgudu 1 248 Опубликовано 29 Октября 2015 Поделиться Опубликовано 29 Октября 2015 (изменено) @Zander_driver, судя по всему, ты пользуешься старым m_net_utils. upd.quaternion в m_net_utils --> upd.ph_rotation в m_netpk. Помимо названия, в m_netpk существенно изменился сам способ чтения/записи данных, в том числе этого свойства. Я полагаю, что в новой версии модуля твоей ошибки уже не будет. Если это так, а старая версия модуля интегрирована в слишком многие скрипты, тебе даже не обязательно повсеместно переходить на новую. Судя по инициализации там и там, обе версии вполне уживутся рядом друг с другом. Изменено 29 Октября 2015 пользователем Kirgudu 1 Инструмент Ссылка на комментарий
FonSwong 33 Опубликовано 29 Октября 2015 Поделиться Опубликовано 29 Октября 2015 (изменено) Вот что я думаю по этому поводу Составлял не я, не имея опыта в луа, опирался на уже написанное, используя и изменяя в своих целях.Про "проверки на пустоту"- имел ввиду, что-то вроде "здесь просто проверка на «дурака», чтобы избежать вылета".. Спасибо за развёрнутый коммент Изменено 29 Октября 2015 пользователем FonSwong Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти