Skip to content

Severe latency and other issues in ReceiveMessagesOnChannel #698

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
GhettoScouser opened this issue Apr 6, 2025 · 3 comments
Closed

Severe latency and other issues in ReceiveMessagesOnChannel #698

GhettoScouser opened this issue Apr 6, 2025 · 3 comments

Comments

@GhettoScouser
Copy link

Sorry if this is the wrong place but i'm pretty much out of options.

I have a project that was based on ENet and worked flawlessly, however I wanted to move to a system that didn't require players to open ports. I figured that since I would be releasing on steam I would use Steams P2P system. I'm having a terrible time using steamworks and I am starting to think I was woefully wrong about my choice.

My biggest issue is sending and receiving packets.
I can send a simple packet, receive it and process it and it seems to work instantly. However when I try to send a tick based stream of packets it all goes to hell. For starters, the information that comes through seems to be in batches even though on client side I have used NoHagle and NoDelay, the timestamps on the debug log for the outbound packets are consistent as I would expect. Moreover, there's a countable 5+ second delay on this stream and combined with the "batches" im getting makes it comedicaly unusable. Lastly, while this stream of packets are coming in, any packets sent of a different nature simply never make it through (I assume should move these to a different channel but that's not the issue at this point)

I'm fairly new to networking, and have 0 experience in Cpp so its a miracle I got anything working, Ill put some abridged code and hope that the problem is obvious and solvable. Failing that Ill have to look into other solutions.

Client packing + sending stream
This code is ran at 30TPS

public static byte[] PackRealtime(RigidBody player)
    {
        Int16 type = 6;
        UInt64 ID = MyID.m_SteamID;

        float X = player.Position.X;
        float Y = player.Position.Y;
        float Z = player.Position.Z;
        
        byte[] bytes = new byte[65535]; // I know allocating this many bites is probably not ideal but I cant see 50kb being an issue
        BinaryWriter binaryWriter = new BinaryWriter(new MemoryStream(bytes), Encoding.ASCII);
        
        binaryWriter.Write(type);
        binaryWriter.Write(ID);
        binaryWriter.Write(X);
        binaryWriter.Write(Y);
        binaryWriter.Write(Z);

        return bytes;
    }

These bytes are passed to the SendMessage function, the TargetList only has the server (The server has a list of all players so I can use 1 function for both direct and broadcast)

static void SendMessage(byte[] message, ref List<SteamNetworkingIdentity>TargetList) // Internal
    {
        Debug.Log($"Sending message to list size {TargetList.Count}");
        
        for (int i = 0; i < TargetList.Count; i++)
        {
            var Target = TargetList[i];
            
            SendBuffer = Marshal.AllocHGlobal(message.Length);
        
            try
            {
                Marshal.Copy(message, 0, SendBuffer, message.Length);
                SteamNetworkingMessages.SendMessageToUser(ref Target, SendBuffer, Convert.ToUInt16(message.Length), Steamworks.Constants.k_nSteamNetworkingSend_UnreliableNoDelay, 0);
            }
            catch
            {
                Marshal.FreeHGlobal(SendBuffer);
            }
        }
    }

Server receive
This code is ran at 60TPS

void ReceiveMessage()
{
    int messageCount = SteamNetworkingMessages.ReceiveMessagesOnChannel(0, ReceiveBuffers, ReceiveBuffers.Length); // not sure if alternating channels might help


    if (messageCount > 0)
    {

        for (int i = 0; i < messageCount; i++)
        {

            SteamNetworkingMessage_t
                netMessage =
                    Marshal.PtrToStructure<SteamNetworkingMessage_t>(
                        ReceiveBuffers[i]); // Make a NetMessage (it must be a pointer)
            byte[] message = new byte[netMessage.m_cbSize]; // make a byte array with the length we need
            Marshal.Copy(netMessage.m_pData, message, 0,
                message.Length); // Get message out of the pointer and put it into byte array we just made


            Stream stream = new MemoryStream(message);
            BinaryReader binRead = new BinaryReader(stream, Encoding.ASCII);

            var PacketID = binRead.ReadInt16();

            Debug.Log("Reading packet ID: " + PacketID);


            switch (PacketID)
        }
    }
}

Sorry for it being just a wall of text but I didn't want to leave anything out that might be important.

@GhettoScouser
Copy link
Author

Its one of those times where I stare at it for days, post for help then find the solution right after.

Lack of examples on the steamworks P2P is crippling.
Essentially I wasn't clearing the buffer correctly and that lead to being permanently behind and clogged up.

Sorry.

@rlabrecque
Copy link
Owner

Can you post your updated code just for the next person?

@GhettoScouser
Copy link
Author

Ofcourse, wasn't sure if I should as it was a me issue.

Basically, pull all messages out of the buffer, run through them all and then make absolute sure to completely clear the buffer.
I found that the client started to send messages before the p2p was open (by a few frames) and this was enough to permanently put the server behind. Although I'm not sure why clearing each entry in the first for loop is any different to making a seperate for loop at the end.

void ReceiveMessage()
{
    int messageCount = SteamNetworkingMessages.ReceiveMessagesOnChannel(0, ReceiveBuffers, ReceiveBuffers.Length);

    if (messageCount > 0)
    {
        Debug.Log("Message Count: " + messageCount);

        for (int i = 0; i < messageCount; i++)
        {

            SteamNetworkingMessage_t
                netMessage =
                    Marshal.PtrToStructure<SteamNetworkingMessage_t>(
                        ReceiveBuffers[i]); // Make a NetMessage (it must be a pointer)
            byte[] message = new byte[netMessage.m_cbSize]; // make a byte array with the length we need
            Marshal.Copy(netMessage.m_pData, message, 0,
                message.Length); // Get message out of the pointer and put it into byte array we just made

            Stream stream = new MemoryStream(message);
            BinaryReader binRead = new BinaryReader(stream, Encoding.ASCII);

            var PacketID = binRead.ReadInt16();
        }
        
        Debug.Log("Clearing out the SteamNet buffer");
        for (int a = 0; a < messageCount; a++)
        {
            Marshal.DestroyStructure<SteamNetworkingMessage_t>(ReceiveBuffers[a]);
        }
        
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants