Для тех, кто ждет у моря погоды

В 2к16 популярно ловить не только покемонов, но и удачу. А что может быть лучше, чем попытать счастья в совершенно новой сфере? Так решили и на икапе, объявив, что отныне они делают дотку на C, а не на JASS.


Когда кто-то зарепортил баг войда с фейзами (кликабельная пикча).

Скрипт и язык

JASS = just another script syntax, сценарный язык. Это не полноценный язык программирования, а набор заранее подготовленных инструкций с жесткими рамками применения. Он не дает свободы — лишь то, что предусмотрели оригинальные разработчики. Если авторам не нужна была возможность Х, её в поставке и не будет, а самостоятельно её сделать тоже нельзя. Выбраться за пределы песочницы практически невозможно, если только не всплывет баг, позволяющий провести превращение одной переменной в другую или что покруче. Такая возможность была в 2004 году, исчезла в 2008 и вновь обнаружилась совсем недавно, буквально в апреле месяце этого года.

Скрипты позволяют гарантировать конечный результат выполнения. Известно, что борьба с дураком занимает примерно 80% всего кода, и в случае скриптов это истина на все 100. Количество проверок, проводимых под капотом варкрафта при каждом вызове любой операции, превышает 9000.

Язык программирования — более свободная среда, в которой можно делать всё, что угодно. Здесь псевдо-ограничителями выступает лишь синтаксис языка, и тот не стоит на пути опытных программистов. Прямая работа с любыми объектами в памяти, создание новых структур и т.п. — все возможности свободного развития. Впрочем, появляются риски прострелить себе ногу, т.к. все защиты от дурака нужно прописывать теперь автору кода — нет никаких сценариев с готовой защитой.

Как это выглядит на практике

Каждый вызов JASS превращается в вызов конкретных функций из движка игры, который написан на C++ или чем-то очень похожем (не имеет значения). Например:
UnitDamageTarget(source, target, damage, rangedattack, meleeattack, attacktype, damagetype, weapontype)

Одна строчка, создающая урон damage от лица source по target с указанными типами атаки и урона, вызывает функцию:

signed int __cdecl sub_6F3C8850(void *a1, void *a2, _DWORD *a3, int a4, int a5, unsigned int a6, unsigned int a7, unsigned int a8)
{
  signed int result; // eax@1
  int v9; // edi@1
  int v10; // esi@2
  char v11; // [sp+4h] [bp-28h]@10
  char v12; // [sp+8h] [bp-24h]@10
  unsigned int v13; // [sp+28h] [bp-4h]@10

  result = sub_6F3BDCB0(a1);
  v9 = result;
  if ( result )
  {
    v10 = sub_6F3BE5B0(a2);
    if ( v10 && a7 <= 0x80000000 )
    {
      result = 0;
      if ( a6 <= 7 && a8 <= 0x18 )
      {
        if ( a4 )
          result = 256;
        if ( a5 )
          result |= 1u;
        sub_6F2556E0((int)&v12, a3, 1 << a7, v9, result, a8);
        v13 = a6;
        (*(void (__thiscall **)(int, char *, char *, _DWORD, _DWORD))(*(_DWORD *)v10 + 288))(v10, &v11, &v12, 0, 0);
        result = 1;
      }
    }
    else
    {
      result = 0;
    }
  }
  return result;
}

Кто такие sub_6F3BDCB0, sub_6F3BE5B0 и sub_6F2556E0? Для чего нужны эти битовые сдвиги? Что лежит в вызываемых динамических функциях? А хер его знает. Близзарды не давали исходников варкрафта, где было бы прямо написано "проверяем, что юнит 1 существует, а затем — что цель существует. Потом высчитываем тип урона, добавляя нули в конец для получения нужного типа урона, записываем объект «нанесение урона» и вызываем личный обработчик внутри цели, который будет лежать в смещении 0x120". Поэтому о назначении каждой операции придется догадаться самостоятельно.

Или еще пример:

GetHeroAgi(hero,includeItems)

Раскладывается в

int __thiscall sub_6F2778B0(int this, int a2)
{
  char *v2; // edi@1
  int v3; // eax@1
  int v4; // ebx@1
  int v5; // eax@1
  int *v6; // eax@1
  signed int *v7; // eax@1
  int v8; // eax@1
  int v9; // esi@1
  int result; // eax@2
  int v11; // [sp+Ch] [bp-C4h]@1
  char v12; // [sp+10h] [bp-C0h]@1
  char v13; // [sp+14h] [bp-BCh]@1
  char v14; // [sp+18h] [bp-B8h]@3
  int v15; // [sp+6Ch] [bp-64h]@3
  char v16; // [sp+74h] [bp-5Ch]@3

  v2 = (char *)this;
  v3 = *(_DWORD *)(this + 496);
  v4 = *(_DWORD *)(v3 + 168);
  v11 = *(_DWORD *)(v3 + 228);
  v5 = sub_6F473170(v3 + 108);
  v6 = (int *)sub_6F6EF350((unsigned int *)&v13, v5);
  v7 = (signed int *)sub_6F6EEE20((unsigned int *)&v12, v6, &v11);
  v8 = sub_6F6EEC20(v7);
  v9 = v4 + v8;
  if ( a2 )
  {
    result = v4 + v8;
  }
  else
  {
    sub_6F077E80((int)&v14);
    sub_6F077E80((int)&v16);
    sub_6F077FA0(v2, (int)&v14, (int)&v16);
    result = v9 - v15;
  }
  return result;
}

