we use BinaryFormatter to serialize the player state into a string which we store in PlayerPrefs.
We occasionally get reports of players losing their data upon updating to a newer version of the game.
We’re not sure exactly as to why this happens, and who’s the culprit behind it. Is it BinaryFormatter, PlayerPrefs, or something to do with the user device/manifest settings?
I don’t think the data saved in PlayerPrefs gets erased on every update otherwise all players would have their data wiped and not just a few of them.
- Where does PlayerPrefs store its data on the device?
- Are there any settings/manifest stuff that should be turned on/off for storage to work properly?
- We do ‘add’ fields to the class we serialize and from what we’ve tested, BinaryFormatter can handle ‘new’ fields gracefully, it only breaks when there’s a field rename or change of data type (BinaryFormatter seems to add metadata about the field’s name and type in the stream, I assume that’s why it breaks if either of those change). Am I correct, or is there still a chance that the stream gets corrupt upon adding new fields?
- What are the alternatives to PlayerPrefs? I read about Application.persistentDataPath but that just seems more risky to me due to the whole internal vs external storage. We could also store things in a DB but that would require users to have a connection to play which we don’t want.
It’s really frustrating for players and us when we hear someone lost their data.
Any help, thoughts, ideas or suggestions are appreciated!
I wouldn’t recommend to use the BinaryFormatter as it’s not save to change the structure of the class you serialize / deserialize. It’s better to use something that isn’t bound too strictly to a certain class type. Most serializers will complain when there’s missing data (adding fields) or missing fields (removing fields). The most reliable way is to manually match the serialized data with your fields and simply use XML or JSON as data format. You’re still free to store that either with PlayerPrefs or simply writing a file.
The way how PlayerPrefs are stored depends on the platform. On Android PlayerPrefs are always stored internally inside the data folder of your app. This path can’t be viewed by the user (except when the device is “rooted”). Only your app can access this path. Just see the docs:
On Android data is stored (persisted)
on the device. The data is saved in
Android Java and Native code can all
access the PlayerPrefs data. The
PlayerPrefs data is physically stored
Which path Application.persistentDataPath returns seems to depend on your write access settings and if you do a development build or not. See “colchambers” answer over here. I’m not sure if you can always manually write to
/data/data/pkg-name/files/ anyways. You have to do some testing on that topic i guess ^^.
My SimpleJSON “framework” also has the ability to save the JSON structure in a compact binary format. SaveToStream, SaveToCompressedStream, SaveToCompressedFile and SaveToCompressedBase64 all use that custom binary format. I haven’t implemented any kind of object serialization so you would have to read / write your data “manually”. I usually use an interface that has a
JSONNode Serialize() and a
void Deserialize(JSONNode aNode) method. That way each class can implement it’s own serialization / deserialization.
The version on the wiki has been modified and improved by others and i don’t really have an eye on those changes.
There only ways it is possible are:
- If for some reason, by accident you are setting the playerprefs or updating whenever the new application launches and its only happening a few time rather then happening everytime.(For some reason :P)
- Users wipe their cache/data before installing or after installing for some reason.
- And last but not the least, i only can think of write permissions in your players’ phones.