[ Music ]
[ Applause ]
Good morning, everyone.
Thank you for coming.
My name is Megan Gardner.
I am a Software Engineer on the Game Center Team and today we're going to be talking about what's new in Game Center.
So if you don't know what Game Center is already, Game Center is Apple's social gaming network.
It allows you, as developers, to define leaderboards which your users can then submit scores to, also define achievements that your players can earn.
We also have challenges which leverage both leaderboards and achievements to add a multiplayer element to your single player games.
We also have two multiplayer API's, both real-time and turn-based.
And we ship all of these things on iOS, macOS, tvOS, and this year we are announcing watchOS.
So what's new?
We've got a few new things this year.
First is we have a great new way of sending multiplayer invites.
Next we have big news for the Game Center app if you haven't figured it out already.
We have a brand new API for persistent game sessions that we're really excited about.
And we're also announcing Apple Watch support.
Now we don't have time to talk about Apple Watch in this session, but if that's what you're interested in, I really suggest that you go to the "Game Technologies for Apple Watch" later this afternoon in this room.
So let's talk about message-based multiplayer invites.
Now you can play with anyone that you can message.
Currently our multiplayer for Game Center pretty much looks like this.
This is our GKMatchmakerViewController and this is what most of you are using to set up your matches.
This is a built-in UI that we have done.
It allows your users to be able to invite their Game Center friends as well as do play now which is automatch.
Some of you have implemented GKMatchmaker which is our programmatic API which allows you to do your own UI and set up your own invites.
But if you've been using GKMatchmakerViewController, it now looks like this.
This is our new integrated Messages View Controller.
You'll notice some differences.
There's no bubbles but that's not the most important part.
It now integrates directly in with Messages which will allow your users to be able to send a message to anyone in their Contacts and then be able to play a game with them.
So let's see what this looks like.
This is the Multiplayer View Controller in Doodle Jump.
You can click Play Now and automatch will work just as it has before.
However, we're more interested in seeing what happens when we click Invite Friends.
So that will bring in this new Messages View Controller.
You can see we have this beautiful rich link here that we've got.
We've got the little Doodle Jump icon in the corner.
I added a little bit of text that can tell your users about what this link is going to let them do.
And this is all based on iCloud technology so all of your users will need to be signed into iCloud for this to work.
You can then start typing in the To field.
This will autocomplete to Contacts or you can just type in a email address or phone number of anyone that you know or anyone that you just met.
Or you can click on that Plus button which is going to bring in the Contacts.
So these are all my Contacts that I have Messages information for.
You'll also see that there's a Recents tab in the middle.
That is where your Game Center friends are going to be located as well as anyone that your users have recently played on Game Center.
And Nearby also functions the same way that Nearby has worked in that it will be looking for players on local network that are also playing this game.
So I'm going to click on Alisha, invite my friend, Alisha, to play.
And then we'll click Add and it's going to fill her in into that To field.
You can then, this functions just exactly as Messages.
This is basically Messages UI so you're users can add additional text and then it's going to send to all the players.
If I clicked on a Game Center player, their name is going to show up in gray and they will getting a Game Center notification.
They're not going to get some sort of weird Game Center iMessage.
It will come in as a notification.
So if we click on that Send button, then that will send it to Alisha and this is what it's going to look like on Alisha's screen.
She can then tap the link to accept the invite, and that will take her directly into the game, and start connecting just like it would have if she had tapped on the notification.
And the same functionality we'll have if she did not have Doodle Jump, then it will take her to the store where she can then download and play just like she would be able to from a notification.
Now I said that there's nothing that you need to do in order to implement this.
We have just replaced the View Controller so if you have been using this View Controller, then you've got this just straight out of the box.
As soon as iOS 10 is shipped all of your users will be able to do this and invite anyone that they know.
They will no longer be limited to their Game Center friends.
However, we have one thing that you can customize if you would like, which is this rich link image.
So you'll notice right here it's the Game Center icon currently.
If you would like to change that to be something else that you feel more appropriately represents your game, or more appropriately indicates that this is a gaming invite, or a fun thing that people will want to click on, then you can, all you need to do is add this file: GKMessageInvite to your bundle.
And the same way that we will just pull that out if you wanted to customize your notification sound, we'll just pull that out and customize your rich link.
Notice this is the same rich link technology that is being used for Safari and so it's used to taking a wide variety of images.
So what does this mean for Game Center Friends?
Well, we don't need friends anymore because we can play with anyone.
So we're freezing the friends list.
But you will still be able to see any of the Game Center friends that you have in that Recents Player tab.
And you can still pull the friends.
Friends still exists.
We're not deleting them.
They're still there.
But you won't be able to send, receive, or respond to any more friend Requests.
And because of that, GKFriendRequestCompose ViewController is now deprecated.
It wasn't really used that much anyway.
So what does that mean for the Game Center app?
Well, if you've downloaded The Siege, you might notice some changes.
Well, what is the Game Center app used for?
In iOS 9 it was basically used to manage your account, manage your friends.
You could browse your games list.
You could look at your leaderboards, check out your achievements, view your challenges, send challenges, and also view your turns.
Well, it turns out all of these things you can basically do in other places in the system and more importantly, in your app.
And so we have removed the Game Center app.
So where did we do all these things?
[ Laughter ]
[ Applause ]
If you want to manage your account, you can do that in settings.
If you want to manage your friends, you can still do that in settings.
If you want to browse your games, we've got the App Store, you can look at your Home screen.
You view your leaderboards, achievements, and challenges from GKGameCenterViewController.
If you're not using the View Controller, you can also do your own UI.
If you're not presenting challenges or leaderboards and achievements in your game, we strongly suggest that you start doing that now.
And you can also view and take your turns from GKMatchmaker, GKTurnBasedMatchmaker ViewController.
So we've removed the app.
Everything is really available in other places and, more importantly, in your app.
We would love our users to spend, your users to spend, more time in your app.
We've got the rest of the phone.
We don't need any more of their time.
And so we've removed the app.
Now let's talk about Sessions.
This is our brand new API and we're really, really excited about this.
This is a brand new way to multiplay.
So Game Center Multiplayer, what does it look right now?
We basically have our two main API's with real-time and turn-based.
Real-time will connect just two to four players.
Those connections will require like an immediate handshake.
If anyone drops from that connection, then that whole connection will be lost.
You're just passing data back and forth.
And as soon as that match is over all of that data is gone.
Turn-based can connect to 16 players.
We have a very formal API for passing of turns and also exchanges but you kind of really have to follow those rules and you have to make sure your game like fits within that structure.
And all games are stored on the Game Center server until they are aged out.
So what is Sessions?
Sessions is our new iCloud-based multiplayer.
So we have this great generalized interface for saving and sharing game data.
These are easily shareable little instances of data that people can share with people that they would like to play with.
It's a completely flexible game structure.
We don't impose anything on you.
You can do whatever you want.
And we have really stable, solid real-time streams that you can set up within these sessions.
And this is going to allow you to play with anyone.
So what does a Session look like?
So we have two main items that we have.
We've got our game data.
It's probably one of the more important parts.
But also equally important is their players.
And really this is all that you need and all the basics that you have to have to have a session, is a player and some game data.
You can have multiple players which is useful if you would like to play with other people.
We also have the ability to send messages between those players.
These messages will come in as Game Center notifications.
So you can have those messages being passed back and forth between players or multiple players can send multiple messages all at the same time.
Along with these messages we have the ability to badge.
So you can send those messages and also badge those players to let them know that there's something within your game, something within that session, that they might want to take care of.
Now I only show four players here but we can actually have up to 100 players in a single session which is a lot more than we've been able to have before.
And we can have multiple different kinds of sessions.
So you can have small sessions that have one or two players.
You can have four players, 100 players, seven players.
Those players can be functionally grouped onto different teams.
And you can have all of these sessions up and your player can be in all of these different kinds of sessions all at the same time.
We also have real-time streams so if you're in this session and you would like to be able to pass data quickly back and forth between your different players, then your players merely need to set their connection states and we will be setting these pipes up in the background that will allow the players to be able to start communicating with each other.
So, let's get into the actual code, the actual API of what makes up a session.
So we've got a couple of classes.
We've got GKGameSession which is going to allow your players to basically interact with that session data as well as the other players.
We have GKCloudPlayer which is a player in a session.
We have GKEventListener which will help you know when important things happen on any of your sessions that your players are in.
And we also have GKGameSessionError which will give you a little bit more specific errors that you might encounter when working with Sessions.
So let's talk about GKGameSession.
So this is your main workhorse.
This is where almost all of the work is going to be done per session.
It allows you to do basically everything.
You can create a session, leave sessions, load and store your game data, share your sessions, add your players, remove your players, see who's playing, send your notifications, set and clear your badges, join your streams, send data on those streams.
Basically everything you're going to be doing is going to be interacting with GKGameSession.
Some more details about that.
With your game data you can store up to 512 kilobytes of data.
This data is going to be stored in the user's iCloud so it's not something associated with your game.
And the user is going to have it in their iCloud.
It will count against their iCloud limits.
And it's going to follow CloudKit conventions in terms of who owns that data, how the data is shared, privacy, and what happens when that data is deleted.
Messages and Badges, as I've said, come in as Game Center notifications and they're badged as such.
And badging is now going to be more directly controlled by you, as the developer.
We'll get into that a little bit more but it's going to be very clear where that badge number is coming from and you should be able to understand why it is what it is and change it to pretty much whatever you want.
And we also have these real-time streams which basically leverage existing Apple infrastructure.
This is running on the same technology that runs FaceTime as well as iMessage so it's really strong, it's really stable, and it's built to carry a lot of data.
So if we want to make a session, what do we need to do?
Well, first we need a title, something to describe the session.
Either you can define that or you can get that from your user.
You need your container ID which your iCloud container that you set up with your app.
And also set up a container that can be used across multiple apps so if you want multiple games to be able to access that same data, say if you had your free version, your pay version, or, you know, other different kinds of versions of your game, they will still, if you set that up correctly, they will still all be able to access that same data.
And you can also set the max number of streaming players.
There's a hard limit of 16 players that can be in that real-time stream but if you would like to make that lower, or something different, then you can lower that when you create the session but you need to decide that when you create.
So once you've, so you just will call createSessionInContainer with all of that relevant information and that will give you a session that you can start manipulating and using.
One of the first things you're probably going to want to do with the session is be able to figure how to load and save your data.
Any player that's in a session can access that data.
It's just one big blob that everybody plays with.
And there's a little bit of metadata provided with that session that will help you avoid and resolve conflicts which is last modified date and last modified player.
So you'll know who was touching it last and whether or not it's important for you to save or if your data is more than likely up to date.
So you can just call loadDataWithCompletionHandler, that will pass you your data.
You'd also probably like to save your data.
As I said before, 512 kilobytes but you can do whatever you want with that data.
It can be whatever will fit in that size.
So you'll call saveData with completionHandler.
If there is a conflict, if someone else has tried to save in the interim, you will get an error and you will get that conflicting data back.
And we'll talk a little bit more about that in a second.
Anytime someone does save data there's an Event Listener that goes along with that.
So if you set up your Event Listener to listen for a session player to save data, then you will know when someone else has saved data and you will know that you will more than likely will need to update and resolve any conflicts local you have with that data.
So as I said, Save conflicts can occur.
And this will happen where two players who were basically going to try to save data in about the same time.
Since there's no real formal turn passing it's very possible that two players can be taking a turn at the same time if that's how you design and implement your game.
So say we've got Players Two and Three and they both try to save at the same time.
Well, one of them is going to win so I'm going to say it's Player Two.
That means when Player Three tries to save they're going to get an error and that conflicted data will be returned.
Now you are going to need to figure out how to resolve this conflict.
Since we have no specific formalities for what this data is we also don't know what the data means.
And so it's going to be up to you to architect your data in such a way that it's going to be easy for you to figure out what those conflicts are, resolve those conflicts, and recall saved data in order for that data to actually be saved.
If you do not recall saved data, your data will not be saved and you need to continue to call saved data until you return without a conflict.
And then everything will be up to date.
Everything will be the same for all your users and you can continue forward.
And then everything will be grand.
We've talked about having multiplayers, well, how do you get additional players into your session?
Any player that's in a session can invite other players to join.
Basically you're going to be provided with a URL that you need to get to someone else.
You can send this via iMessage, email, Twitter, Facebook, print it out, paste it on a tree that's probably not the best way.
But as long as you can get this URL to other people and they can click on it, then it will be able to be added to that session.
The easiest way to do this is through the share sheet because it just pops up right there and you can send off a message.
And that's probably the easiest way to do that.
So if like the Player One, if they pull the URL from their, from the session, they set up an iMessage with that share sheet to send to Player Two.
They've added a little bit of text, "Hey, want you want to play with me?"
It'll come out as this iCloud URL.
It will be sent to Player Two, they will click on it, and as soon as they click on it Player Two is added.
So in order to get the URL you just call getShareURLWith CompletionHandler.
It will give you the URL that you can then do whatever you want with.
And then anytime a player is added to a session the Event Listener didAddPlayer will be called.
And that will let you know that someone else has joined your session and be able to proceed with your game accordingly.
So we've been talking about players so what exactly are they?
Well, we've got GKCloudPlayer.
This is different than the GK Players that you've been dealing with before.
GKCloudPlayer is only for, to be used for Sessions.
It basically has two pieces of data, a player ID that is unique to your app as well as the display name, that is what the user will have as what they want they name to be displayed.
This is not a GKPlayer object at all.
If you try to use this for a leaderboard, for achievements, for other multiplayer, for anything else, it will not work.
So please don't do that.
Everyone will be very disappointed.
So how do we get our Cloud Players?
Basically you can get your current signed in player.
Most of the things in Sessions basically are going to be called from your current player though there's not a whole lot of need to make sure that you have the player, that you are then saying, "Oh, this player is saving this data."
All that's handled for you in the background.
But you might be interested to know basically like who owns this session?
So you might want to know if the session is being deleted, if other player owns it, then that will delete the data for everyone else.
And you also might want to be able to clear your badges, send messages, be a little more aware of that.
You can also get any of the other players that are in the session, it's just a property on that session.
And that's the best way that you're going to need to be able to send those messages to those other players, especially setting and clearing badges.
So speaking of messages and badges, let's talk about that.
These messages, we say messages but they're coming in as Game Center notifications.
As I said before, all players can send messages at any time to any other player.
Those messages are easily localizable.
You can also send a little bit of data along with that message if there's any sort of relevant information that you might want to pass to the other players about what this message is about or what they might want to be looking at specifically.
And you can also optionally badge the message recipient so anyone that gets this message can also receive a badge as well as that message.
So what does the code look like?
You've got all these arguments, who to send it to, whether or not you would like to badge those players.
And the Event Listener that is called is session didReceiveMessage fromPlayer.
And that will be called any time a notification comes in to let the player know that something has come in that they might want to be aware of or might want to deal with.
So I've said badges can be included with these messages.
So basically anytime you send a message you can basically turn that badge state on for that player.
You've got one badge per session so basically it means like there's something you need to deal with or there's not.
And these badges can be set and cleared at any time.
So if you send a message and then you're like, "Hey, I need some help with this thing that we're doing in the game," and then no one shows up you can, you know, clear those badges and be like, "Never mind.
I didn't want to talk to you anyway."
And so that you can keep all of that badge data relevant and up to date.
The app icon will show the overall tally so if you've got three sessions and all of them are badges, that app icon will say three.
If you have one, you know, only one of them is badge, it will say one.
We could aggregate that for you but based off of the, what is set in that session it should be very clear where that badge number is coming from.
So let's talk about managing these sessions.
So we've made a session.
We've saved it.
We've loaded it.
We've loaded the data.
We've sent it to some players.
Your user has turned off your app.
They've done some other things.
You've come back.
You want to load those sessions and make sure that you've got all the relevant data so that they can start playing again.
So the first thing you'll want to call is Load Sessions.
loadSessionsInContainer, that container, that same app container from the beginning that you made the session in.
This will load the bare bones information for all the sessions that your local player is a part of.
Then based off of that data you're going to want to look and figure out which session you're going to want to load.
That session has two main pieces to identify it.
One is that title that you gave us but the title is not unique.
You can make it anything that you want.
And so that's not enough to be able to just load a session.
Upon creation of a session we will give you an identifier and that is what you will need to use in order to load that specific session.
Call loadSessionWithIdentifier and that will give you all the information for the session including everything that you will need to do in order to start loading that data, sending messages to other players, and continuing on with your game.
You also might want to delete a session.
If you call removeSessionWithIdentifier, that's the same identifier that we just talked about, if the player does not own the session, it will merely remove them from the session.
It will not actually delete any of that data.
However, if you're deleting a session that that player created, then it will delete that data, not only for that player, but for everyone else in that session.
And that may be one of those times that who your local player is, figure out if they are going to be doing that to everyone, and maybe send, alert the user that, "Hey, you're deleting this for everyone," so that they know what they're doing.
At any time a player is removed the Event Listener will be called didRemovePlayer so that you'll know that someone has left and that you can continue to update your game accordingly.
So let's talk about Game Session Streams.
So this is the real-time element of Sessions.
Everything else up until this point has kind of sound pretty turn-based.
You're passing messages.
We also have the ability to have real-time elements to your game.
So Game Session Streams, you are going to be able to connect any of the players that are currently in that session.
So everyone who is in that session, if they would like to start sending data to each other, that is how you're going to do it.
You can basically see the status of any other players that are in the session.
You can send data to all the players that are in the connection that you've set up.
And you will be able to add and drop players at any time without having to restart that connection.
So you can someone join in and like two people can be playing, third person wants to come in and join, you don't have to reset everything up.
As soon as they start they'll start receiving data.
They can start sending data.
You don't have to do any handshakes for handling all of that in the background for you.
So how do we set these connections up?
Basically you just need to set the connection state for that player.
So you would just call setConnectionState with completionHandler.
This can fail for a number of reasons but one of the reasons could be if the max players for that session has already been reached.
So if this is the 17th player who is trying to join that stream and you've got that max 17 set, then this will actually fail and they won't actually be able to join into the stream.
You can see whether the players are set with a specific state, basically the states are connected and disconnected so you can see how many other players are currently connected and who they are.
And anytime a player either changes that connection state, either connects or disconnects, the Event Listener session player didChangeConnectionState will be called.
And so you can know whether or not that is changed and how many people you are currently playing with.
Once you set up the connection then you're going to want to probably start sending data.
So all of the data is going to be sent to all of the connected players.
You can send this either reliably or unreliably, just the same as our real-time API now.
Whether or not it's more important to make sure that those players get that data or more important to make sure that they're getting the data as fast as possible.
And any time data is sent the Event Listener didReceiveDataFromPlayer will be called and you'll be able to get that data and update your game locally, and continue on with playing your game.
So that's all like the basic bones of what makes up sessions.
So let's talk about some examples of what this actually really looks like when you're actually making a game.
So first basically you've got, you know, your basic turn-based game.
So you've set up your session.
You've got your game data.
You've added a few players.
Maybe it's Player One's turn.
They're going to start by figuring out what their turn is and they're going to save that data.
That data can then be loaded by Players Two, Three, and Four.
Message Player One can then send a message to Player Two, sending it that badge and saying, "Hey, it's your turn now."
Maybe you would like to do that.
Player Two can load up their game, start playing, figure out what they would want to do with that new data, take their turn, save that data, and then pass the turn on to Player Four.
Since there is no specified way in which these turns can be passed that's up to you.
You can pass it from One to Two, Two to Three, Four to One, whatever you want.
There is no specified way in which these turns can be passed and, frankly, we don't know what you're doing.
So you pass the game on to Player Four.
They get to take their turn and continue on.
So you've got all the elements that you need for a really basic turn-based game.
You can also do a real-time game.
So you've got all of your players set up.
You can then basically have everyone turn on their connection states.
As soon as these connection states are turned on we will set up the pipes in the background to allow them to communicate with each other.
And as soon as all of those are set up then your players can start sending data to everyone else.
And then this data will be just sent as long as these connections are available.
And then with sessions, if there's any sort of information you would like to be able to store at the end, such as, you know, who won, or rankings, or anything for this particular real-time game, you do have that ability to have a little bit more of a persistent data that you might want to save with that session.
So those are your real basic examples.
But the real power session comes in in being able to do much more complicated games.
So say you've got a game session.
It's a turn-based game but you want to do a little bit more of a complicated turn.
They've got a game.
It's got some trading card elements so when it's the player's turn you might be able to trade cards, maybe brick for sheep or something.
And so the things that you might be able to accomplish with table talk on an actual board game you can now more easily accomplish with sessions.
So say it's Player One's turn and they want to trade with the other players and so they send out a message and say, "Hey, I'd like trade brick for sheep.
So you can send that message.
You can send a little bit of data with that message to let the users know, "Hey, this is what I want," and send it out to everyone.
Say Player Four is like, "Oh, yeah.
That sounds really good.
You know, I'll take that trade," or, "Yeah, well, you know, that doesn't work for me.
How about wheat for sheep?"
or something else.
So they can send a message back to Player One, badging them and saying, "Hey, this is, I either, I'll accept your trade or I have a different trade."
You can send that message back and forth, figure out what you want to do.
As soon as Player One decides, "Okay.
Well, I'll take that trade," or, "I won't take that trade," they can their turn, unbadge everyone else, and save their data, unbadge themselves, and then pass the turn on to Player Two.
We also have the ability to more easily join into multiplayer games that might be a little bit more complicated.
So say you've got a multiplayer game that's a little bit more like a King of the Hill type stuff.
You've got all these people in session but you only want two of them to be able to play at a time.
So you're going to start up your session.
You've got Players One and Two.
They're going to turn on their connection state.
They're going to join into a game and they're going to pass their data back and forth.
They're going to have a little head-to-head, a little one-on-one, and fight.
And one of those players will be eliminated.
In this case let's say Player One.
And then Player Two will go on and then play with the next person in line.
You don't have to stop your game in any way.
You don't have to set up any sort of connection screen.
As soon as Player Three sets their connection state then you can start sending that data back and forth to Players Two and Three immediately and they will be able to have their little bout, see who wins.
This time [inaudible] and then Player Four can then come in and join in the fray.
They can make that connection and continue on.
And you can continue on with this, continuing to do any sort of round-robin.
If you've got like 100 players, you can go through all 100 players.
And just continue to have a little King of the Hill style fight.
And then you can store that data to your game data that will allow to have a little bit more persistent rankings and a little bit more persistent [inaudible] among the people that are in this session.
Another situation that we might run into is assisted single player.
So say you've got a single player game.
You're using Sessions to basically store your data which is totally fine.
You can absolutely do a single player game with Sessions and basically use this as a way to store your data and send your data so that all of your data can be updated across all of your devices very easily.
But say your player is having a little bit of a hard time.
They've been playing this game for a little while.
Then they can't get passed this level.
They're having a really hard time.
Well, if you implement your game as such, then Player One can then share their game with another player.
And so they can bring in Player Two.
And then you can either add some elements that will allow Player Two to help Player One through that level, through some co-op methods, or you could even just allow Player Two to just play that level for Player One so that they can get past that really sticky point in your game, allowing Player One to have a little bit more enjoyment.
So Player Two can come in, say, do whatever you would like to let them do.
Save that data, so the game data.
And then they can lead themselves, removing themselves from that game and Player One can continue on playing that game just as if Player Two had never actually even been there.
So that is Game Sessions.
This is going to allow you to be able to basically play with anyone, anyone that has an iCloud account you can play with.
You don't need to be their friend in any sense of the word.
So much more flexible game structure that is going to allow you, as developers, to be able to set up your games in whatever manner you would like.
We have really, really simple multiplayer connections.
They are really easy to set up, really stable.
They allow for lots of data to be passed back and forth.
And we're really excited to see what new possible game styles you're going to come up with because of the power of Sessions.
Because of this mixing of turn-based and real-time elements for these games we're really excited to see what you're going to come up with.
So that's what's new in Game Center this year.
We had our new message-based multiplayer invite which are now going to allow you to play with anyone that you can message.
We have removed the Game Center app.
We have those persistent game sessions that we just talked about.
And we have also announced Apple Watch support.
If you would like any more information on this session, you can go to this link.
We are session number 611.
And we have a few related sessions that you might be interested in.
We have the "Game Technologies for Apple Watch" later on in this afternoon.
We've also had several sessions earlier this week that you can go and watch the videos for, and several others, even more than what's listed here.
Thank you for coming and have a great WWDC.
[ Applause ]