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

Разработка Need For Speed III Modern Patch

Вообще я достаточно редко играю в компьютерные игры. Бывало, не играл по несколько лет подряд. Но иногда во мне просыпается маленький реверс-инженер, который мотивирует меня забраться в машинный код какой-нибудь любимой игрушки из прошлого. В последний год я занимался доработкой Need For Speed III: Hot Pursuit (1998 года). Это моя любимая игра в жанре, но теперь я, к своему сожалению, знаю о том, насколько отвратительно она написана. Большое количество маленьких багов в самых неожиданных местах — прямое следствие низкого качества кода.

Насколько всё плохо?


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

Сколько ошибок может быть в 4 вариантах одного и того же кода?


В игре присутствовал один незначительный баг, связанный с отступами в выпадающих меню. Например, если был выбран режим «Hot Pursuit», левый отступ всех верхних выпадающих списков значительно увеличивался без явной на то необходимости.

image image

Я предположил, что это связано с ошибкой в коде, который добавляет пространство для вывода иконок прохождения в выпадающем списке трасс, которые как раз и должны отображаться только в режиме «Hot Pursuit».

image image

Обычные выпадающие списки тоже имели проблемы с отступами в зависимости от режима, но не в такой явной форме. Поскольку я как раз копался рядом с соответствующим кодом, решил заодно исправить и это странное поведение.

Тут стоит отметить, что в коде игры не встречаются следы вещей вроде наследования, так что скорее всего она писалась на чистом C. В игре реализован код, который читает списки элементов меню и их свойства из внешних текстовых файлов, но разработчики часто ленились добавлять поддержку какого-то нового свойства, и писали дополнительный код, опираясь просто на имя элемента. Например, код вывода выпадающих списков сам проверяет название текущего элемента и какие-то другие переменные, и в зависимости от этого может применять какую-то дополнительную логику.

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

Вариант 1 (при вычислении отступа левой границы обычной выпадашки):
image
На C это выглядело примерно так:
dw_padding = (stricmp(str_element_name, "tracks") == 0 && dw_cfg_race_type == 3) ? 35 : 15;

Вариант 2 (при вычислении отступа правой границы обычной выпадашки):
image
На C это выглядело примерно так:
dw_padding = (stricmp(str_element_name, "tracks") == 0 || stricmp(str_element_name, "rectrk") == 0) ? 35 : 15;

Варианты 3 и 4 (при вычислении отступа левой и правой границ выпадашки под заголовком):
image image
На C это выглядело примерно так:
dw_padding = (dw_cfg_race_type == 3) ? 35 : 15;

Все варианты вместе (для наглядности):
dw_padding = (stricmp(str_element_name, "tracks") == 0 && dw_cfg_race_type == 3) ? 35 : 15;
dw_padding = (stricmp(str_element_name, "tracks") == 0 || stricmp(str_element_name, "rectrk") == 0) ? 35 : 15;
dw_padding = (dw_cfg_race_type == 3) ? 35 : 15;

Какой же вариант правильный? Ответ: ни один! Только если мы объединим все проверки вместе, мы можем получить единственно верный вариант кода, и выглядел бы он примерно так:
dw_padding = (dw_cfg_race_type == 3 && (stricmp(str_element_name, "tracks") == 0 || stricmp(str_element_name, "rectrk") == 0)) ? 35 : 15;

Итого у нас 4 варианта одного и того же кода, при этом в разных вариантах допущено 3 разные ошибки! Просто уникальный случай и отличная демонстрация того, почему копипаста — это плохая идея.

Как это было исправлено?


О том, как вносятся изменения в машинный код, я писал ранее. Для исправления проблемы я написал одну функцию:
image
Все приведённые выше фрагменты кода были заменены на вызов этой функции. Теперь отступы в списках выбираются правильно :) И это лишь одно из более чем 200 изменений, которые были сделаны в патче. Описанное изменение на самом деле одно из самых маленьких, но зато сама ошибка, на мой взгляд, была интересной (как демонстрация вреда от соответствующего антипаттерна).

Выводы?


