Pull to refresh

Comments 43

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

Тут главный вопрос. Команда /roll выполнялась на клиенте или на сервере?
Если на сервере (что логично), то никак ты с роллом не начитеришь.

Как я понял речь о том, что условно проведя 8 роллов, девятый и все последующие вы можете предсказать

Так /roll считается на клиенте или на сервере? Если на клиенте, то это и без этой статьи такой простор для читерства путем подмены пакетов. Если на сервере, то ничего предсказать не получится.

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

Подробнее этим занялись ребята, исследующие случаный генератор Java используемый в Minecraft. В качестве PoC там подстраивали состояние ГСЧ своего игрока так, чтобы предметы зачаровывались по максимуму.

Так если серверный генератор один на сервер то толку его предсказывать? Если на сервере конечно больше двух людей играет.

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

так а что в итоге ломали-то таким образом в вове?

я оч давно играл, не помню особо, что именно там случайного было(

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

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

Это вы так поняли если статью прочитали, но в сам вов не играли и аддоны не писали.

Я и играл и писал, и такой проблемы там нет вообще.

Аддоны в вове наверное лучший пример того как надо делать расширяемую игру со скриптовым языком. Это event based система, у которой есть огромный лист эвентов за которые можно цепляться и выполнять свой код, реагируя на это как угодно, либо как-то обрабатывая данные логически, либо рисуя на экране что угодно (с довольно простым фреймворком который позволет быстро накидывать на экран примитивы - цифры там разные, либо небольшие спрайты, либо UI элементы которые можно описать .xml файлами).

Так вот этот event stream просто огромен, вов отправляет абсолютно всю инфу в клиента и она вся доступна для того чтобы к ней цепляться. И твои изменения здоровья, и изменения здоровья всех вокруг и все эвенты в определённом радиусе даже если ты их не видишь на экране. Даже рудиментарное отслеживание движений присутствует. То есть можно узнать насколько от тебя далеко кто-то находится, и даже прицепиться к эвенту типа "что-то стало ближе такого-то расстояния ко мне". Отличная, мощная система, спроектированная так, как нужно делать нерд системы для нердов в играх, а не какой-то куцый обрубок с "ну мы подумали вот этого вам хватит, чё вам там ковыряться в нашей игре, вы же не программисты".

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

Короче всё со скриптовой подсистемой в вове нормально, логично, не противоречиво и совсем практически ничем не ограничено.

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

Абсолютно никаких проблем, описаных в статье я вообще не помню, и автор комментария выше задал тот же самый вопрос который возник и у меня после прочтения - "и чо?". Не помню ни одной проблемы в вове которую можно было бы размотать предсказав следующее число в генераторе случайных чисел на клиенте. Да я даже не представляю особо что там на клиенте генератором случайных чисел производится...

У близзард все было очень круто в то время с кастомизацией.

Достаточно вспомнить редактор уровней вар3 куда впилили язык JASS. Кастомизация была на таком уровне, что вар3 превратилась из игры в песочницу. Каких только игр не делали на ее базе.

Почему "в то время"? До сих пор хорошо. И до сих пор аддоны делаются для современного вов, также и для Starcraft2 редактор карт очень мощный, чего только там не делают. В Overwatch сделан визуальный скриптинг такой себе, там тоже всякого натворить можно, хотя и ограничено, не сравнить с вовом конечно, но и тип игры другой совсем.

Это круто, если они до сих пор поддерживают такой уровень. Я просто как-то выпал из игрушек.

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

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

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

Ничего он там не предопределял. Я специально внимательно прочитал что он делал конкретно.

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

вопрос остаётся всё тем же - и чо?..

castrandom итак довольно малоприменимый вызов, ума не приложу для чего им можно пользоваться, ну так ты получишь возможность узнать что из списка который ты сам же составил будет вызвано следующим. умопомрачительные знания, просто хоть стой хоть падай (сарказм). с тем же успехом можно просто составить лист заклинаний и вызывать их подряд, и они ВОТ ЭТО ПОВОРОТ будут вызываться в нужном тебе порядке...

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

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

Нет, он именно предопределял

  1. Мы предсказываем результат следующего вызова RNG. Если он (делённый по модулю на длину нашего списка действий) не даёт нам нужного результата, то мы сдвигаем RNG и пробуем снова. Процесс повторяется, пока следующее случайное число не будет соответствовать нужному действию.

т.е. да, он используем возможность предсказать следующее значение, но если оно, не то, что нужно, то он прокручивает дальше пока не будет нужное (вызывает рандом в холостую)

Нет, он имеет ввиду что он делает /castrandom, получает то, что выбросил внутренний рандом игры, сравнивает с той последовательностью что есть у него исходя из формулы, если число совпало, повторяет и сверяет следующее (в своей последовательности), если не совпало - двигается дальше по своей последовательности, пока не найдёт тот участок, на котором в данный момент находится внутренний рандом. собственно узнав место в последовательности на котором находится внутренний рандом все следующие числа которые будут выкинуты - доступны. ничего он не передопределяет, "сдвигаем RNG" в этом контексте - это поиск по последовательности которая у него на руках в поисках последовательности которую выкидывает внутренний рандом.

"прокручивать рандом пока не выпадет нужное число" в вашей концепции прямо скажем сильно странное занятие. ну вот мне нужно число 6, я буду крутить рандом пока не выпадет 6. докручу. ииииии...??? ну как бы, я победитель, безусловно, что дальше-то?..

Повторюсь, я не играл и не писал аддонов, поэтому я может что-то и упускаю, но по моему вы тоже не поняли что он сделал.

Я не знаю, что такое /castrandom. Ни в переводе, ни в оригинале, такое вообще не упоминается, возможно ваш мозг зацепился за это и увел вас в неправильном направлении.

Что он написал на самом деле (так как это понимаю я, опять же оговорившись, то не играл, не писал) есть два окружения:

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

  • Закрытое: Может исполнять действия, но не имеет информации об окружающем мире. Соответственно не знает, когда нужно применить то или иное действие.

К какому решению он пришел. Создаем захардкоженый список из, допустим, 10 действий, которые будут оптимальными реакциями на внешние события. Список одинаковый и в коде закрытого и в коде открытого окружений.
В открытом окружении, при срабатывании такого события решаем какое действие из списка будем оптимальным, например действие №6 - применить зелье лечения.

Вызываем рандом current_random = random(), далее предсказываем следующий рандом next_random = predict_random(current_random). И делаем это, пока next_random по модулю длины списка не выдаст нужную нам шестерку while (next_random % 10 != 6).

После вступает в дело закрытое окружение, там вызывается current_random = random() и из него получаем номер необходимого действия action_index = current_random % 10. Далее берем действие из списка и выполняем его actions[action_index].trigger()

Перечитал еще раз ваши сообщения, и в принципе /castrandom, в зависимости от реализации, возможно, и делает то, что я написал в последнем абзаце, в таком случае он просто использовал его, да. Но все сказанное до этого так же остается верным.

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

Но разве настолько плохая реализация PRNG вообще может пригодиться для чего-либо?

Например, в Doom 1/2 в качестве генератора случайных чисел вообще использовался массив из 256 unsigned char'ов в псевдослучайном порядке, и этого хватало.

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

В геймдеве своя атмосфера. Такой паттерн с вручную нарисованными значениями там вообще довольно часто используется. Потому что "честная" случайность игрокам, внезапно, не нравится. С честной случайностью вполне возможна всякая фигня типа трех подряд промахов при 95% вероятности попадания. Да, маловероятно, но за десятки и сотни часов игры такое случится хотя бы несколько раз, что вызовет у игрока лютую фрустрацию. И таких возможных кейсов много.

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

Типичный пример - призраки в HoMM 5. У них есть свойство бестелесности, в итоге по ним атаки промахиваются с вероятностью 50%. Но есть правило - не больше трех промахов или попаданий подряд. Было три промаха - четвертая атака всегда попадет, и наоборот. Не очень честно с точки зрения случайностей, зато более играбельно.

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

Фиксированная псевдослучайность тут даже помогает. Демки проигрываются ровно с теми же значениями, достаточно запоминать действия игроков и начальное значение(random seed).

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

Может тут кто-нибудь интересных примеров насыпет)
ну а я первую ссылку из гугла запулю.

