Search code examples
c#unity-game-engineunity-networking

UNET Transport Level API Efficient Message Handling and Types


Along with a friend of mine, we have started development of a multiplayer game utilizing the Transport Level API (UNET LLAPI?) available with the Unity Game Engine.

Because of the need to have upto a hundred concurrent users in the view range of other players I was wondering what is the most efficient way to send messages about the player position, rotation, etc.

So far, adapting from the tutorial (1) on Youtube we were able to set up a system where only the positions of the different moving players are updated. However even with only 5 players moving at the same time the position updates get super delayed on the different clients.

I believe this is due to the string variable type that is used for the messages of the different data. Therefore my main question would be how do I utilize Unity's Transport Level API Data Events at maximum efficiency per message (in this case lets just say for position updates where movement is possible in any direction of the 3d space (x,y,z))

Here is the code that we have for the server script... Just like in the tutorial before calling the correct function every message string is split with appropriate delimiters separating the arguments that are received from the client. The client has a similar message receiving system with a different set of functions. The code below code is of course in Update function of the Server script.

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;
    }

References: 1. https://www.youtube.com/watch?v=qGkkaNkq8co (adapted UNET tutorial)


Solution

  • NetworkTransport.Receive uses a queue, and pops one item at a time.

    Instead of directly executing it in the update, try to wrap it in a do while, which should improve the performance

    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);
    

    source