Skip to content
New issue

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

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

Already on GitHub? # to your account

SteamNetworkingSockets support with the new flat interface in 1.48 #341

Closed
Frooxius opened this issue Mar 12, 2020 · 11 comments
Closed

SteamNetworkingSockets support with the new flat interface in 1.48 #341

Frooxius opened this issue Mar 12, 2020 · 11 comments

Comments

@Frooxius
Copy link

Hello!

I'd like to ask if the SteamNetworkingSockets API is planned to be included as part of Steamworks.NET, with the addition of the flat C interface in the version 1.48 (ValveSoftware/GameNetworkingSockets#70).

The topic mentions that Valve is working with you on the implementation, so I wanted to ask if that's indeed coming and if there's any rough ETA.

Thank you for your time!

@shiftyscales
Copy link

I'm also curious to know the answer to this, as it is necessary for a project I am working on, @rlabrecque. Thanks as well for your time.

@BlueCyro
Copy link

@rlabrecque I would also like to know the answer to this as I use the project that froox and shifty are part of and I'm having issues with the current network implementation that's in place at the moment.

@rlabrecque
Copy link
Owner

Some work has started on this last weekend, should be able to get something in this weekend!

@shiftyscales
Copy link

That's fantastic to hear. Thanks for the update, @rlabrecque.

@rlabrecque
Copy link
Owner

Initial support is in as of 6700235

Note that it's likely very rough, I haven't started trying to use this yet, but it's all there now!

I probably won't get a chance to actually use this for a bit, so if anyone tries it out please let me know any pain points you hit.

@Frooxius
Copy link
Author

Thank you so much for working on this! I have given it a try, but ran into an issue, using any of the functions throws following exception:

System.TypeLoadException: 'Could not load type 'OptionValue' from assembly 'Steamworks.NET, Version=14.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field.'

It seems that it doesn't like this struct:

		[StructLayout(LayoutKind.Explicit)]
		public struct OptionValue
		{
			[FieldOffset(0)]
			public int m_int32;

			[FieldOffset(0)]
			public long m_int64;

			[FieldOffset(0)]
			public float m_float;

			[FieldOffset(0)]
			public string m_string; // Points to your '\0'-terminated buffer

			[FieldOffset(0)]
			public IntPtr m_functionPtr;
		}

Particularly the string member. If I comment it out then it works fine, but it's not possible to use string based options.

Using an IntPtr to explicitly marshaled string (like with Marshal.StringToHGlobalAnsi) should work there, but adds extra work on the API user.

Is there a better solution to this?

@Frooxius
Copy link
Author

Frooxius commented Apr 14, 2020

I found another issue with the wrapper, on the function ReceiveMessagesOnPollGroup and ReceiveMessagesOnConnection.

They use out SteamNetworkingMessage_t ppOutMessages for the messages, but the native function seems to instead fill an array of pointers to the messages.

I've changed the native method import to this:

[DllImport(NativeLibraryName, EntryPoint = "SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnPollGroup", CallingConvention = CallingConvention.Cdecl)]
public static extern int ISteamNetworkingSockets_ReceiveMessagesOnPollGroup(IntPtr instancePtr, HSteamNetPollGroup hPollGroup, IntPtr[] ppOutMessages, int nMaxMessages);

And updated the methods appropriately and then used Marshal.PtrToStructure<SteamNetworkingMessage_t>(ptr) to get the structs, which worked and I managed to successfully send and receive data!

Adding a method that wraps this behavior around could help. The ValveSockets project provides methods for the open source version of the networking library, which I think could be adapted: https://github.com/nxrighthere/ValveSockets-CSharp/blob/master/ValveSockets.cs#L641

EDIT: Also related issue to this, the Release() method on the SteamNetworkingMessage_t will cause crash, because it passes the managed instance of the struct, rather than the pointer to the native struct originally returned by the SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnPollGroup

I've modified the method to this:

[DllImport(NativeLibraryName, EntryPoint = "SteamAPI_SteamNetworkingMessage_t_Release", CallingConvention = CallingConvention.Cdecl)]
public static extern void SteamAPI_SteamNetworkingMessage_t_Release(IntPtr ptr);

And just pass the pointers from the returned IntPtr[] array, but it probably needs a cleaner solution for the library itself.

Other than that, so far it seems to work! I'm sending data back and forth! :D

@rlabrecque
Copy link
Owner

Thanks for having a look dude! Sorry I didn't get to test it out that much!

Particularly the string member. If I comment it out then it works fine, but it's not possible to use string based options.

Using an IntPtr to explicitly marshaled string (like with Marshal.StringToHGlobalAnsi) should work there, but adds extra work on the API user.

Is there a better solution to this?

Hmm yeah that is definitely supposed to be an IntPtr

https://github.com/rlabrecque/SteamworksSDK/blob/master/public/steam/steamnetworkingtypes.h#L1146

Maybe IntPtr with a Getter/Setter like we're looking at in #347 ?

@rlabrecque
Copy link
Owner

455741e

4aa0ee8

@Frooxius
Copy link
Author

Thank you so much! And no worries, you did pretty much the brunt of it which helped a lot, I'm happy to help test it out.

There's one more thing that I had to modify on my end. The m_pfnRelease member of SteamNetworkingMessage_t technically doesn't point to the message itself, but rather a function, the ValveSockets seems to be using it as a shortcut for releasing the message.

This works, I just had to make the member public rather than internal, so in my code I can assign the pointer returned from ReceiveMessagesOnPollGroup or ReceiveMessagesOnConnection in IntPtr[] ppOutMessages to this member and then calling Release() on the message works properly.

It might be worth to wrap this behavior around later to simplify the API for users, but it works without it!

I got the Steam Networking Sockets fully integrated with my project and so far it all works correctly, so it should be good! I haven't used all pieces of the API though, but the main ones seem good. Thanks again for working on this!

@rlabrecque
Copy link
Owner

Oh I understand now, yeah I was following their pattern for Release() but I definitely missed that they assign it themselves like so:

https://github.com/nxrighthere/ValveSockets-CSharp/blob/master/ValveSockets.cs#L653

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

No branches or pull requests

4 participants