Как стать автором
Обновить

Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живёте

Время на прочтение4 мин
Количество просмотров81K
Всего голосов 159: ↑156 и ↓3+153
Комментарии87

Комментарии 87

Может и было раньше просто зависимость от race_type, а потом надобавляли сравнение строк. В одном месте сработало, а в других не сработало. По идее это «нормально». Просто наверное минорным багом посчитали и так и не пофиксили. Люди и не с такими багами в релиз идут.
Это да, просто забавно, что 3 разные ошибки в 4 вариантах одного кода, и при этом ни один вариант не является правильным. На самом деле в этом патче было исправлено большое количество серьёзных проблем, связанных с падениями и зависаниями, но удивительными они мне не показались. Хотя описание поиска и исправление одного deadlock хотелось бы описать в будущем, там был любопытный случай, который связан как раз с с тем, что (судя по всему) забыли удалить один уже ненужный вызов. Как раз и демонстрация работы с WinDbg будет.
Было бы очень интересно почитать про это.
Сегодня читал чей-то класс на 2500 строк, глаза болели от ужасного кода, а больнее всего было в сотый раз натыкаться на комментарий:
"//TODO: сделать нормально"

Не сделали…
2500? Tюю. Да это же так, мелочь пузатая :) В проекте сишный код достался из начала 90х, там файлы по 15-20к строк плюс заголовочные с десятками включений.

А TODO это хорошо, говорит о том, что человек знал что делает, что это плохо и места пометил для потомков. Некоторые даже не понимают, что они плохо делают, потом рефакторинг зубы ломает.
а наследуется он от View на 22к строк… http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/android/view/View.java
В исходниках Clang-а, есть модуль Sema — семантика языка С++. Там SemaOverload.cpp — 12к строк, другие классы ненамного меньше. Но меня больше если честно не размер cpp убивал, а хедеров… очень тяжело ориентироваться.
Полагаю, в данном случае уместнее будет термин «благородное безумие».
Слабоумие и отвага :)
В качестве комментария к предыдущей статье: я предпочитаю патчи делать прокси-дллками системных если честно. По большей части (что конечно тоже само по себе в какой-то мере грязный хак) можно в DllMain сделать все нужные патчи, в том числе с помощью VirtualProtect изменить нужные страницы памяти на чтение и подправить асм код на свой, либо просто записать long jump на свою процедуру, скомпиленную с __declspec(naked), а потом push addr, retn для возврата обратно.
Аналогично, и под линукс это делать куда проще, через LD_PRELOAD. Использую простую функцию:
#define UNPROTECT(addr,len) (mprotect((void*)(addr-(addr%len)),len,PROT_READ|PROT_WRITE|PROT_EXEC))

void detour_function(void * new_adr, int addr)
{
    int call = (int)(new_adr - addr - 5);
    UNPROTECT(addr, 4096);
    *((unsigned char*)(addr)) = 0xE9;
    *((int*)(addr + 1)) = call;
}

Потом достаточно написать свои функции и перенаправить вызов:
detour_function(&hasp_init_game, (int)0x080BD120);

Очень просто и быстро. А если нужна поддержка разных версий, то есть еще и код, который ищет функцию в заданном адресном промежутке по ее сигнатуре.
Однако, такой подход выглядит достаточно костыльным. Вместо того, чтобы исправить проблему «на месте», предлагается создавать отдельную сущность (загрузчик или прокси-dll), которая будет при каждой загрузке на лету вносить те же изменения в машинный код исходной программы в памяти.