А теперь подумайте. Если здесь нашёлся самозванец, который взялся исправлять без спроса чужие баги в программе без исходных кодов, может найтись и тот, кто в итоге будет настолько зол, что у него появится желание отыскать разработчика или его родственников. А оно вам надо? Пишите качественный код :)
Поделиться с друзьями
-->

Комментарии (83)


  1. gsaw
    09.06.2016 17:39
    +1

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


    1. VEG
      09.06.2016 17:44
      +14

      Это да, просто забавно, что 3 разные ошибки в 4 вариантах одного кода, и при этом ни один вариант не является правильным. На самом деле в этом патче было исправлено большое количество серьёзных проблем, связанных с падениями и зависаниями, но удивительными они мне не показались. Хотя описание поиска и исправление одного deadlock хотелось бы описать в будущем, там был любопытный случай, который связан как раз с с тем, что (судя по всему) забыли удалить один уже ненужный вызов. Как раз и демонстрация работы с WinDbg будет.


      1. VBKesha
        09.06.2016 20:09
        +8

        Было бы очень интересно почитать про это.


  1. greywriter
    09.06.2016 17:47
    +6

    Сегодня читал чей-то класс на 2500 строк, глаза болели от ужасного кода, а больнее всего было в сотый раз натыкаться на комментарий:
    "//TODO: сделать нормально"

    Не сделали…


    1. gsaw
      09.06.2016 18:44
      +9

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

      А TODO это хорошо, говорит о том, что человек знал что делает, что это плохо и места пометил для потомков. Некоторые даже не понимают, что они плохо делают, потом рефакторинг зубы ломает.


    1. accipiter
      09.06.2016 22:13
      +1

      Просто загляните в исходники андроида. Там 2500 строк — это обыденность. Вот пример:
      androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java


      1. apachik
        10.06.2016 01:51

        подумаешь 2500… Более известный пример это android TextView.
        Вот сейчас там 10к строк androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/android/widget/TextView.java


        1. apachik
          10.06.2016 10:25

          а наследуется он от View на 22к строк… http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/android/view/View.java


  1. iKBAHT
    09.06.2016 17:51
    -11

    ты псих


    1. Oxoron
      09.06.2016 22:35
      +15

      Полагаю, в данном случае уместнее будет термин «благородное безумие».


      1. VioletGiraffe
        10.06.2016 10:54
        -14

        Слабоумие и отвага :)


  1. Evengard
    09.06.2016 18:08
    +4

    В качестве комментария к предыдущей статье: я предпочитаю патчи делать прокси-дллками системных если честно. По большей части (что конечно тоже само по себе в какой-то мере грязный хак) можно в DllMain сделать все нужные патчи, в том числе с помощью VirtualProtect изменить нужные страницы памяти на чтение и подправить асм код на свой, либо просто записать long jump на свою процедуру, скомпиленную с __declspec(naked), а потом push addr, retn для возврата обратно.


    1. ValdikSS
      10.06.2016 03:37
      +3

      Аналогично, и под линукс это делать куда проще, через 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);

      Очень просто и быстро. А если нужна поддержка разных версий, то есть еще и код, который ищет функцию в заданном адресном промежутке по ее сигнатуре.


      1. VEG
        10.06.2016 08:55

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

        Вообще я бы подключал код на C++ только в случае переписывания огромных частей кода. Например, в NFS3 меню заточено строго под 640?480, и для поддержки современных разрешений его по хорошему нужно полностью переписать (и перерисовать всю соответствующую графику). Вот при такой переделке я бы стал писать новый код уже на C++ :)


        1. ValdikSS
          10.06.2016 11:03
          +2

          Зато можно писать комментарии к каждому патчу, включать и выключать их по отдельности. Но, согласен, иногда проще и пропатчить файл. Но если у вас игра, к которой постоянно выходят обновления, но вы замучаетесь патчить ее каждый раз, все равно придется делать либо лоадер, либо динамический патчер.


        1. Evengard
          10.06.2016 14:24

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

          Теоретически с легальной точки зрения всё тоже проще, но тут к юристам лучше, наверное не всё так просто.


  1. LiarParadox
    09.06.2016 18:08
    +12

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


    1. neomedved
      09.06.2016 18:45

      Batman: Arkham Knight с его кривым исполнением тоже наверняка был рентабельным, хоть его проблемы и видны юзерам.


      1. boblenin
        10.06.2016 04:29

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


        1. neomedved
          10.06.2016 07:32

          Steamspy говорит о 550к владельцах бэтмена. Думаю, затраты на портирование более чем окупились.


          1. jonic
            10.06.2016 11:17

            Я купил, потому что пол Free Edition прошел, и не так уж он и баговал если честно… Особенно текущая версия в стим


            1. neomedved
              10.06.2016 11:19

              Не знаю насчёт текущей версии, но пару месяцев назад она была всё ещё не очень.


              1. jonic
                10.06.2016 11:21

                Я если честно вообще ни разу не натыкался на баг с полётом, хотя играю на мыше :) Единственное под конец игры она начинает фризится сильно, но ssd решил и эту проблему


              1. rdifb0
                11.06.2016 10:31

                Возможно зависит от железа. Я закончил прохождение игры 11.10.2015. и у меня работало все идеально. Скорей всего из-за плохого портирования она потребляет огромное и неоправданное кол-во процессорного времени и оперативной памяти. По этому у кого мощный ПК мог проблем и не заметить.


                1. perfect_genius
                  11.06.2016 16:41

                  Предполагают, что Denuvo тоже влияет на производительность.


    1. VEG
      09.06.2016 19:12
      +4

      К сожалению, уже через несколько лет код этой игры начал ломаться, что точно было заметно пользователям. Например, в рендерере DX6 поддерживаемые форматы текстур записывались в массив из 14 элементов, и если система поддерживает больше — переполнение буфера и падение при запуске. В результате пользователи ругали производителей драйверов (это можно найти на форумах), что при обновлении драйвера версии X на более новую версию X+1 игра начинала падать. А ведь на самом деле драйвер просто узнал о каком-то новом формате текстур, и это объективно хорошо. Это в игре была заложена бомба замедленного действия. И это далеко не единственный пример.


      1. MrShoor
        09.06.2016 20:55
        +9

        Ага. И обычно после такого производитель драйверов вставляет в новую версию драйвера код:
        if (Process_Is_NFS3()) { отдавать старый список форматов текстур };


        1. JerleShannara
          10.06.2016 14:57

          А это вечная практика всех разработчиков. Всеми любимый windows тому пример — вставим таких костылей для стороннего софта (а то покупатель обидится, что его симсити не работает под новой операционкой). Windows не пример? — okay, скатимся в древность и к железу — award bios: обработка исключений для десятка PCI плат расширения (пара звуковушек и S3Trio там были точно), мегакостыльный обработчик int 13h с фиксами для некоторых устройств. А дрова nvidia, ну тут можно и нижнюю челюсть вывихнуть, если посмотреть сколько там индивидуальных настроек для кучи .exe файлов валяется.


    1. eydemidov
      10.06.2016 13:31
      +1

      Многие клиенты/начальники между «идеальный код» и «относительно вовремя и работает» выберут второе. Потому что идеальным кодом не выплатить зарплаты и дивиденды, не заплатить за офис, да и просто тупо не выйти на рынок.

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


      1. NLO
        10.06.2016 19:01

        НЛО прилетело и опубликовало эту надпись здесь


  1. zodchiy
    09.06.2016 18:34

    Сам не успел, т.к. на работе, но брат, сорокадвухлетний бородач уже рубится. Спасибо!


    1. alexxxst
      10.06.2016 12:04
      +1

      Может брата тоже на работу устроить?))


  1. AiMAX
    09.06.2016 19:15
    +1

    После прочтения заголовка думал, что будет процитирована вся история с ныне мёртвого ItHappens: Адекватный друг и абсолютный глюк (http://ithappens.me/story/11872/
    По теме: копипаста действительно может сыграть злую шутку, так как можно не учесть условия применимости используемых кусков, как указано в посте — ещё и с ошибками.


    1. grossws
      09.06.2016 20:07
      +4

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


      1. AiMAX
        09.06.2016 21:21

        Понятно. Я имел в виду, что подобный рассказ неплохо подходит для затравки, по аналогии с картинкой для привлечения внимания.


      1. greenhack
        09.06.2016 22:22

        Но это не его фраза тоже. Он на ее авторство и не претендует. И вроде в его книге я встречал указание на кого-то конкретного, но может ошибаюсь. В электронном варианте нашел один случай упоминания — автором значится Аноним.


    1. PsyHaSTe
      10.06.2016 14:47
      +1

      Кстати, есть информация, что с ним случилось? А то как-то я захожу, а новых историй нет… И молчание везде.


      1. amdf
        10.06.2016 15:54
        +4

        Думаю, уволился копирайтер, придумывавший все истории.


        1. PsyHaSTe
          10.06.2016 17:22
          -1

          Мне они не казались выдуманными. Вполне себе «айтишный башорг», там даже иногда были перепалки, ответ на ответ на ответ на… Нужно обладать очень богатой фантазией, чтобы достоверно придумать подобное.


          1. VEG
            10.06.2016 17:34
            +2

            Ну по крайней мере та история, на которую сослался AiMAX, выглядит выдуманной (или по крайней мере сильно преувеличенной).


    1. Sergunka
      11.06.2016 07:49
      +2

      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!


  1. Alex_ME
    09.06.2016 19:22
    +1

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


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

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


    1. NeonMercury
      09.06.2016 19:47
      +1

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


      1. Alex_ME
        09.06.2016 19:49

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


    1. VBKesha
      09.06.2016 20:15
      +1

      К IDA есть ещё HexRays который может попытаться представить это всё дело как Си код. Получается не всегда хорошо, но значительно облегчает жизнь.


      1. JerleShannara
        10.06.2016 15:02

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

        он раскрывал в полный ужас, понять который было нереально.
        Хотя согласен, длинные функции с кучей параметров через него изучать проще.


      1. Evengard
        10.06.2016 15:21
        +1

        Скорее уж «получается обычно отвратно». Честно. Понять только какие-то оч простые вещи можно, но не более.


        1. VBKesha
          10.06.2016 15:25

          Тут зависит от того что исследуешь. Иногда если разобраться как хранятся стуктуры и ткнуть его носом где что получается Си код который можно спокойно копипастить ещё куда нибудь. Ну а если что то современное написанное с использованием всяких Boost, Qt и прочего то да зачастую только хуже.


  1. greenhack
    09.06.2016 20:26
    +2

    NFS3 навевает приятные воспоминания. Мне тоже кажется лучшей частью в серии. А может просто ностальгия.


    1. VEG
      09.06.2016 21:19

      Не глядя на косяки, NFS3 всё равно классная. Перед тем, как взяться за патч, я пробовал разные варианты на замену, но ничего не зацепило. Не исключаю, что это синдром утёнка. Вообще в современных гонках, как оказалось, сплит-скрин уже не обязательная возможность. А для меня это обязательная возможность, потому что я играю в гонки (и другие игры) как раз тогда, когда кто-нибудь ко мне заглянет в гости поболтать. С геймпадами, сидя на диване, а не как в детстве, два человека за одной клавиатурой.


      1. greenhack
        09.06.2016 21:30

        Вообще в современных гонках, как оказалось, сплит-скрин уже не обязательная возможность. А для меня это обязательная возможность, потому что я играю в гонки (и другие игры) как раз тогда, когда кто-нибудь ко мне заглянет в гости поболтать. С геймпадами, сидя на диване, а не как в детстве, два человека за одной клавиатурой.

        И подобный oldschool, я считаю, здорово. У меня так вообще эти гонки прошли в основном под знаком PS1. Кстати, интересно было бы сравнить код с консольной версией.


        1. VEG
          09.06.2016 21:37

          Судя по всему, какую-то часть кода они делят между собой. Я встречал остатки хардкода, которые предназначались для пасхальных трасс, которые были в NFS3 PS1, но которых не было в NFS3 PC (PC-версия вышла после PS1-версии).


          1. greenhack
            09.06.2016 22:25

            Интересно было бы увидеть еще статьи на подобные темы. Особенно связанные со старыми играми, когда деревья были толще и небо зеленее.


      1. perfect_genius
        10.06.2016 07:40

        «С геймпадами, сидя на диване, а не как в детстве, два человека за одной клавиатурой.»

        Планируете поддержку Xinput?


        1. VEG
          10.06.2016 07:46

          Оно и без Xinput хорошо работает. Единственное, что хотелось бы изменить умолчания для Xbox-совместимых геймпадов. И ещё меню научить управлению с геймпадов. Но сейчас уже не будет времени заниматься проектом, так что если это и будет в патче, то не скоро. Сейчас в меню управляюсь с небольшой беспроводной клавиатуры — это не такое уж и значительное неудобство.


    1. JuniorIL
      13.06.2016 16:52

      ИМХО лучшей по физике и атмосфере была Posche Unleashed. Особенно в золотую эру, раздолбать машину при заносе было абсолютно не проблема. Плюс самые красоты Европы (ну конечно схематично, но зачем нам воображение то?), Пирнеи, Шварцвальд, Альпы, Автобан, Корсика и т.д.


      1. greenhack
        13.06.2016 19:40

        В плане красот Европы соглашусь. Я в эту часть играл просто наслаждаясь видами.


  1. Rast1234
    09.06.2016 22:43

    Спасибо за патчи! Круто, когда есть запал и навыки, чтобы реверсить в свободное время.)
    Кстати, в 1998 году вышла еще одна крутая и сильно багованная игра — Trespasser. И у нее тоже есть фанаты, которые реверсом и такой-то матерью делают патчи, улучшают движок и даже добавляют новые уровни…


    1. perfect_genius
      10.06.2016 07:42

      У Trespasser утекли исходники.


  1. TrueBers
    10.06.2016 00:53

    Эх, круто! Завидую — откуда ж столько свободного времени?

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

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


  1. Yfka
    10.06.2016 02:39
    +6

    Для тех, кто не в теме:

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

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

    Так, что эти глупые ошибки делали Сишные программисты-зомби в анабиозе. (Не стеляйте программиста, пристрелите таких управленцев)


    1. Ogoun
      10.06.2016 12:44

      Программисты не имеют сознания и воли? Если 60-80 часов и низкая производительность, значит это их добровольный выбор.


      1. FoxCanFly
        10.06.2016 13:06

        в США не существует каких-либо обязательных норм про 40 часов. Так что выбора немного.


        1. Ogoun
          10.06.2016 13:10

          Наоборот, это и показывает что выбор был их решением. Даже с наличием норм по 40 часам у нас в России, вы можете работать и 20 и 10 часов. Запретить никто не может.


      1. kpower
        10.06.2016 18:32

        А давайте сейчас все руку на сердце положим. Геймдев и 40 часов? Не верю. Галенкин в подкасте тоже как-то шутил на эту тему…


  1. dima_lur
    10.06.2016 07:11

    Женя, ты хексрейсом часто пользуешься или все по хардкору?


  1. 4renG8
    10.06.2016 07:11

    После таких статей хочется самому наконец что-нибудь разобрать! Но скажите: чем не угодил подход с отражением картинки? В современных играх это точно был бы более рациональный подход так как всё это добро можно легко скинуть на пиксельный шейдер. Тут даже без математических операций можно обойтись, просто единожды верно инициализировав шейдер. То есть по сложности инициализация рендера с одномерным массивом integer, против подготовки зеркального трехмерного меша с привязанной текстурой.

    PS. Сейчас вовсе весомая часть картинки рисуется уже в плоском кадре. Из 3D там разве что карта нормалей кадра и ещё пара карт. К плоскому кадру дорисовывается многое: туман, объёмный свет, объемные тени, самозатенение, просто тени, блеск и даже трёхмерные отражения зачастую просто копируют пиксели из других мест того же кадра. Представьте что бы мы имели если бы считали это честно.


    1. VEG
      10.06.2016 09:06
      +2

      Такой подход плох тем, что вместо кода «отражения» модели трассы в одном единственном месте программы, разработчику необходимо не забывать вставлять соответствующую проверку и инверсию в каждом месте кода, где используется «лево» и «право», то есть это будет размазано по всему проекту. И разработчики таки забыли об этом, о чём было рассказано :) Проблему с отражёнными надписями на машинах нужно решать созданием отдельного варианта текстур с надписями, где надписи будут отражены, что тоже достаточно странно.

      Хотя, конечно, реализация этого костыльного метода была сама по себе проще, и на реализацию переворачивания модели трассы при загрузке наверняка ушло бы больше времени. Зато было бы надёжнее :)


      1. VGrabko
        10.06.2016 09:30
        -1

        а что мешает менять прям в рендере а не везде7


        1. VEG
          10.06.2016 09:35
          +2

          Потому что где находится «лево» и «право» важно не только при рендеринге. Начинаем мы с того, что добавляем условие, которое инвертирует «право» и «лево» в коде ввода. Затем оказывается, что код отрисовки руля (при виде «из кабины») тоже нужно переделать, иначе он будет визуально поварачиваться не в ту сторону. Потом мы вспоминаем, что когда копы ставят шипы, по рации можно услышать, с какой стороны дороги они их поставили, и это тоже нужно не забыть инвертировать… Ну и в этом духе.


          1. VGrabko
            10.06.2016 10:12
            -1

            я бы сделал класс для этого.


            1. VEG
              10.06.2016 10:21
              +3

              И что этот класс будет делать? Это ведь вмешательство в совершенно разные части программы, и по условию «включен режим отражённой трассы» подпирать всё придётся разными костылями. Где-то умножить на -1, где-то инвертировать булево значение, где-то вместо одной текстуры прочитать другую (с отражёнными надписями). А где-то об этом можно просто случайно забыть, что разработчики NFS3 и сделали.


              1. VGrabko
                10.06.2016 12:35
                -1

                он будет хранить все правила.


                1. VEG
                  10.06.2016 12:40
                  +2

                  Изъясните понятнее свою мысль. Что за правила он будет хранить и как он будет это делать? Какую проблему это решит? Почему из-за вашего предложения этот подход перестанет быть костыльным?


          1. VoidEx
            10.06.2016 18:49

            Про руль не понял. Я жму влево, это на этапе ввода интерпретируется как «вправо», соот-но руль поворачивается вправо, но зеркально отражается, и я вижу поворот влево. Зачем дополнительно менять отображение руля?

            update: или кабина там позже рисуется и не отображается зеркально?


            1. VEG
              10.06.2016 18:52
              +1

              Салон авто не отражается, машина из леворульной не превращается в праворульную. Он там выводится так же, как HUD, то есть просто накладывается поверх изображения.


      1. 4renG8
        10.06.2016 18:03

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


  1. KonstantinSoloviov
    10.06.2016 12:28
    +1

    потому что через 20 лет какой-нибудь маньяк будет изучать и дорабатывать машинный код вашего продукта, и он может захотеть вас найти
    Если кто-то через 20 лет захочет изучить и доработать ваш код это значит, что вы написали очень хорошую программу иначе ее бы давным давно выкинули на свалку.


    1. VEG
      10.06.2016 12:38
      +1

      Игры столько лет спустя ценят не за код, а за геймплей. Ничто не мешает хорошей внешне программе иметь отвратительный код.


  1. xakep2011
    10.06.2016 12:57
    +1

    обожаю такие посты! автору желаю вдохновения и времени для новых.


  1. VoidEx
    10.06.2016 18:37
    +1

    Пишите код так, будто маньяк, который захочет вас убить — это вы сами.


  1. Displacer
    12.06.2016 21:12

    Если уровень понимания, как там всё работает и устроено столь велик, то может быть стоило бы подумать о свободной реализации этой игрушки с ресурсами из оригинальной игры?


    1. VEG
      12.06.2016 21:14

      Всё же исправить основные ошибки в существующей программе как-то проще, нежели написать 1 в 1 с нуля. Настолько глубокого понимания кода, чтобы переписать его целиком на C++, нет. Если работать над таким в одиночку — это задача не на один год, как мне кажется.