Меня частенько просят писать не просто новости, но свои мысли и про опыт в геймдеве.
Давайте попробуем тред замутить. 1 ретвит = 1 пример из опыта взаимодействия с Unity за последние 6 лет.
1. За время работы у них несколько раз менялась сетка. В бородатые годы там были [RPC]. Примерно в то же время была альтернатива в виде uLink.
После чего пришлось переехать на HLAPI/LLAPI.
Теперь уже и HLAPI/LLAPI deprecated.
Появился MLAPI, который пока лучше не использовать, т. к. оно пока экспериментально.
Что забавно, в старых доках куча рекомендаций использовать LLAPI, который уже не поддерживается.
А в LLAPI ссылки на новый экспериментальный MLAPI.
При этом куча ссылок ведёт в никуда. Очень много ссылок на туторы и другие страницы тоже уже никуда не ведут.
2. Была у нас однажды проблема с тем, что в какой-то момент просто пропадало всё GUI в игре. В логах спавн сообщений из нативного движка про вертексы.
Так и не было ясно, что не так. В итоге разбили корневой канвас на более мелкие — проблема исчезла.
Баг с UI забавен ещё тем, что, если зайти в иерархию объектов в Редакторе и просто кликнуть по объекту, то гуятина снова появлялась.
3. Были проблемы на конкретных платформах.
В Gameroom от Facebook после какого-то обновления ланчера появилась проблема со скейлом, когда игра реагировала на тачи не в том месте, где они были совершены.
4. С поиском пути AI как-то долго однажды провозился. Было несколько одинаковых (казалось бы) стен. AI рейкастил по маске, чтобы понять, есть ли препятствие на пути.
И почему-то не со всеми каст проходил. Долго возился, а в итоге оказалось, что стенке слой не тот прописали.
5. Когда появился UnityWebRequest, я в наших игровых инстансах серверных (да, они были на Юнити) переписал код для отправки Http-запросов на него.
В какой-то момент запросы переставали отправляться.
Не было ясно, что не так. Даже если экземпляр явно дестроить.
->
Посмотрел в netstat — он показывал сотни незакрытых коннектов.
UnityWebRequest почему-то их вообще не закрывал.
В итоге пришлось остаться на самописном Http-клиенте с использованием дефолтного TcpClient из C#.
6. Касательно серверных инстансов...Мы с определённой периодичностью их обновляли и, соответственно, перезапускали. Поэтому некоторых проблем не замечали.
В какой-то момент не было обновлений на серваке более 2 недель, и, внезапно, мы обнаружили, что на машине закончилась RAM.
Да, серверные инстансы текли. Раньше этого не замечали, т. к. при рестарте память очищалась.
В инстансах у нас поднимались комнаты с аренами. Но в одном из Монобехов оставалась висячая ссылка, из-за чего GC не мог подчистить ресурсы.
Нашли проблемную ссылку, жить стало лучше.
7. Но до конца утечки памяти мы так и не починили. А разбираться на тот момент совсем не было времени.
В итоге сделали так, чтобы инстансы позволяли создавать не более 50 комнат. После чего инстанс сообщал сервису над ним, чтобы тот не инициировал создание новых комнат.
А после закрытия последней комнаты инстанс сам себя закрывал. Но они у меня запускали под супервайзером. Поэтому он сразу перезапускался с чистенькой памятью.
Этот подход так и остался до самого закрытия проекта.
8. В какой-то момент начали приходит тревоги, что на серваке место на диске заканчивается. Но на этих серваках кроме логов ничего не пишется, по сути.
В итоге выяснилось, что Юнитишное LLAPI спамило каждый кадр ошибку из нативного кода, логфайл забил весь хард из-за этого.
Отловить ошибку нельзя. Затрай-кетчить тоже. Что вызывало ошибку? Не ясно.
В итоге я это зарепортил напрямую чуваку из Unity, который сетку пилил (русский, кстати). Через 1-2 апдейта они это потом починили.
9. Периодически игроки жаловались на то, что их выкидывает из игры. С инстансами вроде было всё в порядке. Немного последив за этим делом выяснилось, что это обычно происходило в момент создания новых комнат.
В этот момент часть игроков с текущих комнат дисконнектило...
А Unity у нас однопоточный...Если что-то грузит основной поток, начинаются проблемы.
Всё дело было в парсинге json'ов профилей игроков при создании новой комнаты. На несколько кадров всё фризило. А если одновременно несколько комнат создавалось, то речь уже шла о секундах...
В итоге весь парсинг я просто вынес в отдельный поток, тем самым разгрузив основной.
Это ещё один урок на тему того, что обязательно нужно проводить нагрузочное тестирование.
Пнятненько?
10. Чуть раньше уже писал, что на беке использовался TcpClient для http-запросов. Отлично всё работало, но...иногда на некоторых инстансах ломалась инициализация.
Для сервис дискавери у меня использовался consul.io. Что-то отваливалось в запросах к нему.
Оказалось, что если ответ большой, то он отдавал его чанками. А у меня клиент был простенький, он чанки даже не поддерживал.
Пришлось дописывать, чтоб он умел работать с чанками.
Это урок на тему того, что нужно тщательно читать документацию используемых инструментов.
11. У нас на том проекте никакого DI не было, куча синглтонов юзалось. И если на клиенте ещё более-менее терпимо (нет) было писать что-то типа gamemanager.Player, то на бекенде, ну...сами понимаете.
А большую часть кода мы старались переиспользовать между клиентом и сервером.
Это всё вылилось в то, что на бекенде на всём протяжении разработки периодически всплывали моменты, когда мы обращались совсем не к тому игроку :D
12. А для Json'ов у нас использовался SimpleJSON, который на больших объёмах был не очень. Под капотом там, по сути, хешмепа. В итоге любое обращение к данным было не за линейное время.
На всём протяжении разработки выпиливал это и заменял нормальные классы.
Но даже в самом конце разработки всё равно оставалось множество мест, где мы так и продолжали работать с SimpleJSON и его JSONObject и JSONArray.
Уф. 9 утра уже. Пора баиньки. Как встану, ещё историй подкину.
13. А помните времена, когда в Unity не было Gradle при сборке под Android? А я помню 🌚
Всеми любимая (нет) ошибка при сборке
> Too many field references: 70613; max is 65536
Да, был лимит на число ссылок во всех классах. Как можно было обойти? Выкинуть часть плагинов...
Если у вас использовались тяжёлые плагины вроде FB, Firebase, Крашлитика и т. п, то только они почти весь лимит сжирали.
Ох и намучился я с этим в своё время, чтобы уместить в лимит и билд собрать.
14. Я на тот момент не особо дружил с сертификатами и девопсом. После авторизации наша API'шка клиенту отдавала IP сервака, где игроку комната поднялась.
И всё работало, пока Apple не решили протестировать игру в локальной сети, где что-то намудрили с ipv6...
В общем, запросы до нас не доходили. Возможно это было связано с тем, что они там что-то поменяли по части секьюрности.
В итоге для всех серваков завёл поддомены и API их отдавала, а не голый IP. Проблема решилась.
15. Частенько косячили с очисткой ресурсов/префабов.
Забавный баг, когда при переключении персонажа не удалялась моделька предыдущего. В итоге можно было устроить пати хард.
16. А когда-то в Unity не было своего пакета для платёжек. На тот момент на рынке были Unibill, Prime[31] и Soomla.
Мы использовали Soomla. Говна наелись, особенно при обновления API в Юнити, т. к. порой плагин с обновлениями очень долго не поспевал.
17. С Android очень много всегда было проблем. На момент 4/5 с Android Resolver всё плохо было.
Когда вы обновляете плагин FB, то мог отвалиться плагин Firebase. Хорошо, если в момент билда будет ругаться, что классов нужных нет, но иногда такое только при запуске обнаруживалось
Причём, не все компоненты отваливались. Скажем, Firebase вроде норм инициализировался, а потом в какой-то момент падало по факту что-то, что не на старте срабатывает.
18. С Enum'ами были нюансы. Часто нужно было для них вызывать ToString(), особенно на серваке. Довольно медленно и т. п.
В итоге написали скриптик, который для всех Enum'ов генерил автоматически массивы и считывание уже было по индексу.
19. Про Enum'ы ещё кое-что. Думаю, слышали про боксинг/анбоксинг? В общем, использование Enum'ов как ключей для Dictionary ведёт к постоянному анбоксингу и лишним аллокациям.
Решается двумя путями на выбор: 1. Своей реализацией IEqualityComparer. 2. Использовать int'овый ключ.
Скорость примерно одинаковая.
Мы выбрали второе. В словарях как ключ использовали int, а при получении значений просто приводили enum'ы к int'у.
20. Чтобы разгрузить основной билд и скорость запуска увеличить, часть ассетов вынесли в ассет бандлы и грузили по требованию.
Иногда бывала ошибка "Asset Bundle: CRC Mismatch". Так и не поняли, что с этим делать. При пересборке иногда лечилось. Так и всплывало от раза к разу.
21. Серверный инстанс с аренами представлял собой одну сцену, на который спавнились комнаты с каким-то глобальным оффсетом (скажем, по X сдвиг на 10000).
Как-то задиплоили билд с багом, из-за которого снаряды не уничтожались. В итоге они с одной арены долетали до другой 😅
22. Под конец жизни проекта мы выкатили Батл Рояль режим, где, очевидно, была механика с силовым полем, которое убивало игроков.
После этого на обычных аренах порой стал возникать баг, когда люди в определённом радиусе в центре арены тупо умирали.
23. В Unity для HTTP-запросов раньше был WWW класс, который вообще не поддерживал keep-alive соединения.
В 5.2 (или около того) появился UnityWebRequest, который тоже не поддерживал...И, судя по всему, поддерживать начал только в Unity 2019🤦♂️
24. В Unity очень крутые возможности по кастомизации редактора.
К примеру, можно запросто написать скрипт, которые пробежит по всем префабам/сценам и что-нибудь сделает.
Для одной из игр нужно было для нескольких сотен персов сделать спрайт с их аватаркой (фотка лица).
Я просто настроил положение и камеру. А затем заменял модельку, включал айдл анимацию и скриптом в спрайт сохранял с камеры картинку.
На другом проекте понадобилось ко всем ключам текстовым в специальном компоненте префикс добавить.
Просто пробежал скриптом все префабы/сцены, нашёл все эти компоненты и поменял.
Это уже не говоря про написание отдельных инструментов/окон для редактора, которые упрощают повседневные вещи.
25. Для локализации на проектах порой используем I2 Localization. Обычно проблем не было, но в какой-то момент ко всем строкам добавили префиксы и через некоторое время на проде сломалась у всех локализации.
По дефолту плагин долбится к Гугловским таблицам. Если есть изменения, то качает их.
Раньше проблем не замечали, т. к. не было массовых правок. В общем, не забудьте там в настройках автоапдейт отключить и зашивайте всё в билд.
26. Очень много было проблем с синхронизацией клиента и сервера. К примеру, вот видео, которое нам игрок скинул.
По пушке не проходит урон.
27. С UI и прокликиваниями постоянно сталкивались. Часто были ситуации, когда при довольно быстром нажатии по экрану можно было добиться того, что в каком-то окне оставались части гуи предыдущих окон.
Вот тут в окне похода на арену остался UI от окна открытия сундука с наградой.
28. Синхронизация сервака и клиента вообще довольно непростая штука, особенно, если там всякие оффсеты.
Когда тестируете локально по ходу разработки, то совсем другие условия.
Среда и окружение должны быть максимально приближены к реальным.
Заранее подумайте, как это всё можно тестировать в редакторе, где есть удобный дебаг и прочее.
У нас не для всего так получилось, в итоге приходилось частенько исследовать проблему по логам.
А если это серверная проблема, где сотни игроков, то, ну, сами понимаете...
29. В своё время для авторизации с помощью геймцентра Android нужно было тащить отдельный плагин, тогда как для iOS был Юнитишный класс GameCenterPlatform.
Из того, что вижу, ничего в этом плане не поменялось.
30. С GooglePlayGames вообще много мороки было, начиная с того, что в некоторых версиях некоторые методы не работали, тогда как в других версиях работали эти, но не работали другие.
Больше всего намучился с GetServerAuthCode.
Плагин вообще странный, многие вещи наружу вынесены.
К примеру, для некоторых вещей нужно было использовать и оборачивать вызов методов в GooglePlayGames.OurUtils.PlayGamesHelperObject.RunOnGameThread.
31. Тормозить будет всегда UI. Окна можно инстанциировать на старте игры и отключать (память жрут) либо инстанциировать по надобности (большой фриз при открытии).
Но даже без этого всё равно будут при обновлениях тормоза: 1. Работа с текстом. 2. Перерисовки канвасов. 3. И т. д.
Я: оптимизировал логику AI и рейксаты, а теперь думаю, куда бы направить сэкономленный бюджет кадра.
Тем временем GUI.
32. Случалось, что вы что-то правите в объектах, а потом оказывается, что это всё было в плеймоде, и после нажатия на Stop все изменения терялись?
33. Все, думаю, слышали шутку "если что-то не работает на Винде, то ребутни/переустанови".
С Unity есть похожая тема. Порой, когда начинаются непонятки, ошибки с пакетами и т. п, то советуют удалить папку Library.
Что забавно, это очень часто действительно решает проблему.
• • •
Missing some Tweet in this thread? You can try to
force a refresh
Потихоньку пишу статью про кранчи. С ссылками на исследования и т.п. Довольно порядочно уже текста. Не уверен, что статья будет интересна среднему читателю, но, как минимум, нужно добить этот лонг, чтоб уже отмучиться.
Возможно стоит этот как тред в твиттере выложить 🤔
Пока примерно 20к символов.
Кстати. Про Киберпук. Там многие защитники кранчей кричали, что "пару месяцев можно потерпеть", но напомню, что про кранчи Adam Kiciński в @CDPROJEKTRED говорил ещё в начале года.