Сериализация

На этой странице подробно рассказывается о сериализации, основы смотрите в разделе типы данных.

Mirror создает функции сериализации и десериализации для типов использующих Weaver. Weaver редактирует библиотеки dll после того, как unity скомпилирует их с помощью Mono.Cecil. Это позволяет Mirror иметь множество сложных функций, таких как SyncVar, ClientRpc и сериализация сообщений, без необходимости пользователю вручную все настраивать.

Правила и советы

Существуют некоторые правила и ограничения для того, что может делать Weaver. Некоторые функции усложняют работу и их трудно поддерживать, поэтому они не были реализованы. Эти функции не являются невозможными для реализации и могут быть добавлены, если на них будет высокий спрос.

  • Вы должны иметь возможность писать пользовательские функции Read / Write для любого типа, и Weaver будет использовать.

    • Это означает, что если существует неподдерживаемый тип, такой как int[][], создайте свою Read/Write функцию чтобы синхронизировать int[][] в SyncVar/ClientRpc/и т.д.

  • Если у вас есть тип, содержащий поле, которое невозможно сериализовать, вы можете пометить это поле с помощью [System.NonSerialized] и weaver будет игнорировать это

Неподдерживаемые типы

Некоторые из этих типов не поддерживаются из-за добавленной ими сложности, как упоминалось выше.

ПРИМЕЧАНИЕ: Типы в этом списке могут иметь пользовательские средства записи.

  • Неровный и многомерный массив

  • Типы унаследованные от UnityEngine.Component

  • UnityEngine.Object

  • UnityEngine.ScriptableObject

  • Универсальные типы, например MyData

    • Пользовательское Read/Write должно объявлять T, например MyData

  • Интерфейсы

  • Типы, которые ссылаются сами на себя

Встроенные функции Read Write

Mirror предоставляет некоторые встроенные функции Read/Write. Их можно найти в NetworkReaderExtensions и NetworkWriterExtensions.

Это неконкурентный список типов, которые имеют встроенные функции, проверьте классы выше, чтобы увидеть полный список.

NetworkIdentity, GameObject, Transform

netId объекта отправляется по сети, и объект с таким же netId возвращается с другой стороны у клиента или сервера. Если netId равно нулю или объект не найден, тогда будет возвращено null.

Сгенерированные функции Read Write

Weaver будет генерировать функции Read Write для

  • Классов или структур

  • Enums

  • Массивов

    • например int[]

  • ArraySegments

    • например ArraySegment

  • Lists

    • например List

Классы и структуры

Weaver будет Read/Write каждое общедоступное поле в типе, если только поле не помечено знаком [System.NonSerialized]. Если в классе или структуре есть неподдерживаемый тип, Weaver не сможет выполнить функции чтения/записи для него.

ПРИМЕЧАНИЕ: Weaver не проверяет свойства

Enums

Weaver будет использовать базовый тип перечисления для их чтения и записи. По умолчанию это int.

К примеру Switch будет использовать тип byte Read/Write функций чтобы сериализоваться

public enum Switch : byte
{
    Left,
    Middle,
    Right,
}

Collections

Weaver сгенерирует записи для коллекций, перечисленных выше. Weaver будет использовать функцию чтения/записи элементов. Элемент должен иметь функцию чтения/ записи, поэтому должен быть поддерживаемого типа или иметь пользовательскую функцию чтения / записи.

К примеру:

  • float[] является поддерживаемым типом, поскольку Mirror имеет встроенную функцию чтения / записи для float.

  • MyData[] является поддерживаемым типом, поскольку Weaver способен генерировать функцию чтения / записи для MyData

public struct MyData
{
    public int someValue;
    public float anotherValue;
}

Добавление пользовательских функций Read/Write

Read Write функции - это статические методы в виде:

public static void WriteMyType(this NetworkWriter writer, MyType value)
{
    // напишите данные MyType здесь
}

public static MyType ReadMyType(this NetworkReader reader)
{
    // прочитайте данные MyType здесь
}

Наилучшей практикой является создание функций чтения/записи extension methods таким образом, их можно вызывать как writer.WriteMyType(value).

Это хорошая идея - вызвать ReadMyType и WriteMyType таким образом, очевидно, для какого типа они предназначены. Однако название функции не имеет значения, weaver должен быть в состоянии найти ее независимо от того, как она называется.

Пример свойств

Weaver не записывает свойства, но для отправки их по сети можно использовать пользовательский writer.

Это может быть полезно, если вы хотите иметь приватный набор для своих свойств

public struct MyData
{
    public int someValue { get; private set; }
    public float anotherValue { get; private set; }

    public MyData(int someValue, float anotherValue)
    {
        this.someValue = someValue;
        this.anotherValue = anotherValue;
    }
}

public static class CustomReadWriteFunctions 
{
    public static void WriteMyType(this NetworkWriter writer, MyData value)
    {
        writer.WriteInt32(value.someValue);
        writer.WriteSingle(value.anotherValue);
    }

    public static MyData ReadMyType(this NetworkReader reader)
    {
        return new MyData(reader.ReadInt32(), reader.ReadSingle());
    }
}

Пример неподдерживаемого типа

Rigidbody является неподдерживаемым типом, поскольку он наследуется от Component. Но можно добавить пользовательский writer, чтобы он синхронизировался с помощью NetworkIdentity если тот к нему привязан.

public struct MyCollision
{
    public Vector3 force;
    public Rigidbody rigidbody;
}

public static class CustomReadWriteFunctions
{
    public static void WriteMyCollision(this NetworkWriter writer, MyCollision value)
    {
        writer.WriteVector3(value.force);

        NetworkIdentity networkIdentity = value.rigidbody.GetComponent<NetworkIdentity>();
        writer.WriteNetworkIdentity(networkIdentity);
    }

    public static MyCollision ReadMyCollision(this NetworkReader reader)
    {
        Vector3 force = reader.ReadVector3();

        NetworkIdentity networkIdentity = reader.ReadNetworkIdentity<NetworkIdentity>();
        Rigidbody rigidBody = networkIdentity != null
            ? networkIdentity.GetComponent()
            : null;

        return new MyCollision
        {
            force = force,
            rigidbody = rigidBody,
        };
    }
}

Выше приведены функции для MyCollision, но вместо этого вы могли бы добавить функции для Rigidbody и пусть weaver создаст write для MyCollision.

public static class CustomReadWriteFunctions
{
    public static void WriteRigidbody(this NetworkWriter writer, Rigidbody rigidbody)
    {
        NetworkIdentity networkIdentity = rigidbody.GetComponent<NetworkIdentity>();
        writer.WriteNetworkIdentity(networkIdentity);
    }

    public static Rigidbody ReadRigidbody(this NetworkReader reader)
    {
        NetworkIdentity networkIdentity = reader.ReadNetworkIdentity();
        Rigidbody rigidBody = networkIdentity != null
            ? networkIdentity.GetComponent<Rigidbody>()
            : null;

        return rigidBody;
    }
}

Debugging

Вы можете использовать такие инструменты, как ILSpy и dnSpy чтобы просмотреть соответствующий код после того, как Weaver изменил его. Это может помочь понять и отладить то, что делают Mirror и Weaver.

Last updated