На чем написан wot
Язык программирования WoT
Сервер написан на С++ (из вакансии)
Клиент на питоне(он ругался по питоньи при запуске в линуксе)
ну и на плюсах, следуя из цитаты.
возможно использовались и другие ЯП при написании клиента и сервера.
Сервер написан на С++ (из вакансии)
Клиент на питоне(он ругался по питоньи при запуске в линуксе)
ну и на плюсах, следуя из цитаты.
возможно использовались и другие ЯП при написании клиента и сервера.
А вот про сервер ничего сказать не могу. Не видел.
Клиент на питоне(он ругался по питоньи при запуске в линуксе)
Я из Wargaming: что значит быть программистом?
Иван Петроченко, глава отдела разработки движка World of Tanks Blitz
Как начинали?
Делать игры мечтал с детства. По образованию я эколог. До этого была школа с экологическим уклоном.
В индустрии я уже больше десяти лет. Попал в нее относительно легко: разместил резюме, через день позвонили и позвали «разрабатывать под мобилки» в небольшую, известную в узких кругах компанию Incubus. Ничего удивительного — в 2004 году в Минске игроделов можно было по пальцам пересчитать и отечественный геймдев был в зачаточном состоянии. Со временем, конечно, ситуация поменялась.
Вторым местом работы стала TikGames. По меркам того времени это был уже игрок покрупнее и гораздо известнее — в компании успела поработать приличная часть моих нынешних коллег 😉
Затем была Dava Consulting, которая впоследствии вошла в состав «Гейм Стрим». Так в моей жизни появился World of Tanks Blitz.
Мне всегда нравилось делать игры. К этому лежит душа. Писать код для скучных приложений, наверное, не смог бы.
С чем работаете?
Платформа у нас не одна. Это и iOS, и Android, и Windows 10. Недавно добавилась Mac OS. Что касается языка, то это классика геймдева — всеми любимый C++. Это основа основ и 95% всей работы. Конечно, есть и другие скрипты, которые используются для автоматизации (Python и так далее).
Софт — Visual Studio для Windows, Xcode для Mac и iOS. C Android уже сложнее. Капризная платформа диктует свои правила. Используем то, что удобнее всего, однако идеальный софт еще не нашли.
А какое образование нужно?
Я, наверное, в очередной раз повторю то, что все и так знают. Чтобы создавать первоклассные игры, необязательно иметь три диплома и курсы разработчика за плечами. У нас работают как самоучки, превратившие сырой талант в блестящие результаты, так и те, кто целенаправленно планировал идти в индустрию еще на этапе получения образования.
Хороший геймдев-разработчик должен быть экспертом во многих областях. Современные игры даже среднего уровня основываются на большом количестве технологий (если не брать в счет проекты на высокоуровневых движках, например, на Unity). Нужно хорошо владеть теоретической частью (структура данных, алгоритмы), разбираться в трехмерной графике, знать особенности операционных систем (в случае World of Tanks Blitz их много, так как игра кросс-платформенная).
Это как с иностранными языками — чем больше ты языков знаешь, тем легче тебе даются новые. Если ты освоил 10 технологий, вероятнее всего, с 11-й сложностей не будет.
Известны случаи, когда в программирование приходили прямиком из строителей. Да, и такое бывает. Однако отмечу, что лучше начинать до 30 лет. Чем раньше, тем лучше. Слишком много специфики и нюансов, которые надо охватить. На это нужно время.
Что важно?
Если программист умеет быстро разбираться с незнакомыми технологиями, то он хороший специалист. В этой сфере очень высоко ценится способность адаптироваться. Это архиважно. Безусловно, основа (С++) постоянна. Однако нюансы меняются из года в год. Появляются новые стандарты, что хорошо видно на выставках и конференциях, где демонстрируются достижения мировой IT-индустрии.
Как только ты перестал развиваться, ты дрейфуешь где-то на среднем уровне, несмотря на наличие опыта. Консервация — это плохо. Необязательно посещать все специализированные мероприятия и не пропускать ни одной конференции. Это нужно, скорее, чтобы прочувствовать атмосферу и вдохновиться. Своеобразная моральная подпитка. Учиться и углублять знания можно не выходя из дома. Есть интернет с огромным количеством литературы, технических блогов, лекций.
Сейчас на самом деле передовое время. Та теория, которая была разработана 30–40 лет назад, находит отклик в аппаратных возможностях современных технологий. Появилась возможность реализовать то, что было придумано на бумаге.
Английский?
Без английского в программировании никуда. Вся полезная литература, весь «свежак», новейшие материалы выходят, к сожалению, не на русском. Но никто не говорит, что нужен продвинутый уровень владения языком. Достаточно понимать. Мне сложно представить программиста, не знающего хотя бы азов английского. Разве что специалисты по 1С, где нужно писать кириллицей.
Это скучно?
Нет. Программист — это не тот человек, который сидит и тихонько пишет код. Он придумывает. Особенно если мы говорим об игровой индустрии. Другое дело —проект какой-нибудь банковской системы: когда человек приходит на работу, ему дают программу, которую до него писали десять лет, и он продолжает над ней трудиться, минимально меняя код. Это беспощадная рутина. То же самое и с бухгалтерией — здесь по большому счету нечего изобретать.
В геймдеве динамика намного выше. Во-первых, редко когда игра существует в первозданном виде пять или более лет. Те же «Танки» постоянно обновляются.
А как в Беларуси?
Можно выучиться на гейм-дизайнера в университете (БГУИР) или закончить курсы, которых появляется все больше и больше. Однако огромную роль играет самообразование: интернета хватит с лихвой, надо просто захотеть. Когда приходят резюме, я даже не смотрю на пункт «Образование». Диплом есть почти у всех, ценится опыт и собственные проекты. Недавно на собеседование приходил кандидат, недавний выпускник, который написал свой игровой движок. Он показал, как все работает, объяснил механику. Вижу ли я в нем достойного специалиста в будущем? Конечно. Сразу понятно, что человек интересовался этим с детства, получил хорошие знания в интернете и будет развиваться.
Кого берете?
Людей с техническим складом ума, которые умеют решать новые задачи. Человека, который пришел с опытом работы в геймдеве, видно за версту — диалог выстраивается сам собой и идет по накатанной. Новичка в индустрии разговорить уже сложнее.
«Джуниору» к нам попасть сложно. Команда уже сформирована, необходимости в расширении у нас нет. Нужны люди, которые смогут углубить экспертизу.
Бывает, что в резюме написано одно, а при личной встрече оказывается, что это неправда. Преувеличено, присвоено и так далее. Это всегда узнается.
С чего начать?
Тому, кто очень хочет не только в программирование, но в IT в принципе, лучше начинать с техподдержки. А еще лучше — с QA (знаю реальные примеры). Это бывает, когда есть желание и соответствующий склад ума, но не хватает технической подкованности. Два-три года работы в индустрии в поддержке или тестировании обычно устраняют пробелы.
Совет молодым?
Посоветую никогда не забрасывать профессиональное развитие. Инструментов для поддержания хорошей формы хватает. Для ленивых: существуют сайты, где все представлено в легкой и увлекательной форме. Допустим, есть игра, к которой нужно написать искусственный интеллект. Результатом можно очень сильно вдохновиться.
Разбор протокола World Of Tanks
Часть первая: инструментарий мелкосерийного изобретения велосипедов
Почему и зачем: длинная и необязательная преамбула
Хорошо, что опыта игрового модостроительства у меня было немного — так, пару кастомных прицелов для Deer Hunter 2005 и «нелицензионный» недоклиент VATSIM/FSD с сопутствущим «взломом» протокола последнего. Ещё лучше, что ни разу не приходилось с головой погружаться в сколь-нибудь трудоёмкую и длительную отладку и дизассемблирование. То есть, с IDA и OllyDBG я поверхностно знаком, но не как с ежедневными рабочими инструментами.
Итак, я уверен, что в обозримом будущем никаких планов по введению полноценного режима спектатора в WOT нет и не будет. Под полноценным режимом спектатора я понимаю множественные подключения игроков в сеанс боя изначально как невзаимодействующих на игру «привидений»-наблюдателей, а не на технике. Это тот самый режим, из-за отсутствия которого комментаторы на чемпионатах WOT вынуждены заходить в бой 15-м танком, убиваемым своими на базе. Это тот самый режим, из-за которого появились моды «командирского zoom» и «кинематографической камеры» — по сути, просто костыли. А нужен такой режим затем, чтобы командир роты занимался командованием, а не скакал впереди на лихом танке по-чапаевски, чтобы он видел ситуацию на карте в целом непрерывно, а не отвлекался на неё в пылу нападения из засады. В идеале, командиру даже не нужны красоты трёхмерного мира — достаточно одной большой карты на весь монитор с игровой ситуацией в реальном времени — HP, повреждениями модулей, членов экипажа, направлениями стволов и прицелов союзной техники, засвеченных в каждый момент вражеских юнитов и прочей вспомогательной информации.
WOT предоставляет широкие возможности модостроительства, но такая идея выходит за рамки классического «заменить пару swf-файлов на свои». Потребуется перехват и разбор самого игрового протокола для того, чтобы иметь возможность передать на командирский планшет своё видение игровой ситуации.
Обход шифрования 0x0A-й дорогой
Первые робкие попытки пролезть в протокол танков я предпринял ещё в 2011 году. Начинать это, как и везде в подобных задачах, стоит с хорошего сниффера (кстати, в случае с VATSIM/FSD на этом можно и остановиться — внезапно оказалось, что протокол там текстовый), и я, вооружившись Microsoft Network Monitor’ом, ринулся в бой. За отчётные 3 года в схеме входа ничего кардинально не поменялось, кроме количества игровых кластеров. Сервис авторизации у каждого кластера живёт на одном IP, к нему уходит один пакет с логином-паролем, и от него приходит один пакет — как минимум, с идентификатором конкретного игрового сервера из этого же кластера, на который клиенту надо переключиться, и с чьим IP происходит весь дальнейший обмен. Выглядит это всё приблизительно так
Помеченные октеты, судя по тому, что изменяются они мало и более-менее предсказуемо — заголовок пакета. После них идёт равномерный битовый шум, то есть там уже включается шифрование. Тут можно было вспомнить, что записи боёв в WOT шифруются BlowFish’ем, и что ключ шифрования не изменялся с того момента, как стал известен широкой публике, и покопаться глубже — но смысла в этом особого не вижу. Для задуманного гораздо важнее то, что ходит между клиентом и сервером в процессе игры, чем то, как он авторизуется при входе.
Итак, если трафик проходит потоковое шифрование, логично предположить, что где-то в глубинах программы есть функция наподобие SendToServer(), в которой есть вызов вроде EncryptBuffer() и в которой, в конечном счёте, выполнение доходит до конкретного sendto(). Наша задача, для начала — найти, где это происходит. Загружаем танки в OllyDbg и перед нажатием на кнопку «Войти» ставим логирующий брейкпоинт на sendto().
Через несколько десятков срабатываний, уже в ангаре, вызовы sendto() становятся более монотонными, в том плане, что адрес буфера для отправки данных не меняется:
Чтобы узнать, где шифруется этот буфер, я сначала пошёл по неправильному пути — начал изучать графы вызовов в IDA и отслеживать вручную возвраты из функций. Где-то на 15-й такой функции мне это надоело, я полностью заблудился в коде и поставил брейк на запись по адресу буфера.
Брейк сработал внутри вот такой чудесной функции по адресу 0x00BAF76F, чудесность которой состоит в том, что в неё передаются 3 параметра — два адреса буфера и ещё один — их одинаковая длина. Тот самый EncryptBuffer(ptr_src,ptr_dest,len), который нам нужен. Что там лежит в незашифрованном виде, мы пока смотреть не будем, об этом позже.
Это что касается отправки данных. Как быть с приёмом? Немного сложнее, но, в целом, так же, поэтому не буду утомлять вас большими и страшными скриншотами отладчика. Схема такая — ставим брейк на recvfrom(), смотрим адрес буфера, куда складывается принятый зашифрованный пакет. Ставим брейкпоинт на чтение с адреса буфера и тут нам в очередной раз повезло — брейк срабатывает на вызове функции по адресу 0x00BAFB79, которая занимается расшифровкой блоков по 8 байт и находится, в свою очередь, в теле функции по адресу 0x00BAFB30. А уже эта функция почти такая же чудесная, как и та, что мы нашли выше: она принимает 4 параметра — два адреса буфера, их длину и какой-то флаг.
Назовём её DecryptBuffer(ptr_src,ptr_dest,len,flag). Адреса буферов, как видно, совпадают. Что полностью логично, так как при потоковом шифровании стоит ожидать одинаковой длины блоков исходного и шифротекста.
Осталась одна тонкость. Если функцию EncryptBuffer() достаточно перехватывать непосредственно перед её вызовом (т.е. ставим INT3-брейкпоинт вместо CALL) вытаскивая память по адресу ptr_src длиной len, то в момент вызова DecryptBuffer() оба указателя покажут на один и тот же блок, который ещё пока зашифрован. Поэтому перехватывать эту функцию надо перед самым возвратом, который у неё происходит командой RETN 10 по адресу 0x00BAFBA8. В этот момент на стэке лежат те же параметры, за исключением того, что ptr_src равен нулю (это нововведение версии 0.8.11, в предыдущей указатели как-то оставались равны) и адрес возврата. И ptr_dest, конечно, показывает на расшифрованный буфер. Теперь, когда мы знаем, где в клиенте WOT сообщения ещё не зашифрованы и где уже расшифрованы, нужно их оттуда автоматически вытаскивать для дальнейшего анализа.
Что же там внутри?
Здесь матёрые гуру реверс-инжиниринга, в духе «There’s an emacs command to do that» подумают: «ага, ну теперь можно написать на питоне\эзотерическом языке вот такой скрипт\плагин для ольки\иды, который будет делать с этими данными всё что хочешь и даже за пивом сбегает». Но мы пойдём другим путём. Я хочу сразу ориентироваться на то, что ещё до того, как дело дойдёт до разработки командирского планшета, то есть даже для самого полноценного разбора протокола WOT мне понадобятся помощники и тестировщики, далёкие от мира программирования. Им нужен будет простой инструмент с понятным интерфейсом, выдающий легко читаемые данные.
Так что предвидя скептические ухмылки, я засел за Lazarus и набросал в нём специализированный win32-отладчик, основной функцией которого является поставить два INT3-брекпоинта в нужных местах и по их срабатыванию вытаскивать данные по адресу и длине буфера, лежащим на стеке по известным смещениям. Ещё он умеет вести txt.gz лог с hexdump’ами пакетов и записывать все прошедшие пакеты так, что их потом можно заново «проиграть» через парсер. Вот что получилось. Так WOT клиент только начинает входить в ангар.
А вот так он себя ведёт уже находясь в ангаре.
Какие выводы можно сделать, даже не смотря на пояснения к пакетам, которые я поленился убрать для этих скриншотов? Сразу несколько.
Во-первых, видно, что все пакеты начинаются либо с 0x48, либо с 0x58, либо с 0x78; какой-нибудь закономерности на этот счёт я ещё не уловил, кроме того, что пакеты с уже известной функцией свой значащий байт не меняют.
Во-вторых, почти в каждом пакете есть один или несколько счётчиков сообщений; например, в keep-alive и ответах на них этим занимается третий и четвёртый байт в заголовке, кроме того сам пакет содержит ещё счётчик сообщений общий (включая keep-alive) и какой-то специфический (считающий пакеты без учёта количества keep-alive); всё это имеет отношение к контролю доставки пакетов, который пришлось прикрутить к UDP, вероятно, для оценки потерь и пересылки BLOBов (об этом позже).
Размеры всех пакетов выравнены по границам 8 байт, что ненавязчиво указывает нам на размер блока всё того же BlowFish; пока я до этого догадался, прошло немало времени в попытках обьяснить странную «контрольную сумму» в конце, да ещё и переменной длины. В конце концов, получив в этом паддинге вместо простого мусора слово «Flags» я, наконец, прозрел.
Ну и в лучших хакерских традициях, в конце каждого пакета находится сигнатура мёртвой говядины; кто бы мог подумать где мы её найдём 🙂
После получения Session ID от сервера приезжает пакет, содержащий номер игрока в неожиданно текстовом формате (792067). А вот пакет, который начинается на 0x78 0x00 на первом скриншоте — особо интересен. Сочетание сигнатуры 0x80 0x20 вкупе с тем, что перед каждым строковым литералом в нём стоит 0x55 и байт длины строки, а после каждого 0x71 находится возрастающий номер, должно насторожить опытных питонщиков — это же, чёрт побери, Python Pickle со своим запихиванием всего подряд в мемо! Вот он такой:
В следующей части, если она заинтересует уважаемых обитателей Хабра, я расскажу о том, как в протоколе WOT передаются файлы, размеры которых намного больше реалистичного размера UDP пакета и MTU. И о том, что эти файлы оказывается сжатыми zlib’ом а внутри у них всё тот же Python Pickle с разными неожиданными вещами.
Спасибо за внимание!
UPD. Свежие новости! По агентурным данным из самого сердца КВГ, мой лёгкий намёк на потенциал коммерческого использования командирского планшета поднял «небольшой бугурт» (дословно), в результате чего кровавые модераторы в полнейшей панике наконец заметили и слили в мусорник тему проекта на официальном форуме танков, а мне было доверительным шёпотом посоветовано замылить данные своего аккаунта на скриншотах.
Движок игры
На каком языке в основном написан Клиент?
На каком языке в основном написан Сервер?
Какие программы вы используете на сервере игры?
Какие языки вы использовали при написании Сервера/Клиента?
Интересно что вы ответите
Do you know the way
Победителям Великой Отечественной:
Спасибо Вам за тишину, за наше небо голубое.
За то, что в страшную войну,
Сумели Мир Прикрыть Собою.
Xiaomi Mi Max 6.44″ . G o o g l e Android 6, Miui 8.
Создание World of Tanks Blitz на базе собственного движка DAVA
Пролог
Эта история началась более трех лет назад. Наша небольшая компания DAVA стала частью Wargaming, и мы начали обдумывать, какие проекты делать дальше. Чтобы напомнить, каким был мобайл три года назад, скажу, что тогда не было ни Clash Of Clans, ни Puzzle & Dragons, ни многих очень известных сегодня проектов. Mid-core тогда только-только начинался. Рынок был в разы меньше сегодняшнего.
Изначально всем казалось, что очень хорошей идеей будет сделать несколько мелких игр, которые бы привлекали новых пользователей в большие «танки». После ряда экспериментов оказалось, что это не работает. Несмотря на отличные конверсии в мобильных приложениях, переход от мобильного телефона к PC оказывался пропастью для пользователей.
Тогда в разработке у нас находилось несколько игр. Одна из них носила рабочее название «Sniper». Основной геймплей-идеей была стрельба в снайперском режиме из стоящего в обороне танка, по другим танкам, которыми управлял AI и которые могли атаковать в ответ.
В какой-то момент нам показалось, что стоящий танк — это очень скучно, и за неделю мы сделали прототип мультиплеера, где танки уже могли ездить и атаковать друг друга.
С этого все и началось!
Когда мы начинали разработку “Снайпера”, то рассматривали технологии, которые тогда были доступны для мобильных платформ. На тот момент Unity был еще на достаточно ранней стадии своего развития: по сути, необходимых нам технологий еще не было.
Основной вещью, которой нам не хватало, был рендеринг ландшафта c динамической детализацией, что является жизненно необходимым для создания игры с открытыми пространствами. Было несколько сторонних библиотек для Unity, однако их качество оставляло желать лучшего.
Также мы понимали, что на C# мы не сможем выжать максимум из устройств, под которые мы разрабатываем, и всегда будем ограничены.
Unreal Engine 3 тоже не подходил по ряду похожих причин.
В итоге, мы решили дорабатывать свой движок!
Он на тот момент уже использовался в наших предыдущих казуальных проектах. Движок имел достаточно хорошо написанный низкий уровень работы с платформами и поддерживал iOS, PC, Mac, плюс были начаты работы по Android. Было написано много функциональности для создания 2D-игр. То есть, был неплохой UI и много всего для работы с 2D. В нем были первые шаги по 3D-части, так как одна из наших игр была полностью трехмерной.
Что у нас было в 3D-части движка:
Начало работ
Началось все с доказательства возможности отрисовать ландшафт на мобильных устройствах: тогда это были iPhone 4 и iPad 1.
После нескольких дней работы мы получили вполне функциональный динамический ландшафт, который работал довольно сносно, требовал где-то 8MB памяти и давал 60fps на этих устройствах. После этого мы начали полноценную разработку игры.
Прошло около полугода, и маленький мини-проект превратился в то, чем сейчас является Blitz. Появились совершенно новые требования: MMO, AAA-качество и другие требования, которые движок в его изначальном виде на тот момент уже не мог обеспечить. Но работа кипела полным ходом. Игра работала и работала неплохо. Однако производительность была средней, объектов на картах было мало, и, собственно, было множество других ограничений.
На этом этапе мы начали понимать, что фундамент, который мы заложили в движок, не выдержит пресса реального проекта.
Как все работало на тот момент
Вся отрисовка сцен была основана на простой концепции Scene Graph.
Основной концепции являлись два класса:
Первые шаги по улучшению ситуации
Для начала мы решили полечить проблемы с производительностью и сделать это быстро.
Собственно, сделали мы это, введя дополнительный флаг NEED_UPDATE в каждой ноде. Он определял, нужно ли такой ноде вызывать Update. Это действительно повысило производительность, но создало целый ворох проблем. Фактически код функции Update выглядел вот так:
Это вернуло нам часть производительности, однако началось много логических проблем там, где их не ждали.
LodNode, и SwitchNode — ноды, отвечающие, соответственно, за переключение лодов (по расстоянию) и переключение объектов (например, разрушенных и неразрушенных) — начали регулярно ломаться.
Периодически тот, кто пытался исправить поломки, делал следующее: отключал NEED_UPDATE в базовом классе (ведь это было простое решение), и совершенно незаметно FPS опять падал.
Когда код, проверяющий флаг NEED_UPDATE, был закомментирован раза три, мы, решились на радикальные перемены. Мы понимали, что сделать все сразу у нас не получится, поэтому решили действовать поэтапно.
Самым первым шагом было заложить архитектуру, которая позволит в перспективе решить все возникающие у нас проблемы.
Комбинирование компонентного и data-driven-подхода
Решением этой проблемы стал компонентный подход, комбинированный c data-driven подходом. Дальше по тексту я буду употреблять data-driven-подход, так как не нашел удачного перевода.
Вообще понимание компонентного подхода у многих людей самое разное. То же — и с data-driven.
В моем понимании, компонентный подход — это когда некая необходимая функциональность строится на основе независимых компонентов. Самый простой пример — это электроника. Есть чипы, у каждого чипа есть входы и выходы. Если чипы подходят друг к другу, их можно соединить. На базе такого подхода построена вся индустрия электроники. Есть тысячи разных компонентов: соединяя их друг с другом, можно получать совершенно разные вещи.
Основные плюсы этого подхода в том, что каждый компонент изолирован, и с большего независим. Я не беру во внимание тот факт, что на компонент можно подать неправильные данные, и плата сгорит. Плюсы этого подхода очевидны. Сегодня можно взять огромное количество готовых чипов и собрать новое устройство.
Что же такое data-driven. В моем понимании, это подход к проектированию программного обеспечения, когда за основу потока выполнения программы берутся данные, а не логика.
На нашем примере представим следующую иерархию классов:
Код обхода этой иерархии иерархически выглядит так:
В данной иерархии C++ наследования мы имеем три различных независимых потока данных:
Давайте представим, как это должно выглядеть в data-driven подходе. Напишу на псевдокоде, чтобы была понятна идея:
По сути, мы развернули циклы работы программы, сделав это таким образом, чтобы все отталкивалось от данных.
Данные в data-driven подходе являются ключевым элементом программы. Логика — лишь механизмы обработки данных.
Новая архитектура
В какой-то момент стало понятно, что надо идти в сторону Entity-based подхода к организации сцены, где Entity являлась сущностью, состоящей из многих независимых компонентов. Хотелось, чтобы компоненты были полностью произвольными и легко комбинировались между собой.
Читая информацию по этой теме, я наткнулся на блог T-Machine.
Он мне дал множество ответов, на мои вопросы, однако основным ответом было следующее:
• Entity не содержит никакой логики, это просто ID (или указатель).
• Entity знает только ID компоненты, которые ей принадлежат (или указатель).
• Компонент — это только данные, то есть. компонент не содержит никакой логики.
• Система — это код, который умеет обрабатывать определенный набор данных и выдавать на выходе другой набор данных.
Когда я понял это, в процессе дальнейшего изучения различной информации наткнулся на Artemis Framework и увидел хорошую реализацию этого подхода.
Исходники тут, если предыдущий линк не работает: Artemis Original Java Source Code
Если вы разрабатываете на Java, то очень рекомендую посмотреть на него. Очень простой и концептуально правильный Framework. На сегодняшний день он спортирован на кучу языков.
То, чем является Artemis, сегодня называют ECS (Entity Component System). Вариантов организации сцены на базе Entity, компонентов и data-driven достаточно много, однако мы по итогу пришли к архитектуре ECS. Сложно сказать, насколько это общепринятый термин, однако ECS значит, что есть следующие сущности: Entity, Component, System.
Самое главное отличие от других подходов это: Обязательное отсутствие логики поведения в компонентах, и отделение кода в системы.
Этот пункт очень важен в “православном” компонентном подходе. Если нарушить первый принцип, появится очень много соблазнов. Один из первых — сделать наследование компонентов.
Несмотря на гибкость, заканчивается обычно макаронами.
Изначально кажется, что при таком подходе можно будет сделать множество компонентов, которые ведут себя похожим образом, но чуть-чуть по-разному. Общие интерфейсы компонентов. В общем, можно опять свалиться в ловушку наследования. Да, это будет чуть лучше, чем классическое наследование, однако постарайтесь не попасть в эту ловушку.
ECS — более чистый подход, и решает больше проблем.
Чтобы посмотреть на примере, как это работает в Artemis, можете глянуть вот тут.
Я на примере покажу, как это работает у нас.
Главным классом контейнером является Entity. Это класс, который содержит массив компонентов.
Вторым классом является Component. В нашем случае, это просто данные.
Вот список компонентов, используемых у нас в движке, на сегодняшний день:
Третим классом является SceneSystem:
Функции RegisterEntity, UnregisterEntity вызываются для всех систем в сцене тогда, когда мы добавляем или удаляем Entity из сцены.
Функции RegisterComponent, UnregisterComponent вызываются для всех систем в сцене, тогда, когда мы добавляем или удаляем Component в Entity в сцене.
Также для удобства есть еще две функции:
Эти функции вызываются, когда уже создан заказанный набор компонентов с помощью функции SetRequiredComponents.
Например, мы можем заказать получение только тех Entities, у которых есть ACTION_COMPONENT и SOUND_COMPONENT. Передаю это в SetRequiredComponents и — вуаля.
Чтобы понять, как это работает, распишу на примерах, какие у нас есть системы:
В практически любой системе код выглядит следующим образом:
Системы можно классифицировать по тому как они обрабатывают объекты:
Соответственно, если есть желание можете заходить и смотреть на нашу имплементацию в деталях.
Учитывайте тот факт, что все писалось в реальном проекте, и, конечно, это не академическая реализация.