1
\$\begingroup\$

I I'm trying to make an multiplayer game using golang and unity. Golang server side checking units on scene(like a character move). It also sends the information (position, health) of the units on the scene to the Unity 20 times per second. a unit contains 15 bytes of information. there is an average of 10 units in a scene. So golang sends Unity a byte array of size 150(10*15) 20 times per second.

my question is to make this byte array meaningful on unity side with the best performance.

private void UdpFrameHandle()
{
    // _recieveData -> packet head(2 byte) + units data(150 byte)
    var pureData = _recieveData.packet.Skip(2).Take(_recieveData.packet.Count()).ToList();

    // find unit count
    var unitCount = pureData.Count() / 15;

    // parse units
    for (int i = 0; i < unitCount; i++)
    {
        var unitInfo = ByteToUnitNetwork(pureData.Skip(15 * i).Take(15).ToList());
        FrameManager.SendDataToView(unitInfo.ViewId, unitInfo);
    }
}

protected UnitNetworkDto ByteToUnitNetwork(List<byte> arr)
{
    var viewId = BitConverter.ToInt16(arr.Take(2).ToArray(), 0);
    float x = BitConverter.ToSingle(arr.Skip(2).Take(4).ToArray(),0);
    float z = BitConverter.ToSingle(arr.Skip(6).Take(4).ToArray(),0);
    int health = BitConverter.ToInt16(arr.Skip(10).Take(2).ToArray(), 0);
    int teamType = arr.Skip(12).Take(1).First();
    int targetViewId = BitConverter.ToInt16(arr.Skip(13).Take(2).ToArray(), 0);

    return new UnitNetworkDto
    {
        ViewId = viewId,
        X = x,
        Z = z,
        Health = health,
        TeamType = teamType,
        TargetViewId = targetViewId
    };
}

this is my code. do you think there is a better way. Or do you have any suggestions?

\$\endgroup\$
1
  • \$\begingroup\$ Did I answer the question? \$\endgroup\$
    – aepot
    2 days ago
0
\$\begingroup\$

First of all, use array instead of list. Every time you know the data size, use array instead of list.

Stop instantiating lot of new arrays, it's very slow. Use offset instead.

This one arr.Skip(12).Take(1).First() looks really killing. Why not arr[13]?

Also Int16 is short not int. Use matching types.

Let's assume that _recieveData.packet is byte[].

private void UdpFrameHandle()
{
    int unitCount = (_recieveData.packet.Length - 2) / 15;
    
    for (int i = 0; i < unitCount; i++)
    {
        var unitInfo = ByteToUnitNetwork(_recieveData.packet, i * 15 + 2);
        FrameManager.SendDataToView(unitInfo.ViewId, unitInfo);
    }
}

protected UnitNetworkDto ByteToUnitNetwork(byte[] arr, int offset)
{
    short viewId = BitConverter.ToInt16(arr, offset);
    float x = BitConverter.ToSingle(arr, offset + 2);
    float z = BitConverter.ToSingle(arr, offset + 6);
    short health = BitConverter.ToInt16(arr, offset + 10);
    byte teamType = arr[13];
    short targetViewId = BitConverter.ToInt16(arr, offset + 14);

    return new UnitNetworkDto
    {
        ViewId = viewId,
        X = x,
        Z = z,
        Health = health,
        TeamType = teamType,
        TargetViewId = targetViewId
    };
}

Also BitConverter isn't safe to use because its numbers format depends on CPU architecture. Check BitConverter.IsLittleEndian before use. If available, use BinaryPrimitives instead.

Also always keep in mind when you're thinking of performance: "Linq is slow".

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.