Этим летом вышла очередная игра из серии Batman Arkham, в ПК версии которой оказалось столько багов, что было принято беспрецедентное решение снять её с продаж. Я решил посмотреть, что же там такого ужасного.
Среди прочих наблюдается такой баг, на первый взгляд, случайный: иногда, когда Бэтмен прыгает с крыши, вместо того, чтобы ровно планировать, он колбасится некоторое время, потом делает довольно глубокий нырок, и только потом выравнивается. В результате в лучшем случае — весьма нежелательная потеря высоты, в худшем можно спугнуть врагов, а то и вообще свалиться им на голову.
На скриншоте изображён этот момент: вместо того, чтобы лететь вперёд, Бэтмен повернулся вниз головой, демонстрируя полнейшее пренебрежение к происходящему. Аналогичный баг был в предыдущей игре (Arkham Origins), и он до сих пор не исправлен. Видимо тот же самый кривой код был перенесён в новую игру. Попробуем найти, какие ошибки делают программисты в играх такого уровня, и исправить их.
В Origins баг был не таким неприятным: Бэтмен колбасился, но высоты не терял. А тут он падает вниз, что очень раздражает и мешает игре. Для начала попробуем уточнить, при каких условиях проявляется баг. Это оказывается не так просто. Пытаясь повторить глюк, можно сотни раз прыгать с крыши, и всё будет нормально. Однако, как только начинаешь играть, он появляется, причём в самые неудачные моменты. Вот как это выглядит:
После многочисленных экспериментов выяснилось, что баг проявляется, только если спрыгнуть под определённым углом, да и ещё при этом двигать мышкой. Неудивительно, что на первый взгляд ошибка кажется случайной. Когда вы прыгаете с крыши, обычно смотрите на то место, куда собираетесь лететь. Во время полёта направление корректируется мышью, и при определённом движении, причём только в самом начале (примерно через секунду после прыжка), возникает этот баг.
Почему же так происходит? Как вообще можно найти в игре место с этой ошибкой? Оказывается, можно. Для этого воспользуемся Cheat Engine, который уже не раз упоминался на хабре. Принцип примерно такой:
Найдём какую-нибудь переменную, касающуюся полёта, например, скорость. Сначала делаем снимок всей памяти в момент, когда Бэтмен летит медленно. Затем пикируем (скорость увеличивается) и ищем значения, которые увеличились. Затем опять выравниваемся (скорость уменьшается) и ищем среди ранее найденных значения, которые теперь, наоборот, уменьшились. После нескольких повторений обычно удаётся найти нужную ячейку памяти. Затем по ней (с помощью аппаратной точки останова) найдём код, который её меняет. Вот он:
Это оказалась середина длиннющей подпрограммы, почти наполовину состоящей из вычислений с плавающей точкой. Видимо это и есть код, полностью определяющий весь полёт Бэтмена. Начнём потихоньку его изучать. Как нам сообщил отладчик, скорость изменяется при выполнении команд, выделенных зеленым, значит она содержится в [rdi+0000144C], а перед этим вычисляется в регистре xmm8 (выделено красным).
Проверим это. Заменим команду subss на addss, и теперь скорость не будет падать, а только увеличиваться. Получился забавный аттракцион: можно носиться на огромной скорости по улицам, даже быстрее, чем в бэтмобиле, при этом не теряя высоты. Попадать в повороты на такой скорости становится трудновато. В нормальной игре это конечно, невозможно, то есть мы убедились, что действительно нашли код, отвечающий за полёт Бэтмена.
Теперь попробуем наоборот. Заменим обе команды на «subss xmm8,xmm8», то есть вычтем регистр сам из себя, в результате скорость должна стать равной нулю. Запустим игру. И тут мы обнаруживаем, что перед полётом имеется переходный этап, как раз та первая секунда, от момента, когда Бэтмен делает шаг в пустоту, до того, как он полностью расправит крылья. В этот момент срабатывает изменённая нами команда, и Бэтмен застывает в воздухе.
Это оказалось очень удобно. Теперь не нужно постоянно прыгать с крыши под определённым углом, при этом пытаясь дёрнуть мышкой в нужный момент, чтобы воспроизвести баг. Мы поймали тот самый момент, переход между прыжком и полётом, когда он происходит. Теперь отлично видно: пока камера смотрит выше определённого угла (примерно на линии горизонта), всё нормально, но как только она опускается ниже, вместе с ней опускается и Бэтмен, и после этого любое движение мышью вверх приводит к багу.
Настало время искать ошибку в коде. Попытки отключать куски программы наугад ничего не дали. Бэтмен застывает в нелепых позах, летит не туда, куда надо, вертится как волчок, но баг не исчезает. Остаётся кропотливо анализировать, что где хранится, и какие вычисления делаются. Начинаю просматривать всё ту же подпрограмму с начала, и вскоре находится такой фрагмент:
Не иначе как трем 16-битным значениям (в регистрах eax,edx,ecx) делают расширение знака. Это сразу наводит на мысль о трёх измерениях. А ну-ка посмотрим, что там в регистрах? Небольшие числа с разным знаком. Подвигаем мышью — значения изменяются. Видимо это реакция на манипулятор в виде векторов. Обнулим одно из значений, и убедимся, что Бэтмен теперь не реагирует на движение мыши вверх-вниз, а только в стороны. Конкретно это первое число из трёх, и оно сохраняется в памяти в ячейке [rsp+70] (выделено зелёным). Это поможет нам повторить баг в любой нужный момент.
Попробовав выполнять программу дальше по шагам, я быстро запутался в условных переходах и вычислениях. Однако, дойдя до знакомого места, где вычисляется скорость, я заметил в одном из регистров число, похожее на ранее найденные векторы. Только теперь это оказалась не мышь, а сам Бэтмен, а именно угол его наклона к горизонту, тангаж, если можно так сказать. В нормальном состоянии он имеет значения от -2548 до -15000, то есть от положения чуть ниже горизонта, до почти вертикально вниз.
Теперь воспроизводим баг. И тут оказывается, что когда Бэтмена колбасит, в этом регистре оказывается не нормальная ориентация, а какое-то произвольное число, причём даже не 16-битное, а 32-битное! Это всё объясняет. Где-то в вычислениях происходит ошибка, переполнение, или что-то вроде того, и в итоге Бэтмена мотает, как осенний лист на ветру.
Чтобы проверить это, смоделируем ситуацию. Найдём то место в памяти, где сохраняется «ошибочное» значение, и заменим его 32-битной константой. Получаем Бэтмена, застывшего в полете под фиксированным углом.
В ответ на движение мыши он поворачивает, расправляет крылья, двигает головой. Но его наклон к горизонту остаётся постоянным, причём неправильным. Бэтмен не может так летать, он не собирался так летать, к этому приводит ошибка при вычислении. К текущему углу добавляется неопределённое число, и хотя для рендеринга оно подгоняется под нужные пределы, в памяти хранится в непотребном виде. В каждом следующем цикле они достают это число, берут от него младшие 16 бит, и получают чёрт-те что. Поэтому процесс «дёргания» продолжается довольно долго, пока каким-то чудом число всё-таки не попадёт в правильный диапазон. Тогда бэтмен успокаивается и начинает лететь нормально.
И вот я снова блуждаю в коде, пытаясь определить, где в вычислениях что-то пошло не так. Из всей подпрограммы в 9 килобайт участок поиска сузился до примерно 1 килобайта, но понять здесь что-нибудь по-прежнему трудно. Через некоторое время я стал склоняться к мысли, что всё это будет слишком сложно, как вдруг заметил, что во многих SSE регистрах находится так называемое Nan (нечисло). Замечательно. Так вот в чём дело! Где-то в вычислениях получилось Nan, а стоит нечислу появиться один раз, как все операции с его участием тоже приведут к Nan, и пошло-поехало. Теперь нам достаточно пройти весь цикл по шагам, внимательно наблюдая, когда впервые появится Nan, и мы найдём то, что нам нужно:
Вот после выделенного вызова, оно и возникает. В этот момент xmm1 = 0.5, a xmm0 = -0.01. Заходим внутрь, и оказываемся в msvcr100.dll, функция powf (возведение в степень), то есть в данном случае, берется корень из отрицательного числа. Откуда же оно взялось, и почему это происходит так редко? После подробного изучения удалось выяснить, что здесь вычисляется. Рассмотрим на примере нормальную ситуацию:
В xmm0 у нас 600 — это крейсерская скорость Бэтмена. Из [rdi+0000144C] в xmm2 загружается 731 — это текущая скорость Бэтмена (заметим, это то же смещение, что в первом фрагменте кода, рассмотренном в самом начале). Затем они вычитаются (subss xmm2,xmm0), получается 131. Далее из [rdi+000013EC] берется 2200 — максимальная скорость, умножается на константу, опять вычитается xmm0 (600), получается 1270. Делим первую разницу на вторую (divss xmm2,xmm1), получаем 0,1031. Теперь это умножается на ранее вычисленный в xmm14 коэффициент (он зависит от угла, но сейчас это не важно, главное, что он всегда положительный), в итоге получаем 0,0268. Дальнейшее мы уже знаем, вычисляем из этого корень, всё хорошо.
А теперь, что получается, когда Бэтмен прыгает с крыши. Вся эта ветка выполняется, только если двинуть мышкой вверх, чтобы вычислить, на сколько можно повернуться вверх за следующий квант времени. В этот момент скорость Бэтмена оказалась равной 599. Из неё вычитают 600, получается -1, результат всей формулы отрицательный, и берут квадратный корень. Вот тут и получается Nan. Все дальнейшие вычисления совершенно очевидно идут насмарку, «нечисла» множатся, переводятся в 32-битное целое и в итоге мы получаем то, что видели.
Найдём это же место в предыдущей игре — Arkham Origins. Оказалось, там всё практически то же самое: крейсерская скорость Бэтмена тоже 600, поэтому подпрограмма нашлась почти сразу. Правда угол планирования немного ниже, вычисления идут на FPU, а корень вычисляется другим вызовом msvcr100.dll (потому что двойная точность)
Подведём итоги исследований. Полёт Бэтмена был задуман таким образом, что его скорость никогда не должна быть меньше 600. Когда он летит ровно, его скорость 600. Если он немного накреняется вниз, скорость возрастает. Когда он выравнивается, она плавно снижается до 600, но никогда не должна быть меньше. В результате программисты думали, что разница скоростей никогда не будет отрицательной, и спокойно вычисляют из этого квадратный корень.
Они сделали 3 ошибки. Не учли, что при определённых условиях вычисленная по их формуле скорость может упасть ниже 600. Потом не проверили, что берут корень из отрицательного числа. А потом вычисляли и хранили результат в 32-битной переменной, а брали от неё только 16 бит, в результате корень из отрицательного числа может браться всего один раз, а Бэтмена потом будет колбасить секунд десять.
Кстати, интересно, что при управлении геймпадом (даже на ПК) этого бага нет. Думаю, потому, что геймпад не позволяет сделать таких резких движений вверх-вниз, как мышь. Поэтому, скорее всего, на консолях эта ошибка тоже есть, просто она не проявляется.
Как исправить ошибку? Например, для Arkham Knight перед вычислением корня добавим команду «maxps xmm2,xmm9» (максимум), так как в xmm9 у нас ноль, результат всегда будет положительным. Для Origins используем команду «fabs» (модуль). Запускаем игру и убеждаемся, что глюков больше нет: Бэтмен не дёргается, а летит куда нужно.
Можно даже написать скрипты, которые найдут код по уникальной последовательности байт и исправят его. В принципе, для Origins можно прямо изменить.ехе-шник, а вот Arkham Knight защищен Denuvo, поэтому код можно менять только в памяти, когда игра уже загружена, что и делает Cheat Engine.
<?xml version="1.0" encoding="utf-8"?> <CheatTable CheatEngineTableVersion="18"> <CheatEntries> <CheatEntry> <ID>0</ID> <Description>"Fix gliding bug"</Description> <LastState Activated="0"/> <Color>80000008</Color> <VariableType>Auto Assembler Script</VariableType> <AssemblerScript>[ENABLE] aobscanmodule(INJECT,BatmanAK.exe,F3 41 0F 59 D6 F3 0F 10 8F 28 14 00 00 0F 28 C2 E8 D4) alloc(newmem,$1000,INJECT) label(code) label(return) newmem: code: mulss xmm2,xmm14 maxps xmm2,xmm9 jmp return INJECT: jmp code return: registersymbol(INJECT) [DISABLE] INJECT: db F3 41 0F 59 D6 unregistersymbol(INJECT) dealloc(newmem) </AssemblerScript> </CheatEntry> </CheatEntries> <UserdefinedSymbols/> </CheatTable>
<?xml version="1.0" encoding="utf-8"?> <CheatTable CheatEngineTableVersion="18"> <CheatEntries> <CheatEntry> <ID>0</ID> <Description>"Fix gliding bug (Origins)"</Description> <LastState Activated="1"/> <Color>80000008</Color> <VariableType>Auto Assembler Script</VariableType> <AssemblerScript>[ENABLE] aobscanmodule(INJECT,BatmanOrigins.exe,D9 86 E8 0B 00 00 E8 3E) alloc(newmem,$1000) label(code) label(return) newmem: code: fabs fld dword ptr [esi+00000BE8] jmp return INJECT: jmp code nop return: registersymbol(INJECT) [DISABLE] INJECT: db D9 86 E8 0B 00 00 unregistersymbol(INJECT) dealloc(newmem) </AssemblerScript> </CheatEntry> </CheatEntries> <UserdefinedSymbols> <SymbolEntry> <Name>INJECT</Name> <Address> 00E3AB33</Address> </SymbolEntry> </UserdefinedSymbols> </CheatTable>
Те, кто не хочет лезть в код игры, могут просто не трогать мышку в начале прыжка, или по крайней мере не двигать ей вверх. Ну и надеяться, что когда-нибудь разработчики это исправят. Кстати, пока я готовил пост, они выпустили очередной патч, после которого, похоже, всё стало ещё хуже. У многих игра стала вылетать, и пока не была возвращена в продажу. Впрочем, теперь я этому не удивлён.
Комментарии (98)
Starche
07.09.2015 19:21+21Вот интересно. Вы реверс-инжинирингом смогли выловить и пофиксить баг. Неужели при всех нынешних мощнейших средствах отладки разработчики игры не могут докопаться до этой проблемы самостоятельно уже несколько лет (Origins вышел в 2013ом). Противная же проблема, играть мешает жутко.
halyavin
07.09.2015 23:57Средства отладки со временем становятся только хуже. В релизе из-за все более умного компилятора дебаггер показывает что угодно, но только не значения переменных и не ту строку, которая сейчас исполняется. В дебаге, программа просто работает в 100 раз медленнее и нужно очень долго ждать загрузки (да и удастся ли вообще повторить баг при паре fps?).
У разработчиков нет времени, чтобы 1000 раз по-разному прыгнуть с крыши и воспроизвести баг (и повторять эту процедуру при каждой итерации). А тестеры не знают как отладить проблему, когда они её случайно воспроизвели. Даже автор статьи не смог понять как стабильно воспроизвести баг, пока не разобрался в чем дело.
Каждое исправление плохо воспроизводимого бага — это мини-подвиг.
GavriKos
08.09.2015 08:24+8По разному 1000 раз прыгнуть с крыши — это работа отдела тестирования. Можно и автоматизировать, если баг есть.
По поводу низкого FPS в дебаге — ну, вы не правы. При нормальном подходе можно и тестовую сцену собрать, которая FPS не будет садить и даст проверить физику. В общем — проблема не в средствах отладки, а в лени и жадности — скорее выпустить продукт, не потратив времени и денег на толковых специалистов.
AMDmi3
08.09.2015 00:08+1А при чём тут средства отладки? Это коммерческий продукт: купоны сострижены, никто больше никому ничего не должен, разработчики заняты N+1 игрой.
Sheh
08.09.2015 06:37+10Ну а что вы хотите? Вот я вчера акриловую ванну устанавливал… с ней крепления шли родные. Знаете, сколько там багов?
- Слесарь сверлит отверстия тупым сверлом, так, что металл на выходе рвёт.
- Заводские отверстия находятся не в том месте, где должны были быть, так что саморезы в них не закрутить
- Инструкция одна — комплектющие другие.
- Длинна шурупов в инструкции указана такой, что если эту инструкцию соблюдать, то ванную можно продырявить насквозь и выкинуть.
Вобщем, вместо прогнозируемого 1 часа потратил 4
Это наводит на мысли, что проблема не в технологиях, а всё же в людях, а именно, в организации производства продукта.
Владелец фирмы вовсе не заботится о качестве продукта, который его фирма производит. Видимо, прибыль есть и им этого достаточно.
Dywar
08.09.2015 09:46Думаю потому что у них в голове сотни других конструкций до которых еще никто из третьих лиц не дошел.
Ссылку на пост им в саппорт кинуть, исправят утверждениями.
taliban
08.09.2015 09:51+4А вы думаете у них больше тасков нет? Есть процесс разработки, и никто не даст вам времени сидеть и ковыряться с багом который всплывает иногда, при опреределенных обстоятельствах, не факт что эти обстоятельства нашли и определили. Возможно у них этот баг висит в багтрекере, но до него еще руки не дошли.
varnav
07.09.2015 19:26-54В играх от 3-го лица мышку лучше вообще не трогать — для них есть геймпад.
varnav
07.09.2015 23:05-49минусуют те, кто не смог купить геймпад. зря. они недорогие — а удовольствие от игры несравнимо другое.
mannaro
08.09.2015 00:06+5вы просто в GTA: Vice City не играли ;)
varnav
08.09.2015 11:13+3Не играл. Играл в 4-ю часть. Геймпад отложил и играл мышью. Это же шутер. А прицеливаться удобнее мышью.
А вот Ведьмак, серия AC, серия Arkham, файтинги — это не шутеры, быстрое прицеливание не нужно — зато нужно быстрое движение персонажа и быстрое нажатие кропок. Мышь преимуществ не даёт, а у клавиатуры преимуществ вообще нет.
Кстати в AC преимущество джойстика заметно больше всего — возможность прыгать с места в любую сторону, независимо от направления взгляда, на клавиатуре вообще не воспроизводима, также как и например шаг при небольшом отклонении стика и бег при большем отклонении.
А в такие игры как Ori или Super Meatboy вообще почти невозможно без пада играть, о чём честно предупреждают.
varnav
08.09.2015 14:49Кстати аналоговые тормоз и газ это очень круто и на клаве не воспроизводимо вообще.
AlexanderG
08.09.2015 20:31Не понимаю, почему до сих никто не сделал клавиатуру с реакцией на силу нажатия на клавиши (WASD достаточно).
ZimM
08.09.2015 02:38-1о да! в несравнимо худшую сторону.
varnav
08.09.2015 10:59+3Вообще-то вся серия Arkham изначально сделана под геймпад.
Кроме того на геймпаде можно играть откинувшись в кресле — это огромный плюс.
varnav
08.09.2015 11:21Кстати описанный баг не проявляется при игре с геймпадом. По крайней мере за 20 часов игры я с ним не сталкивался.
SerDIDG
08.09.2015 03:09Играю на геймпаде только в фут сим и гоночки, больше ни на что он не пригоден. Мне не в кайф играть с автоприцелом.
Snakecatcher
08.09.2015 09:55+1Любопытство разобрало — а что такое фут сим? Не нашел в поисковике.
realscorp
08.09.2015 12:33+7Симулятор ступни (англ. foot simulator). Правым стиком двигаете правую ступню, левым — левую. На кнопки — шевеление пальцами. При наступании на детальку от лего геймпад вибрирует.
Snakecatcher
08.09.2015 14:05+8Главная задача, провести Мизинец (не тот, что Петир Бейлиш) среди полного опасностей мира Мебели.
Коллега, мы изобрели новый жанр!
SerDIDG
08.09.2015 16:59+2Я бы на вашем месте перестраховался и сначала бы выложил готовую игру в Стим. Представляете как бы она была популярна у летсплееров на ютюбе :D
halyavin
09.09.2015 13:28Поздно, летсплееры уже в это играют (go home you're drunk): www.youtube.com/watch?v=EP7BXsNAa1E.
Ogra
08.09.2015 07:22+9Ну у меня есть два геймпада, они и правда недорогие. В файтинги/Trine с женой или другом поиграть, например.
Но я все равно играю почти во все игры с мыши и клавиатуры. Даже в некоторые файтинги! Лично мне гораздо удобнее управляться таким образом. Но я не кричу на каждом углу «Вы меня минусуете, потому что не можете купить нормальную клаву/мышь/геймпад/руль/джойстик».Hertz
08.09.2015 13:51Когда у меня временно не было своего места для компьютера, меня спас длинный HDMI кабель, телевизор и Dual Shock 4. С ними я прошел GTA 4 и Fallout: New Vegas прямо сидя на диване :-) Свои плюсы есть. Конечно, есть игры, где намного больше удовольствия с клавиатурой и мышью (с джойстиком там просто будет мучение).
mayorovp
08.09.2015 09:29Удовольствия от мыши, может, и правда меньше — но в начале каждого третьего прохождения игры на ютубе я слышу фразу: «в этот раз я играю с геймпада, поэтому в игре могу тупить, не обращайте внимания».
Конечно, это дело привычки — но новые игры выходят регулярно, перепроходить их, как правило, не интересно, — и у каждой свое управление. Если для клавиатуры WASD уже стандарт — то назначение стиков геймпада каждая игра понимает по-своему.varnav
08.09.2015 11:19+1А в каких играх от 3-его лица назначение стиков отличается от «левым ходить, правым смотреть» — не подскажете?
TheRaven
08.09.2015 11:30Есть игры от третьего лица в которых мышь необходима. Взять хотя бы StarConflict с его догфайтами в кучах астероидов.
varnav
08.09.2015 11:41+2И да, спасибо за минусовую карму. Все мои публикации на хабре распубликованы. Они не пропадут, перенесу в другое место.
realscorp
08.09.2015 12:47Да уж, система «саморегулирования» Хабра как всегда «на высоте». Я, скажем честно, тоже не согласен с вашим мнением насчет игровых контроллеров, но за что тут сливать карму — вообще не понимаю. Ну, немного заносчиво высказались, ну подумаешь — немного же. Без какой-нибудь ругани или там истерики или политических высказываний. Зачем вам минуса в карму отправлять — хоть убей, не пойму, как не пойму и в чем тут положительный эффект системы «саморегулирования».
mayorovp
08.09.2015 13:20+4Карма была слита за оскорбления. Мне вот, к примеру, неприятно читать, будто бы я просто «не смог» купить геймпад. А для кого-то это может оказаться и вовсе больным местом…
varnav
08.09.2015 14:36На тот момент мой первый нейтральный комментарий про геймпад уже набрал -20
AlexanderG
08.09.2015 20:34Потому что он написан в пассивно-агрессивной манере и касается вкусовщины. А о вкусах, как правило, спорить нет никакого смысла.
varnav
08.09.2015 23:30для того кто реально не может по причине крайней бедности — у меня есть логитековский клон контроллера xbox 360, готов подарить.
realscorp
09.09.2015 07:46+1По-моему, для выражения мысли «мне не нравится ваше мнение» нужно использовать минусы на комментарии. И автору коммента будет понятно, что его мнение как минимум не находит общественной поддержки, и из общественной жизни Хабра он за это мнение не «выключится».
«Выключать» хабрапользователя надо за оголтелую неадекватность и прямые оскорбления.
Иначе все это похоже на систему доносов при тоталитарном государстве. «Мне не нравится мнение соседа — пусть его посадят с глаз долой».
Ogra
08.09.2015 13:21+6Пост про высший пилотаж — правку гейзенбага без исходников, зачем тут комменты «минусуют те, кто не смог купить геймпад»?
Здесь вообще не место холивару геймпад/клава, тем более в таком тоне.varnav
08.09.2015 14:42Ну и мне на хабре тоже не место — так решило сообщество, поэтому мои публикации, добавленные в избранное тысячами человек, и имеющие больше сотни тысяч просмотров (я не хвалюсь, это просто статистика), переезжают в другое место.
Этого бага при игре на геймпадах нет.TheRaven
08.09.2015 15:43+2… к вопросу о том, что все что не лежит у вас на жестком диске — может пропасть…
varnav
08.09.2015 17:04Обычно любят утверждать противоположное — что из интернета ничего нельзя удалить.
mayorovp
08.09.2015 21:16Из интернета и правда ничего нельзя удалить — если ставить целью именно удаление некоторой информации из всего интернета.
Удалить же конкретную единицу информации с конкретной площадки — куда проще.
AlexanderG
08.09.2015 20:34+1Столкнулся с этим, когда отложил «на будущее» несколько редких видео на ютубе — исчезли.
Diaver
08.09.2015 18:07+1Я как-то предлагал администрации ввести правило, когда минус в карту дает пол минуса самому минусующему, чтобы народ задумался что делает перед тем как демотивировать человека, но в администрации как всегда ответили: «Все отлично, ничего менять не будем».
Вот и получаем ситуацию, когда за один комментарий сливают человека полностью. В результате, каждый перед как написать свое мнение тысячу раз подумает, а лучше вообще ничего писать не будет, хотя комменты на хабре зачастую интереснее читать чем сами статьи. И последнее время их все меньше и меньше после введения новой системы.
Печаль…stigory
09.09.2015 04:47минус в карту дает пол минуса самому минусующему
Мне кажется, что это не самый удачный вариант. Прямая обратная реакция в этом случае неуместна.
Более правильным был бы подсчет «индекса мизантропии». И учет этого индекса при начислении баллов кармы.
Другими словами: чем больше ты минусуешь — тем меньше ты сам получишь от чужих плюсов в свою карму.
В этом случае нет прямой зависимости от конкретного действия. Ведь минусы бывают вполне оправданными. Но есть глобальное воздействие если ты склонен минусовать постоянно.Diaver
09.09.2015 10:26+2На мой взгляд, очень даже уместна. Минусить человеку карму, это плохо, это демотивирует человека, портит ему настроение и лишает возможности и желания общаться через комментарии. Проблема в том что хаюроюзеры в целом не понимают, что минус в карму это последнее дело и его надо ставить, когда вы для себя решили что человек мудак и вы тут его не хотите видеть. Часто бывает что у человека и статьи есть и комменты в целом положительные и все равно ему сливают карму за один комментарий, как вышестоящему товарищу, просто потому что этот комментарий не понравился или просто следуя тупому стадному инстинкту. Хотя если не понравился комментарий, нужно ставить минус комментарию.
В результате, надо 100 раз подумать прежде писать комментарий, который не следует общему мнению, даже если ты положительный товарищ с положительной оценкой комментариям и статьям, так как тебя легко могут слить в большой минус вот такие вот не сознательные или в комплексом вахтера.
vayho
08.09.2015 17:32+1мде, сочувствую нужно скопипастить ваши статьи на всякий, а то тут куча народа толкового уже свалила или ушла в инактив(не пишут статей) а если еще и статьи удалять начнут нахрен этот хабр вообще тогда нужен, особенно доставляет как ребят минусуют на -70 в статьях про политику
realscorp
09.09.2015 07:50+1Все мои публикации на хабре распубликованы.
Тут вы тоже не правы. Например, я не могу поставить вам плюс в карму для компенсации минусов за неудачный комментарий, потому что плюсование кармы пользователей без опубликованный статей невозможно.varnav
09.09.2015 09:10-1А вот минусованию вижу это не помеха, карма ещё просела.
Такой режим саморегуляции Аристотель называл охлократией.
И да, слова насчёт недорогих геймпадов беру обратно, заказал вчера за 3000 р. контроллер Xbox One, недорогим он мне не показался.
s5656
08.09.2015 11:51-3Геймпады пригодны только для платформеров и файтингов, во все остальное играть мучительно больно.
jonic
07.09.2015 19:49С данным багом не сталкивался(сейчас прохожу ее), но фризы при загрузке мира заметны очень :)
agranom555
07.09.2015 20:19+5Может разработчикам написать? Хотя проигнорируют скорее всего, но вдруг.
clamaw
07.09.2015 20:52+4Я думаю, что если, как пишет автор, игру сняли в продаж, то тех разработчиков там уже может и не быть.
agranom555
08.09.2015 16:42Нее.Они выпустили ее летом. Из-за багов сняли с продаж. Сейчас делаю патч. Как сделают, тогда снова выпустят в продажу. Они же еще дополнения делать будут. Там season pass есть даже.
cher11
07.09.2015 20:38+2Со стороны действия в статье похожи на магию. Очень интересно, спасибо!
PS. На PS4 с багом действительно ни разу не сталкивался
Hertz
07.09.2015 20:48+4Очень занимательно, спасибо!
Можно предположить, что в мире игры очень много состояния, и какие-то области памяти содержат значения, которые в разное время растут и убывают. Сильно мешали подобные значения при поиске скорости персонажа? Или прием с «увеличили, потом уменьшили» отсек большинство мусора?ID_Daemon
07.09.2015 21:46+7Верно. Даже после 2-3 циклов «увеличили-уменьшили» осталось несколько сотен значений, и все они синхронно меняются со скоростью. Для поиска единственного правильного существуют и другие методики, типа наблюдения за ними в реальном времени, отсечения заведомо неправильных, перебор в конце концов.
SerDIDG
07.09.2015 21:21+3Мда, «эффективный» менеджмент Warner Bros запарывает уже вторую игру о бэтмене из пока лучшей серии.
barabanus
07.09.2015 21:42-6Не знаю, уместно ли здесь такое, но все же..Zyoma
07.09.2015 23:01+12Снимаю шляпу, очень сильно. При прочтении создавалось впечатление поиска иголки в стоге сена. Впрочем, так оно и есть.
ReklatsMasters
07.09.2015 23:30+5Аплодирую стоя. До самого конца не верил, что удастся докопаться до проблемы.
zo_oz
07.09.2015 23:45Статья крутая! Проясните, пожалуйста пару моментов.
Это оказалась середина длиннющей подпрограммы, почти наполовину состоящей из вычислений с плавающей точкой. Видимо это и есть код, полностью определяющий весь полёт Бэтмена. Начнём потихоньку его изучать. Как нам сообщил отладчик, скорость изменяется при выполнении команд, выделенных зеленым, значит она содержится в [rdi+0000144C], а перед этим вычисляется в регистре xmm8 (выделено красным).
Как вы сходу определили что нужные инструкции лежат по адресам 56F5CD и 56F5DD? а например не по 56F5E8? Или сходу — это только в статье, а на самом деле после отладки?
Как исправить ошибку? Например, для Arkham Knight перед вычислением корня добавим команду «maxps xmm2,xmm9» (максимум), так как в xmm9 у нас ноль, результат всегда будет положительным. Для Origins используем команду «fabs» (модуль). Запускаем игру и убеждаемся, что глюков больше нет: Бэтмен не дёргается, а летит куда нужно.
А что лежит в xmm9? Почему вы уверены что там всегда 0? Или это регистр вообще не используется?
Еще раз спасибо за статью, логика ошибки понятна, это же порт с консоли…ID_Daemon
07.09.2015 23:51+21. Аппаратная точка останова ставится на ячейку памяти, чтобы определить, какие инструкции меняют её содержимое. В ходе выполнения игры Cheat Engine запоминает все адреса и выдаёт список.
2. Немного ранее если посмотреть по коду в xmm9 заносится 0. Я конечно не могу быть полностью уверенным, что каким-нибудь условным переходом мы не попадём сюда с другим значением в xmm9, но если это случится, можно будет исправить ;)
Vanger13
08.09.2015 00:07+22Этот труд стоит того чтобы перевести и ткнуть носом издателей\разработчиков. Пользы для общества с рускоязычной статьи почти что 0, а вот такая же на реддите или блоке cynical brit'a может сильно изменить доверие к предзаказам громикх AAA игр вообще и к студии-разработчику в частности. Используя аргументы воде «вот, тут человек без исходников понял что происходит», а эти ребята до сих пор бананы пинают… А тут может и издатель подтянется, мол «а мы и не знали» :)
pehat
08.09.2015 03:04+1В лицензионном соглашении, как правило, написано: DO NOT DISASSEMBLY/DECOMPILE. Каким бы душком от этого кода ни пахло, его просто нельзя вскрывать (по крайней мере, на глазах у издателя). Вы только представьте – отсудить денег за игру, которую толком и продать нельзя!
Areso
08.09.2015 06:10+4Согласно российскому законодательству это весьма спорный пункт, разве нет? Статья 1280 ГК РФ. Особенно в случае, если лицензия приобретена а) законно б) указанный баг нарушает функционал продукта.
nikitasius
08.09.2015 13:57+1Во Франции право расковыривания программ превыше любого соглашения и зашито в законе. Поэтому компания, которая работает во Франции должна это учитывать.
boblenin
08.09.2015 01:24+1Вот у меня, пока я читал статью, в голове звучал вопрос. Почему же чудесная компания, выпускающая этот чудесный продукт, не наймет толковых людей? Таких как автор статьи.
cjmaxik
08.09.2015 02:53+9Только теперь это оказалась не мышь, а сам Бэтмен
В этом месте на секунду случился когнитивный диссонанс =)
Отличная статья, спасибо!
SHVV
08.09.2015 08:41+7Шикарно!
Если не секрет, сколько времени у вас примерно ушло, чтобы обнаружить и пофиксить баг?ID_Daemon
08.09.2015 18:46+6Это происходило в течение нескольких дней, поэтому трудно сказать. Где-то 5-10 часов. Я тут очень кратко всё описал, в основном удачные моменты. Если рассказать о всех фейлах, которые были в процессе поиска, возможно, будет даже интереснее. Это было действительно похоже на детектив. Например, я записывал видео со множеством полётов, и потом анализировал запись, пытаясь определить, при каких условиях появляется баг. Много времени ушло на то, чтобы докопаться до смысла вычислений. Чтобы можно было не просто написать «я тут нашёл, они берут корень из отрицательного числа», а что именно они делают, и почему.
Orgazmo
08.09.2015 12:58+4Вот это вот всё что Вы проделали, это для меня кажется чем-то из разряда квантовой хромодинамики и теории струн. Браво брависсимо!
TimsTims
08.09.2015 15:46+4Статья на 5. Особенно порадовал не столько сам поиск ошибки, но и записанные ролики с помежуточными результатами.
А бесконечный полет бэтмена — так вообще заглядение!
pehat
Поймали злодеи академика, математика и программиста. Привели их на крышу высотного дома и сказали, что внизу натянут тент, кто спрыгнет и на тент попадет, тот жив останется. Академик развел теорию, долго чего-то думал, прыгнул – разбился. Математик быстро посчитал, прикинул, все учел, прыгнул и попал на тент, спасся. Программист думает: ну, математик все сосчитал, я сейчас так же сделаю. Разбегается, прыгает, и с воплем «Блин, перепутал знак!» улетает в небо…
novoxudonoser
pehat
Ваш ник мумифицирует бороду деда.
Juster
И что? найдутся те, кто читает впервые.
kivsiak
«И что дед таки разбился? Не он задолбал прыгать туда-сюда, пристрелили нафиг»