Need help deciding the backend architecture for a game

Thank you for your time. I don’t have friends or colleagues to help me out with this.

The game is 1v1 turn based, kindish. There is a plan phase that last 30seconds, and an action phase. Both players submit their actions in the 30seconds window, then the backend does the calculation.
The data format sent or read by the client (Unity) is in JSON format.

In the future there will be 2v2, or 4 players free for all.

What I have right now:

  • Google Cloud Firestore Databse
    – Holds the game state.
    – Each client will subscribe to match entry and update on change.
  • Unity Lobby
    – Holds the match id.
    – Track if players submited their actions.
  • Unity Cloud Code - for match creation
    – Receive params: game mode
    – Reads Unity Remote Config
    – Returns the first state of a match
  • Unity Cloud Code - for action phase
    – Receives params: game state, players actions.
    – Calculates the output of a round and returns it.

Now my problems:

  • How do I read each player actions to pass it to Cloud Code? (when the 30seconds pass, or both submited)
  • Where do I connect to database to update state?
    – Relay would be a solution, but that is on a client side, and can result in cheating. (we don’t like cheaters, we try to avoid that)

Can Lobby get information from each client? I see it can hold player data, but 2KB is not enough. Also Lobby is created by a client, can’t offer access to oponent actions/state.

Any suggestions?

The game is playable atm as single player, with the opponent being a very bad AI. The backend development will be the next major step.

Thank you.

This sounds similar to a turn-based battler I built, just using different tech.

First problem:

Your client should send the player actions to a cloud function that sanitizes and then saves them to the game state (your Firestore DB in this case). When all actions for a turn are submitted to this cloud function, it should execute the turn using the data and send the result to both clients (I used websockets on clients that listened for DB changes).

Second problem:

The only thing that should have the ability to update the game state is your cloud functions. The clients should never be able to write to the database directly. It looks like you can use javascript in Unity Cloud Code, which is probably the most accessible way to access Firebase. I think there is also a C# SDK for Firebase, just probably isn’t as widely used or well documented.

In a nutshell, the clients should just send data and listen for changes to the database (read-only access). The server side cloud functions should receive data and change the database (read/write access).

1 Like

I understand the issues, and the limitations, i’ve mentioned them, but I didn’t get your soulution.

Who are you refering to as “your client”? One of the players? It can’t be as he can’t have the rights to write in database.
Also, when calling Cloud Code, i need current game state and the actions of all players.

Having a Cloud Code connecting to a database and writing in it, is not cost efficient. Cloud Code should run as fast as possible, and should not wait for async calls.

Cloud code execution time excludes time spent waiting for async calls.

You have to have a server-side layer for clients to write data into the database. The client must never have a direct connection to the database. Commonly, clients will interact with a remote webrequest API like “SetPlayerName” to ensure the player is verified, the name is within string limits, it may even do a simple profanity check but most importantly it will sanitize the string to prevent SQL injection attacks.

FWIW Relay has nothing to do with your requirements. Relay is required to enable client-hosted games, so that clients can connect to the host player without the host having to set up port forwarding and firewall rules.

1 Like

Wow, this is hudge information. Thanks for sharing.

Yes, I get that. But with Cloud Code (Game state management) each player will make a request to function. That doesn’t work for me, as the function needs the actions of both players and current state, and it must run after 30s, even if players didn’t submit their actions.

Should this work:

  • Lobby starts 30s countdown.
  • Clients call Cloud Code #1 to save actions with Cloud Save
  • Clients notify Lobby of succesfull actions submision
  • If both clients notify Lobby OR 30s countdown ended
    – Lobby will call Cloud Code #2 for new state
    — Read actions from Cloud Save
    — Perform logic of new state
    — Write new state in database (for history)
    — Notify clients of new state with Push Messages

That will be 3 writes and 1 read for each turn.

Should I look into Multiplay Hosting, although it’s advertised for “large scale gamemodes”?

Not even with read only permissions, for a specific field in database?

How about letting Cloud Code trigger a client-side request every 30s? Check if we can set up a timer trigger like this. In that case it would work as follows:

  • CC runs trigger “30s elapsed”
  • CC requests actions from both clients
  • CC has a timeout eg “5 seconds” for clients to deliver the actions
  • CC notifies clients of new state, updates database, etc
  • CC restarts 30s trigger

Strictly speaking, no. You would have to include user account information (name, password) in the app. There’s always the risk that a) user permissions are changed to allow writes by accident or because someone wasn’t aware and b) the database might have a security flaw that might allow even read-only users to execute write statements, or even gaining root access to the server. The latter is extremely unlikely but if it occurs, the potential damage could be disastrous.

Thank you for guidance.

Will look into your solution.
Will also research more what Cloud Code can do, and will come back.

Yes, by client I mean one of the players.

The cloud function they send data too should receive, sanitize and only write to the database if it’s determined to be a valid action. When the cloud function is executed you can have it read the game state to get the actions of all players.