В исходном коде Jedi Academy нашли гневные комментарии разработчиков

Не так давно я предавался ностальгии по Star Wars Jedi Knight: Jedi Academy — проекту, в котором в юности провел, пожалуй, с десяток тысяч часов. Углубившись в историю игры, я наткнулся на весьма примечательный эпизод.

Оказалось, что в 2013 году, сразу после поглощения Lucasfilm корпорацией Disney и ликвидации студии LucasArts, разработчики из Raven Software, опасаясь, что результаты их многолетнего труда навсегда канут в Лету, в экстренном порядке опубликовали исходный код Jedi Outcast и Jedi Academy в открытом доступе.

Этот «слив» произошел настолько стремительно, что программисты даже не потрудились удалить внутренние комментарии. В результате код превратился в своего рода капсулу времени, позволяющую прочувствовать все муки и отчаяние разработчиков, пытавшихся «подружить» физику светового меча с движком Quake 3.

Если заглянуть в ключевой модуль боевой системы (bg_saber.c), становится очевидно, что логика сражений держится на «спагетти-коде» — исполинской конструкции switch, насчитывающей около пяти тысяч строк.

Я изучил репозиторий и нашел там совершенно поразительные комментарии:

1. sv_savegame.cpp — ради того, чтобы игрок успел заметить уведомление «Saving», автору пришлось имитировать цикл ожидания.

// Если мне придется еще раз писать этот бред, я, пожалуй, брошусь под автобус. 
int startOfFunction = Sys_Milliseconds(); 
// ...спустя несколько десятков строк... 
// Отложенный скрипт первым делом закрывает плашку "Saving", 
// но нам критически важно, чтобы она висела хотя бы секунду, поэтому крутимся здесь. 
// См. заметку про автобус выше.

2. AI_Jedi.cpp — попытки заставить NPC эффективно использовать Силу и ориентироваться в трехмерном пространстве на процессорах 2003 года явно давались с трудом.

{ // к черту, просто прыгаем
{ // к черту, просто применяем Силу

3. Расчленение (G2_bones.cpp) — для отрисовки отрубаемых конечностей Jedi Academy использовала собственную систему скелетной анимации. Необходимость ручной настройки углов сочленений вызвала у разработчика приступ сарказма:

// зачем это нужно делать — известно одному дьяволу. Но делать это нужно.

4. bg_pmove.cpp — борьба с персонажами, которые упорно скользили по ровным поверхностям, видимо, отняла немало нервов.

{ // мы на земле, стоим неподвижно на плоской поверхности, не надо добавлять сраную гравитацию через clipvelocity!!!

5. NPC_reactions.cpp — логика поведения, когда игрок наводит прицел прямо в лицо дружелюбному NPC.

// спрашиваем, какого черта он творит

6. Математика Quake (q_math.cpp) — знаменитый алгоритм битового хакинга из движка Джона Кармака. Даже спустя годы специалисты Raven признавались, что не понимают, как это вообще работает.

i = 0x5f3759df - ( i >> 1 ); // что за чертовщина?!

7. mhead.c — реакция на поврежденные заголовки в MP3 или WAV файлах.

return 0; // бог знает, что это такое, но явно не наше...

8. Фатальный краш (win_glimp.cpp) — что случается, если графический рендерер категорически отказывается запускаться в среде Windows.

// сообщение об ошибке, к которому я откачусь, если случится нечто непоправимое

9. Ненависть к Win32 (инструмент ModView) — те, кто имел «удовольствие» работать с Win32 API, поймут негодование, скрытое в названии этой функции обновления заголовка окна.

void FuckingWellSetTheDocumentNameAndDontBloodyIgnoreMeYouCunt(LPCSTR psDocName) {
    if (gpLastOpenedModViewDoc) {
        // чтобы он, черт возьми, сделал именно то, что от него требуется...
        gpLastOpenedModViewDoc->SetTitle(psDocName);
    }
}

10. wp_saber.cpp — ситуация, когда из-за чьего-то сомнительного архитектурного решения приходится объявлять переменные через extern.

// Приходится прописывать extern вручную. Нельзя сделать include qcommon.h из-за одного конкретного олуха

11. Ограничения скелетных мешей (g_client.cpp) — попытка сделать поворот позвоночника персонажа вслед за мышью, не разрушив при этом хитбокс.

// УХ... ломаем его до основания
// ...18 строк спустя... 
// УХ... позвоночник болтается, к чертям всё это

12. Исправление коллизий NPC (g_active.cpp) — самый «эффективный» метод борьбы с багом физики, из-за которого NPC погибали при контакте друг с другом.

Так как движок Quake 3 затачивался под мультиплеер, в котором все объекты — «клиенты», при портировании под синглплеер столкновение NPC на большой скорости приводило к их мгновенной смерти. Разработчики не стали тратить недели на переработку ИИ и просто добавили if, отключающий урон при столкновении NPC между собой.

{// да ну его к черту, клиенты больше не наносят друг другу урон, если только это не игрок

13. Логика транспорта (g_vehicles.c) — обработка инцидентов, когда летающие спидеры врезаются в препятствия.

{// просто катапультируемся

14. Урон от взрыва (g_mover.c) — вычисление урона по целям рядом с разрушаемым объектом.

{// разносим их в щепки

15. к черту високосные годы

16. Отказ от линейной алгебры (r_surface.cpp). ModView использовался для рендеринга персонажей. Видимо, работа с 3D-матрицами и поверхностями стала для кого-то последней каплей.

// К черту эту математику, она все равно не работает
// #define real_nclip(x0,y0,x1,y1,x2,y2) ( (y1-y0)*(x2-x1) - (x1-x0)*(y2-y1) )

17. Конфликты с «железом» начала нулевых (textures.cpp). Жесткая фильтрация ошибок ради того, чтобы драйверы AMD/ATI не обрушивали утилиту.

if (error && error != GL_STACK_OVERFLOW
    /* кривые карты ATI почему-то иногда выкидывают эту ошибку */ )

18. Проблемы с аудио (cl_mp3.org). Чтобы экономить память, движок декодирует звук последовательными блоками, поэтому перемотка аудиобуфера назад невозможна. Если из-за лагов движка аудиопоток «отставал», программист решил просто смириться.

// Чё?! Я что, должен уметь путешествовать во времени? Идите к черту

Поразительно осознавать, что на этом «архитектурном чуде» работает один из лучших мультиплеерных шутеров в истории. Огромная благодарность команде OpenJK за то, что привели этот хаос в порядок и подарили игре вторую жизнь.

 

Источник

Читайте также