Общее.

Обмен с сервером происходит по протоколу WebSocket в бинарном формате. Слово "arraybuffer" должно что-то сказать JS-экспертам. Возможно вы хотите почитать вот это: https://developer.mozilla.org/en-US/docs/Web/API/WebSocket.

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

Сервер имеет право подумать про вас плохо и порвать соединение без объяснения причин, если вы попытались прислать 100 килобайт мусора, зафлудить его подозрииельными запросами (типа "дай карту за километр от меня, которую я не вижу") и т.п. Если с вами совсем жить нельзя, то сервер может послать файрволу -j DROP на всю вашу подсеть или сделать что-то подобное.

Server -> Client

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

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

Каждое поле данных может иметь тип uint8, uint16, uint32 или string(N). uint16 - это 16-битное целое little-engian, остальное вы поняли.

Тип string передаётся так: len:uintN, data:(len), где len - длина строки, N - битность len (8, 16, 32) и далее указанное число байт самой строки. Если это строки текста, то передаются не помню в какой кодировке, кажется cp1251 для компактности.

string будем обозначать как string(N), где N определяет битность len в конкретном случае.

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

OpcodePacketОписание

0x64

opcode:uint8
id:uint32
reset:uint8

CMD_OUT_SETTINGS - неиспользуемая или устаревшая команда "сброс состояния". Не нужна. Ничего не делает.

0x65

opcode:uint8
id:uint32

CMD_OUT_LOGIN - танк id появился в поле зрения. Клиент может выделить память под id (создать объект танка с таким id) и считать все дальнейшие команды про данный id валидными.

0x66

opcode:uint8
id:uint32

CMD_OUT_LOGOUT - обратная от 0x65. id пропал из поля зрения.

0x67

opcode:uint8
id:uint32
money:uint32
health:uint32
points:uint16
extended:uint8

Если extended != 0, то добавляются ещё такие поля:

look:uint8
paused:uint8
name:string

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

0x68

opcode:uint8
size:uint16

Далее size число раз передаётся строка таблицы в формате:

money:uint32
health:uint16
points:uint16
name:string(N)

CMD_OUT_RATING_USERS - обновление рейтинга юзеров; та табличка, которую видно сверху-справа.

0x69

opcode:uint8
id:uint32
x:uint32
y:uint32
sx:uint32
sy:uint32
dirlook:uint16

CMD_OUT_POS - текущие координаты (x, y) и скорость (sx, sy) танка id. Скорость (sx, sy) передаётся умноженной на 1000000.0, поэтому после получения нужно поделить на эту константу и работать с sx, sy как с типами float/double. dirlook - направление, в котором смотрит танк (0 - up, 1 - down, 2 - left, 3 - right).

0x6A

opcode:uint8
id:uint16
type:uint16
x:uint32
y:uint32
sx:uint32
sy:uint32

CMD_OUT_PARTICLE_BORN - создана частица. Это может быть пуля, здоровье и т.п. Клиенту нужны эти данные только для анимации полёта частиц. Клиент не рассчитывает столкновения, хотя ему никто не может помешать делать это для себя. (x, y) - координаты рождения частицы, (sx, sy) - скорость частицы; передаётся умноженной на 1000000.0.

0x6B

opcode:uint8
id:uint16

CMD_OUT_PARTICLE_DIE - частица id померла (с чем-то столкнулась или истек срок годности/дальности). Можно удалить из памяти и перестать анимировать. Причина исчезновения частицы не сообщается.

0x6С

opcode:uint8
type:uint16
bx:uint32
by:uint32
size:uint32

Далее передаётся size кирпичей в таком формате:

x:uint32
y:uint32
value:uint8

CMD_OUT_MAP - квадрат кирпичей карты.

type - всегда ноль, (bx, by) - верхний левый угол блока этих кирпичей - клиент передаёт это в запросе

size - число кирпичей в квадрате

val - значение (цвет) кирпича:
0 - пусто
[1-8] - кирпич стены соответствующего цвета
[9-10] - желтая монетка или алмаз
11 - аптечка
[12-14] - бомбы blue, red, black
[15-16] - дверь красная-зелёная
[17-18] - синие кирпичи: тёмный/светлый.

0x6D

opcode:uint8
x0:uint32
x1:uint32
y0:uint32
y1:uint32
value:uint8

CMD_OUT_BRICK - апдейт значения указанного кирпича. Возможно крипич усилили, ослабили или удалили совсем. Координаты кирпича: (x0, y0), x1 и y1 не используются. value как в команде CMD_OUT_MAP.

0x6E

opcode:uint8
x:uint32
y:uint32
id:uint32
type:uint8
value:uint32
zone_size:uint32

Далее size пакетов такого содержания:

x:uint32
y:uint32

CMD_OUT_BRICK_INFO - информация о кирпиче по указанным координатам. Приходит по запросу от юзера. Есть проверка на область видимости, бесполезно получать слишком далёкие кирпичи от себя. Через эту команду реализована функция отображения крепости и типа кирпича, когда вы водите по кирпичам мышкой. Запросная команда - CMD_IN_POINTER_POS описана в секции Client -> Server.

0x6F

opcode:uint8
mainloop_us:uint32
avg_ping:uint32
now_remote_users:uint32
now_remote_users_active:uint32
max_remote_users:uint32
cnt_logins:uint32
cnt_bricks_created:uint32
cnt_bricks_erased:uint32

