- BrainTools - https://www.braintools.ru -

Недавно я вспомнил о игре Star Wars Jedi Knight: Jedi Academy, на которую подростком потратил больше десяти тысяч часов. Изучая материалы о ней, я наткнулся на любопытную историю.
Оказывается в 2013 году, сразу после покупки Lucasfilm компанией Disney и закрытия LucasArts, разработчики Raven Software запаниковали, что их работа будет навсегда положена под сукно, поэтому они в спешке выложили весь исходный код Jedi Outcast и Jedi Academy онлайн.
Этот дамп был таким внезапным, что они даже не подчистили внутренние комментарии разработчиков. Весь код превратился в капсулу времени, прочитав которую, можно узнать о том, как вымотанные программисты сходят с ума, пытаясь реализовать физику светового меча на движке Quake 3.
Заглянув в основной файл боёв (bg_saber.c), можно увидеть, что вся система схваток на световых мечах представляет собой огромную спагетти-конструкцию switch из пяти тысяч строк.
Я прошерстил кодовую базу [1] и нашёл потрясающие комментарии:
1. sv_savegame.cpp — разработчику пришлось написать имитацию цикла загрузки, чтобы игрок успевал прочитать всплывающее сообщение «Saving».
// Если мне ещё раз придётся писать такую белиберду, я просто брошусь под автобус.
int startOfFunction = Sys_Milliseconds();
// ...спустя несколько десятков строк...
// Первым дело отложенный скрипт закрывает всплывающее сообщение "Saving",
// но нам нужно, чтобы оно отображалось хотя бы секунду, поэтому сидим здесь
// в ждущем цикле. См. примечание об автобусе в начале функции.
2. AI_Jedi.cpp — пытаться заставить ботов пользоваться Силой и перемещаться по 3D-картам на CPU 2003 года явно было не самым лучшим решением.
{ //нахрен, просто будем прыгать
{ //нахрен, просто шарашим Силой
3. Отрезание конечностей (G2_bones.cpp) — для того, чтобы можно было отрезать конечности, в Jedi Academy использовалась собственная система скелетной анимации. Необходимость ручного переопределения углов шарниров привела к этому примечанию:
// зачем это нужно делать, одному дьяволу известно. но это нужно делать.
4. bg_pmove.cpp — кому-то пришлось слишком долго отучать модели персонажей соскальзывать по плоским поверхностям.
{ //мы на земле, не движемся и находимся на ровной поверхности, не надо добавлять сраную гравитацию с помощью clipvelocity!!!
5. NPC_reactions.cpp — реальная логика [2] кода, когда игрок стоит, направив прицел прямо в лицо дружественного NPC.
//спрашиваем, какого хера он делает
6. Математика [3] Quake (q_math.cpp) — это знаменитый трюк с битовым хакингом позаимствован прямиком из движка Quake 3 Джона Кармака. Даже разработчики из Raven, читавшие его годы спустя, не смогли разобраться, как он работает.
i = 0x5f3759df - ( i >> 1 ); // это что за нахрен?
7. mhead.c — когда движок находит повреждённые заголовки данных файлов MP3 или WAV.
return 0; // чёрт знает, что это такое, но точно не наше...
8. Ошибка [4] с фатальным вылетом (win_glimp.cpp) — что происходит, если графический рендерер полностью отказывается загружаться в Windows.
// сообщение об ошибке, к которой я сделаю откат, если навернётся что-то серьёзное
9. Ярость [5], направленная на Win32 (инструмент ModView) — те, кому доводилось бороться с Win32 API, оценят имя этой функции, которая заставляла UI обновлять панель заголовка документа.
void FuckingWellSetTheDocumentNameAndDontBloodyIgnoreMeYouCunt(LPCSTR psDocName) {
if (gpLastOpenedModViewDoc) {
// чтоб, сука, он точно делал то, что нужно...
gpLastOpenedModViewDoc->SetTitle(psDocName);
}
}
10. wp_saber.cpp — когда другой разработчик ломает главный файл заголовка, и тебе приходится вручную объявлять свои переменные через extern.
// Нужно вручную написать для них extern. Нельзя сделать #include qcommon.h из-за какого-то дятла
11. Ограничения скелетных мешей (g_client.cpp) — попытка изогнуть позвоночник персонажа игрока на основании отклонения мыши, не поломав при этом хитбокс.
//ФУХ-Х-Х... ломаем его полностью
// ...18 строк спустя...
//ФУХ-Х-Х... позвоночник мотыляется, к хренам всё это
12. Исправление мультиплеер-коллизий в однопользовательской игре game (g_active.cpp) — самый быстрый способ устранить баг физики, при котором NPC убивались, залезая друг в друга моделями.
Так как движок Quake 3 создавался для мультиплеера, все части игры — это «клиенты»; Raven переделали движок под однопользовательскую компанию, поэтому если NPC сталкиваются друг с другом на слишком большой скорости, то они просто умирают. Вместо того, чтобы тратить недели на изменение алгоритмов поиска пути искусственного интеллекта [6], разработчики одним оператором if просто избавились от урона при коллизиях между NPC.
{//ой, в жопу всё это, клиенты больше не наносят друг другу урон, только если это не player
13. Логика состояния транспорта (g_vehicles.c) — обработка логики при столкновении летающих спидеров со стеной.
{//просто сваливаем из него
14. Урон от взрыва (g_mover.c) — вычисление урона игрокам, стоящим рядом с разрушаемым объектом карты.
{//просто разносим их к чертям
15. нахрен високосные года [7]
16. Отказываемся от линейной алгебры (r_surface.cpp). ModView — это внутренний инструмент, который использовался для рендеринга моделей и анимаций 3D-персонажей. Очевидно, работа с матричными 3D-преобразованиями и математикой поверхностей вынула из кого-то душу.
// В дупу эту математическую хрень, она не работает
// #define real_nclip(x0,y0,x1,y1,x2,y2) ( (y1-y0)*(x2-x1) - (x1-x0)*(y2-y1) )
17. Ярость из-за «железа» начала 2000-х (textures.cpp). Жёстко прописываем исключение просто для того, чтобы графические карты AMD/ATI не вызывали вылет инструмента.
if (error && error != GL_STACK_OVERFLOW
/* дебильные карты ATI почему-то иногда выдают эту ошибку */ )
18. Машина времени аудиобуфера (cl_mp3.org). Для экономии ОЗУ движок декодирует сжатое аудио линейными блоками, поэтому не может просто перемотать аудиобуфер назад. Разработчик решил, что если часы игрового движка внезапно подтормаживают и из-за этого он запрашивает аудиосэмпл из прошлого, то нужно сдаться и ничего не делать.
// чё?!?!?! Я назад в прошлое должен улететь или чего? Да ну нафиг
Очень странно осознавать, что на этом коде работает одна из самых качественных многопользовательских игр. Выражаю благодарность команде OpenJK [8] за улучшение этого спагетти-кода и сохранение жизни игры.
Автор: PatientZero
Источник [9]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/30594
URLs in this post:
[1] кодовую базу: https://github.com/grayj/Jedi-Academy
[2] логика: http://www.braintools.ru/article/7640
[3] Математика: http://www.braintools.ru/article/7620
[4] Ошибка: http://www.braintools.ru/article/4192
[5] Ярость: http://www.braintools.ru/article/6134
[6] интеллекта: http://www.braintools.ru/article/7605
[7] нахрен високосные года: https://github.com/grayj/Jedi-Academy/blob/d71d53e8ecc1edd300c7a9dd22b8fbc39c095423/tools/ModView/oldskins.cpp#L596
[8] OpenJK: https://github.com/JACoders/OpenJK
[9] Источник: https://habr.com/ru/articles/1037908/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1037908
Нажмите здесь для печати.