Implementing the Steam SDK with Unreal Engine 4
As part of my multiplayer game project Shotgo (working title) I wanted to implement the Steam SDK to gain access to Steam's stats, matchmaking and friends systems. Luckily, Unreal has an official plugin which implements the Steam SDK. Unfortunately, however, that plugin is missing some important features and is even broken in some places. To add some of those missing features I am also using the Advanced (Steam) sessions plugin which is made and maintained by a community member.
What does the Unreal OnlineSubsystemSteam plugin provide:
Well, for the most part, it handles the binding of the Steam SDK's API callbacks to functions that we can use. There are unfortunately some missing. In my case, I needed to manually edit the plugin to add a binding for the GameServerChangeRequested_t callback to allow players to join through right-clicking a friend and selecting "Join" if the friend's game is in progress.
Why use Advanced (Steam) Sessions:
There are two main reasons to use advanced sessions. Firstly, it exposes a lot of matchmaking functionality to blueprints, this makes a lot of UI work like making a server browser a lot easier. Secondly, it has a neat system for adding extra tags to your server which can be used to filter the match results based on custom options. Unfortunately, the creator of this plugin made it with the intent to not replace the official OnlineSubsystemSteam plugin but to instead build upon it without changing it directly (to not give Epic games a reason not to fix the problems with their official plugin). So besides adding a bunch of cool functionality, this plugin is limited to what it can do as a separate plugin.
The first problem I ran into in trying to get Shotgo to work with Steam matchmaking was setting the game name and server name in the Steam server list. To change this I needed to change a couple of defines in the OnlineSubsystemSteam plugin. I ran into a problem there. The OnlineSubsystemSteam plugin is installed at the engine level so in order to change these defines I needed to copy this plugin over to my project (Or I had to rebuild the engine from source). After moving the plugin into the projects "plugins" folder I was able to change the defines and server name variable in "OnlineSessionAsyncServerSteam.cpp" to make the correct info show up for my servers in the server list.
The Advanced Sessions plugin adds some useful functions to create and search for sessions. Unfortunately, most of the classes are specified with the MinimalAPI flag which prevents their functions from being accessible from other modules (like the game module in this case). This means that I had to remove those flags for the classes that had functions that I wanted to use in c++ from the game module. The main example of this would be the "CreateSessionCallbackProxyAdvanced" which provides a useful way of setting up the session with a bunch of parameters.
To get joining from the steam interface to work I had to go through quite a checklist. I mainly had to check three ways of joining through the steam interface:
And then finally, I had to come up with a way of testing this. This requires some way to have two steam accounts available, preferably on the same computer that can both launch the game and send each other invites to join the server. One possible solution that I found was to use a tool like Sandboxie to get two steam clients to launch at the same time. However, when I tried this I still was not able to join the same server from the same computer twice. So I decided to instead use a virtual machine to run the second steam account and client. One thing I had to take into consideration here was that I needed a VM that was capable of launching Unreal games, which means it has to support DirectX 10 at the very least. I ended up using VMWare Workstation Player as it meets that requirement and is free for non-commercial use. I installed an evaluation copy of Windows 10 onto it and set up a shared folder on the host so that both the VM and the host can launch the game from the same location. This allowed me to test all the steam interactions.
Unreal Engine's Steam SDK implementation is far from perfect. It does, however, get the job done. I was able to set up steam matchmaking, inviting and joining friends. I was also able to use steam's achievement and stats system. Having these services available, hosted on valves servers will be a great boost to our project.