Skip to content
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

SteamNetworkingSockets.SendMessages has incorrect parameter types; can't be called successfully #598

Closed
Idles opened this issue Mar 1, 2024 · 5 comments

Comments

@Idles
Copy link

Idles commented Mar 1, 2024

I was trying to put to use the newly-fixed connection lanes API and ran into something else; getting SIGSEGV in Unity when trying to call SteamNetworkingSockets.SendMessages.

The native method has this signature:

void SendMessages( int nMessages, SteamNetworkingMessage_t *const *pMessages, int64 *pOutMessageNumberOrResult );

The Steamworks.NET binding for that method has the signature:

public static void SendMessages(int nMessages, SteamNetworkingMessage_t[] pMessages, long[] pOutMessageNumberOrResult)

So looks to me like there's an issue with the pMessages parameter type. For other native APIs that take ** parameters, Steamworks.NET appears to use IntPtr[]. Seems like the fix should be similar to the one for #597

I did a search and wasn't able to find any projects on Github calling this method using Steamworks.NET, so it might not be in use by anyone else and thus went unnoticed

@rlabrecque
Copy link
Owner

The pOutMessageNumberOrResult parameter definitely sounds wrong in the exact same way as 597 was; and I agree about pMessages as well.

In interfaces.py we do have this line: "SteamNetworkingMessage_t **": "IntPtr[]", assuming that SteamNetworkingMessage_t *const * is basically the same as ** in this case, then hopefully we end up with IntPtr[] as you suggest. (Note that IntPtr[] itself is probably not actually ideal -- but alas that's where we are.)

Same story as last time, if you get it working just let me know what signature you ended up with 👍

@Idles
Copy link
Author

Idles commented Mar 5, 2024

Just tested with a locally-edited copy of the package and succeeded in sending a message at runtime.

  • pOutMessageNumberOrResult parameter type is fine as-is
  • pMessages needs to change to IntPtr[]

The working, full signature in NativeMethods.cs is:

public static extern void ISteamNetworkingSockets_SendMessages(IntPtr instancePtr, int nMessages, [In, Out] IntPtr[] pMessages, [In, Out] long[] pOutMessageNumberOrResult);

For anyone from the future interested in how to call this method, this (roughly) works:

public bool Send(byte[] messageBytes, int sendFlags, ushort lane, HSteamNetConnection recipient)
{
    var msgPtrsToSend = new IntPtr[] { IntPtr.Zero };
    var ptr = IntPtr.Zero;
    try
    {
        ptr = SteamNetworkingUtils.AllocateMessage(messageBytes.Length);
            
        var msg = SteamNetworkingMessage_t.FromIntPtr(ptr);

        // Unfortunately, this allocates a managed SteamNetworkingMessage_t,
        // but the native message currently can't be edited via ptr, even with unsafe code
        Marshal.Copy(messageBytes, 0, msg.m_pData, messageBytes.Length);

        msg.m_nFlags = sendFlags;
        msg.m_idxLane = lane;
        msg.m_conn = recipient;

        // Copies the bytes of the managed message back into the native structure located at ptr
        Marshal.StructureToPtr(msg, ptr, false);

        msgPtrsToSend[0] = ptr;
    }
    catch (Exception e)
    {
        // Callers only have responsibility to release the message until it's passed to SendMessages
        SteamNetworkingMessage_t.Release(ptr);
        return false;
    }

    var msgSendResult = new long[] { default };
    SteamNetworkingSockets.SendMessages(1, msgPtrsToSend, msgSendResult);
    EResult result = msgSendResult[0] >= 1 ? EResult.k_EResultOK : (EResult)(-msgSendResult[0]);

    return result == EResult.kEResultOK;
}

@rlabrecque
Copy link
Owner

public static extern void ISteamNetworkingSockets_SendMessages(IntPtr instancePtr, int nMessages, [In, Out] IntPtr[] pMessages, out long pOutMessageNumberOrResult);

    long msgSendResult;
    SteamNetworkingSockets.SendMessages(1, msgPtrsToSend, out msgSendResult);
    EResult result = msgSendResult >= 1 ? EResult.k_EResultOK : (EResult)(-msgSendResult);

Would this not be better?

@Idles
Copy link
Author

Idles commented Mar 8, 2024

The API returns 1 messagenumber/error code per message sent (and the API supports sending multiple messages at once, though my examples only show sending 1), so that parameter needs to be an array.

@rlabrecque
Copy link
Owner

That makes sense! Let me know if you run into any problems with this

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