Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Question Unity WebGL Saving system for a game.

Discussion in 'Web' started by Dim1tar, Jul 28, 2023.

  1. Dim1tar

    Dim1tar

    Joined:
    Jul 28, 2023
    Posts:
    2
    Hello, I am currently trying to make my first game in unity, and wanted to upload it on itch.io and github pages. Problem is I made the saving system and all but it only works in the Unity play mode, when I upload it on the web it just doesn't work.
    Code (CSharp):
    1. using System;
    2. using System.IO;
    3. using System.Linq.Expressions;
    4. using System.Runtime.InteropServices;
    5. using System.Runtime.Serialization.Formatters.Binary;
    6. using UnityEngine;
    7.  
    8. public class DataSave
    9. {
    10.     private const string FileType = ".txt";
    11.     private static string SavePath => Application.persistentDataPath + "/saves/";
    12.     private static string BackUpSavePath => Application.persistentDataPath + "/backups/";
    13.  
    14.     private static int SaveCount;
    15.     public static void SaveData<T>(T data, string fileName)
    16.     {
    17.         Directory.CreateDirectory(SavePath);
    18.         Directory.CreateDirectory(BackUpSavePath);
    19.        
    20.         if (SaveCount % 5 == 0)
    21.             Save(BackUpSavePath);
    22.         Save(SavePath);
    23.         SaveCount++;
    24.  
    25.         void Save(string path)
    26.         {
    27.             using (StreamWriter writer = new StreamWriter(path + fileName + FileType))
    28.             {
    29.                 BinaryFormatter formatter = new BinaryFormatter();
    30.                 MemoryStream memoryStream = new MemoryStream();
    31.                 formatter.Serialize(memoryStream, data);
    32.                 string dataToSave = Convert.ToBase64String(memoryStream.ToArray());
    33.                 writer.WriteLine(dataToSave);
    34.             }
    35.         }
    36.     }
    37.  
    38.     public static T LoadData<T>(string fileName)
    39.     {
    40.         Directory.CreateDirectory(SavePath);
    41.         Directory.CreateDirectory(BackUpSavePath);
    42.  
    43.         bool backUpInNeed = false;
    44.         T dataToReturn;
    45.        
    46.         Load(SavePath);
    47.         if (backUpInNeed)
    48.         {
    49.             Load(BackUpSavePath);
    50.         }
    51.        
    52.         return dataToReturn;
    53.  
    54.         void Load(string path)
    55.         {
    56.             using (StreamReader reader = new StreamReader(path + fileName + FileType))
    57.             {
    58.                 BinaryFormatter formatter = new BinaryFormatter();
    59.                 string dataToLoad = reader.ReadToEnd();
    60.                 MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(dataToLoad));
    61.                 try
    62.                 {
    63.                     dataToReturn = (T)formatter.Deserialize(memoryStream);
    64.                 }
    65.                 catch
    66.                 {
    67.                     backUpInNeed = true;
    68.                     dataToReturn = default;
    69.                 }
    70.             }
    71.         }
    72.     }
    73.  
    74.     public static bool SaveExists(string fileName)
    75.     {
    76.         return (File.Exists(SavePath + fileName + FileType)) ||
    77.                (File.Exists(BackUpSavePath + fileName + FileType));
    78.     }
    79. }
    99% sure the problem is in the Application.persistentDataPath, but I have no idea how to fix it.
     
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    4,368
    You have very limited access to file system in a webgl app. I believe File.Write..() with just the filename should work because that maps to the app’s sandbox storage area (limited to 10mb at most, possibly less). But when you try to access specific paths that is likely to fail because specific paths do not exist in a webgl app.

    See this post and thread: https://forum.unity.com/threads/how-does-saving-work-in-webgl.390385/#post-3108881
     
  3. Dim1tar

    Dim1tar

    Joined:
    Jul 28, 2023
    Posts:
    2
    What I did at the end is using PlayerPrefs, which I don't think is the best solution but it worked. I hope this helps someone in the future.

    Code (CSharp):
    1. using System;
    2. using System.IO;
    3. using System.Linq.Expressions;
    4. using System.Runtime.InteropServices;
    5. using System.Runtime.Serialization.Formatters.Binary;
    6. using UnityEngine;
    7.  
    8. public class DataSave
    9. {
    10.     private const string FileType = ".txt";
    11.  
    12.     private static int SaveCount;
    13.     public static void SaveData<T>(T data, string fileName)
    14.     {
    15.         Save();
    16.  
    17.         void Save()
    18.         {
    19.             BinaryFormatter formatter = new BinaryFormatter();
    20.             MemoryStream memoryStream = new MemoryStream();
    21.             formatter.Serialize(memoryStream, data);
    22.             string dataToSave = Convert.ToBase64String(memoryStream.ToArray());
    23.             PlayerPrefs.SetString(fileName + FileType, dataToSave);
    24.         }
    25.     }
    26.  
    27.     public static T LoadData<T>(string fileName)
    28.     {
    29.         T dataToReturn = default;
    30.  
    31.         Load();
    32.  
    33.         return dataToReturn;
    34.  
    35.         void Load()
    36.         {
    37.             string dataToLoad = PlayerPrefs.GetString(fileName + FileType, "");
    38.             if (!string.IsNullOrEmpty(dataToLoad))
    39.             {
    40.                 BinaryFormatter formatter = new BinaryFormatter();
    41.                 MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(dataToLoad));
    42.                 try
    43.                 {
    44.                     dataToReturn = (T)formatter.Deserialize(memoryStream);
    45.                 }
    46.                 catch
    47.                 {
    48.                     dataToReturn = default;
    49.                 }
    50.             }
    51.             else
    52.             {
    53.                 dataToReturn = default;
    54.             }
    55.         }
    56.     }
    57.  
    58.     public static bool SaveExists(string fileName)
    59.     {
    60.         return PlayerPrefs.HasKey(fileName + FileType);
    61.     }
    62. }
     
  4. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    4,368
    Keep in mind: the storage limit for PlayerPrefs in WebGL is just 1 MB!

    Check the length of dataToSave and multiply by how many different save games you have, and consider if a player will be able to grow that size - for example if it stores inventory items and the inventory size is fixed you can calculate the max. memory usage relatively well. But if the savegame contains data per object spawned and there is no limit to how many the player can spawn, then technically you have no limit for savegame size and can't use PlayerPrefs.
     
    Dim1tar likes this.
  5. Unitiblis

    Unitiblis

    Joined:
    Aug 7, 2018
    Posts:
    13