using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
#if UNITY_SWITCH
using nn.account;
using nn.fs;
#endif
using System.IO;
[Serializable]
public class SaveData
{
public Dictionary<string, int> SavedInt = new Dictionary<string, int>();
public Dictionary<string, float> SavedFloat = new Dictionary<string, float>();
public Dictionary<string, string> SavedString = new Dictionary<string, string>();
}
public static class SaveManager
{
#if UNITY_SWITCH
private static Uid userId; // user ID for the user account on the Nintendo Switch
private const string mountName = "saveData";
private static string saveDataPath = mountName + ":/";
private static FileHandle fileHandle = new nn.fs.FileHandle();
// Save journaling memory is used for each time files are created, deleted, or written.
// The journaling memory is freed after nn::fs::CommitSaveData is called.
// For any single time you save data, check the file size against your journaling size.
// Check against the total save data size only when you want to be sure all files don't exceed the limit.
// The variable journalSaveDataSize is only a value that is checked against in this code. The actual journal size is set in the
// Unity editor in PlayerSettings > Publishing Settings > User account save data
private const int journalSaveDataSize = 65536; // 65 KB. This value should be the actual journal size in bytes. This should by 32KB less than
// the value entered in PlayerSettings > Publishing Settings > User account save data
private const int loadBufferSize = 32768; // 32 KB
#endif
static string buildTitle = "Immortal_Save";
#if !UNITY_SWITCH
static string dataPath = Application.persistentDataPath + "/SavesDir/";
#endif
private static bool loadedData = false;
private static bool initialized = false;
public static SaveData data = new SaveData();
public static bool HasKey(string key)
{
if (!initialized) Initialize();
if (!loadedData) LoadData();
bool haskey = false;
if (data.SavedFloat.ContainsKey(key)) haskey = true;
if (data.SavedInt.ContainsKey(key)) haskey = true;
if (data.SavedString.ContainsKey(key)) haskey = true;
return haskey;
}
public static void Initialize()
{
#if UNITY_SWITCH //&& !UNITY_EDITOR
nn.account.Account.Initialize();
nn.account.UserHandle userHandle = new nn.account.UserHandle();
nn.account.Account.OpenPreselectedUser(ref userHandle);
nn.account.Account.GetUserId(ref userId, userHandle);
// mount save data
nn.Result result = nn.fs.SaveData.Mount(mountName, userId);
//print out error (debug only) and abort if the filesystem couldn't be mounted
if (result.IsSuccess() == false)
{
Debug.Log("Critical Error: File System could not be mounted.");
result.abortUnlessSuccess();
initialized = false;
}
else
{
initialized = true;
}
#endif
}
public static void Unmount()
{
#if UNITY_SWITCH
nn.fs.FileSystem.Unmount(mountName);
#endif
}
public static int GetInt(string key, int defaultValue = 0)
{
#if UNITY_XBOXONE
return defaultValue;
#endif
if(!initialized) Initialize();
if (!loadedData) LoadData();
int returnValue = defaultValue;
if (!SaveManager.data.SavedInt.TryGetValue(key, out returnValue))
{
returnValue = PlayerPrefs.GetInt(key, defaultValue);
}
return returnValue;
}
public static float GetFloat(string key, float defaultValue = 0)
{
#if UNITY_XBOXONE
return defaultValue;
#endif
if (!initialized) Initialize();
if (!loadedData) LoadData();
float returnValue = defaultValue;
if (!SaveManager.data.SavedFloat.TryGetValue(key, out returnValue))
{
returnValue = PlayerPrefs.GetFloat(key, defaultValue);
}
return returnValue;
}
public static string GetString(string key, string defaultValue = "")
{
#if UNITY_XBOXONE
return defaultValue;
#endif
if (!initialized) Initialize();
if (!loadedData) LoadData();
string returnValue = defaultValue;
if (!SaveManager.data.SavedString.TryGetValue(key, out returnValue))
{
returnValue = PlayerPrefs.GetString(key, defaultValue);
}
return returnValue;
}
public static void SetInt(string key, int setValue)
{
data.SavedInt[key] = setValue;
}
public static void SetFloat(string key, float setValue)
{
data.SavedFloat[key] = setValue;
}
public static void SetString(string key, string setValue)
{
data.SavedString[key] = setValue;
}
public static void Save()
{
//Debug.Log("Writing Stream to Disk.", saveDataPath);
#if UNITY_SWITCH && !UNITY_EDITOR
string filePath = saveDataPath + buildTitle;
byte[] dataByteArray;
using (MemoryStream stream = new MemoryStream(journalSaveDataSize)) // the stream size must be less than or equal to the save journal size
{
BinaryWriter binaryWriter = new BinaryWriter(stream);
binaryWriter.Write(data.SavedInt.Count);
binaryWriter.Write(data.SavedFloat.Count);
binaryWriter.Write(data.SavedString.Count);
foreach (var _keyValuePair in data.SavedInt)
{
binaryWriter.Write(_keyValuePair.Key);
binaryWriter.Write(_keyValuePair.Value);
}
foreach (var _keyValuePair in data.SavedFloat)
{
binaryWriter.Write(_keyValuePair.Key);
binaryWriter.Write(_keyValuePair.Value);
}
foreach (var _keyValuePair in data.SavedString)
{
binaryWriter.Write(_keyValuePair.Key);
binaryWriter.Write(_keyValuePair.Value);
}
stream.Close();
dataByteArray = stream.GetBuffer();
}
#endif
#if UNITY_SWITCH && !UNITY_EDITOR
// This next line prevents the user from quitting the game while saving.
// This is required for Nintendo Switch Guideline 0080
UnityEngine.Switch.Notification.EnterExitRequestHandlingSection();
#endif
#if UNITY_SWITCH && !UNITY_EDITOR
// If you only ever save the entire file, it may be simpler just to delete the file and create a new one every time you save.
// Most of the functions return an nn.Result which can be used for debugging purposes.
nn.fs.File.Delete(filePath);
nn.fs.File.Create(filePath, journalSaveDataSize); //this makes a file the size of your save journal. You may want to make a file smaller than this.
nn.fs.File.Open(ref fileHandle, filePath, nn.fs.OpenFileMode.Write);
nn.fs.File.Write(fileHandle, 0, dataByteArray, dataByteArray.LongLength, nn.fs.WriteOption.Flush); // Writes and flushes the write at the same time
nn.fs.File.Close(fileHandle);
nn.fs.SaveData.Commit(mountName); //you must commit the changes.
#endif
#if UNITY_SWITCH && !UNITY_EDITOR
// End preventing the user from quitting the game while saving.
UnityEngine.Switch.Notification.LeaveExitRequestHandlingSection();
#endif
#if !UNITY_SWITCH
if (!Directory.Exists(dataPath))
{
Directory.CreateDirectory(dataPath);
}
string saveDataPath = dataPath + buildTitle + ".sf";
FileStream fileStream = File.Open(saveDataPath, FileMode.Create);
using (BinaryWriter writer = new BinaryWriter(fileStream))
{
writer.Write(data.SavedInt.Count);
writer.Write(data.SavedFloat.Count);
writer.Write(data.SavedString.Count);
foreach (var _keyValuePair in data.SavedInt)
{
writer.Write(_keyValuePair.Key);
writer.Write(_keyValuePair.Value);
//Debug.Log("Writing "+_keyValuePair.Key+" / "+_keyValuePair.Value);
}
foreach (var _keyValuePair in data.SavedFloat)
{
writer.Write(_keyValuePair.Key);
writer.Write(_keyValuePair.Value);
}
foreach (var _keyValuePair in data.SavedString)
{
writer.Write(_keyValuePair.Key);
writer.Write(_keyValuePair.Value);
}
}
fileStream.Close();
Debug.Log("Saved to " + saveDataPath);
#endif
}
public static void DeleteAll()
{
data.SavedInt.Clear();
data.SavedFloat.Clear();
data.SavedString.Clear();
Save();
}
public static bool LoadData()
{
//CreateDefaultInputMappings();
//CreateWorldData();
SaveManager.loadedData = true;
#if UNITY_XBOXONE
return;
#endif
data.SavedInt.Clear();
data.SavedFloat.Clear();
data.SavedString.Clear();
#if UNITY_SWITCH && !UNITY_EDITOR
Debug.Log("Loading data");
data.SavedInt.Clear();
data.SavedFloat.Clear();
data.SavedString.Clear();
nn.fs.EntryType entryType = 0; //init to a dummy value (C# requirement)
nn.fs.FileSystem.GetEntryType(ref entryType, saveDataPath);
nn.Result result = nn.fs.File.Open(ref fileHandle, saveDataPath + buildTitle, nn.fs.OpenFileMode.Read);
if (result.IsSuccess() == false)
{
return false; // Could not open file. This can be used to detect if this is the first time a user has launched your game.
// (However, be sure you are not getting this error due to your file being locked by another process, etc.)
}
byte[] loadedData = new byte[loadBufferSize];
nn.fs.File.Read(fileHandle, 0, loadedData, loadBufferSize);
nn.fs.File.Close(fileHandle);
using (MemoryStream stream = new MemoryStream(loadedData))
{
BinaryReader reader = new BinaryReader(stream);
int IntCount = reader.ReadInt32();
int FloatCount = reader.ReadInt32();
int StringCount = reader.ReadInt32();
for (int i = 0; i < IntCount; i++)
{
data.SavedInt[reader.ReadString()] = reader.ReadInt32();
}
for (int i = 0; i < FloatCount; i++)
{
data.SavedFloat[reader.ReadString()] = reader.ReadSingle();
}
for (int i = 0; i < StringCount; i++)
{
data.SavedString[reader.ReadString()] = reader.ReadString();
}
}
#endif
Debug.Log("Data Loaded");
#if !UNITY_SWITCH
if (!Directory.Exists(dataPath))
{
Directory.CreateDirectory(dataPath);
}
string saveDataPath = dataPath + buildTitle + ".sf";
if (File.Exists(saveDataPath))
{
FileStream fileStream = File.Open(saveDataPath, FileMode.Open);
using (BinaryReader reader = new BinaryReader(fileStream))
{
int IntCount = reader.ReadInt32();
int FloatCount = reader.ReadInt32();
int StringCount = reader.ReadInt32();
for (int i = 0; i < IntCount; i++)
{
data.SavedInt[reader.ReadString()] = reader.ReadInt32();
}
for (int i = 0; i < FloatCount; i++)
{
data.SavedFloat[reader.ReadString()] = reader.ReadSingle();
}
for (int i = 0; i < StringCount; i++)
{
data.SavedString[reader.ReadString()] = reader.ReadString();
}
}
fileStream.Close();
}
#endif
return true;
}
public static void DeleteKey(string keyToDel)
{
if (data.SavedInt.ContainsKey(keyToDel)) data.SavedInt.Remove(keyToDel);
if (data.SavedFloat.ContainsKey(keyToDel)) data.SavedFloat.Remove(keyToDel);
if (data.SavedString.ContainsKey(keyToDel)) data.SavedString.Remove(keyToDel);
}
}