вполне возможна всякая фигня типа трех подряд промахов при 95% вероятности попадания.

Типичный X-COM :) Вообще забавно, что его куча народу до сих пор обвиняют в читерстве с рандомом в пользу компа на высокой сложности. При том, что там уже всё отреверсили и доказали, что читерство есть только в сторону игроку на низхких уровнях сложности.

Не знаю насчет ванильных X-COM но в моде Long War, при отсутствии потерь солдат несколько миссий, рандом буквально переворачивался наизнанку, выдавая кренделя в духе "5 промахов по 80%, пришелец критует с 20%*20%" по 3-4 раза за бой

В Доте 2 используется такой же рандом в критах или станах. Там нет жесткого правила не более трех подряд но с каждым не кританувшим ударом вырастает шанс крита на следующем ударе.

А обычный рандом в играх людям не нравится и они называют его корейским.

Корейски рандомом все-таки называли ситуацию когда вероятность выпадения какого-то события очень маленькая, и его натурально нужно гриндить (условный шанс 0.001% на выпадение шмотки). И там степень случайности уже не особо принципиальна.

Корейски рандомом все-таки называли ситуацию когда вероятность выпадения какого-то события очень маленькая, и его натурально нужно гриндить (условный шанс 0.001% на выпадение шмотки). И там степень случайности уже не особо принципиальна.

Корейским рандомом называли ситуацию когда рандом работает неправильно(по мнению игрока конечно). Когда делаешь десять заточек в ряд с шансом в 60% а они все фейлятся.

