I'm developing a multiplayer word game for mobile in Unity. I've been using GameSparks as a backend, but felt that it didn't give me the control I wanted over the project. After looking around a bit, I decided to go with Firebase. It felt like a good decision, but now I'm experiencing some serious slowness with the database + Cloud Functions
The game has a turn based mode where you play a round and get a notification when your opponent has finished. A round is uploaded via a cloudscript call, with only the necessary data. The new game state is then pieced together in the cloudscript and the game database entry (activeCasualGames/{gameId}) updated. After this is done, I update a gameInfo (activeCasualGamesInfo/{gameId}) entry with some basic info about the game, then send a cloud message to notify the opponent that it's their turn.
The data sent is only 32 kb, and no complex changes are made to the code (see cloud function code below). The complete database entry for the game would be around 100kb max at this point, yet the time from sending the round to the game being updated on server and opponent notified ranges from 50 seconds to more than a minute. On GameSparks, the same operation takes maybe a few seconds.
Does anyone else experience this slowness with Firebase? Have I made some mistake in the cloud script function, or is this the performance I should expect? The game also has a live mode, which I haven't started implementing in Firebase yet, and with this kind of lag, I'm not feeling that it's gonna work out too well
Many thanks in advance!
exports.uploadCasualGameRound = functions.https.onCall(
(roundUploadData, response) => {
const roundData = JSON.parse(roundUploadData);
const updatedGameData = JSON.parse(roundData.gameData);
const updatedGameInfo = JSON.parse(roundData.gameInfo);
console.log("game data object:");
console.log(updatedGameData);
console.log("game info:");
console.log(updatedGameInfo);
const gameId = updatedGameData.gameId;
console.log("updating game with id: " + gameId);
admin
.database()
.ref("/activeCasualGames/" + gameId)
.once("value")
.then(function(snapshot: { val: any }) {
let game = snapshot.val();
console.log("old game:");
console.log(game);
const isNewGame = (game as boolean) === true;
if (isNewGame === false) {
console.log("THIS IS AN EXISTING GAME!");
} else {
console.log("THIS IS A NEW GAME!");
}
// make the end state of the currently stored TurnBasedGameData the beginning state of the uploaded one (limits the upload of data and prevents timeout errors)
if (isNewGame === true) {
updatedGameData.gameStateRoundStart.playerOneRounds =
updatedGameData.gameStateRoundEnd.playerOneRounds;
} else {
// Player one rounds are not uploaded by player two, and vice versa. Compensate for this here:
if (updatedGameData.whoseTurn === updatedGameData.playerTwoId) {
updatedGameData.gameStateRoundEnd.playerTwoRounds =
game.gameStateRoundEnd.playerTwoRounds;
} else {
updatedGameData.gameStateRoundEnd.playerOneRounds =
game.gameStateRoundEnd.playerOneRounds;
}
updatedGameData.gameStateRoundStart = game.gameStateRoundEnd;
}
game = updatedGameData;
console.log("Game after update:");
console.log(game);
// game.lastRoundFinishedDate = Date.now();
game.finalRoundWatchedByOtherPlayer = false;
admin
.database()
.ref("/activeCasualGames/" + gameId)
.set(game)
.then(() => {
updatedGameInfo.roundUploaded = true;
return admin
.database()
.ref("/activeCasualGamesInfo/" + gameId)
.set(updatedGameInfo)
.then(() => {
exports.sendOpponentFinishedCasualGameRoundMessage(gameId, updatedGameInfo.lastPlayer, updatedGameInfo.whoseTurn);
return true;
});
});
});
}
);