Протокол используется как для web-приложения, так и для отдельных клиентов. Запрос к серверу — обычный POST-запрос в кодировке UTF-8. Ответ сервера — объект, сериализованный в JSON.
Для идентификации пользователя используется идентификатор сессии. Отдельные клиенты получают сессию при авторизации. В случае с web-клиентом код сессии может внедряться в код клиента — в этом случае он не должен совпадать с кодом обычной сессии, хранящейся в куках, что служит защитой от CSRF-атак.
Версия протокола, разумеется, не последняя, в будущем наверняка появятся новые. Чтобы упростить жизнь игрокам и разработчикам клиентов, сервер, реализующий протокола версии N, обязан поддерживать работу с клиентами, реализущими версию N-1. Также желательно поддерживать и более ранние версии.
Новый сервер совместим с клиентом, использующим старую версию протокола, если:
Две версии протокола совместимы, если в новой версии имеются только следующие отличия от старой:
Для совместимости клиенты должны выполнять следующие требования:
| Тип в JavaScript | Тип в POST-запросе |
|---|---|
| null | пустая строка |
| boolean | «0» (ложь) или «1» (истина) |
| number | строковое представление числа |
| string | строка |
В случае с массивами и объектами генерируется отдельное поле запроса для каждого скалярного элемента или поля всех уровней вложенности. Имя такого поля имеет форму имя_объекта[ключ_или_индекс1][ключ_или_индекс2]… Например, год[2012][декабрь][21].
Для задания времени используется число, представляющее метку времени UNIX.
Массив, отсортированный по убыванию времени окончания боя. Формат элемента:
| Ключ | Значение |
|---|---|
| FightId | идентификатор боя |
| FightType | тип боя: «train» (тренировочный) или «challenge» (рейтинговый) |
| FightTime | время окончания боя |
| TurnLimit | лимит ходов на бой |
| TurnCount | длительность боя |
| PlayerId | идентификатор игрока, «заказавшего» бой |
| PlayerName | имя игрока, «заказавшего» бой |
| Snakes | список из 4 змей (null для отсутствующих), участвующих в бою; см. поле Snakes |
Массив, содержащий от 1 до 9 карт программы. Карта представлена в виде объекта:
| Поле | Описание |
|---|---|
| Description | текстовое описание карты |
| HeadX | координата x головы своей змеи (0 – 6) |
| HeadY | координата y головы своей змеи (0 – 6) |
| Lines | массив из описаний строк карты |
Голова змеи всегда смотрит вверх. Описание строк карты является объектом:
| Поле | Описание |
|---|---|
| X | координата x начала линии (0 – 6) |
| Y | координата y начала линии (0 – 6) |
| Line | описание линии карты |
Линия карты длиной n клеток задается строкой из 2×n символов. Первый символ пары задает набор элементов:
| Символ | Значение |
|---|---|
| - | шаблон не определен либо в данной клетке находится голова своей змеи |
| A – D | пользовательские наборы элементов 1 – 4 |
| S | тело змеи игрока |
| T | хвост змеи игрока |
| V | пустая клетка |
| W | граница поля |
| X | голова змеи противника |
| Y | тело змеи противника |
| Z | хвост змеи противника |
Соответствующие символы в нижнем регистре обозначают инвертированные наборы элементов; так, например, символ «t» означает «все, кроме хвоста своей змеи». Второй символ пары задает группу, к которой принадлежит шаблон:
| Символ | Значение |
|---|---|
| - | шаблон не определен либо в данной клетке находится голова своей змеи |
| 0 – 3 | И-группа 1 – 4 |
| 4 – 7 | ИЛИ-группа 1 – 4 |
Строка описывает часть линии карты слева направо с координаты (X; Y). Если длина строки слишком велика, то остаток строки переносится на следующую линию с координаты (0; Y + 1). Например, объект {X: 6, Y: 2, Line: «A1B2C3»} описывает клетки с координатами (6; 2), (0; 3), (1; 3). «Переполнение» последней линии карты является ошибкой.
Массив. Формат элемента:
| Ключ | Значение |
|---|---|
| PlayerId | идентификатор игрока |
| PlayerName | имя игрока |
| Rating | текущий рейтинг; null, если не участвует |
Массив. Формат элемента:
| Ключ | Значение |
|---|---|
| SnakeId | идентификатор змеи |
| SnakeName | имя змеи |
| SnakeType | тип змеи: «B» (бот) или «N» (обычная) |
| SkinId | идентификатор окраски |
Массив. Формат элемента:
| Ключ | Значение |
|---|---|
| PlayerId | идентификатор игрока |
| PlayerName | имя игрока |
| Rating | текущий рейтинг игрока |
| SnakeId | идентификатор бойца |
| SnakeName | имя бойца |
| SkinId | идентификатор окраски бойца |
Массив, осортирован по названию окраски. Формат элемента:
| Ключ | Значение |
|---|---|
| SkinId | идентификатор окраски |
| SkinName | название окраски |
Массив из 10 элементов, null для отсутствующих. Формат элемента:
| Ключ | Значение |
|---|---|
| SlotName | имя сохраненного боя |
| FightId | идентификатор боя |
| FightType | тип боя |
| FightTime | время окончания боя |
Массив. Формат элемента:
| Ключ | Значение |
|---|---|
| SnakeId | идентификатор змеи |
| SnakeName | имя змеи |
| SnakeType | тип змеи: «B» (бот) или «N» (обычная) |
| SkinId | идентификатор окраски |
| PlayerId | идентификатор владельца |
| PlayerName | имя владельца |
Массив из 4 элементов, содержащих описания змей, null для отсутствующих. Элемент является объектом:
| Ключ | Значение |
|---|---|
| SnakeId | идентификатор змеи, null для временной |
| SnakeName | имя змеи |
| SnakeType | тип змеи: «B» (бот) или «N» (обычная) |
| SkinId | идентификатор окраски |
| PlayerId | идентификатор владельца |
| PlayerName | имя владельца |
Массив из 4 элементов, содержащих информацию о змеях, участвовавших в бою, null для отсутствующих. Элемент является объектом:
| Ключ | Значение | |
|---|---|---|
| Status | состояние змеи на последнем ходу боя: | |
| «free» | змея сделала шаг | |
| «blocked» | не смогла сделать шаг (заблокирована) | |
| «eaten» | змея съедена | |
| FinalLength | итоговая длина змеи | |
| InitialRating | рейтинг владельца перед началом боя; отсутствует для тренировочных боев | |
| FinalRating | рейтинг владельца по итогам боя; отсутствует для тренировочных боев | |
| ProgramDescription | описание программы (отсутствует для чужих обычных змей) | |
| Templates | пользовательские шаблоны (отсутствует для чужих обычных змей); см. Templates | |
| Maps | карты программы (отсутствует для чужих обычных змей); см. Maps | |
| DebugData | отладочная информация (отсутствует для чужих обычных змей) | |
DebugData является строкой, кодирующей последовательность решений змеи на каждом ходу. Каждый символ кодирует число в диапазоне 1 – 79, равное ASCII-коду символа минус 32 («!» – «o»). Число состоит из двух или трех полей:
Если используется карта:
| Биты | Описание | |
|---|---|---|
| 0 – 1 | ориентация карты: | |
| 0 | оригинал | |
| 1 | по часовой стрелке | |
| 2 | перевернута | |
| 3 | против часовой стрелки | |
| 2 | отражение карты по вертикальной оси оригинала (0: нет, 1: есть) | |
| 3 – 6 | номер карты (1 – 9) | |
Если карта не используется:
| Биты | Описание | |
|---|---|---|
| 0 – 1 | причина: | |
| 1 | нет возможных ходов, пропуск хода | |
| 2 | только один возможный ход | |
| 3 | нет подходящей карты | |
| 2 – 6 | 0 | |
В случае, если отладочная информация для змеи недоступна (чужая обычная змея или в бою участвуют меньше 4 змей), то соответствующий элемент массива содержит null.
Массив из 4 строк длиной от 1 до 6 различных символов. Каждая строка задает пользовательский набор элементов. Элементы кодируются следующими символами:
| Символ | Значение |
|---|---|
| S | тело змеи игрока |
| T | хвост змеи игрока |
| V | пустая клетка |
| W | граница поля |
| X | голова змеи противника |
| Y | тело змеи противника |
| Z | хвост змеи противника |
Другие символы недопустимы. Порядок символов не имеет значения.
Массив из 1 – 1000 чисел, кодирующих очередность и направления шагов. Формат:
| Биты | Значение |
|---|---|
| 0 – 1 | первый номер змеи (0 – 3) |
| 2 – 3 | второй номер змеи (0 – 3) |
| 4 – 5 | третий номер змеи (0 – 3) |
| 6 – 7 | направление движения первой змеи |
| 8 – 9 | направление движения второй змеи |
| 10 – 11 | направление движения третьей змеи |
| 12 – 13 | направление движения четвертой змеи |
Все номера змей различны. Четвертый номер однозначно выводится из первых трех. Порядок всегда генерируется для четырех змей. Если змея с указанным номером отсутствует, то при расчете/отображении боя она пропускается.
Направление движения змеи:
| Число | Значение |
|---|---|
| 0 | не движется (нет ходов, съедена или не участвует) |
| 1 | налево |
| 2 | прямо |
| 3 | направо |
| Поле | Описание |
|---|---|
| Compatible | минимальный номер версии клиента, совместимого с текущим |
| Count | количество запрашиваемых записей |
| Error | текстовое описание ошибки; может содержать данные, вызвавшие ошибку, в т. ч. имя поля в формате «поле.элемент.подэлемент» |
| ErrorCode | числовой код ошибки |
| FightId | идентификатор боя |
| FightList | отсортированный список боев, см. выше |
| FightListType | тип списка боев: «ordered» (заказанные) или «challenged» (рейтинговые, заказанные другими) |
| FightResult | результат боя: «limit» (лимит ходов), «eaten» (съедены все змеи, кроме одной) или «blocked» (нет возможных ходов) |
| FightTime | дата и время окончания боя |
| FightType | тип боя, «train» (обычный) или «challenge» (рейтинговый) |
| FirstIndex | индекс первого элемента списка |
| Hash | хэш: SHA1(SHA1(SHA1(логин «:» пароль) соль) штамп); соль выдается сервером в ответе «login data» |
| Lifetime | время жизни сессии после последнего запроса к серверу, в секундах |
| Login | логин пользователя, в нижнем регистре |
| OtherSnakeIds | массив из 3 идентификаторов змей, null для отсутствующих |
| PlayerId | идентификатор игрока |
| PlayerIds | массив из 3 различных идентификаторов игроков, участвующих рейтинге, кроме текущего игрока |
| PlayerList | отсортированный список игроков, см. выше |
| PlayerName | имя пользователя |
| PlayerSnakes | список змей игрока, см. выше |
| ProgramDescription | описание программы |
| Rating | числовой рейтинг игрока |
| Ratings | отсортированная таблица рейтингов, см. выше |
| Request | тип запроса |
| RequestId | клиентский идентификатор запроса, любой тип |
| Response | тип ответа |
| Salt | соль, используемая для генерации хэша при авторизации |
| Sid | идентификатор сессии |
| SkinId | идентификатор окраски змеи, целое неотрицательное число |
| SkinList | список вариантов окраски змей, см. выше |
| SlotIndex | номер сохраненного боя (0 – 9) |
| SlotList | отсортированный список сохраненных боев, см. выше |
| SlotName | описание сохраненного боя |
| SnakeId | идентификатор змеи, null для временной |
| SnakeIds | массив из 4 идентификаторов змей, null для отсутствующих |
| SnakeList | отсортированный список змей, см. выше |
| SnakeName | имя змеи |
| Snakes | массив из 4 описаний змей, null для отсутствующих, см. выше |
| SnakeStats | массив из 4 элементов, содержащих результаты боя для каждой змеи, null для отсутствующих, см. выше |
| SnakeType | тип змеи: «B» (бот) или «N» (обычная) |
| SnakeTypes | строка из 1 – 2 символов типов змей |
| SortBy | список вида [<имя_поля/>имя_поля*], задающий имена полей для сортировки и порядок их сортировки («<» — по возрастанию, «>» — по убыванию) |
| Templates | пользовательские шаблоны для программы, см. выше |
| Timestamp | метка времени; не должна отличаться от метки времени сервера больше, чем на 3 минуты |
| TotalCount | общее количество объектов (игроков, змей) |
| TurnLimit | максимальное количество ходов для боя, 1 — 1000 |
| Turns | информация о ходах, см. выше |
| Version | текущий номер версии протокола |
Все имена полей и их содержимое регистрозависимы. Поля, которые не могут входить в данный запрос, игнорируются.
Все поля, перечисленные в описании запроса, обязательны (если в описании явно не указано иное). Помимо перечисленных полей запрос должен содержать поле Sid (если в описании запроса не указано иное). Также запрос может содержать необязательное поле RequestId. В этом случае ответ сервера будет содержать одноименное поле, содержимое которого совпадает с этим полем запроса.
В случае успешного выполнения запроса сервер выдает ответ, указанный в описании запроса. В случае неудачи возвращается один из следующих ответов:
relogin, если время жизни сессии истекло либо данные авторизации были изменены;nack, если в запросе есть ошибки;error, если произошла внутренняя ошибка сервера.При авторизации используется хэш-функция SHA1, ее реализацию для JavaScript можно найти, например, здесь. На входе функции — строка в кодировке UTF-8, на выходе — шестнадцатиричное текстовое представление хэша в нижнем регистре (40 символов 0 – 9, a – f). Примеры:
SHA1(SHA1(«hello»)) == «9cf5caf6c36f5cccde8c73fad8894c958f4983da»
SHA1(SHA1(«привет»)) == «60a72cfc2aa27af4b1bda6d18cf50a27046914c4»
получение информации о сервере
Request: «info»
Sid: не требуется (игнорируется)
ответ: «info»
получение информации о текущем пользователе
Request: «whoami»
ответ: «whoami»
получение данных (соль, штамп сервера) для авторизации
Request: «login data»
Sid: не требуется (игнорируется)
Login:
ответ: «login data»
авторизация и открытие сессии
Request: «login»
Sid: не требуется (игнорируется)
Login:
Timestamp:
Hash:
ответ: «login»
выход и закрытие сессии
Request: «logout»
ответ: «ack»
таблица рейтингов игроков
Request: «ratings»
FirstIndex: необязательно, по умолчанию 0
Count: необязательно, 1 – 50, по умолчанию 30
SortBy: необязательно, возможные ключи: PlayerName или Rating, по умолчанию [«>Rating»]
ответ: «ratings»
список игроков, отсортированный по имени
Request: «player list»
FirstIndex: необязательно, по умолчанию 0
Count: необязательно, 1 – 50, по умолчанию 30
SortBy: необязательно, возможные ключи: PlayerName, по умолчанию [«<PlayerName»]
ответ: «player list»
информация об игроке
Request: «player info»
PlayerId:
ответ: «player info»
список всех змей
Request: «snake list»
SnakeTypes: необязательно, по умолчанию «BN»
FirstIndex: необязательно, по умолчанию 0
Count: необязательно, 1 – 50, по умолчанию 30
SortBy: необязательно, возможные ключи: SnakeName или PlayerName, по умолчанию [«<SnakeName», «<PlayerName»]
ответ: «snake list»
получение списка вариантов окраски змей
Request: «skin list»
ответ: «skin list»
информация о змее
Request: «snake info»
SnakeId:
ответ: «snake info»
создание новой змеи
Request: «snake new»
SnakeName:
SnakeType:
SkinId:
ProgramDescription:
Templates:
Maps:
ответ: «snake new»
удаление своей змеи
Request: «snake delete»
SnakeId:
ответ: «ack»
редактирование змеи
Request: «snake edit»
SnakeId:
SnakeName: необязательно
SnakeType: необязательно
SkinId: необязательно
ProgramDescription: необязательно
Templates: необязательно
Maps: необязательно
ответ: «ack»
назначение своей обычной змеи бойцом
Request: «snake assign»
SnakeId:
ответ: «ack»
список боев игрока
Request: «fight list»
FightListType:
ответ: «fight list»
информация о бое
Request: «fight info»
FightId:
ответ: «fight info», «fight delayed»
начать бой со временной змеей; временная змея будет первой
Request: «fight test»
TurnLimit: необязательно
SnakeName:
SkinId:
ProgramDescription:
Templates:
Maps:
OtherSnakeIds:
ответ: «fight info», «fight delayed»
начать обычный бой
Request: «fight train»
TurnLimit: необязательно
SnakeIds:
ответ: «fight info», «fight delayed»
начать рейтинговый бой
Request: «fight challenge»
PlayerIds:
ответ: «fight info», «fight delayed»
отменить бой
Request: «fight cancel»
ответ: «ack»
список сохраненных боев
Request: «slot list»
ответ: «slot list»
загрузить информацию о сохраненном бое
Request: «slot view»
SlotIndex:
ответ: «slot view»
сохранить информацию о бое
Request: «slot save»
SlotIndex:
SlotName:
FightId:
ответ: «ack»
изменение описания сохраненного боя
Request: «slot rename»
SlotIndex:
SlotName:
ответ: «ack»
очистить сохраненный бой
Request: «slot delete»
SlotIndex:
ответ: «ack»
обновление сессии
Request: «ping»
ответ: «ack»
Все поля, перечисленные в описании ответа, обязательны (если в описании явно не указано иное). Если в запросе было поле RequestId, то ответ также содержит это поле с тем же значением. В будущих версиях протокола могут появиться дополнительные поля ответов; старые версии клиентов должны игнорировать такие поля.
Сообщение об ошибке может быть выдано в ответ на любой запрос.
требуется заново авторизоваться (истекло время жизни сессии, изменились данные авторизации или просто указан неверный идентификатор сессии)
Response: «relogin»
ошибка в запросе
Response: «nack»
ErrorCode:
Error:
внутренняя ошибка
Response: «error»
ErrorCode:
Error:
подтверждение выполнения запроса
Response: «ack»
информация о сервере
Response: «info»
Version:
Compatible:
Lifetime:
информация о текущем игроке
Response: «whoami»
PlayerId:
PlayerName:
FightId: текущий отложенный бой (null, если отложенных боев нет)
Rating: отсутствует, если игрок не участвует в рейтинге
SnakeId: ид бойца; отсутствует, если игрок не участвует в рейтинге
SnakeName: имя бойца; отсутствует, если игрок не участвует в рейтинге
SkinId: окраска бойца; отсутствует, если игрок не участвует в рейтинге
данные для авторизации; если в запросе «login data» указан неизвестный логин, это не считается ошибкой
Response: «login data»
Login:
Salt:
Timestamp:
успешная авторизация
Response: «login»
PlayerId:
PlayerName:
Sid:
таблица рейтингов
Response: «ratings»
FirstIndex:
SortBy:
TotalCount:
Ratings:
список игроков
Response: «player list»
FirstIndex:
SortBy:
TotalCount:
PlayerList:
информация об игроке
Response: «player info»
PlayerId:
PlayerName:
Rating:
SnakeId: идентификатор бойца или null
PlayerSnakes:
список змей
Response: «snake list»
SnakeTypes:
FirstIndex:
SortBy:
TotalCount:
SnakeList:
список вариантов окраски
Response: «skin list»
SkinList:
информация о змее
Response: «snake info»
SnakeId:
SnakeName:
SnakeType:
SkinId:
PlayerId:
PlayerName:
ProgramDescription: необязательно, выдается только для ботов и своих змей
Templates: необязательно, выдается только для ботов и своих змей
Maps: необязательно, выдается только для ботов и своих змей
создана новая змея
Response: «snake new»
SnakeId:
список боев
Response: «fight list»
FightListType:
FightList:
информация о бое
Response: «fight info»
FightId:
FightType:
FightTime:
FightResult:
TurnLimit:
Turns:
Snakes:
SnakeStats:
расчет боя не завершен
Response: «fight delayed»
FightId:
список сохраненных боев
Response: «slot list»
SlotList:
информация о сохраненном бое
Response: «slot view»
SlotIndex:
SlotName:
FightType:
FightTime:
FightResult:
TurnLimit:
Turns:
Snakes:
SnakeStats:
| Код | Описание | Текст ошибки содержит: |
|---|---|---|
| 0 | сервер временно недоступен | причина |
| 1 | неизвестное имя запроса | содержимое поля Request |
| 2 | неизвестное имя поля | имя поля |
| 3 | отсутствует необходимое поле | имя поля |
| 4 | некорректное значение поля | имя поля, содержимое поля |
| 5 | слишком длинная строка | имя поля, максимальная длина |
| 6 | неизвестный логин или неверный хэш | |
| 7 | неизвестный идентификатор игрока | идентификатор |
| 8 | неизвестный идентификатор змеи | идентификатор |
| 9 | неизвестный идентификатор боя | идентификатор |
| 10 | игрок не участвует в рейтинге | идентификатор |
| 11 | некорректный формат поля | имя поля, содержимое поля |
| 12 | невозможно удалить бойца или сменить его тип | идентификатор змеи |
| 13 | некорректная окраска змеи | идентификатор змеи, указанная окраска |
| 14 | невозможно назначить бойцом бота | идентификатор змеи |
| 15 | сохраненный бой с указанным индексом отсутствует | индекс |
| 16 | чужая змея | идентификатор |
| 17 | невозможно «заказать» бой, поскольку есть незавершенный бой | идентификатор боя |
| 18 | у игрока уже максимально допустимое количество змей | количество |
| 19 | некорректные данные в запросе | описание |
| 20 | некорректное описание линии карты | номер карты, номер линии, линия |
В будущих версиях протокола могут появиться новые (более специфические) коды ошибок.