Some users unable to create/read files in persistentDataPath

Some users of my game are experiencing an error where the game freezes whenever it tries to write a file to the persistent data path, which it does before starting a new game. This doesn’t throw an error in the log. Not all users experience this issue, and I am unable to replicate it on my end; this code works fine for me. Here is the code that seems to be causing the issue:

public void SaveGameSettings()
    {
        GameSettings gS = new GameSettings();

        gS.version = float.Parse(Application.version);

        //setting a bunch of settings in the file to write

        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Create(Application.persistentDataPath + "//settings.game");
        bf.Serialize(file, gS);
        file.Close();

        Debug.Log("Saved game settings");

        //spawn a UI element to indicate settings were saved
        CollectibleDat dat = new CollectibleDat();
        dat.text = "Saved Game Settings";
        dat.sprite = settingsIcon;

        GameObject indicator = Instantiate(indicatorPrefab, new Vector2(Screen.width / 2, 0), Quaternion.identity, Data.dialogueManager.transform);
        indicator.SendMessage("GetDat", dat);
    }

I wonder if perhaps more-recent operating system versions have been patched to make BinaryFormatter() objects fail to even be created… not even sure if making such an object involves as syscall that could be intercepted… here’s why I wonder that:

Do not use the binary formatter/serializer: it is insecure, it cannot be made secure, and it makes debugging very difficult, plus it actually will NOT prevent people from modifying your save data on their computers.

Have you tried just writing a normal “dummy” text file and reporting if that succeeded?

Otherwise perhaps these users have insufficient drive space, perhaps because something is configuring their saves to go to a smaller drive or partition?

I was unaware of this! No, I have not tried that, but I’ve been corresponding with some users who are having this issue and will give it a try.

Just heard back that this worked, it seems like the BinaryFormatter is the issue. I guess I need to learn .xml or something and figure out a way to make it backwards-compatible with existing save data for those users that didn’t have any problems.

Oh my goodness, anything but XML!

"So let’s say you have a problem to solve.
And you decide to use XML.
Now you have two problems to solve."

Just use JSON.

Problems with Unity “tiny lite” built-in JSON:

In general I highly suggest staying away from Unity’s JSON “tiny lite” package. It’s really not very capable at all and will silently fail on very common data structures, such as bare arrays, tuples, Dictionaries and Hashes and ALL properties.

Instead grab Newtonsoft JSON .NET from the Unity Package Manager (Window → Package Manager).

If you want to avoid the Package Mangler’s UI, just add this to your Packages/manifest.json file:

"com.unity.nuget.newtonsoft-json": "3.0.2",

The former asset store package is now deprecated, as you can see here:

Also, when working with JSON, always be sure to leverage sites like:

https://csharptojson.com

1 Like

Addendum: all I/O operations should be within a try/catch block! Only then do you have a chance of logging and otherwise handle the error, such as displaying a message to the user, telling him a failure reason like “hey, your disk is full”.

As a rule of thumb: Any I/O operation can, and will, fail for some users for some reason.

The same goes for Parse … at least use TryParse so if Unity did happen to modify their version string you don’t have to have a seemingly random crash bug in your save method.

I hope this is the one and only place where you call SendMessage. Aka: From anywhom, to anywhere, with strings attached. Goodbye decoupling, welcome almighty blob of unreliably executable strings!

Additionally it’s been disabled as of .NET 8 and is scheduled to be removed with .NET 9. Code you write for Unity won’t be impacted until the release of the scripting runtime update, but if you need code in Unity to communicate with .NET code outside of Unity (eg ASP .NET or similar server-side code) you won’t be able to use it.

https://github.com/dotnet/designs/blob/main/accepted/2020/better-obsoletion/binaryformatter-obsoletion.md

Unity provides a serialization package too which supports text and binary JSON. I don’t believe it’s as capable as Newtonsoft JSON .NET but it’s designed for Unity and more importantly its deserialization is compatible with the Unity JobSystem and Burst compiler if you need high performance deserialization with no allocations.

https://docs.unity3d.com/Packages/com.unity.serialization@3.1/manual/index.html

Hello! I converted to Json and it didn’t work. It looks like the problem might have been a number parsing error in regions that use commas for decimal places, causing an overflow exception. The problem was with my version number:

gS.version = float.Parse(Application.version, System.Globalization.CultureInfo.GetCultureInfo("en-US"));

Adding the CultureInfo argument seems to have fixed it.