Вообще я бы подключал код на C++ только в случае переписывания огромных частей кода. Например, в NFS3 меню заточено строго под 640×480, и для поддержки современных разрешений его по хорошему нужно полностью переписать (и перерисовать всю соответствующую графику). Вот при такой переделке я бы стал писать новый код уже на C++ :)
Зато можно писать комментарии к каждому патчу, включать и выключать их по отдельности. Но, согласен, иногда проще и пропатчить файл. Но если у вас игра, к которой постоянно выходят обновления, но вы замучаетесь патчить ее каждый раз, все равно придется делать либо лоадер, либо динамический патчер.
Позволяет не модифицировать исходные бинари. Что вызовет элементарный механизм отключения патчей если вдруг что не то, да и вообще очень сильно упрощает установку — согласитесь, гораздо проще просто закинуть в папку лишнюю длл чем, собственно, заменять (а ещё лучше сначала забэкапить оригинал!) файл. Плюс может динамически апплаиться к нескольким версиям файлов если сделать либо чек версии, либо просто патч по паттерну который слабо изменяется — конечно не совсем касается ретро-игр, но тем не менее.

Теоретически с легальной точки зрения всё тоже проще, но тут к юристам лучше, наверное не всё так просто.
Есть 2 момента:
1) Вполне возможно, что и с таким кривым исполнением Need For Speed III была весьма рентабельна для производителя. Если юзер не видит бага (а юзер не будет в коде ковыряться) — проблемы для рынка условно нет.
2) Бывает еще, что начальство бегает и орет: «Где результат, млин? Сроки прошли!». В такой ситуации человеку придется делать кое-как с комментариями "//TODO: сделать нормально". Ибо кушать хочется, дети малые дома сидят, ипотека не плачена…
Batman: Arkham Knight с его кривым исполнением тоже наверняка был рентабельным, хоть его проблемы и видны юзерам.

На PC не был. Деньги вернули и если, что и заработали, то только на тех кто не успел вернуть деньгу.

Steamspy говорит о 550к владельцах бэтмена. Думаю, затраты на портирование более чем окупились.
Я купил, потому что пол Free Edition прошел, и не так уж он и баговал если честно… Особенно текущая версия в стим
Не знаю насчёт текущей версии, но пару месяцев назад она была всё ещё не очень.
Я если честно вообще ни разу не натыкался на баг с полётом, хотя играю на мыше :) Единственное под конец игры она начинает фризится сильно, но ssd решил и эту проблему
Возможно зависит от железа. Я закончил прохождение игры 11.10.2015. и у меня работало все идеально. Скорей всего из-за плохого портирования она потребляет огромное и неоправданное кол-во процессорного времени и оперативной памяти. По этому у кого мощный ПК мог проблем и не заметить.
Предполагают, что Denuvo тоже влияет на производительность.
К сожалению, уже через несколько лет код этой игры начал ломаться, что точно было заметно пользователям. Например, в рендерере DX6 поддерживаемые форматы текстур записывались в массив из 14 элементов, и если система поддерживает больше — переполнение буфера и падение при запуске. В результате пользователи ругали производителей драйверов (это можно найти на форумах), что при обновлении драйвера версии X на более новую версию X+1 игра начинала падать. А ведь на самом деле драйвер просто узнал о каком-то новом формате текстур, и это объективно хорошо. Это в игре была заложена бомба замедленного действия. И это далеко не единственный пример.
Ага. И обычно после такого производитель драйверов вставляет в новую версию драйвера код:
if (Process_Is_NFS3()) { отдавать старый список форматов текстур };
А это вечная практика всех разработчиков. Всеми любимый windows тому пример — вставим таких костылей для стороннего софта (а то покупатель обидится, что его симсити не работает под новой операционкой). Windows не пример? — okay, скатимся в древность и к железу — award bios: обработка исключений для десятка PCI плат расширения (пара звуковушек и S3Trio там были точно), мегакостыльный обработчик int 13h с фиксами для некоторых устройств. А дрова nvidia, ну тут можно и нижнюю челюсть вывихнуть, если посмотреть сколько там индивидуальных настроек для кучи .exe файлов валяется.
Многие клиенты/начальники между «идеальный код» и «относительно вовремя и работает» выберут второе. Потому что идеальным кодом не выплатить зарплаты и дивиденды, не заплатить за офис, да и просто тупо не выйти на рынок.

