UNET Transport Level API Эффективная обработка сообщений и типы

Вместе с моим другом мы начали разработку многопользовательской игры с использованием API транспортного уровня (UNET LLAPI?), доступного с игровым движком Unity.

Из-за необходимости иметь до сотни одновременных пользователей в поле зрения других игроков, мне было интересно, как наиболее эффективно отправлять сообщения о позиции игрока, его вращении и т. д.

До сих пор, адаптируя учебник (1) на Youtube, мы смогли настроить систему, в которой обновляются только позиции разных движущихся игроков. Однако даже если одновременно перемещаются только 5 игроков, обновления позиций на разных клиентах сильно задерживаются.

Я считаю, что это связано с типом строковой переменной, которая используется для сообщений различных данных. Поэтому мой главный вопрос будет заключаться в том, как использовать события данных API транспортного уровня Unity с максимальной эффективностью для каждого сообщения (в данном случае скажем просто для обновлений позиции, когда движение возможно в любом направлении трехмерного пространства (x, y, z))

Вот код, который у нас есть для скрипта сервера... Как и в туториале, перед вызовом правильной функции каждая строка сообщения разбивается соответствующими разделителями, разделяющими аргументы, полученные от клиента. В клиенте аналогичная система приема сообщений с другим набором функций. Приведенный ниже код, конечно же, находится в функции обновления сценария сервера.

NetworkEventType recData = NetworkTransport.Receive(out recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);
    switch (recData)
    {
        case NetworkEventType.Nothing:
            break;
        case NetworkEventType.ConnectEvent:
            Debug.Log("Player " + connectionId + " has connected");
            OnConnection(connectionId);
            break;
        case NetworkEventType.DataEvent:
            string msg = Encoding.Unicode.GetString(recBuffer, 0, dataSize);
            Debug.Log("Receving from " + connectionId + " : " + msg);
            string[] splitData = msg.Split('|');

            switch (splitData[0])
            {
                case "NAMEIS":
                    OnNameIs(connectionId, splitData[1]);
                    break;

                case "MYPOSITION":
                    OnMyPosition(connectionId, float.Parse(splitData[1]), float.Parse(splitData[2]), float.Parse(splitData[3]));
                    break;

                case "MOVESELECT":
                    OnMoveSelect(connectionId, bool.Parse(splitData[1]), new Vector3(float.Parse(splitData[2]), float.Parse(splitData[3]), float.Parse(splitData[4])));
                    break;
                case "NEWPLAYERSTARTED":
                    OnNewPlayerStarted(connectionId);
                    break;
                case "POSITIONTOANOTHER":
                    OnPositionToAnother(connectionId, float.Parse(splitData[1]), float.Parse(splitData[2]), float.Parse(splitData[3]), int.Parse(splitData[4]));
                    break;
                default:
                    Debug.Log("invalid Message : " + msg);
                    break;
            }
            break;
        case NetworkEventType.DisconnectEvent:
            Debug.Log("Player " + connectionId + " has disconnected");
            OnDisconnection(connectionId);
            break;
        case NetworkEventType.BroadcastEvent:

            break;
    }

Ссылки: 1. https://www.youtube.com/watch?v=qGkkaNkq8co (адаптированное руководство по UNET)


person makrasnov100    schedule 07.06.2018    source источник


Ответы (1)


NetworkTransport.Receive использует очередь и извлекает по одному элементу за раз.

Вместо того, чтобы выполнять его напрямую в обновлении, попробуйте обернуть его во время выполнения, что должно улучшить производительность.

int recHostId;
int connectionId;
int channelId;
int dataSize;
byte error;
NetworkEventType recData = NetworkEventType.Nothing;
do {
    recData = NetworkTransport.Receive (out recHostId, out connectionId, out channelId, workingBuffer, workingBuffer.Length, out dataSize, out error);
    if (recData == NetworkEventType.Nothing) {
        break;
    }
    byte[] recBuffer = new byte[dataSize];

    if (dataSize > 0) {
        Buffer.BlockCopy (workingBuffer, 0, recBuffer, 0, dataSize);
    }

    // Switch statement
} while (recData != NetworkEventType.Nothing);

источник

person MX D    schedule 07.06.2018
comment
Циклический подход решил нашу проблему, спасибо! Единственное изменение, которое я сделал, это объявить recData с помощью NetworkTransport.Receive перед началом цикла и использовать цикл while вместо do-while. Это позволило избавиться от второй проверки на отсутствие сообщения внутри цикла. Обратите внимание, что нам также нужно было повторно объявить recData со следующим сообщением в конце блока while, чтобы избежать бесконечного цикла. - person makrasnov100; 08.06.2018