Steam Multiplayer API

I split this off from my Multiplayer on Nintendo Switch thread because I want to start with Steam multiplayer and then add Switch multiplayer as a second step. It didn’t seem right to make Steam API wrapper requests in the Switch forum so I’ve started a new topic here.

Again, very grateful to be able to work with you guys to enhance Defold, my favourite game engine. When they are implemented, I will test these functions and let you know how they go.

For now I don’t want to browse lobbies etc. I just want people to be able to invite their friends and accept invites. I also want to implement this functionality in game - it seems that although it’s convenient to use the Steam overlay to invite and accept, it’s good practice to let the user do it through the game for a seamless experience (especially for gamepad games) and I’ll want this in my UI for the Switch anyway.

Looking at the Defold Steam API I don’t see the required functions so if someone could confirm this for me and let me know what to do next that would be much appreciated.

Referring to the Friends, invites, and lobbies example, it seems I need;

  • SetRichPresence - so other friends know you’re in a joinable game
  • GetFriendCount - to get a total amount of friends to iterate through
  • GetFriendByIndex - to iterate through the friends to build a list of friends to invite
  • InviteUserToGame - to send the invite to the friend
  • GameLobbyJoinRequested_t - so the receiving game instance can respond to the invite and prompt the user to accept the invite
  • JoinLobby - so the invited user can join after accepting the invite from within my game’s interface

FYI those functions are only available through the global accessor functions SteamFriends() and SteamMatchmaking() not sure what that means for your back end but just thought it was worth mentioning.

As for actually keeping the gameplay in sync with each other, according to the Steam Networking docs, looks like I need;

  • ISteamNetworkingMessages - seems it’s a high level interface to send data between the games, it might be easier if this works, but if I need to be more lower level for bandwidth, I’ll have to use ISteamNetworkingSockets
  • ISteamNetworkingUtils - it would be good to have this because I think it’s normal to show someone’s ping next to their username somewhere in the interface

I’ve literally never done this before and have no way to test it in Defold without access to the functions (or perhaps setting up my own C++ project to test out the Steam API I guess :laughing:) so it’s possible I’ve asked for too much or too little. But even just the friends & matchmaking stuff would be a good start. In fact if you want to do it piecemeal and let me know when each one is done, I don’t mind testing individual functions as you implement them.

3 Likes

Perfect, thanks for the request. I created a feature request in the extension repo:

2 Likes

Oh awesome - would you like me to always make these as feature requests, or start on the forum first?

If you are uncertain of a feature request or would like to discuss if it makes sense to create one then start on the forum, but if it is a straight forward request or has already been discussed then start on GitHub!

1 Like

Ok cool, I have a good idea of where to start then :+1:

Hi @britzl ,Just referring to your reply here https://forum.defold.com/t/online-multiplayer/80523/24 - but I think the conversation is supposed to continue in this thread because this is the Steam Multiplayer thread and that’s the Switch Multiplayer thread.

I’ve got as far as being able to right click on a person running the game and click “Join Game” but the game on the other end doesn’t receive a GameLobbyJoinRequested_t event via the steam event handler (set with steam.set_listener). I get other events though, like PersonaStateChange_t

Just checking if this was implemented yet?

It should be. Could you please open a bug report on GitHub?

Edit: Yes, the event should be triggered here

1 Like

Ok thank you, I’ll look into this further :+1:
EDIT: Yes I was using this wrong, it all appears to be working fine! Have to make sure both are running from inside Steam, and the event is triggered on the end that tried to join.

1 Like

Ok now that I’m attempting to actually do it, looks like there are more functions and events that need mapping that I didn’t realise when just reading the documentation. The next immediate issue I ran into is missing a mapping for “CreateLobby”.

EDIT: Rather than bulk out the thread here, I’ve attempted to follow due process and put the full list of functions in a new feature request here:

Thanks for your help so far guys. So far it’s going smoothly with this approach of implementing as we go.

2 Likes

Thanks. I will take a look next week when I am back in front of a computer.

1 Like

I see the completed feature request on GitHub, thank you Team.

I just took a short contract job but I’m so keen to try these functions out that I’ll be trying to squeeze in getting the multiplayer working around my contract job.

2 Likes

steam.zip (14.7 KB)

I modified some Steam extension files to suit my needs — lobby, matchmaking, and so on.
This could save us all some time.

{ “matchmaking_request_lobby_list”, SteamMatchmaking_RequestLobbyList },
{ “matchmaking_add_request_lobby_list_string_filter”, SteamMatchmaking_AddRequestLobbyListStringFilter },
{ “matchmaking_add_request_lobby_list_numerical_filter”, SteamMatchmaking_AddRequestLobbyListNumericalFilter },
{ “matchmaking_add_request_lobby_list_near_value_filter”, SteamMatchmaking_AddRequestLobbyListNearValueFilter },
{ “matchmaking_add_request_lobby_list_filter_slots_available”, SteamMatchmaking_AddRequestLobbyListFilterSlotsAvailable },
{ “matchmaking_add_request_lobby_list_distance_filter”, SteamMatchmaking_AddRequestLobbyListDistanceFilter },
{ “matchmaking_add_request_lobby_list_result_count_filter”, SteamMatchmaking_AddRequestLobbyListResultCountFilter },
{ “matchmaking_add_request_lobby_list_compatible_members_filter”, SteamMatchmaking_AddRequestLobbyListCompatibleMembersFilter },