Вспоминается история Oracle, где пока их конкуренты вдумчиво пилили что-то, ораклы методом «херак херак и в продакшн» получили рабочий (более-менее) продукт и начали получать заказы от крупных клиентов, в том числе военщины.
НЛО прилетело и опубликовало эту надпись здесь
Сам не успел, т.к. на работе, но брат, сорокадвухлетний бородач уже рубится. Спасибо!
Может брата тоже на работу устроить?))
После прочтения заголовка думал, что будет процитирована вся история с ныне мёртвого ItHappens: Адекватный друг и абсолютный глюк (http://ithappens.me/story/11872/
По теме: копипаста действительно может сыграть злую шутку, так как можно не учесть условия применимости используемых кусков, как указано в посте — ещё и с ошибками.

Если вы про фразу в заголовке статьи, то фраза старая и встречается у многих авторов. Обычно приписывают Стиву Макконелу, в Code Complete.

Понятно. Я имел в виду, что подобный рассказ неплохо подходит для затравки, по аналогии с картинкой для привлечения внимания.
Но это не его фраза тоже. Он на ее авторство и не претендует. И вроде в его книге я встречал указание на кого-то конкретного, но может ошибаюсь. В электронном варианте нашел один случай упоминания — автором значится Аноним.
Кстати, есть информация, что с ним случилось? А то как-то я захожу, а новых историй нет… И молчание везде.
Думаю, уволился копирайтер, придумывавший все истории.
Мне они не казались выдуманными. Вполне себе «айтишный башорг», там даже иногда были перепалки, ответ на ответ на ответ на… Нужно обладать очень богатой фантазией, чтобы достоверно придумать подобное.
Ну по крайней мере та история, на которую сослался AiMAX, выглядит выдуманной (или по крайней мере сильно преувеличенной).
Ну да, там её больше для юмора, наверное, выложили.
Кстати, есть информация, что с ним случилось
Да я сам хотел бы знать. Тоже искал — нигде никакой информации, а уже больше года с последнего «поста» прошло про сильных программистов… Только и остается, что перечитывать старые истории, поностальгировать, так сказать…
Хотя один плюс в этом есть — IThappens хотя бы остался до самого своего конца «айтишным», а вот с того же Баша, как писали недавно на нём же, сначала исчезли айтишные шутки и истории, потом — околоайтишные, а затем и просто шутки, а остались срачи.
http://stackoverflow.com/questions/876089/who-wrote-this-programing-saying-always-code-as-if-the-guy-who-ends-up-maintai

Bill Mitchell View profile More options Sep 26 1991, 1:57 am In article <5...@ksr.com> j...@ksr.com (John F. Woods) writes:

[...] Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. Code for readability.
Damn right!


1991 year — OMG!

Каждый раз, когда вижу вот такие реверс-инженерные статьи, я восхищаюсь авторами.
Но смотря на вроде бы знакомые команды в целом нефига не понятно.
Поэтому вопрос: в какую сторону покурить, чтобы быть немного в теме? (Так-то некоторые представления об ассемблере х86 имею, писал на нем, правда совсем чуть-чуть). Какие программные средства используются для этого дела?


Пример непоняток

image
Что это за блоки кода с соединительными линиями?

Для реверса часто используется IDA (скрины оттуда же) (https://ru.wikipedia.org/wiki/IDA).
Красные/зелёные стрелки для обозначения перехода по ложному/истинному условию, синие для безусловного перехода.

Спасибо. Я был знаком только с OllyDbg, там все выглядело несколько иначе

К IDA есть ещё HexRays который может попытаться представить это всё дело как Си код. Получается не всегда хорошо, но значительно облегчает жизнь.
HexRays весело плющит, когда он натыкается на оптимизации компиляторов. В часности вызов функции из массива, который казалось-бы выглядит примерно как(до оптимизации, и чего тут оптимизировать)
mov eax, ds:[functable+ebx*4h]
call eax

он раскрывал в полный ужас, понять который было нереально.
Хотя согласен, длинные функции с кучей параметров через него изучать проще.
Скорее уж «получается обычно отвратно». Честно. Понять только какие-то оч простые вещи можно, но не более.
Тут зависит от того что исследуешь. Иногда если разобраться как хранятся стуктуры и ткнуть его носом где что получается Си код который можно спокойно копипастить ещё куда нибудь. Ну а если что то современное написанное с использованием всяких Boost, Qt и прочего то да зачастую только хуже.
NFS3 навевает приятные воспоминания. Мне тоже кажется лучшей частью в серии. А может просто ностальгия.
Не глядя на косяки, NFS3 всё равно классная. Перед тем, как взяться за патч, я пробовал разные варианты на замену, но ничего не зацепило. Не исключаю, что это синдром утёнка. Вообще в современных гонках, как оказалось, сплит-скрин уже не обязательная возможность. А для меня это обязательная возможность, потому что я играю в гонки (и другие игры) как раз тогда, когда кто-нибудь ко мне заглянет в гости поболтать. С геймпадами, сидя на диване, а не как в детстве, два человека за одной клавиатурой.
Вообще в современных гонках, как оказалось, сплит-скрин уже не обязательная возможность. А для меня это обязательная возможность, потому что я играю в гонки (и другие игры) как раз тогда, когда кто-нибудь ко мне заглянет в гости поболтать. С геймпадами, сидя на диване, а не как в детстве, два человека за одной клавиатурой.

И подобный oldschool, я считаю, здорово. У меня так вообще эти гонки прошли в основном под знаком PS1. Кстати, интересно было бы сравнить код с консольной версией.
Судя по всему, какую-то часть кода они делят между собой. Я встречал остатки хардкода, которые предназначались для пасхальных трасс, которые были в NFS3 PS1, но которых не было в NFS3 PC (PC-версия вышла после PS1-версии).
Интересно было бы увидеть еще статьи на подобные темы. Особенно связанные со старыми играми, когда деревья были толще и небо зеленее.
«С геймпадами, сидя на диване, а не как в детстве, два человека за одной клавиатурой.»

Планируете поддержку Xinput?
Оно и без Xinput хорошо работает. Единственное, что хотелось бы изменить умолчания для Xbox-совместимых геймпадов. И ещё меню научить управлению с геймпадов. Но сейчас уже не будет времени заниматься проектом, так что если это и будет в патче, то не скоро. Сейчас в меню управляюсь с небольшой беспроводной клавиатуры — это не такое уж и значительное неудобство.
ИМХО лучшей по физике и атмосфере была Posche Unleashed. Особенно в золотую эру, раздолбать машину при заносе было абсолютно не проблема. Плюс самые красоты Европы (ну конечно схематично, но зачем нам воображение то?), Пирнеи, Шварцвальд, Альпы, Автобан, Корсика и т.д.
В плане красот Европы соглашусь. Я в эту часть играл просто наслаждаясь видами.
Спасибо за патчи! Круто, когда есть запал и навыки, чтобы реверсить в свободное время.)
Кстати, в 1998 году вышла еще одна крутая и сильно багованная игра — Trespasser. И у нее тоже есть фанаты, которые реверсом и такой-то матерью делают патчи, улучшают движок и даже добавляют новые уровни…
У Trespasser утекли исходники.
Эх, круто! Завидую — откуда ж столько свободного времени?

Сам раньше часто ковырялся в игрушках популярных, иногда код вызывает ночные кошмары, когда видишь, например, что все данные сделаны глобально статическими и доступны просто отовсюду из любой функции! Удобно ж блин! :D

Зато потом за свой код не стыдно особо, когда видишь, что мировые гиганты пишут такое говно в продакшн.
Для тех, кто не в теме:

EA Games прославилась как самая соковыжимающая компания. Переработки обязательны. Разработчики в кубиклах и ящики редбула. (Довольно известная история, с фотографиями и десятилетиями обсуждения)

И уже давно ДОКАЗАНО, что те 60-80 часов в неделю, которые EA Games требует привели к меньшей эффективности, чем традиционные 40 часов.
Насколько я знаю они не меняли подхода к разработке до сих пор.

Так, что эти глупые ошибки делали Сишные программисты-зомби в анабиозе. (Не стеляйте программиста, пристрелите таких управленцев)
Программисты не имеют сознания и воли? Если 60-80 часов и низкая производительность, значит это их добровольный выбор.
в США не существует каких-либо обязательных норм про 40 часов. Так что выбора немного.
Наоборот, это и показывает что выбор был их решением. Даже с наличием норм по 40 часам у нас в России, вы можете работать и 20 и 10 часов. Запретить никто не может.
А давайте сейчас все руку на сердце положим. Геймдев и 40 часов? Не верю. Галенкин в подкасте тоже как-то шутил на эту тему…
Женя, ты хексрейсом часто пользуешься или все по хардкору?
НЛО прилетело и опубликовало эту надпись здесь
Такой подход плох тем, что вместо кода «отражения» модели трассы в одном единственном месте программы, разработчику необходимо не забывать вставлять соответствующую проверку и инверсию в каждом месте кода, где используется «лево» и «право», то есть это будет размазано по всему проекту. И разработчики таки забыли об этом, о чём было рассказано :) Проблему с отражёнными надписями на машинах нужно решать созданием отдельного варианта текстур с надписями, где надписи будут отражены, что тоже достаточно странно.

