===== Протокол обмена данными, версия 1 ===== Протокол используется как для web-приложения, так и для отдельных клиентов. Запрос к серверу — обычный POST-запрос в кодировке UTF-8. Ответ сервера — объект, сериализованный в JSON. Для идентификации пользователя используется идентификатор сессии. Отдельные клиенты получают сессию при авторизации. В случае с web-клиентом код сессии может внедряться в код клиента — в этом случае он не должен совпадать с кодом обычной сессии, хранящейся в куках, что служит защитой от CSRF-атак. Версия протокола, разумеется, не последняя, в будущем наверняка появятся новые. Чтобы упростить жизнь игрокам и разработчикам клиентов, сервер, реализующий протокола версии N, обязан поддерживать работу с клиентами, реализущими версию N-1. Также желательно поддерживать и более ранние версии. Новый сервер совместим с клиентом, использующим старую версию протокола, если: * сервер автоматически определяет, какую версию протокола использует клиент, и использует ту же (либо совместимую) версию; * либо новая версия протокола совместима со старой. Две версии протокола совместимы, если в новой версии имеются только следующие отличия от старой: * добавлены новые типы запросов, использование которых не требуется; * в существующие типы запросов добавлены необязательные поля (или элементы полей), использование которых не требуется; * для полей в существующих типах запросов добавлены новые типы или возможные значения, использование которых не требуется; * добавлены новые типы ответов, которые могут быть выданы только на новые типы запросов; * в существующие типы ответов добавлены новые поля, которые клиент может игнорировать; * добавлены новые коды ошибок (ответ «nack»). Для совместимости клиенты должны выполнять следующие требования: * клиент должен игнорировать все неизвестные ему поля ответов; * клиент не должен полагаться на код ошибки (поле «ErrorCode») или ее текст (поле «Error»). ==== Стандартные типы полей ==== ^Тип в JavaScript^Тип в POST-запросе^ |null|пустая строка| |boolean|«0» (ложь) или «1» (истина)| |number|строковое представление числа| |string|строка| В случае с массивами и объектами генерируется отдельное поле запроса для каждого скалярного элемента или поля всех уровней вложенности. Имя такого поля имеет форму имя_объекта[ключ_или_индекс1][ключ_или_индекс2]... Например, год[2012][декабрь][21]. Для задания времени используется число, представляющее метку времени UNIX. ==== Нестандартные типы ==== === FightList — список боев === Массив, отсортированный по убыванию времени окончания боя. Формат элемента: ^Ключ^Значение^ |FightId|идентификатор боя| |FightType|тип боя: «train» (тренировочный) или «challenge» (рейтинговый)| |FightTime|время окончания боя| |TurnLimit|лимит ходов на бой| |TurnCount|длительность боя| |PlayerId|идентификатор игрока, «заказавшего» бой| |PlayerName|имя игрока, «заказавшего» бой| |Snakes|список из 4 змей (null для отсутствующих), участвующих в бою; см. поле Snakes| === Maps — карты программы === Массив, содержащий от 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). «Переполнение» последней линии карты является ошибкой. === PlayerList — список игроков === Массив. Формат элемента: ^Ключ^Значение^ |PlayerId|идентификатор игрока| |PlayerName|имя игрока| |Rating|текущий рейтинг; null, если не участвует| === PlayerSnakes — список змей игрока === Массив. Формат элемента: ^Ключ^Значение^ |SnakeId|идентификатор змеи| |SnakeName|имя змеи| |SnakeType|тип змеи: «B» (бот) или «N» (обычная)| |SkinId|идентификатор окраски| === Ratings — таблица рейтингов === Массив. Формат элемента: ^Ключ^Значение^ |PlayerId|идентификатор игрока| |PlayerName|имя игрока| |Rating|текущий рейтинг игрока| |SnakeId|идентификатор бойца| |SnakeName|имя бойца| |SkinId|идентификатор окраски бойца| === SkinList — список окрасок змей === Массив, осортирован по названию окраски. Формат элемента: ^Ключ^Значение^ |SkinId|идентификатор окраски| |SkinName|название окраски| === SlotList — список сохраненных боев === Массив из 10 элементов, null для отсутствующих. Формат элемента: ^Ключ^Значение^ |SlotName|имя сохраненного боя| |FightId|идентификатор боя| |FightType|тип боя| |FightTime|время окончания боя| === SnakeList — список змей === Массив. Формат элемента: ^Ключ^Значение^ |SnakeId|идентификатор змеи| |SnakeName|имя змеи| |SnakeType|тип змеи: «B» (бот) или «N» (обычная)| |SkinId|идентификатор окраски| |PlayerId|идентификатор владельца| |PlayerName|имя владельца| === Snakes — информация о змеях, участвующих в бою === Массив из 4 элементов, содержащих описания змей, null для отсутствующих. Элемент является объектом: ^Ключ^Значение^ |SnakeId|идентификатор змеи, null для временной| |SnakeName|имя змеи| |SnakeType|тип змеи: «B» (бот) или «N» (обычная)| |SkinId|идентификатор окраски| |PlayerId|идентификатор владельца| |PlayerName|имя владельца| === SnakeStats — результаты боя для каждой змеи === Массив из 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. === Templates — пользовательские шаблоны === Массив из 4 строк длиной от 1 до 6 различных символов. Каждая строка задает пользовательский набор элементов. Элементы кодируются следующими символами: ^Символ^Значение^ | S |тело змеи игрока| | T |хвост змеи игрока| | V |пустая клетка| | W |граница поля| | X |голова змеи противника| | Y |тело змеи противника| | Z |хвост змеи противника| Другие символы недопустимы. Порядок символов не имеет значения. === Turns — запись ходов === Массив из 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 можно найти, например, [[http://code.google.com/p/crypto-js/#SHA-1|здесь]]. На входе функции — строка в кодировке UTF-8, на выходе — шестнадцатиричное текстовое представление хэша в нижнем регистре (40 символов 0 – 9, a – f). Примеры: ''SHA1(SHA1("hello")) == "9cf5caf6c36f5cccde8c73fad8894c958f4983da"''\\ ''SHA1(SHA1("привет")) == "60a72cfc2aa27af4b1bda6d18cf50a27046914c4"''\\ ==== Запросы ==== === Авторизация === == info == получение информации о сервере ''Request'': "info"\\ ''Sid'': не требуется (игнорируется)\\ ответ: "info" == whoami == получение информации о текущем пользователе ''Request'': "whoami"\\ ответ: "whoami" == login data == получение данных (соль, штамп сервера) для авторизации ''Request'': "login data"\\ ''Sid'': не требуется (игнорируется)\\ ''Login'':\\ ответ: "login data" == login == авторизация и открытие сессии ''Request'': "login"\\ ''Sid'': не требуется (игнорируется)\\ ''Login'':\\ ''Timestamp'':\\ ''Hash'':\\ ответ: "login" == logout == выход и закрытие сессии ''Request'': "logout"\\ ответ: "ack" === Игроки === == ratings == таблица рейтингов игроков ''Request'': "ratings"\\ ''FirstIndex'': необязательно, по умолчанию 0\\ ''Count'': необязательно, 1 – 50, по умолчанию 30\\ ''SortBy'': необязательно, возможные ключи: PlayerName или Rating, по умолчанию [">Rating"]\\ ответ: "ratings" == player list == список игроков, отсортированный по имени ''Request'': "player list"\\ ''FirstIndex'': необязательно, по умолчанию 0\\ ''Count'': необязательно, 1 – 50, по умолчанию 30\\ ''SortBy'': необязательно, возможные ключи: PlayerName, по умолчанию ["