Efficiently matchmaking players in firestore - firebase

I'm working on a game that requires player matchmaking i.e. putting 2 players into 1 battle room.
While there are few players online in the game this is not an issue, however if we assume scenario of 1,000,000 players online at a time, who are all trying to matchmake, then picture becomes more complex.
Assuming following flow
My first instinct was to
When player clicks "play" call cloud function that checks if "open" battle room exists.
If there is one open, place player in it and start the battle or set battle to be active.
In case there wasn't an open room, we create new one and wait for another player to join.
However I see a lot of issues here given that we have 1,000,000 players who would be performing this action. For example, while performing step 2 and setting room to be "active" we might be pushing more players into it during the time those requests resolve?

If you want to deal with concurrency, I think you should use transactions to perform this action (adding a player to a room). That way, you ensure to check if the room is still open before adding a player in it. If 2 players start a matchmaking at the same time and find the same room, then only one single player will be added to that room
https://firebase.google.com/docs/firestore/manage-data/transactions

As far as I understand I can suggest One way to make it easier is have state of a user itself instead of calling cloud function to create room
Make user state like active, online, offline. When a user press play set its state active.
Call a query to fetch user where state == active , limit to 5(example).
start a transaction to match it with first user if succeed change status to playing for both else if failed ( you got matched to someone else or player you were trying with got matched to someone) check next player.
If during this you should be always observing your own state if it changes to playing because someone else matched to you then straight head to game.

Related

Tracking events and making sense of it

Lets say I wish to track
User action - game he played - which area he stays - his house number.
If I were to track these event actions in Tabular format, it would look like:
UserId|Game|Area|House|Timestamp so on.
Then I can always run SQL queries if I want to answer few business queries. Like
1. In a given day/week, who is the most active User
2. Which game is most-played?
3. Which area plays most events
4. Which user from which area are the most active
Whats the best way to capture this using Google analytics? Will custom dimensions be useful. Or GA is not suitable for this kind of insight?
Thanks.
First of all, the house number is too precise, it would be against GA's ToS.
In GA everything is captured in "hits", you can think of this as one "row" of data.
Let's look at what you wanted to find out:
Most Active User? - This depends on how you determine "Active". Is it the longest Session durations? Tried most games? Most logins? Most sessions? To track a user, you'd need a User ID tracked.
Which game is played the most? - Again, what is played the most? Longest time in game? Most "start" games? This would require you to know the Game that was played and when someone started playing
Which area is most active? -This would go back to the definition of active, the region information is needed along with the active definition
Which users are most active in an area? Same as above, the user would need to be identified and area
To determine which Custom Dimensions (CDs) you want, let's look at the example data points you want to track and try to determine the scope and if it already exists as a standard dimension:
User ID - this is obviously related to the user, makes sense to be user-scoped
Game - This is a tougher CD. I would think that in a single session, users can play multiple games, thus I'd think you'd want this to be hit-scoped.
Area - GA already provides this based on the ISP
Timestamp - GA already provides time dimensions
From above, we can determine that you need to create two CDs, one to track User ID, the other to track the Game.
You can also look into using the userid feature in GA for cross-device tracking.

Best Practices using Firebase (Saving)

I'm currently making a online mobile game. It's like an online Idle Clicker.
In order to save the data I will use firebase. I'm still deciding if I should use the "Realtime Database" or " Cloud Firestore". (If any of you could help me too I would appreciate).
My main question is: When should I save my data ?
Saving the data every second is crazy because I will spend millions of euros. Even saving the data every minute seems not a viable solution to me.
I have searched and I can save the game everytime the user press the Home Button to leave the app. What if the user is playing and the phone dies?
Is there any other better solution that I am not thinking of ?
Thank you very much, Gonçalo
I would use OnApplicationQuit() for this. It's called whenever your game is closed. It won't be called if the device loses power though, so if you're worried about that you could start a timer when the game is opened and do autosaves every 10 minutes or on certain scene switches (if the player exits to the main menu for example).
This thread has more info on the topic that you may find useful.

