Синхронизацию действий игроков в игре с клиент-серверной архитектурой. Должна быть возможность играть из браузера. Для примера реализуем простую чат-комнату: При соединении:  Клиент получает уникальный ID;  Клиент получает информацию о всех остальных игроках (ID + имя);  Все остальные игроки получают информацию о новом игроке (ID + имя по умолчанию);  В консоли появляется сообщение о входе.  При потере соединения:  Все остальные игроки получают информацию о выходе игрока с сервера (ID);  В консоли появляется сообщение о выходе.  При изменении имени:  Если имя уже занято - игрок получает ошибку;  Все игроки уведомляются об изменении имени;  В консоли появляется сообщение.  При отправке сообщения в чат:  Все игроки видят сообщение в логе/консоли.  Примечание: ничего не мешает реализовать более сложный нетворкинг (например, передвижения игроков, какие-то другие действия) - но это выходит за рамки этой статьи и само по себе является достаточно сложной темой. Чат - это самый простой пример для демонстрации того, что такой подход для передачи данных, в принципе, работает - и цель моей статьи как раз в этом. Готовый проект можно изучить здесь: https://github.com/ktori/godobuf-over-websocket-demo Скриншоты можно посмотреть в конце статьи. Godot - free and open source кроссплатформенный игровой движок;  Protobuf - механизм для эффективной сериализации/десериализации данных;  Godobuf - плагин для Godot, позволяющий генерировать .gd (GDScript) файлы из .proto;  Ktor - фреймворк для создания асинхронных сервисов Kotlin (в этой статье я буду использовать Kotlin - но бэкэнд может быть написан на любом другом языке, главное - иметь в фреймворке возможность принимать вебсокет-соединения и желательно - генератор кода из Protobuf, эти генераторы существуют для множества языков).  Все сообщения, которыми обмениваются клиент и сервер, описываются в одном месте:  Из этих файлов можно сразу сгенерировать код и для сервера и для клиента;  В них же можно вести документацию, оставляя комментарии;  Описание протокола можно легко хранить в любой VCS, т.к. по сути это просто текстовые файлы;  Можно точно знать что обе стороны будут сериализовывать и десериализовывать сообщения одинаково - генерация кода обеспечит отсутствие забытых полей и каких-либо других ошибок свойственных при ручном чтении/записи.  Protobuf - бинарный формат, и в отличие от, например, JSON - будет использоваться меньший объем трафика для передачи одного и того же объема данных;  Protobuf позволяет добавлять новые поля, не ломая совместимость со старыми клиентами.  Совсем явных минусов я назвать не могу - но: Сериализация/десериализация в protobuf будет проходить медленнее, чем, например, прямая запись в буфер в собственном формате;  Код, который генерируется из protobuf часто получается довольно громоздким и, соответственно, имеет определенную стоимость в рантайме.  Готовый протофайл можно посмотреть здесь: game.proto Создадим пустой .proto-файл, например - game.proto. В этом файле нужно описывать все сообщения, которыми будут обмениваться сервер и клиент (если сообщений будет много - можно выносить их в отдельные файлы и импортировать из основного). В этот файл следует сразу прописать опции для парсера и кодогенератора: А теперь определимся, какие сообщения нам вообще нужны: Это сообщения, которые клиент отправляет серверу - часто они будут по сути RPC вызовами с ответом в сообщении Cl**Result от сервера. Здесь был бы очень кстати gRPC - возможно в будущем с помощью godobuf можно будет делать и gRPC-сервисы. Но пока: Таким образом получаем следующую структуру: Все возможные сообщения от клиента обернуты в ClMessage;  Все возможные сообщения от сервера обернуты в SvMessage;  Ответы на вызовы клиента обернуты в поле result - сообщение ClMessageResult.  Лично для себя я определилась с такой naming convention: ClFooBar для сообщений, которые шлёт клиент серверу;  SvFooBar для сообщений, которые шлёт сервер клиенту, за исключением:  ClFooBarResult для передачи результата обработки ClFooBar.  Для начала нужно создать проект и основную сцену (обычную пустую 2D сцену). Плагин можно скачать здесь: https://github.com/oniksan/godobuf, инструкция по установке есть в README репозитория - нужно распаковать себе в проект папку addons.  Для соединения с сервером используется класс WebSocketClient (документация по WebSocketClient). Работать с ним просто: устанавливаем обработчики событий, а затем указываем URL сервера для соединения. Создадим скрипт, который будет открывать соединение на корневой ноде сцены - там же будут заготовки для функций обработки событий от вебсокета: Здесь всё очень просто! Во вкладке Godobuf указываем путь до нашего proto-файла и путь куда будет сохранен получившийся скрипт:  Если в прото-файле нет ошибок, то мы увидим сообщение об успешной компиляции и в папке проекта появится нужный скрипт.  В своей сцене я сделала отдельный контейнер для сообщений и два поля - для ввода текста и имени. Сигналы pressed от кнопок Send и Rename я подключила в скрипт на корневой ноде. Также для вывода сообщений на сцену я сделала функцию show_message, она просто добавляет новый объект Label с текстом сообщения в VBoxContainer, который располагает объекты вертикально. После создания этих полей ввода и кнопок нужно сделать так чтобы они что-то делали. Сперва загрузим получившиеся биндинги в наш скрипт: Теперь можно добавить код создания ClMessage при нажатии на кнопки Send/Rename: Самое интересное - сама отправка сообщения по вебсокету происходит в функции send_msg. Вот она: Функция to_bytes (как и весь класс ClMessage) сгенерированы плагином godobuf - и никаких операций с буферами руками нам делать не надо! Теперь наш клиент может отправлять сообщения - но он ещё не способен их принимать. Сейчас мы это исправим, добавив обработку входящих сообщений - этот блок кода будет объемнее, но по большей части код там повторяется.  Важно периодически вызывать poll на WebSocketClient, иначе сигналы о входящих сообщениях никогда не придут. В данном случае это происходит в _process После этого остается только заполнить логику обработки конкретных сообщений - но сначала добавим хранилище известных клиенту имён и переменную для ID текущего клиента: И обработку одного из возможных сообщений с сервера: Остальные блоки в этом if/elif примерно одинаковы. Получившийся код для каждого отдельного сообщения можно посмотреть на GitHub: Main.gd Серверная часть очень подробно разбираться не будет. Её можно написать на любом языке - и в данном случае это будет Kotlin с фреймворком Ktor. Напоминаю, что весь код этого проекта доступен на GitHub - сервер там достаточно простой. Но в двух словах выделю основные моменты моей   сервера: Основной gradle-проект состоит из двух модулей: server - сам сервер;  proto - прото-файлы и сгенерированные из них биндинги:  Стоит обратить внимание на плагин com.google.protobuf, зависимость com.google.protobuf:protobuf-java  и их конфигурацию;  В процессе сборки этого модуля генерируются классы, позволяющие сериализовывать/десериализовывать сообщения описанные в прото-файле.  Сам сервер работает по простому алгоритму - хранит открытые соединения, broadcast-канал для уведомлений и сообщений, принимает сообщения от клиента пока это возможно и отвечает на его запросы. Получившийся Godot-проект может работать как из браузера, так и с нативных сборок под Linux/Windows/Android и т.д. - всё взаимодействие клиента с сервером описывается в одном месте и в протокол легко вносить изменения. В этой статье рассматриваются только самые основы этого метода. Помимо того что написано здесь, будет важно реализовать: Обработку ошибок (например, передавать отдельное сообщение error в ClMessageResult);  Обработку потери/восстановления соединения;  Многое другое.  Я надеюсь эта статья оказалась полезной и помогла разобраться в Godot, вебсокетах и protobuf. Backend-разработчик