Important
В проекте используется .NET 8.
Перед тем как начать разработку, ознакомься с Wiki.
Note
Чтобы в Godot настроить интеграцию с Rider, необходимо зайти в Editor -> Editor Settings -> Dotnet -> Editor. В списке External Editor выбрать JetBrains Rider и очистить значение Custom Exec Path Args.
Note
Для более быстрого дебага игру можно запускать с различными параметрами командной строки.
--server сразу запускает игровой сервер.
--auto-connect-ip 127.0.0.1 запускает клиент и автоматически подключается к серверу по указанному адресу (в данном случае 127.0.0.1).
--auto-connect-port 25566 запускает клиент и автоматически подключается к серверу по указанному адресу и указанному порту (в данном случае 25566). Работает только вместе с --auto-connect-ip.
Для быстрого и удобного тестирования рекомендуется настроить в Rider следующие конфигурации запуска:
- Тип:
.Net Executable. Название:Server. Program Arguments:--server. - Тип:
.Net Executable. Название:Autoconnect (1). Program Arguments:--auto-connect-ip 127.0.0.1. - Тип:
.Net Executable. Название:Autoconnect (2). Program Arguments:--auto-connect-ip 127.0.0.1. - Тип:
Multi-Launch. Название:Fast-test (1 client). Tasks:Server, Autoconnect (1). - Тип:
Multi-Launch. Название:Fast-test (2 clients). Tasks:Server, Autoconnect (1), Autoconnect (2).
Проект разделен на несколько модулей, каждый из которых отвечает за отдельную сцену или функциональность.
- Scenes: Содержит игровые сцены и их обработчики
Root: Самая верхнеуровневая сцена. Вызывает инициализцию других систем, содержит в себе сцену Game или MainMenu, а также ссылку на PackedScenesContainer.Game: Сцена с игрой (не меню). Отвечает за инициализацию сети, подключение, управление общеигровым состоянием, содержит в себе сцену SafeWorld или BattleWorld.PackedScenesContainer: Контейнер, который содержит ссылки на все прототипы сцен в игре (тип PackedScene).Screen: Содержит набор сцен с интерфейсом пользователя (HUD, меню, экран загрузки, консоль сервера).World: Содержит верхнеуровневые сцены SafeWorld и BattleWorld, а также все игровые объекты и их логику.
- Scripts: Содержит вспомогательный код, не содержит сцены (tscn файлы)
Content: Содержит контейнеры со ссылками на ресурсы игры (музыка, звуки, текстуры, частицы)KludgeBox: Библиотека с наработками из других проектов (шина событий, перехват сетевых пакетов, логеры, таймеры и т.п.)Utils: Вспомогательные классы (обработка ошибок, работа с аргументами командной строки) и код вспомогательных нод, без tscn файлов (нода с системой пинга, нода-таймер)
Сцены и обработчики хранятся в одной папке. Например, в папке ClientRoot хранится ClientRoot.tscn (сцена) и ClientRoot.cs (обработчик).
Обработчики могут быть разбиты на несколько partial классов по функционалу. Например, класс ClientRoot разбит на файлы ClientRoot.cs, ClientRootSceneContainer.cs, ClientRootSingleton.cs.
Сцены и обработчики для клиента и сервера хранятся в соседних папках. Например:
- Root: Общая папка со всеми файлами связанными со сценой Root
- ClientRoot: Папка с файлами сцены
Rootдля клиента.ClientRoot.tscnClientRoot.csClientRootSceneContainer.csClientRootSingleton.cs
- ServerRoot: Папка с файлами сцены
Rootдля сервера.ServerRoot.tscnServerRoot.csServerRootSceneContainer.csServerRootSingleton.cs
RootService.cs: Статичный класс с общими функциями, которые используются и на клиенте и на сервере.
- ClientRoot: Папка с файлами сцены
Сетевые пакеты объявляются в partial классе в файле с суффиксом Packets в том же классе, где они обрабатываются.
Например, есть пакеты, которые обрабатываются в классе ClientGame, обработчики описаны в файле ClientGameNetworkListener.cs. В файле ClientGamePackets.cs описан класс ClientGame, в котором находятся вложенные классы пакетов.
Root/StarterScene- Является точкой входа и определяет, будет ли запускаться
ClientRootилиServerRootсцена.
- Является точкой входа и определяет, будет ли запускаться
ClientRoot/ServerRoot- Вызывает инициализацию других систем в
Init()и запускает игру вStart(). - Является контейнером для сцен
MainMenuMainSceneиClientGame/ServerGame.
- Вызывает инициализацию других систем в
ClientGame/ServerGame- Инициализирует сеть и осуществляет подключение.
- Является контейнером для сцен типа
World.
- Завершение работы клиента
- Завершение работы клиента осуществляется при помощи вызова функции
ClientRoot#Shutdown(). - При любом способе уничтожения сцены
ClientGame(включая завершение игры), автоматически будет вызванClientGame#ServerShutdowner. И если данный клиент является хостом (запускал серверный процесс), то будет вызвана функцияOS.Kill()для завершения работы сервера.
- Завершение работы клиента осуществляется при помощи вызова функции
- Завершение работы сервера
- Завершение работы сервера осуществляется при помощи вызова функции
ServerRoot#Shutdown(). - Дополнительно на сервере каждые несколько секунд запускается проверка в
ServerGame#ClientDeadChecker. И если в ОС не будет найден процесс клиента игры, который запустил данный сервер, то сервер автоматически завершит свою работу.
- Завершение работы сервера осуществляется при помощи вызова функции
- Root: Общая папка со всеми файлами связанными со сценой
Root- ClientRoot: Папка с файлами сцены
Rootдля клиента.ClientRoot.tscn: Техническая сцена без игровых объектов.ClientRoot.cs: Имеет ссылки наPackedScenesContainer(клиентская версия),WorldEnvironmentи настройки игрока. При запуске инициализирует все необходимые сервисы, анализирует параметры командной строки и запускает игру.ClientRootSceneContainer.cs: Отвечает за смену меню (MainMenuMainScene) на игру (ClientGame) и обратно.ClientRootSingleton.cs: Реализация паттерна singleton для доступа к классуClientRootиз любой точки проекта.
- ServerRoot: Папка с файлами сцены
Rootдля сервера.ServerRoot.tscn: Техническая сцена без игровых объектов.ServerRoot.cs: Имеет ссылки наPackedScenesContainer(серверная версия),Console. При запуске инициализирует все необходимые сервисы, анализирует параметры командной строки и запускает сервер.ServerRootSceneContainer.cs: Отвечает за создание дочерней сцены (ServerGame).ServerRootSingleton.cs: Реализация паттерна singleton для доступа к классуServerRootиз любой точки проекта.
- StarterScene: Папка с файлами сцены
StarterScene. Общая для клиента и сервера.StarterScene.tscn: Техническая сцена без игровых объектов. Сцена выбрана в качестве стартовой сцены в Godot.StarterScene.cs: Имеет ссылки на прототипы сценClientRootиServerRoot. В зависимости от параметров командной строки заменяет загруженнуюStarterScene.tscnнаClientRoot.tscnилиServerRoot.tscn.
RootService.cs: Статичный класс с общими функциями, которые используются и на клиенте и на сервере. Отвечает за инициализацию сервисов использующихся и на клиенте и на сервере.
- ClientRoot: Папка с файлами сцены
- Game: Общая папка со всеми файлами связанными со сценой
Game- ClientGame: Папка с файлами сцены
Gameдля клиента.ClientGame.cs: Запускает функции инициализации из другихpartialклассовClientGame.ClientGameSceneContainer.cs: Отвечает за переключение междуBattleWorldMainSceneиSafeWorldMainScene.ClientGameBaseNetwork.cs: Отвечает за инициализацию сети и подключение к серверу.ClientGameNetworkListener.cs: Отвечает за обработку сетевых пакетов с сообщениями верхнего уровня (начало игры, смена мира и т.п.).ClientGamePackets.cs: Место хранения всех сетевых пакетов, которые обрабатываются в классеClientGame.ClientGameLoadingScreen.cs: Предоставляет возможность отображения загрузочного экрана.ClientGameServerShutdowner.cs: Отвечает за добавление к сценеClientGameсценыProcessShutdowner, которая завершает работу сервера при уничтожении сценыClientGame.- MainScenes: Папка с файлами сцен типа
WorldMainSceneдля клиента. Такая сцена объединяет в себе сценыWorldиHud.IWorldMainScene.cs: Общий интерфейс для всех сцен типаWorldMainScene- BattleWorld: Папка с файлами сцены типа
WorldMainSceneдля боевого мира.BattleWorldMainScene.tscn: Техническая сцена без игровых объектов. Содержит сценыBattleWorldиBattleHud.BattleWorldMainScene.cs: Просто контейнер со ссылками наBattleWorldиBattleHud.
- SafeWorld: Папка с файлами сцены типа
WorldMainSceneдля безопасного мира.SafeWorldMainScene.tscn: Техническая сцена без игровых объектов. Содержит сценыSafeWorldиSafeHud.SafeWorldMainScene.cs: Просто контейнер со ссылками наSafeWorldиSafeHud.
- ServerGame: Папка с файлами сцены
Gameдля сервера.ServerGame.cs: Запускает функции инициализации из другихpartialклассовServerGame.ServerGameSceneContainer.cs: Отвечает за переключение междуServerBattleWorldиServerSafeWorld.ServerGameBaseNetwork.cs: Отвечает за инициализацию сети.ServerGameNetworkListener.cs: Отвечает за обработку сетевых пакетов с сообщениями верхнего уровня (игрок подключен, игрок отключен, игрок хочет сменить мир и т.п.).ServerGamePackets.cs: Место хранения всех сетевых пакетов, которые обрабатываются в классеServerGame.ServerGameServerShutdowner.cs: Отвечает за добавление к сценеServerGameсценыProcessDeadChecker, которая завершает работу сервера, если в ОС будет отсутствовать запущенный игровой клиент.ServerGamePlayerProfiles.cs: Контейнер с информацией об игроках. Содержит мапу с классамиServerPlayerProfile.- PlayerProfiles: Папка с информацией об игроках. В отличие от
ServerPlayerне является сценой и не удаляется вместе сServerWorldпри переключении миров.ServerPlayerProfile.cs: Класс с информацией об игроке (id, ник, уровень, характеристики и т.п.).
- ClientGame: Папка с файлами сцены
- PackedScenesContainer:
- ClientPackedScenesContainer:
ClientPackedScenesContainer.tscn: Техническая сцена без игровых объектов. Необходима, чтобы в редакторе Godot настраивать ссылки на прототипы других сцен клиента.ClientPackedScenesContainer.cs: Содержит ссылки на прототипы других сцен клиента. Получение прототипа любой сцены (для последующего создания сцены), должно начинаться отсюда.
- ServerPackedScenesContainer:
ServerPackedScenesContainer.tscn: Техническая сцена без игровых объектов. Необходима, чтобы в редакторе Godot настраивать ссылки на прототипы других сцен сервера.ServerPackedScenesContainer.cs: Содержит ссылки на прототипы других сцен сервера. Получение прототипа любой сцены (для последующего создания сцены), должно начинаться отсюда.
- ClientPackedScenesContainer:
Все сетевые пакеты имеют аннотацию [GamePacket].
Все сетевые пакеты имеют суффикс Packet и префикс SC_ или CS_. Префикс означает направление передачи (server->client или client->server). Пример наименования: CS_PlayerMovementPacket.
Стараемся наследовать сетевые пакеты от BinaryPacket. Сериализацию JSON используем только в крайних случаях (например, для вложенных коллекций кастомных классов). В идеале переделываем структуру пакета так, чтобы получилось избежать использования сериализации в JSON.
Стараемся объединить больше данных в один сетевой пакет (например, разом передать координаты нескольких юнитов).
Все сетевые обработчики имеют аннотацию [EventListener]. Всегда указываем на какой стороне мы обрабатываем пакет (например, ListenerSide.Client).
Все сетевые обработчики начинаются с префикса On и повторяют название пакета без префикса SC_ или CS_.
В название переменной сетевого пакета также убираем префикс SC_ или CS_. Пример наименования: OnChangeWorldPacket(SC_ChangeWorldPacket changeWorldPacket).
Если приходится использовать статический обработчик, то к названию в конце добавляем Listener. Например: OnChangeWorldPacketListener. Статический обработчик не должен содержать логики, а должен просто вызывать нестатический обработчик.
Стараемся использовать резолверы сетевых пакетов. В ClientGame и ServerGame заданы дефолтные резолверы: Network.SetDefaultResolver(nid => World.NetworkEntityManager.GetNode((long) nid));.
Можно делать свои кастомные резолверы. Например, в ClientGame задан резолвер: Network.AddInstanceResolver(typeof(ClientGame), id => this);
Используем ванильную версию Godot. Время хранится в double, а все координаты и углы в float.
Для большинства некритичных вещей (например, визуал и вспомогательные функции) используем float, и при расчетах просто кастим deltaTime из double к float. Для критичных вещей (например, характеристики юнитов) используем double.