Как работают патчи в играх?

37

В консольных и компьютерных играх иногда есть исправления для исправления ошибок, которые разработчики пропустили / не успели исправить.

Мой вопрос, как они работают?

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

MulletDevil
источник
Вы хотите изменить скомпилированные игры, которые вы сделали, используя небольшой патч?
wolfdawn
Нет, я просто интересуюсь теорией, стоящей за этим. Мои игры достаточно малы, чтобы просто перекомпилировать их и снова распространять всю игру :)
MulletDevil
4
Это интересный вопрос. Это не основано на проблеме, с которой вы сталкиваетесь при разработке игры. Есть также много способов обработать исправления самым наивным способом, заменяя все файлы, которые были изменены, на самые сложные, получая инструкции по изменению определенных вещей в существующих файлах. Я не уверен, что этот вопрос подходит для этого сайта.
wolfdawn
3
Несколько мегабайт не "маленький". Предположим, у нас есть файл размером три мегабайта, который представляет собой сжатый исполняемый код размером шесть мегабайт. Предположим, что инструкции в среднем имеют длину шесть байтов, поэтому это около миллиона инструкций. (Давайте проигнорируем статические данные, такие как строковые литералы и тому подобное.) Если строка C соответствует примерно десяти машинным инструкциям, это 100 000 строк кода. Это кажется достаточным для основного движка игры. Большая часть размера установки будет такой, как карты текстур, экраны, видео последовательности.
2
несколько мегабайт вполне могут быть маленькими, все зависит от того, что находится в нем и какой процент от общей кодовой базы. Если, скажем, всю 3D-карту уровня необходимо заменить из-за выбранных форматов файлов и т. Д., Включая все текстуры, а что нет, несколько мегабайт действительно могут быть очень маленькими.
jwenting

Ответы:

30

Есть несколько способов сделать это, самым простым будет XOR двух файлов и сжатие их (GZIP или так далее). Теория, лежащая в основе этого, состоит в том, что мы надеемся, что вы можете получить большую последовательность нулей (длинные последовательности с одинаковыми значениями хорошо сжимаются).

Вы можете продолжить эту концепцию и попытаться найти области двух файлов, в которых данные идентичны, и полностью их опустить.

Наконец, вы можете использовать структуру каждого типа файлов в ваших интересах. Например, в EXE вы можете упаковать каждый метод отдельно (только те, которые были изменены) и восстановить EXE самостоятельно во время применения патча; имейте в виду, однако, что это очень вероятно в области избыточного убийства и может не стоить усилий (выигрыш по сравнению с простым bdiff может не оправдать дополнительную сложность, которая может сломаться в дикой природе). В качестве другого примера вы можете использовать файлы diff для скриптов.

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

Джонатан Дикинсон
источник
Что вы подразумеваете под упаковкой каждого метода в exe индивидуально. Это практично?
wolfdawn
@ArthurWulfWhite да. Для инди-дома, вероятно, не стоит времени, так как это потребовало бы огромного количества времени и усилий (вам, по сути, нужно написать собственный компоновщик) - как компании, занимающейся исключительно «исправлением технологии», это стоило бы усилий. Все зависит от того, насколько велик исполняемый код - я быстро взглянул на Sacred 2, и он составил 26 МБ (8 МБ для основного EXE-файла). Бинарный diff может быть в состоянии приблизиться к нему, но все же это идея, которую стоит изложить (я знаю, что CAB-файлы получают хорошее сжатие на EXE-файлах, потому что они используют преимущества этой структуры).
Джонатан Дикинсон
Это очень интересно. Я предполагаю, что с пропускной способностью, какой она является сегодня, минимизация размера игровых патчей не является большой проблемой. +1 интересный продуманный ответ.
wolfdawn
В большинстве игр не представляется возможным использовать отдельные методы. Компилятор может иметь довольно разный вывод даже с простыми изменениями кода. Могут меняться автоматические решения по встраиванию, может изменяться формат таблицы символов и т. Д. Изменения в коде также часто изменяют внутреннюю структуру API. Оптимизация уже стирает грань между границами функций по сравнению с тем, что вы видите в редакторе кода. Системы DRM также сильно мутят воду. Патч-системы используют оптовые замены или двоичные различия и сжимают их. Всё, что ты предлагаешь, просто слишком хрупкое, чтобы отправлять его в реальном мире.
Шон Мидлдич
2
@SeanMiddleditch Я собираюсь сделать это, чтобы доказать, что это возможно :).
Джонатан Дикинсон
15

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

Патч может исправлять проблемы в любой из этих частей, не требуя изменений во всех из них.

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

(Это, конечно, будет работать только с файлами, которые, как вы можете гарантировать, не будут изменены пользователем.)


источник
2
Вы можете упомянуть это в качестве примера: daemonology.net/bsdiff
wolfdawn
2
Хороший практический ответ. +1
волчий рассвет
2

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

Большинство современных игр содержат сотни мегабайт игровых данных (в основном текстуры, модели, данные уровней и т. Д.). Это требует исправления довольно часто. Насколько я знаю, у издателей обычно есть стандартный запатентованный способ сделать это.

Излишне говорить, что есть примеры с открытым исходным кодом. Некоторые дистрибутивы Linux (Fedora?) Используют бинарные различия для своих патчей. Вы можете исследовать их и прочитать их исходный код или документацию.

MarkR
источник
-1

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

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

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

MSalters
источник