CMD_OUT_SERVER_STATS - разная серверная техническая статистика. Не использовать. Может быть выпилена-переделана. Возможно даже не передаётся.

0x70

opcode:uint8
type:uint8
pingcode:uint32

CMD_OUT_PING - пинг от сервера. type - не используется/рандом. pingcode - важно это запомнить и ответить в PONG, иначе могут отключить.

0x71

opcode:uint8
key:uint32
value:string(16)

CMD_OUT_KEY_SVAL - передача какого-то key=value. Смысл key определяется key. Не относится к критичным функциям, можно выкинуть. Чаще всего применяется для отображения какого-нибудь окошка со свойствами выделенного танка в интерфейсе. Подробнее спецификация появится не сегодня.

0x72

opcode:uint8
key:uint32
value:uint32

CMD_OUT_KEY_IVAL - аналогично CMD_OUT_KEY_SVAL, только value имеет тип uint32

0x73

opcode:uint8
dir_radians:uint32
state:uint8

CMD_OUT_RADAR - направление стрелки радара вашего танка; показывает на ближайший танк с живым человеком. dir_radians передаётся в радианах типом float, умноженным на 10000. state - не используется. Если клиент не получал этой команды более 300 мсек, показания радара считать невалидными.

0x74

opcode:uint8
key_type:uint8
refs:uint32
money:uint32
0xFADE8819:uint32
0x77881133:uint32
0xBB7A9A05:uint32
0x81922828:uint32

CMD_OUT_KEY_STATUS - информация о ключе, введённом клиентом. Сколько в этом ключе денег, поинтов и т.п. Команда будет переделана в перспективе. Последние 4 32-битных поля содержат бред, вы не хотите о нём думать, просто он есть. Не тратьте годы жизни на взлом, это реально мусор.

0x75

unknown

reserved

0x76

opcode:uint8
id:uint32
state:uint8

CMD_OUT_SELECTED - информация о том, какой танк выделен. Нужно клиенту для рисования этого танка на синем фоне, больше незачем. id - кто выделен, state - выделен ли он.

0x77

unknown

reserved

0x78

opcode:uint8
from:uint32_t
text:string(32)

CMD_OUT_MESSAGE - текстовое сообщение клиенту. Сюда входят и системные сообщения от сервера и сообщения чата. Если from == 0, значит это системное сообщение. Странно, что длина строки сдеана 32 битой, но всё же 4 GiB данных здесь не бывает.

Client -> Server

Эти комнады клиент отправляет серверу, чтобы сообщить что он поехал, повернул, начал стрелять, ответил на пинг или отправил что-то в чат.

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

Передача невалидных/неполных команд молча пропускается сервером.

OpcodePacketОписание

0x01

opcode:uint8
state:uint8
dirhold:uint8
dirdrive:uint8

CMD_IN_MOVE - двигатель и руль - "ехать или нет и куда ехать".

state - [0-1] - стоять-ехать;

dirhold - [0-1] - нажата ли клавиша shift для удержания направления носа танка;

dirdrive - [0-4] - в каком направлении вы едете; 0 - up, 1 - down, 2 - left, 3 - right

0x02

opcode:uint8
state:uint8
dir_radians:uint32

CMD_IN_FIRE - стрельба.

state - [0-1] - выкл-вкл;

dir_radians - направление стрельбы в радианах, умноженное на 10000;

0x03

opcode:uint8

CMD_IN_CLICK_SCREEN - устарело, не применяется.

0x04

opcode:uint8
type:uint8
pingcode:uint32
fps:uint8

CMD_IN_PONG - ответ на пинг. Нужно передать запомненный из PING pingcode. Остальные поля - 0.

0x05

opcode:uint8
x0:uint32
y0:uint32
x0:uint32
x1:uint32
y0:uint32
y1:uint32

CMD_IN_GETMAP - получить кусок карты. Через эту команду клиент видит окружающий мир.

Формат может показаться запутанным, но он простой:

Запрашивается прямоугольник R = (x0, x1, y0, y1) карты.

Например, вы хотите видеть кусок размером 5x5 с левым верхним углом (X=100, Y=200), тогда ваш R будет (100, 105, 200, 205).

Не стоит запрашивать прямоугольник слишком далеко от себя или слишком большой (иначе просто ничего не придёт в ответ - на сообщения об ошибках мы не тратим трафик) - ограничивайтесь размерами 10x10. Попробуйте запросить карту вокруг себя небольшими квадратиками, получив после соединения в какой-то момент своё местоположение после команд LOGIN и POS.

0x06

opcode:uint8
unused:uint8
key:uint32
value_int:uint32
value_str:string(16)

CMD_IN_CONTROL - передача разнообразных параметров на сервер. Параметр определяется key, смысл его значения зависит от key и помещается в одно из двух полей: value_int, value_str.

Некоторые важные key:

900 - покупка предмета; класс покупаемого предмета нужно передать в value_str, например "aid" - это аптечка; Тут нужно расписывать все возможные типы, но вы можете загребать JS-код, они там где-то перечислены. Проверка на длину строки стоит, не парьтесь с хаканьем.

[1000-1003] - выбор одного из 4 текущего оружия танка; value не важны; например передача ключа 1000 выбирает первую красную стрелялку.

0x07

opcode:uint8
x:uint32
y:uint32
type:uint32

CMD_IN_POINTER_POS - запрос информации о кирпиче (x, y). type не используется, передавайте 0 туда на всякий случай.