ИСТРЕБИТЕЛИ БАГОВ: БУДЕШЬ МОИМ КРЭШЕМ?

Выпуск от 14 февраля 2018г.

Марк Эйбент знает, что в жизни самое лучшее – это истреблять баги, смотреть, как они вынужденно волочатся перед вами, и слышать плач их кода. В этом эпизоде он расследует причины возникновения крэша, связанного с предметными портами. Приступим к истреблению!

Мы здесь на моем изысканном тестовом уровне, где при уничтожении предметов случается один веселый крэш, связанный с предметными портами. Процесс его воспроизведения довольно странный, однако у нас тут есть хороший пользовательский пример. Когда дизайнеры собирали 600i, они случайно оставили внутри двух этих манекенов. Это не реальные люди, а просто анимационные объекты, то есть «ложные» геометрические модели. Внутри корабля, само собой, находится контейнер объектов. Это значит, что сначала мы загружаем внешнюю оболочку транспортного средства, а затем помещаем внутрь этот контейнер объектов, который представляет собой некое подобие отдельного мини-уровня.

Что хорошо – контейнер объектов позволяет вам проводить любые работы над кораблем и создавать сборки, которые затем просто транслируются внутрь. И это довольно изящное решение. Итак, находясь в редакторе вы можете перейти в игровой режим (Ctrl+G) и сыграть в игру так, как будто она была запущена по-настоящему. А если я нажму Esc, то вернусь обратно в режим редактирования. К несчастью, когда я перехожу в игровой режим, случается крэш. И этот крэш происходит на одном из анимационных объектов.

Найдем один из них в коде под обозначением «AnimObject-003». Когда мы заходим в игру, где стоит наш корабль, мы удаляем внутренности и создаем их заново. И этот объект также удаляется и затем создается заново. Это необходимо, поскольку в ходе игрового процесса и редактирования вещи могут изменяться, и нам нужно обновлять их состояние. И когда мы начинаем удалять объекты внутри контейнера объектов, то этот анимационный объект, то есть наш парень-манекен, вызывает крэш при попытке удалить свой предметный порт, к которому прикреплено все надетое снаряжение.

Странно тут то, что… найдем деконструктор контейнера предметных портов… Когда этот объект удаляется, функция деконструктора вызывается в последнюю очередь перед очисткой памяти. И здесь приведен список предметных портов (как вы можете видеть, она их уничтожает). К несчастью, когда происходит уничтожение, любые слушатели, следящие за генерацией этого события, начинают получать доступ к удаляемым предметным портам и контейнерам предметных портов. Однако порты в этот момент находятся в деконструкторе, поэтому когда вы получаете к ним доступ, происходит полный разлад, и вы крэшитесь.

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

Поставим редактор на паузу и добавим в код отладочные точки остановки, которые помогут отследить происходящее. Этот код не пойдет в производство, но покажет порядок возникновения ошибок. Установлю точки остановки в дереве анимационных объектов для любой ситуации, когда мы удаляем предметные порты. Также нам понадобятся точки для каждого факта добавления предметных портов. Надеюсь, это поможет отследить последовательность событий. Скомпилируем все и вернемся в редактор.

Вот мы снова в редакторе. Запустим игровой режим и посмотрим, что произойдет. Итак, первые данные, что мы получили, говорят, что при входе в игровой режим у нас идет правильный вызов. Мы удаляем эту вещь, так что транспортное средство избавляется от контейнера объектов, удаляя все сущности внутри него. Весь интерьер пропадает, а наш анимационный объект избавляется от всех своих предметных портов в правильной последовательности. Это значит, что раз функция удаляет их здесь и производит где-то в другом месте, должно быть какой-то еще элемент добавляет их в иное время. И, конечно, вот он.

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

Вот появилась еще одна новая сущность. Посмотрим, что это такое. Ага, мы отправляем события сразу всем. Значит, что происходит: мы удалили нашу сущность, избавившись таким образом от предметных портов. После этого при переключении в игровой режим программа сгенерировала широковещательное событие сброса для всей системы. А когда наш анимационный объект получил команду на сброс, он, по сути, вернул обратно свое прежнее состояние, добавил все отсутствующие предметные порты (вот такие забавы происходят из-за использования языка LUA), а затем сам был удален на следующем кадре. И теперь, когда сам объект исчез, у нас остаются его предметные порты, которые удаляются деконструктором, в результате чего происходит крэш. Короче говоря, после получения сообщения на сброс, объект восстанавливает удаленные предметные порты лишь затем, чтобы мы снова их уничтожили. И это вызывает хаос.

Что нам нужно сделать – так это обратиться к широковещательному сообщению. Технически нас волнует лишь сброс всех событий, которые установлены на уровне вручную, а не размещены там динамически. То есть если мы вручную устанавливаем транспортное средство, ему понадобится сброс. Но контейнер объектов, который создается внутри корабля, не нужно сбрасывать, поскольку корабль сам разберется с ним. Внесем простое и забавное исправление – добавим условие: «если мы удаляем эту сущность, то не нужно передавать это специфическое системное событие всем сущностям.» Давайте теперь перекомпилируем код и посмотрим на результат.

Мы вернулись в сцену, где стоит мой 600i. Я захожу в игру, и мы удаляем старый контейнер объектов, избавляясь от всех сущностей. Затем избавляемся от анимационного объекта-манекена, который удаляет все свои предметные порты. После чего создается новый объект. Еще раз проверим память… у нас нет предметных портов. Отлично. Продолжаем,… и я в игре. Конечно, мой 600i просто падает вниз, поскольку у меня не задана гравитация.

Я думаю, это решение задает настроение. Надеюсь, вам понравилось. Увидимся в следующий раз.

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

Источник: https://star-citizen.ru

logo

ПОХОЖИЕ СТАТЬИ

Корабельная верфь: прочие корабельные предметы

Корабельная верфь: прочие корабельные предметы

Руководство к новой матрице кораблей Приветствуем, Граждане! В этой статье мы обсудим наши конечные пункты в списке специализированных корабельных предметов новой матрицы кораблей. А именно речь пойдет о служебных и системных предметах. Хотя их наличие легко проигнорировать, ведь они...

Страховка в Star Citizen

Страховка в Star Citizen

  Как работает страховка в Star Citizen и как игроки будут ей пользоваться. Автор: Кристофер Ливингстон Когда я играл в билд альфы 3.0, несколько недель назад в студии CIG в Лос-Анджелесе,  обратил  внимание на нечто, что раньше не видел на...

Обновление дорожной карты

Обновление дорожной карты

Теперь карта будет обновляться каждые 2 недели по средам, и сопровождаться пояснительной запиской к этим правкам. На этой неделе разработчики представили группу Core Tech Group в Progress Tracker и состоялся дебют Release View, разработчики сразу заявляют что речь идёт о потенциально...