Хотя, конечно, реализация этого костыльного метода была сама по себе проще, и на реализацию переворачивания модели трассы при загрузке наверняка ушло бы больше времени. Зато было бы надёжнее :)
а что мешает менять прям в рендере а не везде7
Потому что где находится «лево» и «право» важно не только при рендеринге. Начинаем мы с того, что добавляем условие, которое инвертирует «право» и «лево» в коде ввода. Затем оказывается, что код отрисовки руля (при виде «из кабины») тоже нужно переделать, иначе он будет визуально поварачиваться не в ту сторону. Потом мы вспоминаем, что когда копы ставят шипы, по рации можно услышать, с какой стороны дороги они их поставили, и это тоже нужно не забыть инвертировать… Ну и в этом духе.
я бы сделал класс для этого.
И что этот класс будет делать? Это ведь вмешательство в совершенно разные части программы, и по условию «включен режим отражённой трассы» подпирать всё придётся разными костылями. Где-то умножить на -1, где-то инвертировать булево значение, где-то вместо одной текстуры прочитать другую (с отражёнными надписями). А где-то об этом можно просто случайно забыть, что разработчики NFS3 и сделали.
он будет хранить все правила.
Изъясните понятнее свою мысль. Что за правила он будет хранить и как он будет это делать? Какую проблему это решит? Почему из-за вашего предложения этот подход перестанет быть костыльным?
Про руль не понял. Я жму влево, это на этапе ввода интерпретируется как «вправо», соот-но руль поворачивается вправо, но зеркально отражается, и я вижу поворот влево. Зачем дополнительно менять отображение руля?

