Steam Mate

Introduction

This blog post documents the development of the iOS application Steam Mate developed by Simon H. Larsen and Anders Bundgaard for the Autumn 2018 class in iOS programming at SDU. The purpose of the application is to connect players of games on the Steam platform with each other based on distance and preferences. Steam Mate aims to aid players in finding new people to play their favourite games with and enable more cooperative play. The application draws inspiration from Tinder, a very popular dating app for Android and iOS, in which opportunities to communicate are granted based on mutual interest.

Context

Steam is a social gaming platform developed by Valve. It features a store where millions of games can be bought or downloaded for free, a platform for playing said games, and a community in which players can befriend and chat with each other and participate in groups. Steam is the most popular platform on which video games are published and served today.

Importance of the Subject

While Steam does facilitate socialization between gamers, it does not provide an easy way to connect with new people who play similar games. Steam is especially unhelpful with finding players near you. While the application does show a player’s country of residence in their profile, there is no automatic way to browse player profiles in your area. This results in users mostly having real life friends and acquaintances on their Steam friend list.

Problem Stament

The problem that this project seeks to solve is stated below:

“How can like-minded Steam users be connected in a convenient, user friendly way?“

The main objective of the project is to facilitate new connections between gamers and enable players to play their favorite games with like-minded people.

Methods and Materials

Paper prototype

The first prototype created of the solution was a simple paper prototype made as a proof-of-concept for the application design. It is shown in the picture below.

First paper prototype

First paper prototype

Two approaches to the login process are shown, one is standard login screen with input fields for username and password and the other is imagined as a Steam-integrated login button. An initial draft of the match screen inspired by Tinder is also shown. It features buttons for accepting and rejecting a pairing, as well as viewing info about the pairing.  A list of matches, a chat client and a preferences window are also presented.

After the paper prototype was made, another idea was drawn in a separate sketch, shown below.

Paper prototype with lobbies

Paper prototype with lobbies

This pair of views would enable the user to see a list of currently active game lobbies, and select a lobby to chat with its members.

The paper prototype along with the additional sketch shown above was presented to a number of potential users. Feedback was received from the users, and the main points of critique were:

  • Integrated Steam login would be preferable to a separate login specifically for Steam Mate.
  • Users would like to view the profile of themselves and others in the app.
  • The lobby view idea is unnecessary, as players in a game lobby are most likely already situated by a computer with access to Steam as well as social applications such as Skype or Discord.

After the paper prototype showcase the feedback received from the potential users was taken into consideration, and it was decided to honor all three main requests.

Navigational Prototype

Next step of the planning process was to apply the feedback received from the first evaluation and use it to build a navigational digital prototype of the improved version of the application. To do this, a Marvel app was created, accessible by this link. The rather primitive interactive prototype shows the basic flow of logging in, viewing a pairing, accepting it and moving on to chatting with a matched user.

This prototype was also shown to a few potential users, and the feedback received confirmed user requests from the first round. As an addition, a discussion with one user about the Steam login process resulted in revealing another issue to be addressed in the final solution. Having logged in through Steam before means that users will automatically login to Steam Mate. This means that unauthorized users can access personal data of existing users just by opening the app. It was decided that another factor of authentication was needed, and fingerprint identification was chosen as the preferred solution.

The following use case diagram shows the possible interaction flows that the solution provides. An unauthorized user is referred to as ‘Anonymous’ and must log in using Steam to use the application. After logging in they become a ‘User’.  A user can view their pairings with other users. For each pairing, the user shows their interest or lack thereof by either accepting or rejecting the pairing. The user is also able to view a short description of the reasoning behind each pairing.   

Steam mate use case diagram

Steam mate use case diagram

In addition to viewing their pairings, a user can view a list of the users they have been matched with. These are other users which have accepted their pairing with the user and vice versa, indicating mutual interest in playing with each other. Once a user has matched with another, they are able to chat with each other and also send an invitation to add them to their Steam friend list. When viewing their pairings or matches, the user is able to visit the profile of the user they are currently viewing. Finally a user is able to visit their own profile, and from there change their matching preferences such as favourite games and maximum match distance.

The following flow diagram shows how a user will navigate the application:

Steam Mate application flow diagram

Steam Mate application flow diagram

The flow reads similarly to the use case diagram presented earlier, but is more explicit about the navigation. Once logged in, the pairing view is the main view of the application. From there, the user can accept or reject the current pairing presented to them, view info about the pairing and visit the paired user’s profile. From the pairing view the user can navigate to view their matches. In the matches view, a user can select a match to chat with them, visit their profile or add them to their Steam friend list. Lastly, the user can visit their own profile also from the pairing view. From their own profile the user can change their matching preferences.

Design Results

After feedback from the users the final design layout is as follows.

The main storyboard of the application

The main storyboard of the application

From the Storyboard image 6 view controllers can be seen. One of which is just a dumb Navigation Controller – this controller is dumb in the sense that we implemented no logic for this controller (however, it is really not that dumb as it just works perfectly out of the box). The other 5 controllers required a bit more logic from our side

  • LoginController – functions as a pretty login and welcome screen to new and existing users of the application. It lets users login to their account by using Steam integrated login functionality.
  • MatchingController – will enable users to match with other users. This is done by letting using say ‘yes’ or ‘no’ to pairings. If two users say ‘yes’ to eachother, then they will be matched. It is also possible to get a short description about why a pairing was presented to the user – If a user is in doubt why a pairing was chosen for him.
  • MatchesController – is a list of all the users matches. Much like any other chat application all chatroom will be listed here.
  • ChatController – will enables matches to communicate with each other. Their message history will be listed and it is possible to send new messages.
  • ProfileView – shows information about the user. This information will be used to help the matching algorithm and to present the user to pairings.

