-
Notifications
You must be signed in to change notification settings - Fork 1
Network
Синглтон Network
предоставляет пользователям возможность отправлять и принимать пакеты по сети.
PacketRegistry - это хранилище известных типов пакетов. Он позволяет сопоставить ID типа пакета с его непосредственным типом. Подобное сопоставление позволяет экономить ценные байты, позволяя не передавать по сети еще и полное имя пакета при каждой его отправке, ограничиваясь всего лишь числом.
Перед тем как создать сервер или подключиться к игре необходимо просканировать все загруженные сборки и найти в них типы пакетов. Для этого нужно выполнить следующий код где-то перед началом работы с сетью:
PacketRegistry.ScanPackets();
После сканирования и регистрации типов пакетов можно переходить к сети.
Для начала работы класс Network
предоставляет 2 метода:
-
CreateServer(int port)
- создает локальный сервер и слушает входящие подключения на указанном порту. Помимо сервера будет инициализирован локальный клиент. -
ConnectToRemoteServer(string host, int port)
- подключается к серверу, инициализируя локальный клиент и удаленный сервер.
Первое, что необходимо сделать после подключения к серверу - синхронизировать PacketRegistry клиента и сервера, так как ID на обеих сторонах могут различаться.
Это делается автоматически при подключении, поэтому первым отправленным по сети пакетом всегда будет RegistrySynchronizationPacket
, который ВСЕГДА должен иметь ID 0 в PacketRegistry. После того, как типы пакетов будут синхронизированы, на стороне клиента, будет вызвано статическое событие SynchronizationCompleted
в классе PacketRegistry
, сигнализирующее о том, что теперь можно слать пакеты на сервер.
Note
Событие SynchronizationCompleted
не имеет непосредственного отношения к шине событий. Это обычный делегат, объявленный прямо в классе PacketRegistry
.
Note
При создании локального сервера, локальный клиент также будет создан, но так как локальный клиент не может буквально подключиться к локальному серверу, и использует при этом тот же PacketRegistry, что и локальный сервер, необходимо вручную вызвать обработчик события SynchronizationCompleted
, чтобы сэмулировать процесс "подключения" локального клиента.
Чтобы получить доступ к сетевому функционалу Godot, используемому классом Network, можно обратиться к свойствам Network.Api
и Network.Peer
Класс Network имеет несколько свойств, позволяющих определять его текущее состояние.
-
Network.IsClient
- будет равенtrue
, если инициализирован локальный клиент -
Network.IsServer
- будет равенtrue
, если инициализирован локальный сервер -
Network.MyPeerId
- вернет ID пира, используемый MultiplayerApi. Если был запущен сервер, то MyPeerId ВСЕГДА будет равен 1, иначе - случайному числу. -
Network.MyPlayerId
- вернет ID игрока. Если был запущен сервер, то MyPlayerId ВСЕГДА будет равен 0, иначе -MyPeerId
.
При использовании CreateServer(int port)
оба свойства станут true
.
При использовании ConnectToRemoteServer(string host, int port)
IsClient будет true
, а IsServer - false
Network.MyPlayerId
особенно важен при работе с пакетами на стороне локального клиента, так как отправка пакетов локальному клиенту происходит прямым вызовом метода вместо RPC, в результате чего Api.GetRemoteSenderId()
вернет 0 (что значит, что метод был вызван не по RPC).
Для отправки пакетов предоставляется 3 основных метода:
-
SendPacketToClients(AbstractPacket packet, bool reliable)
- Отправит указанный пакет всем подключенным клиентам. Может быть вызван ТОЛЬКО еслиNetwork.IsServer == true
. -
SendPacketToServer(AbstractPacket packet, bool reliable)
- Отправит указанный пакет на сервер. Может быть вызван ТОЛЬКО еслиNetwork.IsClient == true
. -
SendPacketToPeer(long id, AbstractPacket packet, bool reliable)
- Отправит указанный пакет клиенту с указаннымid
. Может быть вызван ТОЛЬКО еслиNetwork.IsServer == true
.
Во всех трех методах имеется параметр reliable
. Он отвечает за гарантию доставки пакета клиенту.
- true - пакет будет гарантированно доставлен.
- false - никаких гарантий.
Не все пакеты требуют того, чтобы быть отправленными здесь и сейчас. Обычно это касается пакетов, которые не обязательно должны быть доставлены получателю и могут быть потеряны.
Тип PacketBuffer
может записывать очередь пакетов, которые затем будут отправлены все разом в удобное время (напрример, пакеты перемещения персонажей. Они отправляются несколько раз в секунду и могут быть потеряны по пути. Идеально чтоб накопить их и отправить все вместе).
Для отправки буферизованых пакетов можно сипользовать 2 метода:
-
SendPacketsToServer(PacketBuffer buffer)
- отправит все пакеты из буфера на сервер. Под капотом вызывает SendPacketToServer, так что ограничения SendPacketToServer здесь так же актуальны. -
SendPacketsToClients(PacketBuffer buffer)
- отправит все пакеты из буфера клиентам. Под капотом вызывает SendPackSendPacketToClientstToServer, так что ограничения SendPacketToClients здесь так же актуальны.
Класс Network имеет 2 события, вызываемые при получении пакета.
-
Network.ReceivedRawPacket
- содержит в себе ID отправителя и не десериализованный текст пакета. -
Network.ReceivedPacket
- содержит в себе десериализованный пакет.
Note
Десериализованные пакеты имеют свойство Sender
, содержащее информацию об отправителе.
Note
По умолчанию Network не имеет прямой связи с шиной событий, но так как все пакеты по умолчанию являются подтипами AbstractPacket
, который в свою очередь является собтием, ничто не мешает вам сделать так:
Network.ReceivedPacket += (packet) => EventBus.Publish(packet);
где-нибудь в процессе инициализации игры.
После этого можно можно обрабатывать пакеты как события (см. EventBus)
Пакетами будут считаться классы, которые:
- являются подтипами
AbstractPacket
- имеют конструктор по умолчанию
- помечены атрибутом
[GamePacket]
- последнее не касается пакета RegistrySynchronizationPacket
Note
При выборе имени пакета рекомендуется добавлять в конце слово Packet
При создании пакета также необходимо явно определить его поведение по умолчанию. Для этого в типе AbstractPacket
объявлены 2 абстрактных свойства, которые необходимо переопределить для каждого нового типа пакета:
-
bool IsBufferable { get; }
- еслиtrue
, то пакет можно (рекомендуется) буферизовать перед отправкой, иначе рекомендуется отправлять немедленно. -
bool IsReliable { get; }
- еслиtrue
, то пакет рекомендуется гарантированно доставлять получателю.
Эти свойства сами по себе не гарантируют указанного поведения при отправке (за исключенирем буферизации, где при отправке будет учтено свойство IsReliable), но могут быть использованы при написании сервисов и хелперов.
В статическом классе KludgeBox.Net.DefaultNetworkSettings
определены настройки по умолчанию, которые на самом деле нигде не используются (пока что), но вот вам его содержимое:
public static class DefaultNetworkSettings
{
public const int DefaultMaxPlayers = 4;
public const int ServerPeerId = 1;
public const int LocalPeerId = 0;
public const string Host = "localhost";
public const int Port = 25564;
}