update: или кабина там позже рисуется и не отображается зеркально?
Салон авто не отражается, машина из леворульной не превращается в праворульную. Он там выводится так же, как HUD, то есть просто накладывается поверх изображения.
НЛО прилетело и опубликовало эту надпись здесь
потому что через 20 лет какой-нибудь маньяк будет изучать и дорабатывать машинный код вашего продукта, и он может захотеть вас найти
Если кто-то через 20 лет захочет изучить и доработать ваш код это значит, что вы написали очень хорошую программу иначе ее бы давным давно выкинули на свалку.
Игры столько лет спустя ценят не за код, а за геймплей. Ничто не мешает хорошей внешне программе иметь отвратительный код.
обожаю такие посты! автору желаю вдохновения и времени для новых.
Пишите код так, будто маньяк, который захочет вас убить — это вы сами.
Если уровень понимания, как там всё работает и устроено столь велик, то может быть стоило бы подумать о свободной реализации этой игрушки с ресурсами из оригинальной игры?
Всё же исправить основные ошибки в существующей программе как-то проще, нежели написать 1 в 1 с нуля. Настолько глубокого понимания кода, чтобы переписать его целиком на C++, нет. Если работать над таким в одиночку — это задача не на один год, как мне кажется.

Привет из 2022, существуют ли утёкшие в сеть дебажные символы?

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории