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?
1 Answer 1
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".
-
\$\begingroup\$ hi, thanks for your reply. actually this is just a sample code. Of course I'm not using linq. Also, I didn't ignore the IsLittleEndian issue, it just doesn't exist in this code. Finally, I wrote a more advanced version of this system. When I prepare the codes of that system, I will upload them here and update this comment. I would like you to have a look at those codes :) \$\endgroup\$snn– snn2022年01月31日 08:23:30 +00:00Commented Jan 31, 2022 at 8:23
-
\$\begingroup\$ slightly more advanced version codereview.stackexchange.com/questions/273568/… \$\endgroup\$snn– snn2022年01月31日 09:07:33 +00:00Commented Jan 31, 2022 at 9:07
-
\$\begingroup\$ @sinanc less advanced because you're calling
SubArray
which is probably wasting memory and CPU time while creating a new array. Use offset in the original array like here. You didn't took everything from this review. In C# 8 syntax likearray[2..4]
is also possible but it creates a new array too. \$\endgroup\$aepot– aepot2022年01月31日 10:21:32 +00:00Commented Jan 31, 2022 at 10:21