Sign In Register

How can we help you today?

Start a new topic
Answered

cloud code scheduler best practices

A big part of my game is buildings that generate resources, for example, a lumber mill that generate X logs per every X seconds.


 I'm wondering what the best approach is for handling large numbers of buildings like this. 


It would be pretty straightforward to handle this by using your scheduler, but I'm not sure if that will scale well with large number of buildings with a large number of users (a building recursively schedules its own resource update). 


Another possibility is performing the resource generation in batch with the system scheduler. 


One problem with this is that updates can only happen on intervals of a minimum of 1 minute with your system.


I also could potentially do all the updates lazily, right before someone attempts to retrieve an update (a player queries for an update and all resource updates are calculated on demand). But this seems to complicate the implementation significantly, especially for handling cases where a building completed construction between lazy updates and taking into account its additional resource production.

          


Best Answer
Hey Bruce,

You are totally right, it could get very complicated trying to calculate all this on the server side.
If you wanted to do this all on GameSparks however, you can.
I would advise you to store the player data in a collection, along with the player id, so when requesting the data on the client-side you can get data back for a specific player, something like the form below.

You will probably want to be able to update that list from the client too. I would expect up might want to upgrade the production rate and amount if the buildings get ungraded through the game for example(?), and it would be a good idea to do an update when the session ends so the players details are all defiantly in sync. So, you will probably want an event that will update the player's game-details and one to retrieve and update the game-data client-side.

But updating your game-data server-side might be a problem.
Adding a date to the building info isnt a problem, and you can always use the less-than mongo-request ( { "updateTime: {" $lt : new Date()   }}) which will let you know if the building needs to be updated by checking if a certain time has passed the current time.
However, you will most likely need check each player's building list to see if it needs updating and that might get expensive. If you are expecting some really heavy loads you should probably contact us and see if we can simulate those numbers, but i think you might be okay if you wanted to go that way. The cloud-code is pretty efficient, and since you are doing an update once a minute, it shouldn't be too much of load, and remember that all the building wont need to be updated each minute. You could also reduce the load by getting the more immediate updates and sending them to a batch that only updates when the list has been checked, so you aren't updating the list while it is still being searched through (also use findAndModify instead of update to make the update more efficient).

Or, another alternative, as you said, you could do all the updates when the player tries to retrieve the information, which will also be every minute or so. This wont reduce the requests you'll have to do to the server but it is more efficient as you only have to worry about one event running updates, instead of updates running every minute, and the server can handle a request every minute no problem. You can simply find the seconds passed between the last update, and check how many units you could have produced in that time. Its probably a better alternative, and one that should be easier to program on both the server and client side.
You could event have the update and retrieve events be the same one; so long as you submit data to the event, it will rewrite the buildings data, if there is no data send it will only update and return the new resource data in the Spark.setScriptData()

It sounds like you already have an idea of what you can do and what the up/down-sides are, but i hope that helps.

- Sean

 

 "id": "5620e74d6e7827b123445a37",
 "resources": [
  {
   "Wood": 10,
   "Stone": 10,
   "Food": 10,
   "Gold": 1
  }
 ],
 "buildings": [
  {
   "generatorID": "lumberYard1",
   "resource": "Wood",
   "productionRate": 120,
   "unitProduction": 10,
   "updateTime": {
    "$date": {
     "$numberLong": "1445009190449"
    }
   }
  },
  {
   "generatorID": "quarry1",
   "resource": "Stone",
   "productionRate": 120,
   "unitProduction": 30,
   "updateTime": {
    "$date": {
     "$numberLong": "1445009190449"
    }
   }
  },
  {
   "generatorID": "farm",
   "resource": "Food",
   "productionRate": 60,
   "unitProduction": 10,
   "updateTime": {
    "$date": {
     "$numberLong": "1445009190449"
    }
   }
  },
  {
   "generatorID": "goldmine1",
   "resource": "Gold",
   "productionRate": 300,
   "unitProduction": 10,
   "updateTime": {
    "$date": {
     "$numberLong": "1445009190449"
    }
   }
  }
 ]

 

 

1 Comment

Answer
Hey Bruce,

You are totally right, it could get very complicated trying to calculate all this on the server side.
If you wanted to do this all on GameSparks however, you can.
I would advise you to store the player data in a collection, along with the player id, so when requesting the data on the client-side you can get data back for a specific player, something like the form below.

You will probably want to be able to update that list from the client too. I would expect up might want to upgrade the production rate and amount if the buildings get ungraded through the game for example(?), and it would be a good idea to do an update when the session ends so the players details are all defiantly in sync. So, you will probably want an event that will update the player's game-details and one to retrieve and update the game-data client-side.

But updating your game-data server-side might be a problem.
Adding a date to the building info isnt a problem, and you can always use the less-than mongo-request ( { "updateTime: {" $lt : new Date()   }}) which will let you know if the building needs to be updated by checking if a certain time has passed the current time.
However, you will most likely need check each player's building list to see if it needs updating and that might get expensive. If you are expecting some really heavy loads you should probably contact us and see if we can simulate those numbers, but i think you might be okay if you wanted to go that way. The cloud-code is pretty efficient, and since you are doing an update once a minute, it shouldn't be too much of load, and remember that all the building wont need to be updated each minute. You could also reduce the load by getting the more immediate updates and sending them to a batch that only updates when the list has been checked, so you aren't updating the list while it is still being searched through (also use findAndModify instead of update to make the update more efficient).

Or, another alternative, as you said, you could do all the updates when the player tries to retrieve the information, which will also be every minute or so. This wont reduce the requests you'll have to do to the server but it is more efficient as you only have to worry about one event running updates, instead of updates running every minute, and the server can handle a request every minute no problem. You can simply find the seconds passed between the last update, and check how many units you could have produced in that time. Its probably a better alternative, and one that should be easier to program on both the server and client side.
You could event have the update and retrieve events be the same one; so long as you submit data to the event, it will rewrite the buildings data, if there is no data send it will only update and return the new resource data in the Spark.setScriptData()

It sounds like you already have an idea of what you can do and what the up/down-sides are, but i hope that helps.

- Sean

 

 "id": "5620e74d6e7827b123445a37",
 "resources": [
  {
   "Wood": 10,
   "Stone": 10,
   "Food": 10,
   "Gold": 1
  }
 ],
 "buildings": [
  {
   "generatorID": "lumberYard1",
   "resource": "Wood",
   "productionRate": 120,
   "unitProduction": 10,
   "updateTime": {
    "$date": {
     "$numberLong": "1445009190449"
    }
   }
  },
  {
   "generatorID": "quarry1",
   "resource": "Stone",
   "productionRate": 120,
   "unitProduction": 30,
   "updateTime": {
    "$date": {
     "$numberLong": "1445009190449"
    }
   }
  },
  {
   "generatorID": "farm",
   "resource": "Food",
   "productionRate": 60,
   "unitProduction": 10,
   "updateTime": {
    "$date": {
     "$numberLong": "1445009190449"
    }
   }
  },
  {
   "generatorID": "goldmine1",
   "resource": "Gold",
   "productionRate": 300,
   "unitProduction": 10,
   "updateTime": {
    "$date": {
     "$numberLong": "1445009190449"
    }
   }
  }
 ]