Idle Game Background Progress

Godot Version

4.4

Question

I want to build an idle mobile game in which the player can earn in-game currency passively while their shop runs “in the background” when the app is closed.

This question has been asked at least three times before, here, here, and in a third question in which the prior two were referenced in the answer. But I’m not satisfied with the answers given.

The answer given to each of these questions, and the solution I thought of a long while ago, was simply calculating progress when you re-launch the game based on time elapsed between when the game was last closed and when the time the game is being launched. This is a fine solution for the most part, but it does open the door to a possible exploit—One could theoretically close the game, change their system time, then reopen the game to regain tons of instant progress. I know most people wouldn’t do this, but it’s still a possible exploit. I suppose you could query time from a server, but I don’t want to require internet access for this game.

One possible determent solution to this exploit is to cap the amount that can be earned while the game is closed, which is a common feature of idle games, but I’m wondering if there are other solutions.

Many mobile games only allow you to take certain actions when you have “fuel” to do so. And when you’re out of fuel you’ll either need to wait for your tanks to refuel, watch ads to earn fuel, or perform in-game transactions to gain fuel. Some of these games will send you a push notification when the tanks are “refueled” telling you to come back to the game. So there are some sort of background processes running on many of these popular idle games, regardless of whether it’s just a timer based notification or actual “background refueling.” Similarly, if you’ve ever played the Lifeline mobile game, there are messages that come from Taylor, the astronaut lost on an alien planet, a certain amount of time after an action was taken. So, even if this is just timer-based, there is a background timer the game is using to send push notifications when it’s off.

How can this be achieved in Godot?

I’m not sure if Godot has access to it, but the trick I’ve seen used in mobile games is invisible local notifications. An app/game on mobile platforms can set a local notification for itself at a future time. There’s a limit to the number you can set, but if you use the system-clock based scheme you can look for discrepancies between the expected notification time and the actual wall time.

You can also chain local notifications, so (say) fire one once a day, and have it queue up the next one. I wouldn’t advise making it happen too often, though; this kind of thing can become abusive if overused.

Actual background processes on mobile are difficult to keep running; the OS actively fights it unless you do something nasty like start grabbing GPS coords or playing music to keep the app alive, and that both eats battery and creeps your players out.

One thing you might want to think about is: Do you really care if someone cheats by playing with the system time? Unless there’s some exploit where they can somehow turn that into an actual expense for you, my philosophy is: Let people play the game they bought however they want. If they want to cheat in a single-player game that’s not net-connected, why stop them?

1 Like

That makes sense, thank you.

I guess the real reason I actually care if a player cheats is because I intend to implement a net-connected scoreboard for events. The likelihood of someone going through the meticulous process of changing their system time over and over again to cheat is unlikely, but cheating is incentivized when your score is publicly displayed. Of course, a scoreboard implies the game will be net-connected, but I don’t want the gameplay to require an internet connection. The optimal setup I’d want would be only utilizing a network connection for uploading and downloading high scores, but not for any facet of the actual gameplay.

If you have a net-connected scoreboard, you could require people to decide at the beginning whether they wanted to do a scored run or a non-scored run. If they do a scored run, connect to the scoreboard at the beginning of the run and submit a UUID or something. At the end when they want to submit the score, submit the same UUID with it.

That still only requires two connections (one at the very beginning, one at the very end), but it gives you two points in time you can timestamp on your server where they can’t mess with the time.

With that, you should be able to detect any obvious shenanigans; submit an accumulated runtime along with the score, and if it doesn’t more or less match up with the distance between the two timestamps (particularly if it’s significantly longer than the real-world passage of time) flag them as a cheater.

1 Like

That’s a good idea, thank you! I’d need to kinda modify the way I intend to set up events to make this work, but this is definitely a solution! Thank you!