> { “matchmaking_get_lobby_by_index”, SteamMatchmaking_GetLobbyByIndex },
> { “matchmaking_create_lobby”, SteamMatchmaking_CreateLobby },
> { “matchmaking_join_lobby”, SteamMatchmaking_JoinLobby },
> { “matchmaking_leave_lobby”, SteamMatchmaking_LeaveLobby },
>
> { “matchmaking_get_lobby_owner”, SteamMatchmaking_GetLobbyOwner },
> { “matchmaking_set_lobby_owner”, SteamMatchmaking_SetLobbyOwner },
> { “matchmaking_set_lobby_type”, SteamMatchmaking_SetLobbyType },
> { “matchmaking_set_lobby_joinable”, SteamMatchmaking_SetLobbyJoinable },
> { “matchmaking_set_lobby_member_limit”, SteamMatchmaking_SetLobbyMemberLimit },
> { “matchmaking_get_lobby_member_limit”, SteamMatchmaking_GetLobbyMemberLimit },
>
> { “matchmaking_set_lobby_data”, SteamMatchmaking_SetLobbyData },
> { “matchmaking_get_lobby_data”, SteamMatchmaking_GetLobbyData },
> { “matchmaking_set_lobby_member_data”, SteamMatchmaking_SetLobbyMemberData },
> { “matchmaking_get_lobby_member_data”, SteamMatchmaking_GetLobbyMemberData },
>
> { “matchmaking_get_num_lobby_members”, SteamMatchmaking_GetNumLobbyMembers },
> { “matchmaking_get_lobby_member_by_index”, SteamMatchmaking_GetLobbyMemberByIndex },

2 Likes

That’s awesome, I didn’t realise anyone else was currently trying to implement Steam multiplayer, thanks for contributing this.

I only had a quick look but I get the feeling this stuff may be essential. I was prepared for my previous list to fall short since ChatGPT came up with it and understandably doesn’t get everything right, but I was going to have to find out when I got into it and actually started using it. Yes, I bet you’ve saved all of us some time :+1:

It’s helpful indeed, but it would be better if this was contributed as a pull request rather than a zip file floating around on the forum.

2 Likes

I apologize, I’m having trouble with time, and I don’t know how to make pull requests (I really have problems with Git).

Nevertheless, I am using the source code I provided, and I have already implemented a fully functional multiplayer via Steam Networking. That’s what this whole thing was about!

8 Likes

It took me ~45 minutes to grab your changes and apply them on top of existing code. Also added doc annotations. I’ll be happy to guide you through the process next time you make an improvement!

3 Likes

This is very reassuring! Thanks for the video!

Also I learned how to do a pull request for Defold not long ago myself, I did find it a bit time consuming to learn how TBH, but I found a tutorial online somewhere, and now it’s not so bad. Plus ChatGPT should be able to help you through it as well.

Super convenient, I just have to update extensions. Can’t wait to check this out after I get a chance to be back on the project again. :+1:

  1. Fork extension-steam: https://github.com/defold/extension-steam/fork
  2. Clone your forked repo (if you use GitHub Desktop it’s as easy clicking “Open with GitHub Desktop”.

  1. Make changes in your checked out clone of the repo
  2. Commit changes
  3. From GitHub Desktop you can now select “Branch->Create Pull Request” OR go to github.com/<your_user>/extension-steam and you’ll see a notification about your recent commit and an option to create a Pull Request
1 Like

I would love to know how you got a response from the other machine. I have 2 PCs, 2 different user accounts (I gifted the other one of my steam keys for the game), running a build of the game from within Steam (using “Add non-steam game”), and the steam_appid.txt in their respective local folders containing the actual ID for my game (not SpaceWar).

I can create a lobby, I get 2 steam callback events for “LobbyCreated_t” (on the same machine, I assume this is normal), and I’ve set Rich Presence settings so that both copies are Joinable from the other’s friend list: it says they’re playing “Hopsquash” and “At the main menu” - Right click on the name, click “Join game”

But nothing happens on the other end… I’m printing all events in my on_steam_event function, and nothing happens, no GameLobbyJoinRequested_t nor GameRichPresenceJoinRequested_t or anything else for that matter.

Good news - got one account finally joining the lobby of the other account. I’ll post my sticking points here, maybe they will help someone.

2 very important road blocks:

Don’t use right-click “Join Game” when testing

Joining via “Rich Presence” i.e. open Friends list, right click on friend, click “Join Game” will NOT work unless the game build has been uploaded to Steam and running from within Steam (eg. in a test branch)

But you can do your tests running local builds by adding it as a non-steam game and making sure it has the steamapp_id.txt and relying on internal functions to join, eg. search for lobbies, request lobby by index, and join lobby ID (don’t forget to set lobby joinable when creating the lobby)

You can also test from your Defold project directly if the steamapp_id.txt is in the project root.

Lobby total is given as a STRING!

The steam extension provides the “total lobbies” number as a STRING! (a discussion with ChatGPT explained that this is due to standard Lua not supporting 64 bit numbers internally, so it’s converted to a string to avoid precision loss)

On the client when you get LobbyMatchList_t you need to convert the total to a NUMBER:

local total = tonumber(data.m_nLobbiesMatching)

Otherwise, when you go ahead and treat this as number, eg. “if total > 0”, it will always result in false as if you got no lobbies! :person_facepalming:

Steam extension contains examples

I forgot about these. But, it looks like the insidious reason that the example doesn’t run into the issue of m_nLobbiesMatching being a string, is this line here, which happens to cause Lua convert it into a number…
for i=0,message.m_nLobbiesMatching-1 do

4 Likes