В настоящее время я занимаюсь разработкой сетевой библиотеки для Unity, поскольку интегрированная библиотека - это не совсем то, что нужно нашей игре.
Некоторые вещи, такие как слишком большая абстракция и множество ограничений, заставили нас придумать собственное решение.
Вся связь происходит поверх стандартных .Net Sockets.
Система, которую мы разработали, в основном построена с использованием внутренних классов и структур, которые не нуждаются в дальнейшем объяснении.
Важным является наш ShatNetTransportLayer
класс.
Это статический класс, который внутренне использует два буфера, один для приема данных, один для передачи.
Другой класс более высокого уровня работает во многом как «сетевой gc».
Сообщения помещаются в список отправки, который регулярно проверяется и освобождается после отправки всех сообщений. Это, конечно, упрощено, на самом деле есть проверки для разных каналов и т. Д.
Пока что до настройки.
Важно знать следующее.
Каждый объект в игре, который должен быть подключен к сети, будет содержать ShatNetIdentity
.
Это основной класс, который регистрирует сетевые объекты на сервере и поддерживает их синхронизацию на каждой стороне клиента.
Хотя это еще не полностью реализовано, нам нужно преодолеть еще одну проблему.
Планируется, что каждый ShatNetIdentity
будет основным компонентом сетевого игрового объекта, так что любой ShatNetBehaviour
сможет получить к нему доступ через игровой объект.
ShatNetBehaviour
- это класс, производный от monobehaviour, который является классом Unity по умолчанию для работы с элементами сцены.
Единственное, что он добавляет, это возможность получить ShatNetIdentity
, связанный с объектом, к которому прикреплен скрипт.
Теперь идет решающая часть:
Поскольку в нашей команде есть разработчики, которые никогда не касались сетевой системы, нам требуется до аннотация синхронизации переменных, возможно, даже удаленных вызовов методов.
Внутренне все, что будет отправлено, - это сообщение с максимальным размером 128 байт.
Частью этого является MessageType, целое число без знака длиной 1 байт, которое представляет тип сообщения, такой как переменная синхронизация, вызовы сообщения, отключенные проигрыватели и тому подобное.
Вторым является идентификатор отправителя, представленный 2Byte.
Отдых это само сообщение.
Существует больше вовлеченных, но это ядро.
Это еще предстоит полностью определить, но вы поняли идею.
Эти сообщения записываются в буфер и отправляются, когда отправка запланирована или получена, когда произошло событие приема.
Назад, когда мы использовали собственный UNet Unity, вы могли просто добавить атрибут с именем SyncVar
к любому полю класса, которое является частью объекта, к которому прикреплен ShatNetIdentity
.
Был также способ определить функцию обратного вызова, если значение изменилось.
Ссылка: https://docs.unity3d.com/ScriptReference/Networking.SyncVarAttribute.html
* +1037 * Пример:
//When this is not our client, this value will be updated automatically across the net
[SyncVar(hook="OnHealthChanged")]
int health;
void OnHealthChanged()
{
doStuff();
}
Итак, мой вопрос, есть ли способ реализовать это самостоятельно?
Мы имели в виду имена NetVar и NetHook.
Чтобы синхронизировать переменную по сети, нужно просто написать
[NetVar]
private int health;
void TakeDamage(int amount)
{
//Updates health for all clients
health-=amount;
}
Чтобы это произошло, должно произойти несколько вещей.
- Когда создается новый ShatNetIdentity, зарегистрируйте его на сервере.
- Зарегистрируйте каждую переменную каждого класса, которая прикреплена к игровому объекту, с помощью
ShatNetIdentity на эту личность.
Вероятно, это невозможно, потому что уровни доступа? Использовать открытые свойства внутри атрибута?
- Когда приемный буфер заполнен, проверьте сообщения для типов обновления переменных, найдите индекс ShatNetIdentity и указанную переменную.
- Обновите эту переменную на каждом клиенте
Так что мне нужно получить подсказку:
- как ссылаться на частные переменные в ShatNetIdentity (конечно, это может быть любой класс). Поддерживаемые типы - это базовые типы, больше ничего, но должен быть один атрибут, который охватывает их все. Ничего подобного NetBool, NetInt ...
- Как мне ссылаться на функции обратного вызова с атрибутом и запускать их при изменении значения поля.
- Какие еще опции я могу использовать.
Идеи, которые у меня были до сих пор:
Создание сетевых базовых типов для каждого базового типа.
Это выглядело бы некрасиво и не помогло бы найти простой код.
Надеюсь, я все объяснил достаточно хорошо. Если нужна какая-то деталь, просто стреляйте.
Большое спасибо за вашу помощь.
Edit:
Похоже, SynVar - это просто тег для генерируемого кода.
http://blogs.unity3d.com/2014/05/29/unet-syncvar
Как это можно сделать?