int __cdecl sub_6F3C6850(void *a1, int a2)
{
  int v2; // eax@1
  int v3; // esi@1
  signed int v4; // eax@2
  signed int v5; // eax@3
  int result; // eax@7

  v2 = sub_6F3BDCB0(a1);
  v3 = v2;
  if ( v2
    && (v4 = sub_6F03FA30(*(_DWORD *)(v2 + 12), *(_DWORD *)(v2 + 16))) != 0
    && (v5 = *(_DWORD *)(v4 + 12) != 727803756 ? 0 : v4) != 0
    && !*(_DWORD *)(v5 + 32)
    && (unsigned int)*(_BYTE *)(v3 + 51) - 65 <= 0x19
    && !(*(_DWORD *)(v3 + 92) & 0x40000000) )
  {
    result = sub_6F2778B0(v3, a2);
  }
  else
  {
    result = 0;
  }
  return result;
}

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

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

Доступ к памяти

В начале апреля мне в руки попал баг, позволяющий открыть память для чтения и записи. Его обнаружил бразильский любитель варкрафта Leandro Teles. Собственно, благодаря его трудам и стало возможным многое то, до чего раньше путь был заказан. За эти месяцы наша команда (Leandro, Absol, RokKnyaz) нашла много полезных и не очень данных, изменив которые мы смогли сделать игру лучше. Во многом задержки в релизах объясняются и этим — вычисление адресов виновных, терморектальное тестирование на устойчивость к крашу занимают кучу времени.

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

В чем загвоздка

Проблема в том, что до этапа "давайте че-нибудь через память ебанем" икапу добираться как до Луны пешком. Если их миссия чинить баги карты, то 99.9% их лежат в сфере чистого JASS, и для их фикса не нужно быть гением, достаточно хоть немного разбираться в предмете. Вот чтобы лепить купоны АЙКАПРУЛЕЗ и продавать шмотки на героев это как раз way to go.

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

Как оказалось, найти хотя бы одного знатока JASS, который бы соизволил страдать на благо платформы, изобретая велосипед, невозможно. Поэтому решили, что на C и в память будет дверь, и синтаксис более знакомый, поэтому гоу на исходниках кодить. Где они найдут сишника, готового за спасибо маяться ерундой в декомпилированных исходниках, для меня загадка. Если это будет Фукей, антихак снова отстанет на десятилетия, а если сторонний — то что же ему пообещают взамен? Те же $50, что за новые хоткеи для лунчера, или что-то большее?

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

В чем плюсы

В названии языка. Ну, и потенциально бОльших возможностях, которые, тем не менее, нужно еще суметь реализовать на практике.

Текущий статус

Сейчас iDotka (да-да, почти как переименование заголовка в DotA Allstars спустя 3 месяца после релиза нашей дотки) тестится админами на предмет того, что она хотя бы работает так же, как и её предшественница. Памятуя легендарный широкоэкранный режим, также прошедший через «качественное тестирование» в течение двух недель, но так и не сделавший ОПЦИИ, остается только верить, что они смогут протестить хотя бы 30% контента.

Взять животинушку к себе можно по этой ссылке. В неё можно даже поиграть в одиночной игре, если запускать с лаунчера, но лучше с фейка — крашит, особенно при вводе чат-команд. Для знатоков MPQ или любителей копаться в DLL — имя доп. файла war3map.dll.

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

21 комментарий

avatar

хуй в говне!

Смеш что животные не могут залить готовое решение на хост боты и чет пытаются запилить своё «особое». Надеюсь у дебса на анте жопа сгорит, когда ты выкатишь 86(87?) патч
avatar
варкрафт не видит их карту (запускал через лаунчер). Наверное из-за веса в 9мб
avatar
«Anyone with this knowledge could create and distribute a modified map and gain complete control over a user's machine.»
Вот это меня пугает больше всего.
avatar
В интернеты как-то люди ходят и ничего, живы до сих пор
avatar
Как я понял, leandrotp выложил рид онли вариант. Всё самое крутое вы сохранили в тайне, чтобы не было злоупотреблений?
avatar
ага
avatar
Отсосал говна из жопы и плюнул в комьюнити
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.