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

Malandrinus

Жители
  • Число публикаций

    1 930
  • Регистрация

  • Последнее посещение

  • Дней в топе

    13
  • AMKoin

    160 [Подарить AMKoin]

Весь контент пользователя Malandrinus

  1. Malandrinus

    X-Ray extensions

    hud_adjust_mode <номер режима 0 - 5> режимы: 0 - не делать ничего 1- подгонка худа в режиме прицеливания 2, 5 - подгонка позиции партиклов стрельбы для разных режимов. Не работает! 3 - подгонка позиции гранаты. По идее должна работать, но я не знаю как именно. 4 - подгонка позиции партиклов гильз. Не работает! Как пользоваться. Команда в движке завязана на жёстко заданные клавиши. в случае с настройкой позиции оружия: ASDW - перемещение, QE - ближе/дальше, JKLI - вращение, P - скинуть полученные координаты в лог. Удерживаете мышой режим прицеливания и настраиваете ствол клавишами. Потом жмёте "P" и в логе смотрите получившиеся настройки ствола. Для других режимов используются те же клавиши. На время настройки имеет смысл отбиндить штатное назначение, поскольку конфликтует. hud_adjust_value <чувствительность настройки в диапазоне 0.0 - 1.0>. Это приращение соответствующего значения за одно нажатие клавиши. По моим ощущениям осмысленными являются достаточно маленькие значения типа 0.01. Есть один побочный эффект, который надо компенсировать скриптом. Режим запоминается в настройках, так что надо его принудительно скриптом выставлять при старте игры в ноль, иначе у игроков начнутся непонятки.
  2. Artos, Это была попытка что-то изменить, сохраняя копию объекта, вместо того, что выдаёт game.get_game_time(). Ничего ровным счётом не изменило, поэтому можно спокойно заменить на просто game.get_game_time() Спасибо, что обратил внимание. Это опечатка (с работы посылал и в игре проверить не мог). Имел в виду log2, моя обёртка над log1, которая работает как string.format. Делать это в x-ray extensions естественно смысла нет. Так что здесь надо добавить string.format. А исходно там стоял вывод в отдельный файл с использованием io. Мне интересно. Вот скажем не сможешь ты воспроизвести эту ситуацию, что будешь делать? Скажешь, что такого не бывает? Мне ведь у себя так и не удалось. Я же говорил, поставил у себя этот код на целый день (пока на работе был), и ни черта так и не дождался. У меня конечно актор просто стоял на месте, и это отличается от ситуации у тестеров. Там всё более активно шевелится, и кто знает, что это меняет. Это не считая разницы в конфигурации системы. Но двое человек отмечали как минимум несколько инцидентов в течении пары дней. Я это естественно видел только в логах.
  3. Вот код с тестовыми проверками (модуль для менеджера сигналов):
  4. Я не пойму, что ты этим сказать хотел.
  5. Artos, Твоя может и не показывает, а я бы не писал так уверенно, если бы не видел это своими глазами. Я же говорю, это происходит один раз на сотни тысяч совершенно безпроблемных вычислений. Кроме того, я на своей машине такого и не видел. Я у себя поставил на целый день загруженную игру и ловушку на этот эффект, и ничего так и не случилось. Эффект обнаруживали наши тестеры, и частота его появления - один на много часов игры при работе вышеприведённого алгоритма на каждом апдейте (т.е. примерно 40 раз в секунду). Мне пришлось давать им отладочный модуль с выводом в лог и по этому логу смотреть. А можно поконкретнее? Весь алгоритм приведён выше, ничего сверх этого с объектами CTime не происходит. Т.е. вот три строки, которые работают на каждом апдейте: local current_time = game.get_game_time() -- <== 1 local dt = current_time:diffSec(previous_check_time) -- <== 2 previous_check_time = current_time -- <== 3 В строке 3 ссылка previous_check_time заменяется на ссылку на объект с текущим временем. В этот момент его значение в норме (проверено выводом в лог после строки 3). После этого до следующего апдейта previous_check_time никто не трогает. Начинается следующий апдейт, имеем строку 1 и перед этой строкой ставим проверку значения объекта CTime, на который ссылается previous_check_time. И это значение уже побитое! Где и что может произойти с этим объектом между этими двумя моментами времени? Переменная локальная, снаружи модуля не доступна. Как я описал выше, меняется именно объект, а diffSec уже честно вычислял получившуюся ерунду. Я именно это и проверял, значение объекта на текущем апдейте, потом его же на следующем. Меняется! Для меня это совершенно дико. Это как если бы я записал в переменную значение 4, а после апдейта там оказалось 5. Бред же, но что-то в этом стиле и происходит. Я бы даже больше понял, если бы портился весь объект разом, но обнуляются только старшие 4 байта. Можно попробовать. Надо также проверить, что не будет копиться существенная ошибка округления, поскольку так итоговая маленькая разница вычисляется между большими числами с плавающей запятой. Я могу предположить, что никто не использует этот класс на регулярной основе. Я видел только единичные применения, которые с точки зрения времени случаются разы. Если мы условно оценим вероятность возникновения этого эффекта примерно как 1/100000 (на основе опыта тестеров), то при разовых применениях можно запросто и не дождаться. Если же и дождаться случайно, то всё равно ничего понять не выйдет, поскольку не удасться воспроизвести. И почему у меня такого не случается? От машины ещё зависит? В общем, у меня ответов нет. Я здесь написал, чтобы констатировать факт. Кто не верит, дело хозяйское. *Shoker*, Это собственно на ТЧ шестого патча. На других не проверял, да и не могу я проверить. Для этого надо ставить отладочный модуль на другую игру и гонять много часов и возможно не на моей машине. Я этого сейчас делать не могу и не хочу. Я решил проблему способом, который я выше описал в первом сообщении (с сохранением объекта поэлементно). Пока вроде работает.
  6. За классом game.CTime замечено странное поведение, а именно: старшие 4 байта 64-х разрядного счётчика в этом классе могут спонтанно обнуляться. Пока такое замечено в объектах, сохранённых на предыдущем апдейте. Т.е. я имею примерно такой код: local previous_check_time function on_spawn() previous_check_time = game.get_game_time() end function on_update() local current_time = game.get_game_time() -- в этом месте previous_check_time может оказаться побитым local dt = current_time:diffSec(previous_check_time) previous_check_time = current_time -- делаю вычисления на основе dt end и вот из-за этого эффекта значение previous_check_time оказывается не тем, которое сохранил. Происходит это крайне редко, и никакой системы обнаружить не удалось. Тем не менее, это может происходить достаточно часто, чтобы приводить к заметным проблемам. К примеру, это может происходить раз в несколько игровых часов. Последствия могут быть от незаметных, до самых тяжёлых. К примеру, если в коде выше значение dt используется для вычислений какого-то эффекта, приводящего к постепенному снижению здоровья, к примеру как-то так: db.actor.health = k*dt гдк k - это скажем влияние артефакта в слоте или ещё что-то, то в результате данной ситуации вычисленная разница dt будет много миллионов, что приведёт к соответственному снижению здоровья на много миллионов и мгновенной смерти актора. Выхода из этой ситуации может быть два. 1. Не использовать CTime вообще, но в этом случае возникает известная проблема переполнения счётчика через игровой месяц. 2. Не хранить объекты CTime, а вместо них хранить их покомпонентно, т.е. в виде набора чисел для лет, месяцев, дней, часов, секунд, миллисекунд. Соответственно, раскладывать объект на эти компоненты, их хранить, потом собирать заново. Это естественно вызывает некие расходы.
  7. Есть предположение по поводу рестрикторов и как они работают. Неписи же по сетке ходят, пространство как таковое для них весьма вторично. Думаю, что рестриктор для ограничения движения скорее всего просто исключает из навигации узлы сетки, попавшие в рестриктор. Т.е. он буквально делает в AI сетке временную дыру. Это косвенно подтверждается тем, что путь сглаживается при подходе к зоне рестриктора. Тем не менее, это ничуть не мешает неписю пройти вдоль аномалии, как только он таки до неё дошёл, что может приводить к тому эффекту, который я описывал выше. Это предположение можно проверить, у меня есть идея как именно. Надо будет заняться на досуге.
  8. Artos, Я это наблюдал своими глазами, когда настроил телепорт на выход рядом с костром. Было отлично видно, как неписи разбегаются из центра костра и попутно жарятся. Добавлено через 13 мин.: Artos, Это не просто слова, всё имеет значение. Настоящее "видит" может срабатывать на расстоянии. Если же не видит, а "видит", то это не понять что и не понять как работает. Если шейп аномалии находится внутри шейпа рестриктора, то "увидеть" его невозможно никак, потому что единственный способ, чтобы непись о нём узнал - это коснуться его. Но он же внутри рестриктора, как непись его коснётся? Ну и зачем его включать тогда? Потому и выключен. Это отвечает на твой вопрос "почему не 2, а 0". Если есть внешний рестриктор, то попасть в него снаружи непись не может никак. Эта часть сетки попросту исключена из навигации. Значит единственным способом для непися попасть внутрь - это оказаться уже внутри, что, логически рассуждая, может произойти только в момент выхода в онлайн. Почему конкретно это происходит (непись стоит в точке костра при выходе в онлайн), я на самом деле не знаю.
  9. Artos, Да не будут они "видеть" два, поскольку внутреннее не сработает никогда. Они вообще ничего здесь не видят, поскольку касание относится к другому типу сенсоров, тактильному, вдобавок рестриктор - вообще не сенсор, а просто тупой запрет на вход. Видеть аномалию неписи не могут хотя бы потому, что у неё нет визуала и сенсор зрения на неё не сработает. Ну а если внутренний шейп, принадлежащий самой аномалии, никогда не сработает, то и нет смысла нагружать движок ненужными проверками. Это же не бесплатно всё, эти проверки вешаются на внутренний апдейт и подразумевают проверку попадания в данный шейп каждого непися на уровне. Не так уж мало вычислений. Что касается неписей, обходящих аномалии. Лично я наблюдал картину противоположную описанной тобой: непись идёт строго по краю аномалии, а та непрерывно на него срабатывает. Непись не дохнет сразу только потому, что степень удара вроде как зависит от расстояния до центра и на краю существенно меньше. Почему неписи жарятся/жарились в кострах - это отдельный разговор. Там кажется были проблемы с оффлайновым перемещением, когда они выходили в онлайн в костре, застревали в бочке и соответственно там благополучно дожаривались. Как-то так вроде, хотя на 100% не уверен. Не боги горшки обжигают =) Сказали кому-то расставить костров на уровне и накрыть рестрикторами. Этот кто-то не заморачиваясь натыкал их за полчаса, после чего все об этом забыли. А мы тут скрытый смысл ищем.
  10. Artos, речь шла о том, почему самой аномалии назначают тип рестриктора 0, т.е. как рестриктор не работает. Так? Я об этом и говорил, что самой аномалии нет смысла придавать ещё и тип рестриктора, поскольку это не будет работать. Вне зависимости от формы и размера встроенного в аномалию шейпа аномалия срабатывает раньше, чем срабатывает задаваемый той же формой рестриктор. Почему бокс, а не сфера, сие мне не ведомо. Может схалтурили просто.
  11. Artos, Это более-менее понятно. Костёр - это аномалия. Да, у него есть шейп и этот шейп может одновременно работать и как ограничитель. Но есть одна неприятность. Дело в том, что механизм работы аномалии таков, что она срабатывает от касания. Это означает, что непись начнёт жариться, ещё фактически не войдя в рестриктор костра, а только коснувшись его. Просто для справки, по такому же механизму работает левелченджер по отношению к актору. С другой стороны, механизм работы рестриктора таков, что он ограничивает на вход по условию геометрического вхождения в рестриктор. Т.е., чтобы считалось, что непись находится внутри, его центр должен попасть внутрь шейпа рестриктора. Короче, условие на касание срабатывает раньше, чем условие на попадание внутрь, соответственно, если использовать саму аномалию костра как рестриктор, то неписи начнут жариться раньше, чем обходить костёр. Поэтому и добавляют второй рестриктор большего размера, а рестриктор аномалии отключают, чтобы не жрал ресурсы.
  12. *Shoker*, Самое главное и не попробовал =) Если ты указываешь просто имя, то файл берётся по текущему пути. А ты его знаешь? Используй класс FS для получения полного пути по относительному от каталога игры или напиши сам руками.
  13. *Shoker*, os.execute работает без проблем. Путь верно задаёшь?
  14. Удаляются рестрикторы, не удаляются... Переведите название функции remove_in_restriction. Речь не о рестрикторах (restrictor), а об ограничениях (restriction). Удаляются ограничения (задаваемые естественно именем рестриктора).
  15. SkyLoader, Я сам хотел бы это знать. По идее, исходные значения где-то там внутри по-любому есть, иначе ида не могла бы делать патчи. Значит можно вернуть к этим исходным значениям, но как - я в своё время тоже голову сломал. В итоге, не нашёл ничего лучше, чем для патчей делать отдельный проект. Для каждого патча в отдельном каталоге открываю dll заново, жду конца анализа, делаю патч. Проект выкидываю или сохраняю в зависимости от планов на него.
  16. _Призрак_, если надо быстро, то забудь про это. Но в самом то деле, зачем выводить быстро и при этом динамически переносить строки? На худ что ли многострочный текст дампить? Думаю, что при выводе на худ лучше как-то решить вопрос компромиссно - самому распределить строки и отформатировать текст. Если же вывод подразумевается в диалоговое окно, то соображения скорости по большому счету не важны. В этом случае однако нет другого решения, кроме как считать символы и слова и формировать текст с переносами. Дополнительная сложность будет в том, что ширина символов почти всех ходовых шрифтов движка - неодинаковая. Придется делать допущения о среднем размере символа и вводить некий запас, чтобы строка ненароком не вылезла за ширину окна. Ну или сформировать таблицу размеров символов и при суммировании брать размеры из этой таблицы по коду. Еще раз, для диалога самое чудовищное решение в плане скорости скорее всего никаких проблем не вызовет. На худ так естественно выводить нельзя.
  17. Artos, лампочки биндятся как физические объекты. Для них можно прописать логику включения выключения. Можно поискать пример по ключевому слову turn_on_object/turn_off_object
  18. CON, оружие не использует класс, оно создается определенного класса. Это самый корневой параметр в секции. Он читается первым, затем в зависимости от его значения создается объект определенного класса, затем из секции читаются параметры для объекта этого конкретного класса.
  19. Malandrinus

    X-Ray extensions

    Небольшое замечание по одной потенциальной проблеме. При сборке желательно использовать по возможности свежую версию ассемблера (годится от последних студий и НЕ годится от masm32). А вот линковщик от последней студии может вызывать проблемы. Итого, линковшик лучше взять как раз от masm32. Суть проблемы я сам до конца не понимаю. Почему-то при определённых условиях линковщик новой версии начинает дурить и смещает стартовую позицию кода от начала сегмента кода на значение, кратное 16. Зачем он это делает и что помещает в освободившееся пространство, я не понимаю. В файле там нули. В результате, патчер, который переносит код из одной либы в другую, этой ситуации распознать не в состоянии и возникает неопределяемый сбой. Решение привёл выше. Если такая ситуация возникнет, то попробуйте использовать старый линковщик. Прежде чем грешить на этот эффект, однако, надо понять, что это именно эта проблема, а не любая другая. Запаситесь заранее исправным файлом mydll.dll (промежуточной либой с нашими правками). Если возникло подозрение на эту проблему, то сравните получившийся проблемный mydll.dll с этим эталонным. Рекомендую использовать для сравнения Total Commander и его инструмент сравнения файлов. При возникновении описанной выше ситуации вы увидите, что фрагменты кода (вкрапления ненулевых значений на фоне в целом нулевого содержимого файла) смещены по отношению к эталонному файлу, а должны быть в одном месте. Важен именно факт смещения, а не сами значения.
  20. Полтергейст, У сталкеров и монстров update серверного объекта не делает ничего, кроме как вызывает brain():update(). У остальных объектов и вовсе ничего не делает. С Scheduled = off вообще-то странно. По-моему, этот параметр нигде и никак не читается: ни в движке, ни в скриптах.
  21. Gun12, В сталкере есть готовое решение, в чистом Lua есть debug, да и никто не мешает его расширить по самое нехочу, поскольку Lua встраивается в свою систему в виде исходников. Что касается решения с перебором таблиц. Проблема в его неустойчивости и плохой сопровождаемости. Если объективно взвесить все плюсы и минусы, то получится, что проще в паре мест кода незатейливо вставить строки с именем файла, поставить внятный комментарий в этом месте и потом при случае эти строки обновлять. Можно для контроля соорудить функцию проверки наличия модуля и поставить там ассерты для отлова ситуации, когда имя файла изменилось, а эту строку не поменяли. В итоге, времени на сопровождение или адаптацию кода будет мизерным + код простой и прозрачный. С другой стороны, решение с перебором может в итоге потребовать примерно тех же самых манипуляций да еще и не дает стороцентной гарантии результата. Хотели сделать один раз и забыть, а получили сравнимый геморрой + усложненный код. Мне интересно, в связи с чем потребовалось узнавать имя модуля? У меня самого такая задача тоже возникала, но настолько редко, что я бы не заморачивался на автоматизацию даже при отсутствии штатных стредств. Добавлено через 29 мин.: Artos, так ведь и тема в основном для отвлеченной болтовни =)
  22. Gun12, если нужен чистый Lua, то тогда имеет смысл задействовать debug. Кажется функция debug.getinfo позволяет получать нужную информацию. К примеру, debug.getinfo(1,"n") дает имя текущей функции, но там можно получить гораздо больше информации. Может и имя модуля можно, точно не знаю.
  23. Gun12, все же куча потенциальнфх проблем: 1. Совпадение имен. Во-первых, а чего плохого в том, что в разных модулях есть функции с разными именами? Наличие функций с одинаковыми именами может быть требованием дизайна, к примеру функции с именами типа init, setup, обработчики событий в модулях, связанных с системами сигналов (наподобие систем xStream или моей). Далее, в некой таблице, не являющейся модулем, может оказаться поле с именем, совпадающим с именем текущей функции. Это может вообще получиться непреднамеренно в ходе динамического заполнения таблицы из файла конфига или именами секций объектов или еще каким-то способом, исключающим контроль на стадии написания кода. 2. Функция может быть безымянной 3. Придется поддерживать синхронность между именем функции, которое в общем может измениться в ходе редизайна кода, и этим фрагментом. Если так рассуждать, то я вероятно выберу из двух зол меньшее: просто буду вставлять вручную строчку с именем модуля. Но однако есть script_name(), так что можно не париться.
  24. Gun12, два вопроса: 1. Как отличить поля с таблицами-модулями от полей просто таблиц, коих в глобальном пространстве имен предостаточно? 2. Как узнать, что это именно твой текущий модуль?
  25. *Shoker*, В чистом Lua можно только через debug. В сталкере однако есть небольшое расширение на этот счёт. script_name() - возвращает имя текущего модуля без расширения Также на всякий случай this - ссылка на текущий модуль (таблица) Работает только в файлах с расширением *.script
×
×
  • Создать...