Предыдущие части: раз, два, три.
Благодарим за игру!
В первой части Wing Commander при выходе из игры мы получали от нашего менеджера памяти EMM386 исключение. Экран очищался и на него выводилась единственная строка, что-то типа «Ошибка менеджера памяти EMM386. Бла-бла-бла».
Нам нужно было выпустить игру как можно быстрее, поэтому я отредактировал ошибку менеджера памяти в hex-редакторе, чтобы она выглядела как «Благодарим за то, что играли в Wing Commander».
— Кен Демарест
Стопроцентно чистые фруктовые соки
Когда я впервые начал работать в игровой индустрии, бОльшую часть времени я трудился в разных небольших скупо финансируемых стартапах. Вот страшилка из тех времён, когда мужчины были мужчинами и использовали DirectX 7. Я работал в компании, которую издатель заставил использовать конкретный 3D-движок. Я не буду его называть, но издатель утверждал, что купил кучу лицензий на него в крупной сделке с лицензированием, поэтому настаивал на его использовании.
Скажем прямо — движок не работал, и бОльшую часть времени работы в компании я занимался тем, что учил 3D-движок правильно делать очевидные вещи, такие как реализация однопроходного наложения карт освещения из нескольких текстур.
Одной из самых интересных неработавших вещей был BSP-компилятор. Дизайнеры уровней создавали геометрию уровней с правильной видимостью, после чего незначительные изменения геометрии нарушали области видимости совсем в другой части карты. Я и по сей день не знаю, почему так происходило, но полагаю, что BSP-компилятор движка добавлял кисти в BSP-дерево в случайном порядке и определённые комбинации… просто произвольным образом всё ломали.
В то время я ещё не слышал о рандомизированном алгоритме, но тем не менее изобрёл его — к BSP-компилятору мы добавили этап предварительной обработки, который перемешивал порядок кистей перед их передачей BSP-компилятору. Если геометрия уровня ломалась в BSP-компиляторе, мы просто пробовали тасовать кисти с другими случайными числами, пока не находили работающую комбинацию и придерживались её, пока BSP-компилятор не ломался в очередной раз.
Сама игра была катастрофой — и движок, и игра попали в комикс Penny Arcade, в котором впервые появился Fruitf*cker 2000. Это остаётся важным пунктом моей карьеры.
— Николас Вининг
Перемотка вперёд
Я работал над NBA JAM TE для Sega Genesis, в которой использовался флеш-чип для сохранения игровых данных. Игру тестировали несколько месяцев, и уже всё было готово к выпуску, поэтому издатель заказал 250 тысяч копий картриджей. Но вскоре стало очевидно, что никто за долгие месяцы не сбрасывал флеш-чипы на тестовых картриджах, чтобы проверить правильность выполнения процедур инициализации флеш-памяти. И никто не заказывал картриджи для тестирования.
Только после заказа всех картриджей мы обнаружили, что код инициализации флеш-памяти умер, и картриджи не могут правильно сохранять игры! Вся студия сошла с ума, пытаясь понять, как выпустить 250 тысяч сломанных картриджей. Мы попробовали реализовать рекомендации производителей, добавив дополнительные резисторы и другие хаки, но ничего не помогало.
Когда всё казалось потерянным, кто-то выяснил, что если играть в игры в очень странном и чётко заданном порядке, то флеш-память вроде бы начинает работать. Поэтому в каждую коробку с картриджем была вложена листовка с описанием того, как использовать эту «фичу».
— Крис Кёрби
Задымление
Мой любимый «хак последней минуты» использовали в режиме для четырёх игроков игры Nitrobike для PS2. Как обычно, дизайнеры уровней и художники делали свою работу, ни капли не осознавая, насколько она осуществима в реальном мире, и, как обычно, работу по «завершению» игры целиком оставили мне.
После множества споров и столкновений я заставил их упростить графику уровней, создать визуально скрываемые области и убрать излишние динамические объекты. Но это не могло спасти один конкретный уровень с кинематографической тематикой. Сам дизайн уровня противился сокрытию лишнего — он состоял из двух огромных комнат (по сюжету — звукозаписывающих павильонов), которые ничем не перекрывались и соединялись двумя открытыми дверями.
Одна дверь была посередине стены. Не было никакого способа выстроить перекрывающие полигоны для блокирования одной комнаты, чтобы её нельзя было видеть из другой, как и не было способов удалить какую-нибудь графику уровня, не разрушив его стиль. Мне необходимо было найти способ подставить на стену один большой перекрывающий среднюю стену полигон. И потом меня озарило — «стена дыма» из частиц, закрывающая среднюю дверь, хорошо будет сочетаться с уровнем в кинотематике и полностью решит мою проблему.
Стену дыма можно проехать насквозь, но не видеть через неё, и она скроет существование моего перекрывающего полигона! Я имел возможность взять себе одного художника для создания такого эмиттера и одного дизайнера уровней, чтобы расположить эмиттеры с обеих сторон двери.
И наконец посередине я вставил один очень большой перекрывающий полигон. Это выглядело хорошо и устраняло последнюю проблему со скоростью уровней.
— Стивен Босуэлл II
… а может сюда?
Я пишу игры уже более 20 лет, а недавно работал техническим руководителем в THQ, поэтому насмотрелся на всевозможные ужасные хаки. Но есть один, над которым я смеюсь до сих пор. Случился он с Beam Software в начале 1990-х.
В ту эпоху, когда ещё не было удобных IDE и умных компиляторов, мы писали все игры на языке ассемблера. Во всех файлах .s содержался соответствующий ассемблерный код для отдельных частей игры: creature1.s, collision.s, controls.s и так далее. Кроме того, мы использовали makefile — программист создавал новый файл .s и размещал его после всего остального в makefile.
Идея заключалась в том, что ты вводишь в командную строку
make
, и ассемблер собирает каждый файл в новый файл .o, после чего компоновщик соединяет их все вместе для сборки готового исполняемого файла. У нас был один программист, печально известный написанием кода с багами, который мешал каким-нибудь случайным областям памяти. Обычно это были переполнения буфера.Он тратил какое-то время на нахождение этих багов, но если ему это не удавалось, то он… изменял порядок файлов в makefile, чтобы файлы статически компоновались в памяти в другом порядке! Это означало, что случайно записываемый фрагмент памяти теперь находился в в каком-то другом месте, но благодаря чистой удаче игра почему-то переставала вываливаться. Он делал так до тех пор, пока практически любые перемены в makefile не начали приводить к сбоям.
В последний момент, когда игру уже нужно было выпускать, он решил эту проблему. Он просто продолжил создавать новые файлы .s, заполненные небольшими фрагментами данных, которые вставлял в произвольные места в makefile, пока они каким-то образом не перестали крашиться, после чего выпустил её! В тот период было по крайней мере две игры (для Game Boy), выпущенные с использованием такой «техники».
— Шейн Стивенс
Подстандарт
Мы стремились выпустить игру World Series of Poker 2008, которая стала нашим первым проектом на PlayStation 3. PS3 поддерживала несколько разных разрешений экрана и два соотношения сторон. Мы создали 2D-оболочку для широкого экрана, но нам не хватило времени и ресурсов на 2D-оболочку со стандартным разрешением. Я тщательно изучил требования разработчика и не нашёл никаких причин, по которым был бы запрещён леттербоксинг.
Поэтому наш режим со стандартным соотношением был просто широкоэкранным режимом с чёрными полосами над и под картинкой. Издатель отчаянно пытался подогнать требования, которые бы заставили нас это исправить, но потом сдался и мы выпустили игру как есть. К тому же, через несколько часов после покупки собственной PS3, поиграв на телевизоре со стандартным соотношением сторон, я пошёл и купил себе широкоэкранный телевизор. Сомневаюсь, что многие подключали это чудо техники (PS3) к старым ламповым телевизорам!
— Стивен Босуэлл II
Стремление к константам
По какой-то причине у нас возникла огромная несовместимость между имевшейся кодовой базой и новыми миллиардами строк кода, написанными для того, чтобы использовать старые библиотеки кода. Первый код был написан людьми, которым была близка идея «безопасного» программирования, как можно более строгого и ограничивающего для избежания ошибок. Поэтому они использовали функцию языка C / C++ под названием CONST.
CONST означает «константа»; она гарантирует, что переменные только для чтения невозможно изменить внутри функций. Код с CONST и без CONST оказался несовместимым друг с другом, из-за чего компилятор ругался. Команда разработчиков решила вставить в код хак и выполнила хитрый маленький трюк: #define const, чтобы константа была… ничем, пустым местом. Поэтому конструкция
const int x;
при предварительной обработке перед компиляцией становилась int x;
. Это аналогично тому, что вы купили машину, сняли два колеса и используете её в качестве мотоцикла.Лично я ужасно ненавижу CONST, поэтому мне понравился этот трюк. Но некоторые считали такой подход аналогом отрезания ремня безопасности ножницами.
— Аноним
Реальность кусается
У нас был баг в игре на движке Unreal Engine 3 для PlayStation 3 (это была первый выпускаемый проект на UE3 для PS3): во режиме отладки игра необъяснимым образом вываливалась во время printf() при подключении к многопользовательской игре.
Клиент в режиме отладки выводил все хэши каждого из пакета контента, который приказывал ему загружать сервер, и очевидно, в одном из хэшей (в этой сборке) присутствовал %. Мы не смогли придумать хорошее решение проблемы, но #ifndef PS3 работал вполне нормально до следующей сборки данных, в которой баг исчез.
Примерно год спустя в следующем проекте я натолкнулся на тот же самый баг и воспользовался точно таким же исправлением. Катастрофа произошла уже после выпуска игры, когда мы работали над патчем контента. Создание DLC/патча выполнялось таким образом, что мы не могли пропатчить скомпилированный UnrealScript, но у нас был баг, при котором два удалённых вызова процедур не были помечены как надёжные; это означало, что пакеты для их вызова будут передаваться заново до получения подтверждения. Поэтому в условиях плохого соединения функции включения готовности и состояния передачи голоса в лобби иногда не вызывались. Однако пометить удалённые вызовы процедур как надёжные можно только UnrealScript, а мы не могли патчить UnrealScript.
Поэтому при загрузке мы обходили в цикле все загруженные объекты UFunction (которые являются представлением функции скрипта на C++), выполняли строковое сравнение имён и присваивали этим двум вызовам флаг «надёжный». Всё работало замечательно.
— Аноним
Ваши данные готовы
Игры Xbox Live Arcade на первом Xbox должны были целиком упаковываться в файл .xex. Чтобы реализовать это, мы хранили все данные в файле .zip, встроенном как раздел данных в исполняемом файле. Постепенно файл так разросся, что мы больше не могли загружать раздел данных в память, выделять достаточно памяти для его распаковки и вытаскивать нужный файл.
Чтобы устранить проблему, я написал код, который после загрузки игры считывает заголовок PE исполняемого файла и записывает смещения разделов данных. Благодаря этому файловый поток, который считывал исполняемый файл, мог просто переходить на смещения разных zip-файлов и выводить их прямо из исполняемого файла без загрузки разделов данных в память.
— Пэт Уилсон
Камера-обскура
Я расскажу о старом случае: Force 21 была одной из первых трёхмерных RTS, в которой использовалась плавающая камера для наблюдения за текущим отрядом. К концу проекта у нас появился странный баг, при котором камера прекращала следовать за отрядом — она просто останавливалась, пока отряд продолжал двигаться, и ничто не могло сдвинуть её с места. Это случалось в случайные моменты времени и мы не могли воспроизвести ошибку.
Так продолжалось до тех пор, пока один из тестеров не заметил, что это происходит чаще, когда рядом с техникой игрока происходит авиаудар. Благодаря этой информации мне удалось найти источник ошибки. Так как камера использовала скорость и ускорение, а также могла участвовать в коллизиях, я сделал её наследуемой от класса PhysicalObject, который обладал такими характеристиками. Но у него была и ещё одна характеристика: PhysicalObject мог воспринимать урон. Авиаудары наносили высокий урон в довольно большом радиусе, поэтому они в буквальном смысле «убивали» камеру.
Я исправил эту ошибку, сделав так, чтобы камеры не получали урона, но чтобы подстраховаться я повысил значения их брони и энергии до огромных значений. Думаю, можно уверенно сказать, что в нашей игре была самая мощная на свете камера.
— Джим Ван Верт
Хексапильность
Я занимался тестингом The New Tetris для N64. У нас случался сбой, который я мог воспроизвести в любой момент: на экран выводился дамп регистров, после чего игра зависала. Чтобы избавиться от зависания, приходилось отключать и включать питание N64: даже клавиша сброса не реагировала.
Версия за версией разработчик говорил, что баг исправлен, и версия за версией я его воспроизводил. Приближался дедлайн выпуска, и чтобы выпустить игру, разработчику необходимо было устранить все приводящие к сбоям баги. (Nintendo самостоятельно выполняла тестирование даже игр других компаний, и для выпуска игры Nintendo должна была её одобрить.) Но от этого бага никак не могли избавиться.
Также в игре были никак не связанные с багом секретные коды, которые можно было вводить для разблокирования разных возможностей. Однажды я пошутил, что разработчику стоит заменить экран шестнадцатеричного дампа надписью «Поздравляем! Вы обнаружили секретный код! Отключите и снова включите консоль, а потом введите имя пользователя HALUCI». А он так и сделал. Именно благодаря этому игра была выпущена.
— Аноним
Короткий стек
В 1982-83 годах я был одним из нескольких интернов в IMAGIC, и в то время все мы делали картриджи для Intellivision. Одному из программистов нужно было вернуться к учёбе, поэтому меня выбрали, чтобы я устранил баг с зависанием в его игре. Это оказалось переполнение стека в обработчике таймерного прерывания.
Так как единственной задачей обработчика было обновление отображения экранного таймера, я добавил в начале процедуры прерывания код для тестирования глубины стека. Если существовала опасность переполнения стека, то процедура выполняла возврат, ничего не делая. Так как обработчик вызывался много раз в секунду, игрок ничего не замечал, а ошибка была исправлена.
— Аноним
Назад к основам
Мы с коллегой Майком Мика портировали игру о собирании тайлов Klax с аркадных автоматов на Game Boy Color. Это был интересный, напряжённый шестинедельный проект по переносу на систему одной из наших любимейших игр.
У нас был исходный код на C (на самом деле от игры Escape from the Planet of the Robot Monsters, только большинство роботом-монстров закомментировано и заменено на код Klax), и мы часто общались с программистом оригинальной аркадной игры Дэйвом Экерсом, который написал за выходные прототип на Amiga BASIC и портировал его на C примерно за день.
Мы кодировали игру на ассемблере Z80. Было много интересного, например, мы переписывали код на белую доску и мысленно проходили строку за строкой, обновляя содержимое памяти на другой белой доске, потому что у нас не было настоящего отладчика. Хорошие были времена.
Сроки уже поджимали, но всё работало нормально. Я играл в аркадную версию, тестировал версию для GBC и обнаружил странный баг подсчёта очков. Саму проблему я не помню, но там было что-то вроде ситуации, когда большой крест разбивался на несколько диагоналей. Как бы то ни было, очки на GBC по сравнению с аркадным автоматом начислялись неправильно.
Не нужно говорить, что я обнаружил это примерно в 11:30 вечера (прямо перед завершением срока). Мы запускали код миллион раз, сравнивали свой ассеблерный код с кодом на C аркадного автомата, и баг был невозможен. Мы считали очки правильно, и наш код выполнял точно то же и в том же порядке, что и программа на C, которая была просто построчным переносом того, что Дэйв изначально сделал на Amiga BASIC. (Подозреваю, что Дэйв был немного похож на Майка — отлично разбирался в ассемблере и BASIC, но недолюбливал C двадцать лет назад, когда был сделан Klax.)
Наконец примерно в пять утра, потратив на это всю ночь, мы пришли к мысли, которая могла и не заработать, но попробовать её стоило. Майк написал систему подсчёта очков на Quick BASIC, и очки начали считаться точно так же, как и на аркадном автомате. Затем мы построчно перенесли BASIC в ассемблер Z80.
Это сработало. Бог знает, почему, но программа вела себя в точности как на аркадном автомате (возможно, это как-то связано с тем, что оригинал был написан на BASIC). Мы отправили сборку Atari, распечатали обе версии кода и пошли в кафе. За завтраком мы целый час смотрели на код и всё равно не поняли, почему он работает по-другому. Мы и сегодня можем оба поклясться, что код должен был давать идентичные результаты! Но иногда, когда становится слишком поздно, настаёт пора заняться вуду-программированием!
— Крис Чарла
Игры — не единственная область, в которой хаки могут спасти ситуацию. Вот два неигровых примера, которые слишком любопытны, чтобы не включить их в качестве бонуса.
Мойщики окон
Пять лет назад я работал программистом в области разработки ПО для видеонаблюдения. Мы писали очень чувствительное и сложное ПО безопасности. У нас был замечательный, хорошо работающий продукт. Самой сложной частью ПО было одновременное отображение на экране 50 видеопотоков. Для работы ПО требовался огромный объём памяти, и оно должно было функционировать 24/7.
За несколько недель до выпуска мы передали заказчикам бета-версию. Неделю спустя мы заметили огромную утечку памяти — примерно по 4 КБ в минуту. Я потратил пару дней на изучение утечки, но это не дало никаких результатов, и у нас не оставалось времени, чтобы устранить её до выпуска. Память была важнейшей частью ПО, и утечка такого размера полностью убила бы приложение. Проводя тестирование (в Windows), мне приходилось сворачивать окно ПО, чтобы возвращаться к окну с кодом, и во время этого я замечал серьёзное снижение занимаемой памяти.
Потом я вспомнил, что при переносе окна в область уведомлений или в панель меню «Пуск» Windows мгновенно восстанавливает неиспользуемую/освобождённую память. Это был наш шанс! Я добавил в приложение таймер, который каждые пару минут перемещал окно в панель меню «Пуск», а потом сразу же разворачивал его во весь экран. На экране это выглядело как мерцание, зато работало! После этого мы смогли выпустить приложение, что дало нам ещё немного времени на исправление бага (который мы обнаружили через несколько дней — какой-то дескриптор окна не выполнял очистку должным образом).
— Йохан Лауни
Результаты могут отличаться
В 1970-х я с командой работал над банковской системой. Мы писали на давно забытом языке программирования MPL2. В этом языке было ограничение в 256 глобальных переменных, и поскольку все они использовались, для добавления новых функцию в систему часто приходилось искать переменную, которую можно освободить или использовать для двух разных целей в разных частях кода.
Это был рискованный и долгий процесс. Внутри программы каждая функция могла иметь 256 собственных переменных, ограниченных областью видимости функции. Однажды, когда я был дома, на меня снизошло озарение. На следующее утро я предложил начальнику обернуть весь код в функцию. Тогда у нас бы появилось для программы 256 глобальных переменных, потому что используемые пока 256 будут надёжно храниться во «внутренней» функции.
Сама программа просто объявляла бы ещё несколько переменных, а затем вызывала бы функцию, в которой находилась бы вся исходная программа. Но теперь бы она могла «видеть» не только собственные 256 переменных, но и новые 256 глобальных переменных. Мой босс был настроен скептически, но выделил мне двухчасовое окно времени компиляции и был ошеломлён тем, что это сработало. Мы смогли обойти проблему, которая стояла перед командой в течение пары лет.
Комментарии (46)
Cheater
24.05.2018 14:14+1#define const, чтобы константа была… ничем, пустым местом.
Лично я ужасно ненавижу CONST
Дичь какая. Разработчику игр вроде бы как раз неплохо знать, хотя бы в общих чертах, что константность влияет в тч на оптимизации, выполняемые компилятором?Cheater
24.05.2018 14:19+1Upd: Ну и не знаю как они при таком трюке не схватили ошибку компиляции для перегрузок вида:
#define const void foo(const int*); void foo(int*);
Antervis
25.05.2018 07:20const не особо влияет на оптимизации даже сейчас, а тогда и подавно был не более чем диагностикой компилятора. Да и появился const в языке си тоже не сразу, и в какое-то время практика его использования еще не выработалась
Upd: Ну и не знаю как они при таком трюке не схватили ошибку компиляции для перегрузок вида:
перегрузки доступны в с++, а не в чистом си, о котором идет речь (возможно, тогда плюсов еще и не было)HenadziMatuts
25.05.2018 08:20нет, там речь идёт не только о чистом Си:
Поэтому они использовали функцию языка C / C++ под названием CONST.
Но можно предположить, использовали именно его, а даже если и C++, то перегрузки могли просто не использовать.
domix32
24.05.2018 15:07Вероятно это было время когда каждый писал собственные баги в компилятор.
poxvuibr
24.05.2018 16:10Ну #define private public — это из кода DOOM 3.
RiseOfDeath
24.05.2018 16:27+1А можно предысторию, зачем им это вообще понадобилось?
poxvuibr
24.05.2018 16:51+2Запутались в модификаторах доступа. Раньше всё писали на чистом Си, там такого не было. Потому решили заюзать С++, ООП все дела. И в один прекрасный момент поняли, что легче всё сделать публичным, чем распутать то, что у них получилось.
TheShock
24.05.2018 20:25+1А почему бы не зареплейсить во всем проекте, вместо того, чтобы видеть private там где public?
mistergrim
25.05.2018 07:27Кармак вообще до последнего оттягивал переход на C++. Думаю, там таких перлов ещё немало.
DistortNeo
24.05.2018 17:21+5Разработчику игр вроде бы как раз неплохо знать, хотя бы в общих чертах, что константность влияет в тч на оптимизации, выполняемые компилятором?
Оптимизации — это фигня. Тем более, чем современные компиляторы обычно сами анализируют код и игнорируют константность.
А вот то, что код на С++ может перестать компилироваться, это уже проблема.
f(const int&)
иf(int &)
— это две большие разницы, т.к. вторая не сможет принять на вход rvalue.to_climb
24.05.2018 19:34-1При таком подходе они скорее всего не обращают внимание на предупреждения компилятора.
AllexIn
24.05.2018 16:47Потом я вспомнил, что при переносе окна в область уведомлений или в панель меню «Пуск» Windows мгновенно восстанавливает неиспользуемую/освобождённую память.
Объясните пожалуйста о чем здесь речь. Что еще за освобождение памяти при сворачивании?zuborg
24.05.2018 17:09+1В тексте ж написано:
какой-то дескриптор окна не выполнял очистку должным образом
Окно свернули — винда его память подчистила сама.AllexIn
24.05.2018 17:10Разве дескриптор окна удаляется при сворачивании?
zuborg
24.05.2018 17:12+2Дескриптор нет, но какие-то ресурсы свернутого (невидимого окна), очевидно, освобождаются операционкой.
AllexIn
25.05.2018 13:03-1Как говорил мой преподаватиель — «Очевидно — значит ты знаешь доказательство»
Откуда информация что там что-то освобождается?mayorovp
25.05.2018 13:26Предположим, что ничего не освобождается. Но в таком случае перенос окна не помог бы, а нам известно что он помогает. Мы получили противоречие, следовательно исходное предположение было неверно. Следовательно, что-то освобождается. Ч. Т. Д.
AllexIn
25.05.2018 13:31Вариант предложенный ниже с «сбрасывается в своп» — тоже возможен.
Проблему откладывает пока своп не кончится и выглядит как решение. Хотя и не подтверждает изначальное утверждение.
Плюс это была не случайная находа, а «вспомнил что освобождается». Откуда он это вспомнил? В какой документации об этом речь идет?antonn
25.05.2018 13:54Это специфика работы менеджера памяти программы, в своп сбрасываются «рабочие» страницы, но с ними освобождается память выделенная для временных/промежуточных работ. Вызывая SetProcessWorkingSetSize() с минимальных объемом рабочего набора мы заставляем менеджер памяти прибрать за собой. Точно так же получается и при сворачивании главных окон, видимо менеджер памяти так отрабатывает, например в софте на старом дельфи (точнее до использования fastmm). И потому множество упоминаний этой winapi'шной функции употребляются в контексте дельфи, но не им единым. В принципе, автор того костыля мог бы сделать его чуть красивей — в таймере вызывать функцию и ничего не сворачивать.
P.S. Частое использование этого трюка приводило к росту числа ошибок обращения к страницам, был такой столбец в «Диспетчере процессов». Но так как он был скрыт по умолчанию, то маркетинг побеждал здравый смысл.
antonn
25.05.2018 08:51Полагаю, это грязный трюк, который позволяет в «диспетчере процессов» для своего процесса «уменьшить» занимаемый объем оперативной памяти (при этом объем выделенной останется неизменным, но эта колонка не отображается обычно). Раньше достигалась вызовом SetProcessWorkingSetSize(), немало разработчиков использовали ее (например я нашел ее в первых релизах Сталкера) в явном или не явном виде. Разумеется массово сброшенные в своп страницы потом опять тянулись в оперативку поедая ресурсы системы, зато «визуально» программа занимала меньше оперативки.
zuborg
24.05.2018 17:11+2Он просто продолжил создавать новые файлы .s, заполненные небольшими фрагментами данных, которые вставлял в произвольные места в makefile, пока они каким-то образом не перестали крашиться, после чего выпустил её!
Гениально, блин!
mspain
24.05.2018 17:11Не хватает откровений вествудовских разрабов Dune 2. Такого глюкодрома ни разу больше не встречал. Современные индусы отдыхают.
RadicalDreamer
24.05.2018 17:22+8Камера-обскура
Напомнило другую историю с наследованием объектов:
ФАУ-2 — это такая немецкая мегапетарда. Германия ими под конец войны докучала Великобритании, но без особого успеха. Вундерваффе страдало от кучи детских болезней и хорошо если могло оторваться от земли. Зачастую взрывалась прямо на стартовом столе, а уж коли отрывалось да еще и летело в сторону Англии, то уж вообще успех. Горючее, между прочим, 3,5 тонны этилового спирта :)
Ну, сделали и мы в Блицкриге эту самую ракету. Как и немцы, сделали ее уже ближе к концу проекта и соорудили на базе объекта «самолет». Но программисты несколько схалтурили и не пооткручивали у бывшего самолета подозрительную для баллистической ракеты функциональность. Оказалость, что если во время полета к цели начинал идти дождь или снег, то во-первых ракета говорила человеческим голосом «Fliege zuruck»(нем. лечу назад), а во-вторых разворачивалась и летела обратно на базу. Фигли там, погода то нелетная.
(с)staticlab
25.05.2018 08:20Ещё напомнило более эпичную копипасту:
Заголовок спойлераJIRA ISSUE #182355 Type: BUG Priority: MEDIUM Created: 21.02.12 18:21 Description: С "Дзуйкаку" взлетает "Зеро" с маркировкой авианосца "Кага".
21.02.12 18:30 Elena Ivanova [community manager] commented:
наблюдательные товарищи пишут в интернете что у нас на утекших в сеть скриншотах на самолетах не та маркировка цветные полосы а должны быть белые
22.02.12 11:51 Elena Ivanova [community management] reassigned to Sergei Lodkin [qa lead]
оформите баг чтобы исправили а то позоримся
05.03.12 15:41 Sergei Lodkin [qa lead] reassigned to Mihail Dorenkov [qa engineer]
11.03.12 10:42 Mihail Dorenkov [qa engineer] reassigned to Alexander Rozhko [art director]
Надо нанести на самолеты две белые полосы.
06.04.12 11:13 Alexander Rozhko [art director] reassigned to Semen Kemshakov [3d artist]
17.04.12 15:50 Semen Kemshakov [3d artist] reassigned to Tatiana Severina [textures artist]
Нужны две одинаковые белые текстуры для полосок. Очень надо!
20.04.12 11:10 Tatiana Severina [textures artist] reassigned to Alexandra Lebedeva [2d artist]
нужны эскизы двух белых полосок, а то я не знаю, на что они похожи
24.04.12 12:00 Alexandra Lebedeva [2d artist] reassigned to Tatiana Severina [textures artist]
У нас полный завал. Полоски сможем не раньше, чем через два месяца.
01.05.12 18:34 Tatiana Severina [textures artist] reassigned to Alexandra Lebedeva [2d artist]
можешь сверхурочно поработать? может, дома? это же пара часов, не больше. очень надо!
02.05.12 12:30 Alexandra Lebedeva [2d artist] reassigned to Tatiana Severina [textures artist]
Взяла работу на дом, ночью засела рисовать. (((((( Парень мой спрашивает: "Чего не спишь?"
А я ему: "Да понимаешь, у меня тут тут две полоски..." Обернулась — а его нет. Где теперь его искать? ((((((
02.05.12 15:54 Tatiana Severina [textures artist] reassigned to Semen Kemshakov [3d artist]
похоже, текстур не будет. возьмите пока любую похожую текстуру, потом заменим, когда сделаем
11.05.12 12:13 Semen Kemshakov [3d artist] reassigned to Andrei Hobotov [programming lead]
Я замоделил две белых полоски, лежат на системном диске. Теперь надо, чтобы движок крепил их к самолетам.
08.06.12 10:33 Andrei Hobotov [programming lead] reassigned to Alexei Mshigorotchitskii [junior programmer]
Леша, прицепи к самолетам по две белые полоски.
08.06.12 12:11 Alexei Mshigorotchitskii [junior programmer] reassigned to Andrei Hobotov [programming lead]
Вдоль или поперек?
10.06.12 17:14 Andrei Hobotov [programming lead] reassigned to Konstantin Krainihin [historical consultant]
Вдоль или поперек?
10.06.12 17:15 Konstantin Krainihin [historical consultant] reassigned to Andrei Hobotov [programming lead]
Поперек
11.06.12 18:35 Andrei Hobotov [programming lead] reassigned to Alexei Mshigorotchitskii [junior programmer]
Поперек
14.06.12 18:35 Alexei Mshigorotchitskii [junior programmer] closed issue.
Готово
17.06.12 14:30 Mihail Dorenkov [qa engineer] reopened issue.
Не видно что-то
21.06.12 11:51 Alexei Mshigorotchitskii [junior programmer] commented:
Как не видно? Вчера в релиз ушло. Тестеры в недоумении, уже триста писем с вопросами, что это за странные полоски на всех самолетах.
25.06.12 12:50 Mihail Dorenkov [qa engineer] commented:
В какой релиз? Даже альфа еще не началась.
29.06.12 20:56 Alexei Mshigorotchitskii [junior programmer] commented:
Вы, простите, в каком проекте работаете?
01.07.12 12:21 Mihail Dorenkov [qa engineer] commented:
World of Warships
01.07.12 19:30 Alexei Mshigorotchitskii [junior programmer] reassigned to: Andrei Hobotov [programming lead]
Я программист World of Warplanes. Смотрите внимательнее, кому баги перекидываете.
07.07.12 14:57 Andrei Hobotov [programming lead] reassigned to Alexei Mshigorotchitskii [junior programmer]
Леха, прикинь, в Киеве твой однофамилец работает. Только он Мщигорочицкий, а ты Мчигоротчитский.
07.07.12 14:58 Alexei Mshigorotchitskii [junior programmer] reassigned to: Andrei Hobotov [programming lead]
Я в курсе, что я там работаю. Я из за ваших гребаных полосок такой нагоняй получил. Теперь вычистить не можем — во все бранчи уже просочились.
07.07.12 14:59 Andrei Hobotov [programming lead] commented:
Упс… сорька. Опять не тому перекинул.
07.07.12 15:00 Andrei Hobotov [programming lead] reassigned to Alexei Mchigorotchitskii [junior programmer]
Леха, прикинь, в Киеве твой однофамилец работает. Только он Мщигорочицкий, а не Мчигоротчитский.
07.07.12 15:01 Alexei Mchigorotchitskii [junior programmer] closed issue.
Клево
16.07.12 13:01 Mihail Dorenkov [qa engineer] reopened issue.
Почему закрыли несделанный таск?
20.07.12 09:31 Andrei Hobotov [programming lead] commented:
Леха, ты выше-то почитай, что сделать надо.
21.07.12 15:59 Alexei Mchigorotchitskii [junior programmer] commented:
Ааааа… я думал, ты таск завел, чтобы про однофамильца рассказать.
Еще удивился, чего не по аське, в одной же комнате сидим.
21.08.12 11:09 Alexei Mchigorotchitskii [junior programmer] closed issue.
Сделано
23.08.12 14:37 Mihail Dorenkov [qa engineer] reopened issue.
Истребители перестали сбивать. Не могут стрелять.
01.09.12 13:26 Alexei Mchigorotchitskii [junior programmer] assigned to Andrei Hobotov [programming lead]
Я не понимаю, в чем дело.
15.09.12 19:03 Andrei Hobotov [programming lead] reassigned to Boris Vovk [senior programmer]
Боря, проверь, в чем там дело.
04.11.12 09:23 Boris Vovk [senior programmer] reassigned to Andrei Hobotov [programming lead]
Полоски закрывают пулеметы. А на них материал, в котором прописана коллизия для пуль. Пули не проходят.
11.11.12 10:00 Andrei Hobotov [programming lead] reassigned to Boris Vovk [senior programmer]
Как полоски могут закрывать пулеметы, если полоски нанесены в задней части фюзеляжа?
14.11.12 11:11 Boris Vovk [senior programmer] reassigned to Andrei Hobotov [programming lead]
А у нас у истребителей настоящие пулеметы как раз в задней части фюзеляжа. А в крыльях — фейковые, для вида только, пыщ-пыщ делать.
Так исторически сложилось, уже не помню, почему. Теперь долго переделывать, на это вся их баллистика завязана.
05.12.12 12:07 Andrei Hobotov [programming lead] reassigned to Semen Kemshakov [3d artist]
Зачем полоски коллизят пули? Сними с них коллизию.
12.12.12 12:03 Semen Kemshakov [3d artist] reassigned to Andrei Hobotov [programming lead]
Я не могу, у нас коллизии захардкожены в текстурах, а других текстур нет.
Эту вырезал с Флетчера, самая белая текстура, какую нашел. А у него там броня четыре сантиметра.
27.12.12 11:34 Andrei Hobotov [programming lead] reassigned to Boris Vovk [senior programmer]
У нас правда коллизии захардкожены в текстурах? Нельзя их оттуда вынести в отдельную настройку?
14.01.13 17:00 Boris Vovk [senior programmer] reassigned to Andrei Hobotov [programming lead]
Да как же их вынесешь? У нас же честный расчет пробития, с учетом карты нормалей текстуры, а в альфа-канале у нее усталость металла закодирована.
03.02.13 12:12 Andrei Hobotov [programming lead] reassigned to Tatiana Severina [textures artist]
Сделайте уже нормальные текстуры для полосок, только визуал. Сколько можно тянуть?
12.02.13 15:45 Tatiana Severina [textures artist] reassigned to Alexandra Lebedeva [2d artist]
как там насчет эскиза?
13.02.13 11:15 Alexandra Lebedeva [2d artist] reassigned to Tatiana Severina [textures artist]
Говорила же уже: у нас завал, сможем не раньше, чем через два месяца.
Срочно перерисовываем все миникарты, сказали поконтрастнее выделить сушу. Кто как, а я выделяю более темненькой водой.
Ночью работать больше не буду (((((((
14.02.13 11:10 Tatiana Severina [textures artist] reassigned to Andrei Hobotov [programming lead]
у нас завал. сможем не раньше, чем через четыре месяца.
01.03.13 18:20 Elena Ivanova [community manager] changed priority to HIGH
высокий проритет задачи они опять заметили что полоски неправильные говорят что не будут играть в такой отстой проект на грани провала
07.03.13 17:27 Andrei Hobotov [programming lead] reassigned to Semen Kemshakov [3d artist]
Подвинь полоски, чтобы не закрывали пулеметы.
07.03.13 17:28 Konstantin Krainihin [historical consultant] commented:
Я щас кому-то подвигаю! До миллиметра по историческим фотографиям вымеряли...
11.03.13 12:36 Andrei Hobotov [programming lead] reassigned to Boris Vovk [senior programmer]
Боря, придумай какой-нибудь хак. Ситуация безвыходная.
17.05.13 14:37 Boris Vovk [senior programmer] reassigned to Vladimir Orlov [game designer]
Пропишите пулеметам дамаг 231 вместо 2. Из него ровно 229 уйдет на пробитие полосок, дальше полетят пули с остаточным дамагом 2, как и должно быть.
27.05.13 11:22 Vladimir Orlov [game designer] reassigned to Boris Vovk [senior programmer]
Прописал пулеметам дамаг 231
29.05.13 15:01 Boris Vovk [senior programmer] closed issue.
Теперь все должно быть в порядке.
30.06.13 16:30 Sergei Lodkin [qa lead] reopened issue:
После вашего изменения Нью-Мексико вдруг начал нагибать всех, кто к нему приблизится.
Нет, не так. Нью-Мексико вдруг начал НАГИБАТЬ КРОВЬ КИШКИ РАСЧЛЕНЕНКА ВСЕХ РАСПИДАРАСИЛО В МЕЛКИЕ КЛОЧКИ.
Мы случайно взяли Нью-Мексико и два раза нагнули геймдизайнеров в товарищеском матче. Нам приятно. Спасибо.
Но теперь они тоже просекли фишку, поэтому пора исправить.
01.07.13 10:02 Boris Vovk [senior programmer] reassigned to Vladimir Orlov [game designer]
Почему Нью-Мексико начал нагибать? Вы кроме пулеметов истребителей ничего не меняли?
01.07.13 17:00 Vladimir Orlov [game designer] reassigned to Boris Vovk [senior programmer]
Оказывается, те же самые пулеметы, отскейленные в 10 раз, используются как орудия второстепенного калибра Нью-Мексико.
По форме очень похожи, вот моделлеры и решили сэкономить.
Дамаг тоже автоматически скейлится, но уже в 1000 раз, пропорционально объему ствола.
Так что у нас теперь у Нью-Мексико дамаг 231000 на выстрел второстепенного калибра.
03.07.13 18:01 Elena Ivanova [community manager] changed priority to VERY HIGH
просьба ускориться нас опять в интернете ткнули носом в этот позор не те полоски мне стыдно за тот отстой что мы делаем аааааааааа
03.07.13 19:39 Boris Vovk [senior programmer] reassigned to Andrei Hobotov [programming lead]
Хак не прокатил. Надо всю архитектуру движка менять, чтобы можно было динамически оверрайдить коллизии в текстурах. Иначе ничего не получится. А это работы на полгода.
04.07.13 10:13 Andrei Hobotov [programming lead] reassigned to Slava Makarov [makarovslava]
Такие решения должны приниматься на высшем уровне.
Ну что, отодвигаем альфу на полгода?
Слава, жду решения.
04.07.13 10:22 Andrei Hobotov [programming lead] reassigned to SerB [vice makarovslava]
Извините, что беспокою.
Это очень важный и срочный баг, его фикса ждут уже больше года.
Вы не знаете, где Слава Макаров?
04.07.13 10:28 SerB [vice makarovslava] reassigned to Andrei Hobotov [programming lead]
Нет, я не знаю, где Слава Макаров.
04.07.13 10:37 Slava Makarov [makarovslava] commented:
Извините, что не сразу ответил. Я тут подумал и решил, что проще забанить того неприятного человека.
Белые полоски делать не надо, всем отбой. Пойду думать, как бан обосновать.
04.07.13 10:39 Slava Makarov [makarovslava] closed issue.
04.07.13 18:21 Alexandra Lebedeva [2d artist] reopened issue:
Как не надо? (((((((( А зачем же я вчера всю ночь эскиз рисовала? ((((((((
Хотела сюрприз сделать ((((((
04.07.13 18:27 Alexander Rozhko [art director] commented:
Скинь эскиз на сетевой диск посмотреть. Может, куда-нибудь пристроим.
04.07.13 18:34 Alexander Rozhko [art director] commented:
А почему там не две белых полоски, а три оранжевых звездочки?
04.07.13 20:48 Alexandra Lebedeva [2d artist] commented:
Я — художник, а не маляр… ((((((( Я творчески переосмыслила… ((((( Я хочу, чтобы у нас была красивая игра… (((((((
RadicalDreamer
25.05.2018 12:20Да-да, это тоже вспоминалось)
Или еще что-то похожее с башорга, вдогонку:
Ошибка: робот погибает при попадании в него гранаты (именно от попадания, а не от взрыва) Д — дизайнер, П — программист.
Д: программисты всё сломали! почему так получается?!
П: естественно так получается! потому, что у гранаты масса 100 кг! зачем вы это сделали?
Д: да?! а чтобы граната в воде тонула!
П: а почему она с нормальной массой не тонет?
Д: а потому что у воды плотность большая! (прим.: больше, чем у ртути)
П: а почему плотность такая большая?!
Д: а чтобы ящики деревянные плавали!
П: а почему они иначе не плавают?!
Д: а потому что у них масса 50 кг!
П: а зачем такая масса?!
Д: а иначе они некрасиво разваливаются!
tongohiti
25.05.2018 16:23Ещё один древний боян про наследование.
Копипаста:
Повторное использование объектно-ориентированного кода (в программах) вызвало головную боль у Австралийских Вооруженных Сил. Т.к. симуляторы все активнее используются для тренировок боевых действий вертолетов, от программистов требуется постоянное повышение реализма используемых сценариев, включая детальные ландшафты местности и — в случае операции Феникс — стад кенгуру (т.к. испуганные животные могут легко выдать расположение воинских частей). Hачальник отдела симуляций наземных операций Defense Science and Technology Organization приказал разработчикам смоделировать перемещения кенгуру и их реакцию на вертолеты. Будучи грамотными программистами, те использовали готовые программные объекты, описывающие поведение пехоты в аналогичной ситуации, заменив изображения солдат на изображения животных и увеличив их скорость. Желая продемонстрировать свое мастерство перед посетителями — американскими пилотами — горячие австралийские парни “разбудили” кенгуру, пройдя над ними на малой высоте во время симуляции. Кенгуру разбежались, как и предполагалось, и американцы понимающе кивнули… А затем сильно удивились, т.к. кенгуру, перегруппировавшись, появились из-за холма и выпустили тучу стингеров по злополучным вертолетам. (Программисты забыли удалить соответствующий кусок кода из “пехотных” объектов).
BingoBongo
24.05.2018 23:17+2Он тратил какое-то время на нахождение этих багов, но если ему это не удавалось, то он… изменял порядок файлов в makefile, чтобы файлы статически компоновались в памяти в другом порядке! Это означало, что случайно записываемый фрагмент памяти теперь находился в в каком-то другом месте, но благодаря чистой удаче игра почему-то переставала вываливаться.
И как ему за такое табуреткой голову не разбили?OnYourLips
25.05.2018 11:40Требования к качеству кода и процессов тогда и сейчас очень сильно отличаются.
Тот, кто лет 10 назад был мидлом, по текущим меркам на джуна еле потянет.antonn
25.05.2018 11:50За последние 10 лет ничего фундаментального не произошло, появилось больше фреймворков которые надо знать, языки в целом те же самые с некритичными различиями (в основном из-за платформ на которых запускаются). А вот 20 лет назад — уже есть разница. Если большинство сегодняшних программистов заставить писать так, как делали 20 лет назад (в условиях IDE и языков тех лет, спуститься с высокоуровневых сред хотя бы до WinApi) — появятся множество таких деятелей, которых табуреткой хочется стукнуть.
Error1024
26.05.2018 03:36То-то с каждым днем софт все тормознее и глючнее, намного глючнее, чем 20 лет назад. Профессионалы!
mistergrim
25.05.2018 07:47«Если бы строители строили здания так же, как программисты пишут программы, первый залетевший дятел разрушил бы цивилизацию.»
ainoneko
25.05.2018 09:35В переводе потерялась игра слов в некоторых заголовках ("Flash forward", «Back to basics»).
Меня больше удивили деятели, которые делают printf() с произвольной строкой.mayorovp
25.05.2018 09:42Ага, причем заметив проблему они убрали printf директивой условной компиляции вместо того чтобы поставить "%s" первым аргументом!
DenimTornado
25.05.2018 10:25Ну и классика)
https://bash.im/quote/413852
Ошибка: робот погибает при попадании в него гранаты (именно от попадания, а не от взрыва) Д — дизайнер, П — программист.
Д: программисты всё сломали! почему так получается?!
П: естественно так получается! потому, что у гранаты масса 100 кг! зачем вы это сделали?
Д: да?! а чтобы граната в воде тонула!
П: а почему она с нормальной массой не тонет?
Д: а потому что у воды плотность большая! (прим.: больше, чем у ртути)
П: а почему плотность такая большая?!
Д: а чтобы ящики деревянные плавали!
П: а почему они иначе не плавают?!
Д: а потому что у них масса 50 кг!
П: а зачем такая масса?!
Д: а иначе они некрасиво разваливаются!
legolegs
25.05.2018 14:42+1Я, конечно понимаю, что не всегда есть время вычистить, например, ошибку порчи памяти, или переделать изначально неудачную иерархию классов, или разобраться с константами в новом странном языке си++. Но man printf то можно почитать и не совать ему данные первым аргументом! Это уж совсем невменяемые кодеры какие-то, как им родители вилку-то за обедом доверяют?
poxvuibr
Забыли ещё #define private public из кода ID Software
vesper-bot
#define true false // happy debugging
Вообще, у меня как у паскалиста всегда возникает истерика при виде такого препроцессинга. Это даже не выстрел в ногу, это выворот себя наизнанку в надежде, что заработает хотя бы вот так.
sumanai
И ведь этот выворот работает.
KVL01
В Делфи тоже никто не запрещает выворачиваться наизнанку: