Простые, бесплатные (и ужасные) доски почёта (а теперь и облачные сохранения) для игр в VK Play.
Поддерживают авторизацию как через GAS так и через "Эмуляцию Steam" (далее - VKSteam) по желанию.
Допускается использование и без какой-либо авторизации вовсе, но это очень опасно.
Сейчас используется на проде в VK Play версии игры Wally and the FANTASTIC PREDATORS.
Доски почёта:
Облачные сохранения:
Служебная информация:
Администрирование:
Сам сервер настраивается в файле config.py
,
от строки # -- КОНФИГУРАЦИЯ -- #
до # -- КОНЕЦ КОНФИГУРАЦИИ -- #
.
См. файл config_template.py
в качестве примера настроек, можете его отредактировать и скопировать как config.py
.
Это сделано из-за того, что сам сервер предназначен для хостинга на бесплатном Deta Spaces (мы разработчики игр для VK Play, откуда у нас деньги? с продаж тем более ничего нет), и это было легче всего сделать файлом.
Если вы используете "Эмуляцию Steam" в VK Play, вам НЕ НУЖЕН GAS!
Вы не можете использовать GAS и "Эмуляцию Steam" одновременно, выберите что-то одно!
Если вы вдруг не видите у себя App ID для "Эмуляции Steam", но точно уверены что должны, пожалуйста, свяжитесь с Integration Team во внутреннем чате платформы (зелёная иконка), только они вам помогут.
Имя переменной | Тип переменной | Описание переменной |
---|---|---|
CONFIG_USE_GAS | bool | Использовать ли авторизацию через GAS? |
CONFIG_GAS_GMR_ID | int | GMR ID игры, см. в Системных свойствах! |
CONFIG_GAS_SECRET | str | GAS секрет игры, см. в Системных свойствах! |
CONFIG_USE_VKSTEAM | bool | Использовать ли авторизацию через VKSteam? (для новых игр) |
CONFIG_VKSTEAM_APP_ID | int | ID для эмуляции Steam из Системных свойств! |
CONFIG_VKSTEAM_KEY | str | Секрет для эмуляции Steam API из Системных свойств! |
CONFIG_SERVER_USER_AGENT | str | Как представляться серверам ВК? Советую поменять на что-то своё |
CONFIG_ADMIN_SECRET | str | Секрет для админских API методов доски |
CONFIG_LEADERBOARD_INFO | dict[str, dict[str, str|int|bool]] | Описание всех досок, об этом ниже |
CONFIG_GREETING_MESSAGE | str | Как приветствовать любопытных, что попытались открыть ваш сервер как ссылку в браузере? HTML-строка. |
Пример CONFIG_LEADERBOARD_INFO:
# dict, конфигурация досок почёта, key - идентификатор доски.
CONFIG_LEADERBOARD_INFO = {
# wally daily runs
'dailyrun': {
# str, 'day' - сброс каждый день, 'week' - каждую неделю, 'hour' - час, None - не сбрасывать
'reset_every': 'day',
# bool, True - сортировать от меньшего к большему
'reverse_sort': False,
# bool, разрешать ли публиковать запись если данный игрок УЖЕ публиковал?
'allow_overwrite': False,
# int, макс. кол-во записей, None - не ограничено (опасно!)
'max_entries': 1000
},
# wally weekly runs
'weeklyrun': {
# str, 'day' - сброс каждый день, 'week' - каждую неделю, 'hour' - час, None - не сбрасывать
'reset_every': 'week',
# bool, True - сортировать от меньшего к большему
'reverse_sort': False,
# bool, разрешать ли публиковать запись если данный игрок УЖЕ публиковал?
'allow_overwrite': False,
# int, макс. кол-во записей, None - не ограничено (опасно!)
'max_entries': 1000
}
}
Ключ это желаемый leaderboard_id
доски, значение это ещё один dict
с описанием доски.
Описание dict-а доски:
Ключ | Тип значения | Описание |
---|---|---|
reset_every | str|None | Интервал сброса доски. None - никогда, 'week' - еженедельно, 'day' - ежедневно, 'hour' - ежечасно, 'minute' - ежеминутно соотв. |
reverse_sort | bool | Если True то сортировать от меньшего значения к большему, если False то от большего к меньшему |
allow_overwrite | bool | Разрешить ли игроку перезаписывать свою запись в доске? Если False то будет выкидываться status ошибка 0 если запись уже есть |
max_entries | int | Максимальное кол-во записей для одной доски, 0 - неограниченно (может забить БД!) |
Поле reset_every
работает так, что ненужные компоненты даты "убираются" в зависимости от частоты сброса.
Например:
при reset_every: 'day'
, сброс будет не через 24 часа после старта сервера, а когда наступит следующий день.
при reset_every: 'minute'
, сброс будет не через 60 секунд после старта сервера, а когда наступит следующая минута.
В возвращаемых JSON
-объектах поле status
может иметь значение от -10
и ниже, это коды ошибок GAS, или -20
и ниже, это коды ошибок VKSteam.
Коды ошибок GAS:
Код в status |
Описание |
---|---|
-10 | Параметр gas_uid неверный, или не задан |
-11 | Параметр gas_hash неверный, или не задан |
-12 | Параметр gas_ip неверный, или не задан (не должно происходить) |
-13 | GMR ID не был задан в Конфигурации сервера |
-14 | Секрет GAS не был задан в Конфигурации сервера |
-15 | Произошла ошибка при подсчёте подписи для запроса в GAS |
-16 | GAS вернул HTTP-код 400 или больше |
-17 | GAS вернул status не ok , (см. документацию VK Play) |
-18 | Произошла ошибка HTTP запроса в GAS (лёг сервак?) |
Коды ошибок VKSteam:
Код в status |
Описание |
---|---|
-20 | Параметр user_id неверный, или не задан (попытка подделки?) |
-21 | Параметр vksteam_ticket неверный, или не задан (попытка подделки?) |
-22 | VKSteam вернул HTTP-код 400 или больше (истёк тикет?) |
-23 | В VKSteam запросе response.params.result не OK (попытка подделки ответа?) |
-24 | Не совпадают данный user_id и steamid в тикете (кто-то химичит трафик?) |
-25 | Произошла ошибка HTTP запроса в VKSteam (лёг сервак?) |
Делает запись в доске почёта.
HTTP метод: POST
Параметры:
Имя параметра | Тип параметра | Описание параметра |
---|---|---|
leaderboard_id | str | Идентификатор доски |
score | int | Очки, 1 или больше |
user_name | str | Имя пользователя, всегда обязательно т.к. GAS и VKSteam не дают данную информацию серверу, зато дают её игре |
metadata | str | Опционально, доп. данные для новой записи |
user_id | str | Идентификатор пользователя, используется для поиска существуюших записей игрока. Для GAS опционален, для VKSteam обязателен. |
gas_uid | str | (ТОЛЬКО ДЛЯ GAS) GAS UID из параметров запуска |
gas_hash | str | (ТОЛЬКО ДЛЯ GAS) GAS OTP Hash из параметров запуска |
vksteam_ticket | str | (ТОЛЬКО ДЛЯ VKSTEAM) Тикет авторизации как hex-строка без префикса 0x с чётным кол-вом символов. Параметр user_id становится ОБЯЗАТЕЛЕН! |
Возвращает: JSON
объект в кодировке UTF-8
, см. ниже.
Пример запроса:
https://wallyboards.duckdns.org/v1/api/post
Тело POST:
leaderboard_id=daily&score=228&user_name=SuperNagibator&user_id=71337&vksteam_ticket=abcdef
Делает новую запись в таблицу daily
, 228
очков у пользователя SuperNagibator
авторизованного через VKSteam.
leaderboard_id=daily&score=228&user_name=SuperNagibator&user_id=71337&vksteam_ticket=abcdef&metadata=mode_hardcode
Повторяет предыдующую запись, но уже с опциональной metadata
строкой mode_hardcode
.
При ошибке (пример):
{
"status": -1,
"error": "сообщение об ошибке на английском"
}
Коды ошибок status
:
Код в status |
Описание |
---|---|
-1 | Неверный параметр score , не дан, ноль или отрицательный |
-2 | Неверный параметр user_id , пустой или не дан (GAS - исключение) |
-3 | Неверный параметр user_name , пустой или не дан |
-4 | Неверный параметр leaderboard_id , пустой или не дан |
-5 | Доски с таким leaderboard_id не существует |
-6 | Что-то странно поломалось во время пересортировки, очень плохо |
0 | Доска не поддерживает перезапись, и запись игрока уже там существует, дождитесь сброса |
1 | Успех, см. ниже |
При успехе (пример):
{
"status": 1,
"error": "",
"new_entry_index": 3
}
Имя | Тип | Описание |
---|---|---|
status | int | В случае успеха всегда 1 |
error | str | В случае успеха всегда пустая |
new_entry_index | int | Индекс новой записи, всегда начинается с нуля |
Получает записи из одной доски почёта.
HTTP метод: GET
Параметры:
Имя параметра | Тип параметра | Описание параметра |
---|---|---|
leaderboard_id | str | Идентификатор доски |
index_start | int | С какого индекса получать записи? -1 значит относительно игрока |
amount | int | Максимальное кол-во записей которое хочется получить. 0 значит получить все записи от index_start (МЕДЛЕННО!) |
user_id | str | Идентификатор пользователя, используется когда index_start == -1 и для проверки запроса в VKSteam. Для GAS опционален, для VKSteam обязателен. |
gas_uid | str | (ТОЛЬКО ДЛЯ GAS) GAS UID из параметров запуска |
gas_hash | str | (ТОЛЬКО ДЛЯ GAS) GAS OTP Hash из параметров запуска |
vksteam_ticket | str | (ТОЛЬКО ДЛЯ VKSTEAM) Тикет авторизации как hex-строка без префикса 0x с чётным кол-вом символов. Параметр user_id становится ОБЯЗАТЕЛЕН! |
Возвращает: JSON
объект в кодировке UTF-8
, см. ниже.
Пример запроса:
https://wallyboards.duckdns.org/v1/api/get?leaderboard_id=daily&index_start=0&amount=10&user_id=71337&vksteam_ticket=abcdef
Получает первые 10
записей из доски если это возможно.
https://wallyboards.duckdns.org/v1/api/get?leaderboard_id=daily&index_start=10&amount=10&user_id=71337&vksteam_ticket=abcdef
Получает следующие 10
записей из доски если это возможно.
https://wallyboards.duckdns.org/v1/api/get?leaderboard_id=daily&index_start=-1&amount=1&user_id=71337&vksteam_ticket=abcdef
Пытается получить свою запись в доске если она присутствует, если записи нет то возвращается status
код 0
.
При ошибке (пример):
{
"status": -1,
"error": "сообщение об ошибке на английском"
}
Коды ошибок status
:
Код в status |
Описание |
---|---|
-1 | Неверный параметр user_id , пустой или не дан (GAS - исключение) |
-2 | Неверный параметр leaderboard_id , пустой или не дан |
-3 | Неверный параметр index_start , меньше -1 или не дан |
-4 | Доски с данным leaderboard_id не существует |
-5 | Неверный параметр amount , меньше 0 или не дан |
0 | Параметр index_start имеен значение -1 , но записи с данным игроком не нашлось в доске |
1 | Успех, см. ниже |
При успехе (пример):
{
"status": 1,
"error": "",
"entries": [
{
"score": 69,
"index": 5,
"timestamp": 1679665740.0,
"user_id": "7652281488420691337",
"user_name": "GladitKotovMyNikogdaNeBrosim",
"metadata": "опционально, может быть пустым"
},
{
"score": 50,
"index": 6,
"timestamp": 1679665632.0,
"user_id": "7654206913372281488",
"user_name": "SuperNagibator",
"metadata": ""
}
],
"amount": 2,
"total": 13
}
Имя | Тип | Описание |
---|---|---|
status | int | В случае успеха всегда 1 |
error | str | В случае успеха всегда пустая |
entries | array | Массив записей, может быть пустым если ничего не было найдено |
amount | int | Сколько записей в entries |
total | int | Сколько всего записей в доске |
Описание записей в массиве entries
:
Имя | Тип | Описание |
---|---|---|
score | int | Кол-во очков, всегда больше нуля |
index | int | Индекс в глобальном массиве записей, всегда ноль или больше |
timestamp | float | Временная метка в формате UNIX UTC |
user_id | str | Идентификатор пользователя |
user_name | str | Имя пользователя |
metadata | str | Опционально, метаданные записи |
Запрос для админских штук, пока скудно реализован, идеи приветствуются!
Если в конфигурации сервера не задан админский секрет, то этот метод будет отключен.
Абсолютно все вызовы к этому методу логгируются в Flask.
HTTP метод: GET
(исключительно для удобства)
Параметры:
Имя | Тип | Описание |
---|---|---|
secret | str | Секрет для API админа, см. Конфигурация |
action | str | Какое админское действие нужно совершить |
Если secret
неверный, или не дан вовсе, запрос вернёт строку ne-a, izvinite
.
Действия:
Значение параметра action |
Описание |
---|---|
reset | Сбрасывает все данные всех досок почёта |
reset_cloud | Сбрасывает все облачные сохранения всех игроков |
get_cloud_save | Получает JSON бэкап облачных сохранений |
get_leaderboards | Получает JSON бэкап досок почёта |
Возвращает: обычную строчку текста (для удобства)
Пример:
https://wallyboards.duckdns.org/v1/api/admin_action?secret=iamadmin&action=reset
Сбросит все данные во всех досках и заставит сделать перезагрузку из конфига.
Если не задан параметр action
, но secret
верный, запрос вернёт строку admin: secret is correct, but no action was given
.
Больше для этого метода особо ничего не реализовано.
Записывает строку данных в облачные сохранения.
Строка не должна содержать спец. символов ASCII/Unicode, и не обязательно в Base64, можно и JSON и Hex-текст.
HTTP метод: POST
Параметры:
Имя параметра | Тип параметра | Описание параметра |
---|---|---|
data | str|None | Строка данных которую нужно записать. Если параметр не дан, сохранение удаляется! |
user_id | str | Идентификатор пользователя. Для GAS опционален, для VKSteam обязателен. |
slot_id | str | Идентификатор слота облачных сохранений |
gas_uid | str | (ТОЛЬКО ДЛЯ GAS) GAS UID из параметров запуска |
gas_hash | str | (ТОЛЬКО ДЛЯ GAS) GAS OTP Hash из параметров запуска |
vksteam_ticket | str | (ТОЛЬКО ДЛЯ VKSTEAM) Тикет авторизации как hex-строка без префикса 0x с чётным кол-вом символов. Параметр user_id становится ОБЯЗАТЕЛЕН! |
Возвращает: JSON
объект в кодировке UTF-8
, см. ниже.
Описание возвращаемого объекта:
Имя | Тип | Описание |
---|---|---|
status | int | 1 при успехе, отрицательное значение при ошибке |
error | str | В случае успеха всегда пустая, иначе сообщение об ошибке |
timestamp | float | Временная метка в формате UNIX UTC, 0 если данные были удалены |
Коды ошибок status
:
Код в status |
Описание |
---|---|
-1 | Неверный параметр slot_id , пустой или не дан |
1 | Успех, см. ниже |
Пример запроса:
https://wallyboards.duckdns.org/v1/api/cloud_set
Тело POST: user_id=612345&vksteam_ticket=abcdef&slot=wally&data=0YXQvtGH0YMg0L7QsdC90LjQvNCw0YjQtdC6
Запишет base64-строку 0YXQvtGH0YMg0L7QsdC90LjQvNCw0YjQtdC6
в облачные сохранения пользователя в слот wally
с идентификатором 612345
и авторизацией через VKSteam.
Тело POST: user_id=612345&vksteam_ticket=abcdef&slot=wally
Удалит облачное сохранение в слоте wally
для пользователя с идентификатором 612345
.
Пример ответа (при сохранении):
{
"status": 1,
"error": "",
"timestamp": 1679738477.0
}
Пример ответа (при удалении):
{
"status": 1,
"error": "",
"timestamp": 0
}
Получает строку данных из облачных сохранений.
HTTP метод: GET
Параметры:
Имя параметра | Тип параметра | Описание параметра |
---|---|---|
user_id | str | Идентификатор пользователя. Для GAS опционален, для VKSteam обязателен. |
slot_id | str | Идентификатор слота сохранения |
gas_uid | str | (ТОЛЬКО ДЛЯ GAS) GAS UID из параметров запуска |
gas_hash | str | (ТОЛЬКО ДЛЯ GAS) GAS OTP Hash из параметров запуска |
vksteam_ticket | str | (ТОЛЬКО ДЛЯ VKSTEAM) Тикет авторизации как hex-строка без префикса 0x с чётным кол-вом символов. Параметр user_id становится ОБЯЗАТЕЛЕН! |
Возвращает: JSON
объект в кодировке UTF-8
, см. ниже.
Описание возвращаемого объекта:
Имя | Тип | Описание |
---|---|---|
status | int | 1 если данные есть, 0 если нет, отрицательное число при ошибке |
error | str | В случае успеха всегда пустая, иначе сообщение об ошибке |
timestamp | float | Временная метка в формате UNIX UTC, 0 если данных нет |
data | str | Строка данных, пустая если данных нет |
Пример запроса:
https://wallyboards.duckdns.org/v1/api/cloud_get?user_id=612345&vksteam_ticket=abcdef&slot_id=wally
Получит строку из слота wally
облачных сохранений для пользователя с идентификатором 612345
и авторизацией через VKSteam.
Пример ответа (при отсутствии данных):
{
"status": 0,
"error": "no data is present for given user_id or slot_id",
"timestamp": 0,
"data": ""
}
Пример ответа (при наличии данных):
{
"status": 1,
"error": "",
"timestamp": 1679738014.0,
"data": "0J/QsNGB0YXQsNC70L7QuiDQvdC1INCx0YPQtNC10YIu"
}
Получает текущее время на сервере и возвращает ваш реальный IP-адрес.
Пожалуйста, учтите несколько вещей:
- Время всегда возвращается по часовому поясу UTC, в формате UNIX Epoch.
- Время может отставать на несколько секунд в зависимости от пинга, прокси и других внешних факторов.
- IP-адрес клиента может быть неверным в зависимости от конфигурации прокси вашего сервера, см. функцию
get_client_ip
чтобы исправить это.
HTTP метод: GET
Параметры:
Нет.
Возвращает: JSON
объект в кодировке UTF-8
, см. ниже.
Описание возвращаемого объекта:
Имя | Тип | Описание |
---|---|---|
status | int | Всегда 1 |
error | str | Всегда пустая |
timestamp | float | Временная метка в формате UNIX Epoch, в часовом поясе UTC |
ip | str | IP-адрес сущности сделавшей запрос |
Пример запроса:
https://wallyboards.duckdns.org/v1/api/server_time
Получит текущее серверное время.
Пример ответа:
{
"status": 1,
"error": "",
"timestamp": 1679816858.012961,
"ip": "5.123.123.200"
}
Если поле ip
равно 127.0.0.1
или другой несуразице, вероятно
что ваш сервер не может нормально получать IP-адреса клиентов, см. документацию вашего хостинга и функцию get_client_ip
.