С честной случайностью вполне возможна всякая фигня типа трех подряд промахов при 95% вероятности попадания.

Это не про XCom случайно? :)

Эх, не дошёл я до lua, мне хватило

/castsequnce в макросах

там случайно оказалось что если у тебя в руках оружие со скоростью ниже чем глобальное время восстановления, а в макросе ты пишешь кастовать яд, применить удар, кастовать проклятье, применить удал, кастовать стрелу...
Потом у тебя выходит однокнопочный Варлок, видишь цель, клацаешь 1 много много раз (тут на клавиатуре драйвер позволяющий режим залипания настроить вообще помогал) и получаешь на 90% идеальную ротацию с уроном в секунду примерно раза в 2 выше чем у всех вокруг. Единственная проблема была - это разбойники которые теряли цель и ломали ротацию. Но против боссов заходило на ура.

В каждой шутке есть доля шутки. У нас был кроссплатформенный движок, который много лет разрабатывался под кучу платформ-консолей, начиная с PS1 (я присоединился к команде когда уже была PS3).

И вот понадобилось игру портировать под какую-то консоль, под которую когда-то наспех сделали порт движка, но не пользовались им. И что-то там странное было с рандомом. Полезли смотреть код генератора случайных чисел. А там вместо вызова платформенного генератора было "return 239".

Почему именно это число? А 239 - одна из топовых питерских школ, и у нас в конторе работали ее выпускники. А они свою школу любят-ценят и любят попонтоваться принадлежностью к ней, в том числе таким вот странным образом. Видимо писать честный ГПСЧ было влом, сделали вот так заглушку.

Однажды мне понадобилось делать invoke для нативных джава-функций андроидного приложения из джаваскрипта внутри webview. Напрямую, без запуска локального сервера и прочего подобного. Внимательное изучение event'ов webview показало, что единственный подходящий event там — это onAlert (очевидно, чтобы создатель приложения сам мог выбирать, в какой форме показывать всплывающие сообщения).

Так на свет родилась технология AlertAPI™ с маленьким DSL'ем для заворачивания имён функций и аргументов в строку, а я думал, что я самый хитрый жук на свете. Но передавать данные через рандомизатор… Снимаю шляпу!

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

Так что это вообще большая и интересная тема, с которой обычные программисты впрочем редко сталкиваются.

Ну, лазерная интерференция для снятия звуковых колебаний стекла - давняя фича. Ей лет 30-40, наверное.

Мигание дисковода - слишком в глаза бросается. Да и дисководы нынче не в моде.

А вот изменение скорости вращения вентилятора кулера, чтобы он морзянкой завывал - это изящно. Причем, разница в звуковых тонах может быть неразличима для немузыкального уха.

Хех вспоминаются легенды древней греции линейки где люди до сих пор спорят о том как правильно точить и пытаются абьюзить корейский рандом.

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

люди до сих пор пытаются разгадать этот корейский рандом

А я как написал?

Помню, в 90-e мы играли всем отделом в какую-то космическую игрушку на PC. В качестве защиты от копирования, сразу после запуска игра задавала внутриигровой вопрос, ответ на который надо было искать в напечатанном гайде (распространённая в те годы практика). Гайда, разумеется, у нас не было. Выбирали мы ответы наугад, пока не натыкались на правильный, так что запуск часто затягивался. Все это дико бесило.

Я предположил, что seed генератора случайных чисел основан на времени и написал крохотный лаунчер, который перехватывал вызов системного времени и выдавал одно и то же время. И вуаля - игра стала спрашивать один и тот же вопрос, ответ на который мы нашли перебором и прилепили на монитор. Чтобы такой перехват не влиял на саму игру, лаунчер возвращал фиктивное время только на первый вызов. Вот и весь "взлом" без взлома.

Помню, в 90-e мы играли всем отделом в какую-то космическую игрушку на PC.

Это был Master of Orion 1. Там именно такая "защита".

  1. Warcraft (I), от Blizard entertainment
    Затем появился и Warcraft II.

  2. Как помню, я писал программу (на Borland TurboPascal 7.0, {BTP}),
    что модифицировала save-файлы, делая видимой те части карты, что были ещё не открыты.

  3. В BTP функция Random (её выдача)
    во-первых, определялась вполне доступным
    (из тела программы) параметром RandomSeed.
    И все последующие выдаваемые псевдослучайные величины - определяются именно значением этого параметра.
    Да, есть там и процедура Randomize, что позволяла придать вполне случайные значения выдаче функции Random.
    Как помню, использовался счётчик часов реального времени,
    располагавшийся по адресу 0:0417(h).
    И вызов процедуры (функции, не возращающей прямо какого-либо результата;
    результат, в зависимости от типа, мог содержаться в регистрах DX:AX {longint тип}, ES:DI или ES:BX {уже не помню точно}.

Randomize как раз приводил к инициализации значения этой переменной.

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

Sign up to leave a comment.

Articles