Обновление игровых файлов
Я разрабатываю игру на C++ с использованием DirectX 9. Это 3D шутер от первого лица (так планируется). В корневой папке с проектом есть ресурсы игры, такие как: configs, models, sounds и locations. К этим файлам очень легко получить доступ. Любой пользователь может заменить модели, звуки или вообще украсть их... Я разработал контейнер, где я упаковываю игровые ресурсы в архив, типа: configs.pck, models.pck и т.д. Игра работает через лаунчер, где этот инструмент проверяет HASH суммы файлов. Данные он берет с сервера. И тут я встретил проблему, которую я не как не могу решить. Как-то эти все файлы нужно обновлять!
Я написал совершенно другую программу, где в корневых файлах ищет версии всех клиентов игры. И создает их патчи. То есть ищет один файл в старой сборке и в новой. Через бинарный анализ ищет байты, которые не хватает в старой сборке или тех, которых воообще нет. Честно? Анализатор вышел очень плохой. Патчи были размером больше, чем оригинал файла. Так как сохранялось и стартовая позиция offset байта и длина и сами данные. Учитывались флаги состояния буфера. Или заменить, или удалить и т.д. Следовательно из-за корявого анализатора не получилось и грамотно сделать и патчинг этих самых файлов. Игровой движок вылетал с ошибкой, что файлы были повреждены. А лаунчер бесконечно старается решить проблему с HASH суммами файлов. Так как после патчинга они всегда разные.
В анализаторе нужно учитывать не просто замена байтов. Эта замена может быть не просто с 3 байтами 0x1, 0x2, 0x3 на 0x15, 0x2, 0x1. А в оригинале может быть и больше байтов, чем в старом блоке. Нужно учитывать множество факторов, чтобы анализатор понял, что с этим куском данных делать.
Небольшая дополнительная информация о этапах загрузки
При парсинге карты и ее сборки, в ней же лежат ссылки на long offsets блоках данных. Эти блоки нужны для того, чтобы как бы вытягивать модели из контейнера. Я ставлю нужный offset из карты в поток чтения models.pck и начинаю читать первые 4 байта - это длина одной модели. Как только данные считались, идет расшифровка простым XOR с ключем (Который загружается с сервера).
Подскажите куда мне копать? Где посмотреть формулы? Есть может у кого готовое решение?
Ответы (2 шт):
Предположения и допущения (прошу уточнить в комментариях, верно ли я полагаю):
- вопрос по сути о том, как организовать апдейтер для ресурсов игры.
- упакованные ресурсы зашифрованы (либо шифром, либо архивированием, иначе толку от простой упаковки в вашем сценарии почти ноль).
- в идеальном случае, зашифрованные и/или упакованные данные - это белый шум (а иначе, дешифровка и распаковка нехитрое дело). Разница между двумя "шумами" равна шуму.
Таким образом, построение дифференциальной разницы ПОСЛЕ создания упаковок - нецелесообразно. Надо её делать на шаге ДО упаковки.
- Берете, например, корпус ресурсов версии 1.0 и сравниваете его с корпусом 1.1. Для простоты - можно просто по-файлово. Получаете дифф.разницу (уж тут должно быть тривиально, какие файлы добавились, какие удалились, какие заменились).
- Пакуете и шифруете разницу, называете например
patch1.pck. - Теперь игре надо уметь, при загрузке составить карту ресурсов на текущую версию. Т.е. определить, что будет взято из оригинального
models.pck, а что изpatch1.pck(а что изpatch2.pck, а что более недоступно, т.к. удалено). - Играете.
Разумеется, тут возможны дальнейшие оптимизации типа:
- делать дифф не по файлам, а по содержимому с использованием более хитрых алгоритмов (например Венгерского) для минимизации размера диффа (см. комментарии про rsync).
- при апдейте перепаковывать ресурсы, внедряя патч в ресурсы.
- делать кросс-патчи для разных версий
- итп итд
P.S. Важно понимать, что от воровства ресурсов 100% защиты нет. Подменная DLL-ка с потрохами выдаст все модели, текстуры и шейдеры. Так что шифровка - это защиты от дурака, не более. Соответственно не тратьте на нее слишком много сил и времени.
Нашел на просторах гита вот такое решение: https://github.com/google/diff-match-patch/blob/master/cpp/diff_match_patch.cpp
Полностью решил свои все проблемы, спасибо всем кто пытался помочь.