Android - safety of saving in-app currency info on local machine

In my game, user collects coins which can later be spent on different skins and upgrades in the shop. Number of owned coins is saved on the local machine wih this primitive code:

function Increase_money(amount)
	local  filename = sys.get_save_file("shep", "money") -- path too save file 
	local data = sys.load(filename) -- loads data
	-- increase
	if data.money == nil then
		data.money = 0 
	end
	data.money = data.money + amount
	-- save money 
	sys.save(filename, { money = data.money })  
end

function Money()
	--returns current money 
	local  filename = sys.get_save_file("shep", "money") 
	local data = sys.load(filename) -- loads data

	-- check if data.money exists
	if data.money == nil then
		data.money = 0 
		sys.save(filename, { money = 0 })  
	end
	
	return data.money 
end

(TLDR: amount of owned coins is saved directly via sys.get_save_file(). =

Apart from collecting coins, user can also buy them via in-app purchases. Because of that, it is in my interest that the in-game currency mechanism would be safe and free of easy-to-find exploits.
I guess this is not the case right now? Data, saved on local machine via sys.get_save_file() can probably be easily accesed and changed from outside the game.

What are some workarounds that fix my problem?

  • I could implement another in-game currency, which is not saved on local machine, but rather just on google servers, and can only be collected via in-app purchases, and than make some of the upgrades available to buy just with this new currency. But I would like to avoid this solution, because I still want every part of the game to be (theoretically) accessible without paying.
  • I could save the number of owned coins just on some servers, but I want to avoid being reliable to internet services. I want my game (outside of iap) to be fully functionable without internet access.

Is there a way to only have one in-game currency and store the number of coins safely on my machine? My guess is, I could encrypt the number somehow before saving, but I do not know which tools are suitable for that.

Is it a single player game or will there be opportunities for players to interact with other players? If it is a single player game I would honestly not bother with trying to protect anything. Sure, there will be a tiny fraction of your player that are willing to root their devices or install hacks or attempt to use developer tools to get more coins or whatever, but the large majority of your players will not. So why care?

If it is a multi player game then you have a completely different situation on your hands and need to consider anti-cheat measures. Server side solutions or server side validation of certain actions is something to consider.

You do mention that you don’t want to involve any servers which makes me thing it is a single player game.

Since you mention Android I would also like to point out the Play Integrity API which you can use to detect risks. Some additional information: Investigate Play Integrity API · Issue #1 · defold/extension-playintegrity · GitHub

3 Likes

Thank you, you answered all my questions!

I had provided insufficient amount of information. Yes, my game is single player and I won’t care if the small percentage of users cheat.

If I’m not wrong, the file content saved by sys.get_save_file() is encrypted so it’s hard to cheat even if they can access it. If your game is offline this is a not bad option to store user coins

No, get save file is only giving you a path to save to.
And, our sys.save() function doesn’t encrypt the data.

1 Like

We do not encrypt save file data. We do however encrypt Lua files in the archive: