I am planning to implement a friend system with online status reporting.
any player can be in one of these states:
- Red: the player is offline (disconnected), or has the (android/ios) app in background
- Green: the player is online and navigating the main menu of the app
- Yellow: the player is currently playing in a match
this info should be made available to all the player friends, which include:
- in-game friends, internal to GS platform (currently implemented with teams and nosql)
- social friends, i.e. facebook and google+
when players changes state, ideally this info should be visible to all their friend as son as possible.
we are currently planning to have each player update their status, then when a player visualize his friend list, we make a request to fetch all the friends' statuses, but by doing so we don't have a realtime update to them. (we could periodically poll them)
another approach is each client sending a message to everyone, but we don't know if this is feasible (considering that we could have many users, and some of them will have many friends, both social and in-game, therefore worst case this is O(n^2) )
what is the recommended approach?
Sparks loadPlayer call may be of use to you here. You'll be able to load a player and then check if they are online from there. You could use the following to do this.
//will return true or false var player = Spark.loadPlayer(playerId) player.isOnline() //get the players status player.getScriptdata(name)
If you set the players current status to scriptData you could also retrieve it using loadPlayer. If players are in a team their scriptData will be visible in the GetTeamResponse. So you could send this request to get an update on all friends at once if you wish. Does this sound like it might work for you ?
yes, this is similar to what I am planning to do (except I already have a custom GetFriends event - I use teams only for in-game friends, social friends are taken directly with FB/GP).
my main question is more like if it's better to polling the db while the player has the friend list open or each player pushing the status change to all their friends. I want a fast feedback on the other side but without surpassing the fair usage limit (5k api calls).
also the 'isOnline' flag is not sufficient - I want to differentiate which part of the app the player is in.
my current setup would be something like:
- when a player starts the app and completes the 'boot' routine - i.e. is in the main menu - we set him as 'online'
- when a player starts a match we set him as 'playing'
- when he either closes the app or navigates to somewhere else (i.e. a scene where we are not setup to start a game - like our support section) we set him as offline ( even though GS is still connected)
when a player is online, his friends - in-game team or social - can challenge him for a game
the missing part is to sync the online status between friends - i.e. pushing the state each transition or polling continuously when needed
If you are manually setting the player status to "online" (and other custom statuses) you could use the loadPlayer suggestion from above. If you have a list of friendIds you could simply use loadPlayer to load the particular status for each friend from scriptData. For example if you opened the friendlist you could load each of the friends and return their online status. For when a players status changes when they are online you could send a SendTeamChatMessageRequest with the status update so the other team members will be updated of the status change. You'll just have to listen for this message and handle it accordingly as it comes in.
ok, if I understand correctly:
- when the player loads his friend list, include the current status
- don't poll the statuses manually
- when a player changes status, send a team chat message to the player team.
-- this works for 'internal' friends. what about social friends? is there an equivalent message to send? we currently manage them client-side with the social SDK and fetching each one with their external id...
also, is there a way to quickly react to a player backgrounding&closing the app? Unity's OnApplicationPause/OnApplicationQuit is too late for sending a networked request (at least in android).
the only other ways I could think involves sending a "ping" LogEventRequest regularly, but then we risk overflowing the fair usage limit for requests...
If a player (you for example) opens the friend list you would ad this point use "loadPlayer" on your friends to retrieve the status that is stored on their script or private data to update your UI. If a friend has a status change in game you would use the scriptMessage method to update the other team mates. To send a message to friends you could use the SendFriendMessageRequest. For the users closing the app you could try sending an EndSessionRequest using Unitys OnApplicationFocus method.
can you explain how do I use the SendFriendMessageRequest? are the player ids the gamesparks ones or the social ones?
client-side, I only have the social ID that I fetch from (e.g.) Facebook SDK. I have a custom 'loadFriends' event that I use for returning some data of all my friends. until then I don't have my friends loaded.
server-side, is there a way to get all the user friends from a social network?
on the "user opens the friend list" => "load from script data" we agree.
on the "user changes state" => send a message to everyone, I potentially don't have the friends loaded (on the client), so I have to send a custom event or a TeamChatMessage + SendFriendMessage without knowing the receivers (team is automatically all friends), and on the cloud code I have the "team" friends but I am missing how to get the social friends.
ideal flow would be "custom event" => cloud code fetches all team + social friends => custom scriptMessage to all that are online. team and social are handled exactly the same except fetching them.
for the EndSessionRequest, I will try experimenting with OnApplicationFocus/Pause/Quit and see if the event reaches the server in time reliably or if Unity delays the processing to after it resumes.
If the non social friends are in a teamType that's marked as "social" then the SendFriendMessageRequest will send the message to both social friends and the team members in the friend team. The SendFriendMessageRequest will send messages to the friends that are returned in the ListGameFriendsRequest. So if a player has social friends and friends in a social team the SendFriendMessageRequest will cover everyone. Does that make sense ?
so, can I do a SendFriendMessageRequest without specifying the friendIds and it gets sent to all of my friends? the docs says it's required (the team was already marked social)
for the EndSessionRequest, I tried sending it in OnApplicationFocus(false) and it got sent in time on android, but on the editor it got sent after resume (it started sending it when it lost focus but didn't arrive to the server until later). I don't know about the other platforms (i.e. iOS).
is there a way to force-flush the socket and send it instantly?
Mauro, why bother trusting the client to relay that information? The server keeps track of the user's activity, if push comes to shove, you can have the server kick them off after a given length of time and just have the client handle the SessionTerminatedMessage.
Hi Christopher. It's actually the other way around: if player kills the app without properly terminating the session (i.e on Android, he press the home button and kills the app with the task manager - or Android itself kills the app in background) GS server will not register the disconnect until it kills it's own socket, and that can take minutes.
I want an "instant" feedback, i.e. if a friend is offline I want to display it as offline in the player's (potentially huge) friend list (so I can't "ping" each friend each time a player wants to see that list)
Apologies I forgot the SendTeamChatMessageRequest required playerIds unlike the TeamChatMessage. What you can do here is use SparkPlayers getFriendIds call to get an array of friend Ids and then use it with a SparkMessage to message all of the friends. Does that sound like it would work for you here ?
it should. I can call getFriendIds and send the message to everyone. the receiver(s) can listen to the message and update the friend status (if they cached the friend list).
I'll try this and tell you if it worked
Exactly, that's how I had imagined you would use it. If you need anything else just let us know.