Implementation

The source code can be found at the following link

https://bitbucket.org/iosprogrammingsdu/steam-mate/src/master

The implementation of the Steam login was done using an iOS UIWebView. It was instantiated through code and the boundaries were set to fill the entire screen using UIScreen.main.bounds.  Upon user interaction this web view would show the login page of Steam’s official webpage. After a successful login transaction the webpage would redirect to user to their Steam profile page e.g. https://steamcommunity.com/id/1cefir3. However, instead of letting the user experience the navigation to this page a UIWebViewDelegate was implemented to check for the specific URL navigation request. Upon this request we would fetch the users SteamID using the XMLMapper pod [3] and persist it to the defaults database UserDefaults.standard. Finally we close the UIWebView and Segue to the next UIViewController.

The next view controller is the MatchingController. This controller lets the user select matches amongst a list of pairings. However, before the user is allowed access to the screen a TouchID authentication process must be completed. This is implemented using the Local Authentication Context LAContext. Initially we try to evaluate the deviceOwnerAuthenticationWithBiometrics policy using the LAContext.evaluatePolicy method. The method accepts a callback method which is called upon receiving a result from the evaluation. If the evaluation was a success then we provide the user with access to the application. If not, then two things can happen. Either we shutdown the application or we show a password dialog. The password dialog will only appear the case that the iOS device does NOT support any biometrics authentication or if the user is simply not enrolled in the biometrics security on their system.

When a user is fully authenticated he is presented with a carousel view of all his pairings. This carousel view is implemented using the iCarousel library provided by nicklockwood [1].

func carousel(_ carousel: iCarousel, viewForItemAt index: Int, reusing view: UIView?) -> UIView {
    var itemView: ProfileView
    
    //reuse view if available, otherwise create a new view
    if let view = view as? ProfileView {
        itemView = view
    } else {
        itemView = ProfileView(frame: carousel.bounds)
    }
    
    return itemView
}

The implementation of the carousel view resembles the implementation of UITableViewController in the sense that you must provide the carousel view with information regarding how many items you want to display and how you want your items to be displayed. In the code above the carousel asks for an item and provides a reusable UIView. This view will be reused if it is not nil and it is of type ProfileView. However, a new view is instantiated If no reusable view is available. In this case it would instantiate the ProfileView which is a custom view.

@IBDesignable
class ProfileView : NibLoadingView {
    @IBOutlet var contentView: UIView!
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        initSubviews()
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        initSubviews()
    }
    
    func initSubviews() {
        view.layer.borderWidth = 1.5;
        view.layer.borderColor = UIColor.lightGray.cgColor;
        view.layer.cornerRadius = 3;
    }
}

The ProfileView extends the NibLoadingView class – this class simply extends UIView and overrides the init constructor methods such that the Nib files are instantiated properly. After instantiation the view will set its borders and then the view will be ready. In order to render the custom view in the interface builder the IBDesignable annotation was used.

When a ProfileView is instantiated and shown in the carousel view three buttons can be pressed. One shows information about the pairing, one says ‘yes’ to the pairing, and the last says ‘no’ to the pairing. Upon pressing one of the buttons a sound will be played.

var audioPlayer = AVAudioPlayer()
let yes = Bundle.main.url(forResource: "theuncertainman-yes-british-male", withExtension: "wav")

@IBAction func acceptMatch(_ sender: UIButton) {
    do {
        audioPlayer = try AVAudioPlayer(contentsOf: yes!)
        audioPlayer.play()
    } catch {
        print("couldn't load sound file")
    }
}

The AVAudioPlayer of the AVFoundation package was used to accomplish the sound effects. A sound resource is loaded and played when a users presses one of the three buttons.

Additionally the SwiftyAvatar [2] library was installed using CocoaPods and used to display circular images in the MatchesController. The XML Mapper and iCarousel libraries was installed using CocoaPod as well.

Discussion

The aim of this project was to enable new connections between Steam users and aid cooperative play. Steam Mate was proposed as a solution which matches players with other like-minded players in their local area. Feedback from the initial prototypes indicates that the concept was well received by potential users. There were however a few requests for changes, which were considered and included in the later versions of the application.

As it stands the UI for the application has been developed and the UX of the application was evaluated through potential users. However, no backend logic has been implemented for the application. This would have to be implemented to support the application. Additionally development on local persistence could be extended to support matches and chat messages.

Future works

Even though requests were addressed, the final application still lacks functionality required to be a fully fledged application. An oversight made during the evaluation phase and later during the implementation of the final application was that no view was added to indicate a match. It would be preferable to jump to a match screen or overlay after accepting a person that results in a match. This would indicate more clearly that a match has been made, and would likely offer an opportunity to chat with the new match.

Likewise, the event of a match occuring might happen while the app is closed, if the matched user is the last to accept the pairing. We would like to address this by notifying the user of matches through notifications, which would direct towards a match screen as described above.

In the future we would also like to work on further integration with the Steam API to show various information and enable Steam-integrated functionality. Use case 11 ‘Add to Steam friends’ was not implemented, and it would be an important further step in the development process in this regard. Other features such as indicating online status, showing which game a user is currently playing, etc. would also be possible with more extensive integration.

References

[1] Open source iCarousel library for iOS to support various types of carousel views https://github.com/nicklockwood/iCarousel

[2] Open source SwiftAvatar custom view for iOS to support circular cutting of images with a border https://github.com/dkalaitzidis/SwiftyAvatar

[3] Open source XML Mapper for iOS  which can map XML input to swift classes or simply create a dictionary of key-value pairs https://github.com/gcharita/XMLMapper