[Мессенджеры, Программирование, Разработка игр, Логические игры] Настольная игра в Telegram с разоблачением
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
при помощи Crystal, Lucky, Tourmaline и Telegram Bot Gaming PlatformФизикам можно сразу в репу.
Как известно(не многим), программист, хотя бы раз в жизни должен – поломать прод и выхватить за это, починить его, а на досуге построить баню и написать игру.
Успешно выполнив первые пункты пришла пора перейти к последнему из них, чтобы пить заслуженное пиво в бане, ни на что уже более не отвлекаясь.
Просто писать игру достаточно скучно и как и миллиард авторов до меня, я решил сделать такую игру – в которую интересно будет сыграть, хотя бы мне самому и не меньше двух, а то и трёх раз.
К моменту принятия решения, закончились новогодние выходные, друзья мои разъехались и я подумал:
- для усложнения задачи неплохо было бы воплотить эту самую игру в телеге.
- игра должна многопользовательской - как минимум для пары человек.
- и почему бы не нарды - мы с удовольствием в них рубимся время от времени?
Время на проект (для борьбы с прокрастинацией) выделил себе ровно месяц. Так появилась задача и сроки.
И если, для ее решения, мне нужны инструменты, то почему бы не взять какой нибудь новенький, сверкающий молоток моей мечты, который я давно хотел применить но не было повода взять его в руки?Итак – Crystal поскольку, я решил, что он прекрасен, удобен и быстр. (спойлер: да, так и есть)Копание в Telegram Bot Gaming Platform несколько разочаровало. Довольно унылые примеры с HTML+JS на тему: нажми кнопку быстро/вовремя или считай в уме быстрее всех, не вдохновляли. Копание в исходниках тележки дало некоторое понимание процесса взаимодействия ее с игрой. Документация на эту тему – довольно мутная. Сценарий взаимодействия получился такой – телеграмм кидает уведомление, о том что пользователь нажал кнопку «Играть в ...» под сообщением с игрой. В ответ нужно отправить уникальную ссылку которую телеграмм откроет для пользователя – и да начнется битва)
Конечно я рассчитывал на что нибудь большее, вроде отправки сообщений через сервер tg для какой то коммуникации между участниками игры, но не случилось. Печально, зато можно поковырять websockets.Что понадобится?
- endpoint который будет обрабатывать сообщения телеги
- еще (как минимум один) который собственно и будет отдавать игровую доску
- нечто, имеющее роутер для обработки запросов, средства собрать html страницу и возможность создавать/хранить/доставать активную игру в базе. Словом небольшой framework который избавит меня от рутины и освободит для высокого)
Выбор мой пал на Lucky (на тот момент версии 0.24) по следующим причинам:
- подход создателей и философия проекта
- хорошая документация
- механизм передачи параметров от контроллера к визуализации
- наличие готовых json api контроллеров нужных для api телеги
- хороший роутер и хелперы к нему
- более менее приемлемый интерфейс для работы с БД
- наличие готового деплоя на Heroku
- всё лишнее можно отключить
- всё отсутствующее дописать
Создание игровой доски в примитивном виде.
Выглядело примерно такДоска была нарисована в Inkscape и содержит несколько слоев. Сама доска, фишки, кости, слой сообщений. В процессе конечно были сделаны всевозможные ошибки относительно размещения начала системы координат, что важно для использования transform rotate преобразований в SVG. В приложении, доска представляет из себя SVG, – генерируемый кодом на Crystal при помощи Lucky конечно. Большую часть нудной работы сделал converting HTML to Lucky methods, (в него я загнал svg из Inkscape) остается только убрать повторения и разбить структуру svg на логические элементы с которыми будет удобно работать.
src/pages/active_games/game_page.crВ результате из 50kb SVG получилось 2-3 сотни строк на Crystal лежащие в соответствующей page. Время на вывод такой страницы без полезной нагрузки на моем буке измеряется µs. Я не стал разносить всё по компонентам исключительно экономя время. Многие возможности Crystal были просто не использованы. На тот момент степень понимания языка ещё не давала мне использовать все его преимущества. К концу проекта глядя на этот код я понимал, что многое можно сделать на много, на много красивее и удобнее. Логика игры, правила и ограничения.Теперь когда есть на чем играть, реализую логику – все правила и состояния игры, в одном классе Game, лежит в src/models/game.cr. Примерно 600 строк. Проследить боль и страдания можно в тестах к этому классу до теста 399 строки когда оно смогло играть с собой до победы. Правила брал здесьСовмещение логики и визуализации игрыДальше я начал натягивать сову на глобус. Совмещать логику и визуализацию, цель: отображать любое сохраненное состояние игры на доске. После победы(сова сопротивлялась как могла) я двинул дальше, Надо добавить управление. Детектировать, что ход сделан и отправлять его на сервер в соответствующий action.
Это удобнее было сделать на JS. Я не фанат JS, но когда надо – тогда надо.
Lucky уже настроен для использования всей этой лабуды с Webpack и.т.д. По умолчанию подключены небольшие и довольно полезные Turbolinks и rails-ujs. Выпиливать их не стал. JS в проекте Lucky лежит в src/js/app.js Управление простое, выбираем кость и фишку которой ходим либо наоборот и отправляем ход на сервер, позднее добавил возможность ходить выбирая фишку и место назначения.Доверять полученному со стороны клиента (без должной проверки) нехорошо. Поэтому, работает только логика на сервере в классе Game. Состояние игры всегда корректно, можно спокойно выйти в другой чат и ответить на сообщение, и без проблем снова открыть игру на том же самом месте. Смычка города с селом, происходит в этом action. По сути это один большой case связывающий действия пользователя с состоянием игры. Если изменение было игрок увидит его после выполнения перенаправления на action отображения игровой доски.
На этом же этапе я подключил Turbolinks и rails-ujs для плавного апдейта страницы.Настало время подключать Telegram.Чтобы тестировать игру в связке с телеграмм нужен сервер с IP или доменом и соответствующим SSL сертификатом для подключения Webhooks через который телеграмм будет слать updates приложению. Сервис размещаю на Heroku. Процесс настройки деплоя сводится к нескольким тривиальным командам, после прочтения главы документации Lucky на эту тему. Heroku работает с телеграмм без возни с сертификатами сразу из коробки. Режим бота для доставки игры выбрал inline mode как наиболее прогрессивный и безопасный.Быстро набросал клиент для взаимодействия с api телеграмм, пара часов отладки и всё заработало. После чего, естественно, обнаружил прекрасный шард реализующий работу с api телеграмм для Crystal и имя ему Tourmaline. У него был всего один недостаток он не умел игры, я это поправил и автор оперативно принял изменения. Немного перетряхнул код и встроил бот уже через Tourmaline.Схема работы приложения с api телеграмм подробно:
- создание игрового бота, всё стандартно через @BotFather
- action в Lucky который будет принимать updates от телеграмм.
- прописать url этого action с помощью setwebhook в телеграмм api. (Tourmaline позволяет динамически устанавливать webhook, но я предпочел самостоятельно контролировать этот процесс)
- при регистрации игры выдается ссылка вида game link (e.g., t.me/bot?game=game) в моем случае http://t.me/tavla_best_bot?game=tavla. Для начала, достаточно этой ссылки чтобы поделится игрой. Клик на нее предложит выбрать чат, куда будет отправлено сообщение с игрой.
- Под сообщением, по умолчанию будет одна обязательная кнопка «Играть в…». Клик пользователем по этой кнопке, отправляет на action (привязанный в пункте 3 к Webhook) структуру Update c вложенной в поле callback_query еще одной структурой с оригинальным названием CallbackQuery. Из нее берется поле game_short_name – имя вызываемой игры (если у нас ссылка вида http://t.me/tavla_best_bot?game=tavla значение должно быть «tavla») и второе поле callback_query.id нужно передать обратно в answerCallbackQuery, чтобы телега понимала на что отвечаем.
Tourmaline активно использует аннотации, что очень удобно в написании бота, но не всегда удобно искать где отработает соответствующая функция. Из action апдейт прилетит сюда.
Структура UpdateВ соответствии с 5 пунктом соглашения при создании игрового бота не получится хранить куки и создавать сессии – поэтому все нужные параметры должны быть в url который генерирую в ответе. Фактически это идентификация игры и пользователя по динамическому url. Проверять такие url надо самостоятельно, поэтому использую helper и mixin.Если всё прошло успешно, телеграмм клиент открывает в браузере встроенном или внешнем переданный ему в answerCallbackQuery url. Параметры user сохраняются в базу при необходимости. Я использую в проекте Postgres скорее по привычке и для потестить ORM Avram, чем по необходимости, а вообще, вполне хватило бы Redis. Выглядит url так (разделение по двойному тире): /active_games/1eae03de19d1e909207c6192baff500771e0cbeb--AgzzzzzzzzzzzzzzUWfH7r74--321232123--5345353343 Первая часть подпись, генерируется из остальных параметров и некоего salt. Вторая часть inline_mesage_id. Третья и четвертая id пользователя телеграмм. Четвертая часть не обязательна, в этом случае за второго игрока станет действовать бот. Идентификаторinline_mesage_id однозначно определяет сообщение с игрой по которому сделан клик, user_idтого кто кликал.На этом работа телеги пока заканчивается и я возвращаюсь к игровой странице.Получив запрос get c url и проверив его валидность смотрю есть ли в базе такая игра. Если есть отображаю ее, если нет - сначала создаю.Общая логика такая (здесь) – если два человека нажали в чате на одном сообщение кнопку играть, до того как игра начата одним из них, игра будет человек – человек, в противном случае человек – бот. Естественно схему можно менять как угодно, вплоть до рейтинга игроков и поиска активных в данный момент соперников не имеющих общих чатов.Последние штрихиДобавил в middleware Lucky websocket обработчик для доставки обновлений. Когда противник сделал ход, игра обновит и доску второго игрока. На тот момент ws actions в Lucky был только в виде пары коммитов в экспериментальной ветке, но это всё равно было немного не то, что мне нужно.
Отладка websocketТут пришлось повозится из за чудесатой поддержки websocket в Heroku, а точнее на бесплатном инстансе.
Он тупо рвет соединение при неактивности сокета. Пришлось добавить пинг от клиента через подобранный эмпирическим путем интервал и отправку мусорного сообщения в ответ.
Вызов бота через inline запросДобавил боту возможность отправлять игру через inline запрос. Для этого в строке чата набираем имя бота @tavla_best_bot в ответ появится подсказка с игрой на которую нужно кликнуть.
Добавил меню c кнопками запуска игры, для комплекта если кто то запустит бот напрямую.
Добавил отправку набранных игровых очков в телеграмм.
На этом процесс можно было считать законченным. Оставшееся время я потратил на визуальщину и вкусовщину. Frontend не является моей специализацией, поэтому прошу отнестись снисходительно. Многое наверняка можно было сделать красивее и проще. Проблема оставшаяся нерешенной из скупердяйства принципиальных соображений – вертикальный режим в каких то (не всех) Iphone/Ipad, – ломает верстку. Я не пользуюсь этими девайсами, а реально бесплатных тестовых сред для разработчика я не нашел. Если кто то пофиксит буду рад.PsКод выложен в том виде к котором был на момент окончания времени проекта, он полностью рабочий, следуя инструкции в Readme можно поднять свой инстанс игры, естественно бот тоже нужен свой. Мест приложения рук, еще довольно много, например добавить боту игры ума. Возможно со временем я сделаю порт TDBackGammon и бот будет красавчик, но пока времени на это нет. Всего на проект я потратил почти 75 часов за отведенные 30 дней, в среднем примерно по 2.5 часа в день, самый длительный непрерывный интервал 9.5 часов.PpsЕще момент который касается бесплатных инстансов Heroku, они засыпают при неактивности, поэтому, отклик которого телеграмм ждет от приложения очень быстро, может не успеть с первого раза. Чтобы избежать подобной ситуации я дергаю инстанс снаружи HEAD запросом 1 раз в минуту, при таком подходе времени бесплатной активности вполне хватает на месяц для всех, кто сейчас играет в tavla. Надеюсь хабраэффекта не случится, и я и дальше смогу спокойно рубиться в нее за завтраком:)Моя искренняя благодарность всем, кто делает и помогает делать Crystal и его экосистему. Мне очень понравился Crystal. Я сделал для себя определённые выводы относительно будущего этого языка и постараюсь сделать на нём еще несколько проектов, не важно по работе или ради собственного удовольствия. Спасибо всем, кто это осилил, успехов и удачных проектов!
===========
Источник:
habr.com
===========
Похожие новости:
- [Программирование, Звук] Книги о цифровой обработке сигналов и звуковом синтезе
- [Программирование, Анализ и проектирование систем, Совершенный код, Проектирование и рефакторинг, ООП] OCP против YAGNI (перевод)
- [C, Программирование микроконтроллеров, Разработка под Arduino, DIY или Сделай сам] Ультразвуковой дальномер на Arduino
- [Программирование, Java] Spring Boot + ControllerAdvice + ResponseBodyAdvice или как обернуть ответ контроллеров
- [Разработка игр, Аналитика мобильных приложений, Игры и игровые приставки, Интервью] Подкаст «Хочу в геймдев» #27 — текстовая версия
- [Разработка игр, Игры и игровые приставки] «Ведьмак 3» получит обновление и DLC, «вдохновлённое» сериалом Netflix
- [Мессенджеры, Работа с видео, Обработка изображений] WhatsApp позволит отправлять изображения и видео в лучшем качестве
- [Разработка игр, Машинное обучение, Искусственный интеллект] Волк, предпочитающий самоубийство съедению овцы (перевод)
- [Python, Программирование, C++, Алгоритмы] Оптимизация на простых типах данных. Часть №2 «Числа»
- [Программирование, Big Data, Конференции, Искусственный интеллект] BeeTech 2021: обзор докладов big-data, искуственный интеллект, IT-архитектура, QA, Back-End
Теги для поиска: #_messendzhery (Мессенджеры), #_programmirovanie (Программирование), #_razrabotka_igr (Разработка игр), #_logicheskie_igry (Логические игры), #_crystal, #_lucky, #_tourmaline, #_telegram, #_telegram_bot, #_nardy. (нарды.), #_tavla, #_messendzhery (
Мессенджеры
), #_programmirovanie (
Программирование
), #_razrabotka_igr (
Разработка игр
), #_logicheskie_igry (
Логические игры
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:48
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
при помощи Crystal, Lucky, Tourmaline и Telegram Bot Gaming PlatformФизикам можно сразу в репу. Как известно(не многим), программист, хотя бы раз в жизни должен – поломать прод и выхватить за это, починить его, а на досуге построить баню и написать игру. Успешно выполнив первые пункты пришла пора перейти к последнему из них, чтобы пить заслуженное пиво в бане, ни на что уже более не отвлекаясь. Просто писать игру достаточно скучно и как и миллиард авторов до меня, я решил сделать такую игру – в которую интересно будет сыграть, хотя бы мне самому и не меньше двух, а то и трёх раз. К моменту принятия решения, закончились новогодние выходные, друзья мои разъехались и я подумал:
И если, для ее решения, мне нужны инструменты, то почему бы не взять какой нибудь новенький, сверкающий молоток моей мечты, который я давно хотел применить но не было повода взять его в руки?Итак – Crystal поскольку, я решил, что он прекрасен, удобен и быстр. (спойлер: да, так и есть)Копание в Telegram Bot Gaming Platform несколько разочаровало. Довольно унылые примеры с HTML+JS на тему: нажми кнопку быстро/вовремя или считай в уме быстрее всех, не вдохновляли. Копание в исходниках тележки дало некоторое понимание процесса взаимодействия ее с игрой. Документация на эту тему – довольно мутная. Сценарий взаимодействия получился такой – телеграмм кидает уведомление, о том что пользователь нажал кнопку «Играть в ...» под сообщением с игрой. В ответ нужно отправить уникальную ссылку которую телеграмм откроет для пользователя – и да начнется битва) Конечно я рассчитывал на что нибудь большее, вроде отправки сообщений через сервер tg для какой то коммуникации между участниками игры, но не случилось. Печально, зато можно поковырять websockets.Что понадобится?
Выглядело примерно такДоска была нарисована в Inkscape и содержит несколько слоев. Сама доска, фишки, кости, слой сообщений. В процессе конечно были сделаны всевозможные ошибки относительно размещения начала системы координат, что важно для использования transform rotate преобразований в SVG. В приложении, доска представляет из себя SVG, – генерируемый кодом на Crystal при помощи Lucky конечно. Большую часть нудной работы сделал converting HTML to Lucky methods, (в него я загнал svg из Inkscape) остается только убрать повторения и разбить структуру svg на логические элементы с которыми будет удобно работать. src/pages/active_games/game_page.crВ результате из 50kb SVG получилось 2-3 сотни строк на Crystal лежащие в соответствующей page. Время на вывод такой страницы без полезной нагрузки на моем буке измеряется µs. Я не стал разносить всё по компонентам исключительно экономя время. Многие возможности Crystal были просто не использованы. На тот момент степень понимания языка ещё не давала мне использовать все его преимущества. К концу проекта глядя на этот код я понимал, что многое можно сделать на много, на много красивее и удобнее. Логика игры, правила и ограничения.Теперь когда есть на чем играть, реализую логику – все правила и состояния игры, в одном классе Game, лежит в src/models/game.cr. Примерно 600 строк. Проследить боль и страдания можно в тестах к этому классу до теста 399 строки когда оно смогло играть с собой до победы. Правила брал здесьСовмещение логики и визуализации игрыДальше я начал натягивать сову на глобус. Совмещать логику и визуализацию, цель: отображать любое сохраненное состояние игры на доске. После победы(сова сопротивлялась как могла) я двинул дальше, Надо добавить управление. Детектировать, что ход сделан и отправлять его на сервер в соответствующий action. Это удобнее было сделать на JS. Я не фанат JS, но когда надо – тогда надо. Lucky уже настроен для использования всей этой лабуды с Webpack и.т.д. По умолчанию подключены небольшие и довольно полезные Turbolinks и rails-ujs. Выпиливать их не стал. JS в проекте Lucky лежит в src/js/app.js Управление простое, выбираем кость и фишку которой ходим либо наоборот и отправляем ход на сервер, позднее добавил возможность ходить выбирая фишку и место назначения.Доверять полученному со стороны клиента (без должной проверки) нехорошо. Поэтому, работает только логика на сервере в классе Game. Состояние игры всегда корректно, можно спокойно выйти в другой чат и ответить на сообщение, и без проблем снова открыть игру на том же самом месте. Смычка города с селом, происходит в этом action. По сути это один большой case связывающий действия пользователя с состоянием игры. Если изменение было игрок увидит его после выполнения перенаправления на action отображения игровой доски. На этом же этапе я подключил Turbolinks и rails-ujs для плавного апдейта страницы.Настало время подключать Telegram.Чтобы тестировать игру в связке с телеграмм нужен сервер с IP или доменом и соответствующим SSL сертификатом для подключения Webhooks через который телеграмм будет слать updates приложению. Сервис размещаю на Heroku. Процесс настройки деплоя сводится к нескольким тривиальным командам, после прочтения главы документации Lucky на эту тему. Heroku работает с телеграмм без возни с сертификатами сразу из коробки. Режим бота для доставки игры выбрал inline mode как наиболее прогрессивный и безопасный.Быстро набросал клиент для взаимодействия с api телеграмм, пара часов отладки и всё заработало. После чего, естественно, обнаружил прекрасный шард реализующий работу с api телеграмм для Crystal и имя ему Tourmaline. У него был всего один недостаток он не умел игры, я это поправил и автор оперативно принял изменения. Немного перетряхнул код и встроил бот уже через Tourmaline.Схема работы приложения с api телеграмм подробно:
Структура UpdateВ соответствии с 5 пунктом соглашения при создании игрового бота не получится хранить куки и создавать сессии – поэтому все нужные параметры должны быть в url который генерирую в ответе. Фактически это идентификация игры и пользователя по динамическому url. Проверять такие url надо самостоятельно, поэтому использую helper и mixin.Если всё прошло успешно, телеграмм клиент открывает в браузере встроенном или внешнем переданный ему в answerCallbackQuery url. Параметры user сохраняются в базу при необходимости. Я использую в проекте Postgres скорее по привычке и для потестить ORM Avram, чем по необходимости, а вообще, вполне хватило бы Redis. Выглядит url так (разделение по двойному тире): /active_games/1eae03de19d1e909207c6192baff500771e0cbeb--AgzzzzzzzzzzzzzzUWfH7r74--321232123--5345353343 Первая часть подпись, генерируется из остальных параметров и некоего salt. Вторая часть inline_mesage_id. Третья и четвертая id пользователя телеграмм. Четвертая часть не обязательна, в этом случае за второго игрока станет действовать бот. Идентификаторinline_mesage_id однозначно определяет сообщение с игрой по которому сделан клик, user_idтого кто кликал.На этом работа телеги пока заканчивается и я возвращаюсь к игровой странице.Получив запрос get c url и проверив его валидность смотрю есть ли в базе такая игра. Если есть отображаю ее, если нет - сначала создаю.Общая логика такая (здесь) – если два человека нажали в чате на одном сообщение кнопку играть, до того как игра начата одним из них, игра будет человек – человек, в противном случае человек – бот. Естественно схему можно менять как угодно, вплоть до рейтинга игроков и поиска активных в данный момент соперников не имеющих общих чатов.Последние штрихиДобавил в middleware Lucky websocket обработчик для доставки обновлений. Когда противник сделал ход, игра обновит и доску второго игрока. На тот момент ws actions в Lucky был только в виде пары коммитов в экспериментальной ветке, но это всё равно было немного не то, что мне нужно. Отладка websocketТут пришлось повозится из за чудесатой поддержки websocket в Heroku, а точнее на бесплатном инстансе. Он тупо рвет соединение при неактивности сокета. Пришлось добавить пинг от клиента через подобранный эмпирическим путем интервал и отправку мусорного сообщения в ответ. Вызов бота через inline запросДобавил боту возможность отправлять игру через inline запрос. Для этого в строке чата набираем имя бота @tavla_best_bot в ответ появится подсказка с игрой на которую нужно кликнуть. Добавил меню c кнопками запуска игры, для комплекта если кто то запустит бот напрямую. Добавил отправку набранных игровых очков в телеграмм. На этом процесс можно было считать законченным. Оставшееся время я потратил на визуальщину и вкусовщину. Frontend не является моей специализацией, поэтому прошу отнестись снисходительно. Многое наверняка можно было сделать красивее и проще. Проблема оставшаяся нерешенной из скупердяйства принципиальных соображений – вертикальный режим в каких то (не всех) Iphone/Ipad, – ломает верстку. Я не пользуюсь этими девайсами, а реально бесплатных тестовых сред для разработчика я не нашел. Если кто то пофиксит буду рад.PsКод выложен в том виде к котором был на момент окончания времени проекта, он полностью рабочий, следуя инструкции в Readme можно поднять свой инстанс игры, естественно бот тоже нужен свой. Мест приложения рук, еще довольно много, например добавить боту игры ума. Возможно со временем я сделаю порт TDBackGammon и бот будет красавчик, но пока времени на это нет. Всего на проект я потратил почти 75 часов за отведенные 30 дней, в среднем примерно по 2.5 часа в день, самый длительный непрерывный интервал 9.5 часов.PpsЕще момент который касается бесплатных инстансов Heroku, они засыпают при неактивности, поэтому, отклик которого телеграмм ждет от приложения очень быстро, может не успеть с первого раза. Чтобы избежать подобной ситуации я дергаю инстанс снаружи HEAD запросом 1 раз в минуту, при таком подходе времени бесплатной активности вполне хватает на месяц для всех, кто сейчас играет в tavla. Надеюсь хабраэффекта не случится, и я и дальше смогу спокойно рубиться в нее за завтраком:)Моя искренняя благодарность всем, кто делает и помогает делать Crystal и его экосистему. Мне очень понравился Crystal. Я сделал для себя определённые выводы относительно будущего этого языка и постараюсь сделать на нём еще несколько проектов, не важно по работе или ради собственного удовольствия. Спасибо всем, кто это осилил, успехов и удачных проектов! =========== Источник: habr.com =========== Похожие новости:
Мессенджеры ), #_programmirovanie ( Программирование ), #_razrabotka_igr ( Разработка игр ), #_logicheskie_igry ( Логические игры ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:48
Часовой пояс: UTC + 5