How to match users randomly with Firebase [duplicate]

This question already has an answer here:
Randomly pairing users in Firebase [closed]
(1 answer)
Closed 2 years ago.
I'm trying to create a game where users are matched with each other randomly using Firebase.
My idea to match them is like this:
User A comes, reads list of games. If there aren't any games waiting start game. Sets himself as initiator, opponent as null.
User B comes, reads list of games. Finds User A's game (opponent is null) and joins it (he becomes the opponent)
What happens if User C comes between the moment where User B read the games list and the moment User B wrote himself as the opponent (for him opponent would still be null). Basically the concurrency problem.
I've read about transactions but I'm not 100% sure they help in this case (Read games with no Opponent, Write opponent to one of the games) because I've seen them used a lot in increasing values rather than reading/writing data.
Transactions blocks are used for concurrency. What they do is prevent issues when two users attempt to write to the same area at the same time. Like you said this is commonly seen with likes. So if the game currently only has 1 player and you save a value of 0 so other players know the game is "open". When a player attempts to connect to that game they write to that area and change the 0 to a 1. If another player attempted to connect at the same time their transaction block will now fire. When they get the data they will see a 1 though not a zero. At this point you back out and look for a new game. Not sure if this is the best method, but it should work.

Unity and Photon Networking - Wait for other players

I am currently trying to integrate a multiplayer option into my unity game with photon networking.
However, I do have some questions: I created the GUI with Unity's new GUI System. I am not using OnGui at all.
What I am trying to do is let a user create a room. After he/she created a room, the user will be redirected in some sort of a "waiting room" in which he waits for other players to join.
How is something like that done? All the tutorials just basically cover up how to jump right into a game. But what I want to do is get them together inside this "waiting room" and start the game (by switching the scene) once max players is reached.
I am able to create a room in the editor. I also made a build so I can test it out on my laptop. I tried to show all rooms inside an update(). But it won't show any rooms at all although I've created one.
I think I'm missing out on something, any tips?
Thanks!
What prevents you from using Photon lobby system? Player created the room sits in the room and waits while other players in the lobby choose which room join.
If you cant use the lobby system then just loop through the amount of photonplayers and see if there is only one of you in there.
if (PhotonNetwork.playerList.Count == 1) Teleport_To_A_Waiting_Zone();
Photon doesn't have a "waiting room" or any sort of pre-room lobby.
When not in a Room:
- You can get the list of rooms, and call create/join.
Once you are in a Room:
- Well.. you're in the room :)
I faked a "lobby" for one of my games by using a "custom property" on the room", when the room is created you can set a property such as ["roomState"] = "notready"
Then when all the players are in the room, change the state.
Your main loop could check the property and if it's not set, then just wait or exit the loop, etc.

How can i stop two people booking the same appointment time

As the title states, how can i stop two users from booking the same appointment time.
Example, two users logging, on there screen they can both see that a 1pm appointment is available. They both try to book themselves into that appointment time.
How can i stop this from happening and ensure only one user can book it, then refresh the screen to show the next available booking time to the other user.
Thanks.
That's a fairly classic use case. You can simply display the appointment plan at a specific time. That can remain static or you can set up a periodic process (for example, every five seconds) to update the plan with new information.
Then, when the user/operator decides to book a free timeslot, it tries to do an (atomic) update that will fail if someone else has slipped in (using primary key or some other unique constraint). The atomicity of the update operation guarantees that only one person can book the timeslot. If the update works, voila, you have your time booked.
If it fails, notify the user of that fact and then load up the new appointment plan.
Rinse and repeat until the user has their booking or they wander off, disgruntled.
I do not think that this is optimal. Why don't you opt for a first clicked/first served pattern ?
What may happen if you have 10 users or more viewing the same page ? A user viewing a page does not mean that he will click on a time slot. So IMHO wait for a user to REALLY click and then notify eventually other users that a time slot they are viewing has been booked (As it happens with StackOverFlow when somebody answers a question while you are answering)

Resources