OctoCore 0.0.1
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e21560fb4a055504984fda6f526e45e8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.Save.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all save data ScriptableObjects.
|
||||
/// Provides a unique identifier for each data instance.
|
||||
/// </summary>
|
||||
public class OctoData : ScriptableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique identifier for this data instance.
|
||||
/// Automatically set to the asset name.
|
||||
/// </summary>
|
||||
[OctoReadOnly] public string Id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 496833ce6e1ccd3458cf6d9185f9d510
|
||||
@@ -0,0 +1,16 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.Save.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Boolean save data ScriptableObject.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "bool_", menuName = "Octo/Data/Bool", order = 0)]
|
||||
public class OctoDataBool : OctoData
|
||||
{
|
||||
/// <summary>
|
||||
/// Default value for this boolean data.
|
||||
/// </summary>
|
||||
public bool Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 198561ebd23de0e4d878efdf99aa6cfc
|
||||
@@ -0,0 +1,16 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.Save.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Float save data ScriptableObject.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "float_", menuName = "Octo/Data/Float", order = 2)]
|
||||
public class OctoDataFloat : OctoData
|
||||
{
|
||||
/// <summary>
|
||||
/// Default value for this float data.
|
||||
/// </summary>
|
||||
public float Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8b5df00abd22564e9e50406e8d5644b
|
||||
@@ -0,0 +1,16 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.Save.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Integer save data ScriptableObject.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "int_", menuName = "Octo/Data/Int", order = 1)]
|
||||
public class OctoDataInt : OctoData
|
||||
{
|
||||
/// <summary>
|
||||
/// Default value for this integer data.
|
||||
/// </summary>
|
||||
public int Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9503febef22124742b1dc154f549b4fe
|
||||
@@ -0,0 +1,16 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.Save.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// String save data ScriptableObject.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "string_", menuName = "Octo/Data/String", order = 3)]
|
||||
public class OctoDataString : OctoData
|
||||
{
|
||||
/// <summary>
|
||||
/// Default value for this string data.
|
||||
/// </summary>
|
||||
public string Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d98ebfcec71f3a247b658908e9fee900
|
||||
@@ -0,0 +1,17 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.Save.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Vector4 save data ScriptableObject.
|
||||
/// Can store Vector2, Vector3, or Vector4 values.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "vector_", menuName = "Octo/Data/Vector", order = 4)]
|
||||
public class OctoDataVector : OctoData
|
||||
{
|
||||
/// <summary>
|
||||
/// Default value for this vector data.
|
||||
/// </summary>
|
||||
public Vector4 Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c87b0a5d0cf3cc4cb19b57e3694102d
|
||||
@@ -0,0 +1,882 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace OctoCore.Save
|
||||
{
|
||||
/// <summary>
|
||||
/// Save system module for managing persistent game data.
|
||||
/// Handles saving and loading of boolean, integer, float, string, and vector data to XML files.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class OctoSave : IOctoModule
|
||||
{
|
||||
public class Data
|
||||
{
|
||||
[HideInInspector] public string Id;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class DataBool : Data
|
||||
{
|
||||
[OctoReadOnly] public global::OctoCore.Save.Data.OctoDataBool Data;
|
||||
public bool Value;
|
||||
public Action<bool> OnValueChanged;
|
||||
|
||||
public void Set(bool value)
|
||||
{
|
||||
bool valueChanged = Value != value;
|
||||
Value = value;
|
||||
|
||||
if (valueChanged)
|
||||
OnValueChanged?.Invoke(Value);
|
||||
}
|
||||
|
||||
public void Set(OctoVirtual.OctoVirtualBool virtualBool)
|
||||
{
|
||||
if (virtualBool != null)
|
||||
Set(virtualBool.Value);
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
Debug.Log($"OctoVirtualBool is null");
|
||||
}
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class DataInt : Data
|
||||
{
|
||||
[OctoReadOnly] public global::OctoCore.Save.Data.OctoDataInt Data;
|
||||
public int Value;
|
||||
public Action<int> OnValueChanged;
|
||||
|
||||
public void Set(int value)
|
||||
{
|
||||
bool valueChanged = Value != value;
|
||||
Value = value;
|
||||
|
||||
if (valueChanged)
|
||||
OnValueChanged?.Invoke(Value);
|
||||
}
|
||||
|
||||
public void Set(OctoVirtual.OctoVirtualInt virtualInt)
|
||||
{
|
||||
if (virtualInt != null)
|
||||
Set(virtualInt.Value);
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
Debug.Log($"OctoVirtualInt is null");
|
||||
}
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class DataFloat : Data
|
||||
{
|
||||
[OctoReadOnly] public global::OctoCore.Save.Data.OctoDataFloat Data;
|
||||
public float Value;
|
||||
public Action<float> OnValueChanged;
|
||||
|
||||
public void Set(float value)
|
||||
{
|
||||
bool valueChanged = Value != value;
|
||||
Value = value;
|
||||
|
||||
if (valueChanged)
|
||||
OnValueChanged?.Invoke(Value);
|
||||
}
|
||||
|
||||
public void Set(OctoVirtual.OctoVirtualFloat virtualFloat)
|
||||
{
|
||||
if (virtualFloat != null)
|
||||
Set(virtualFloat.Value);
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
Debug.Log($"OctoVirtualFloat is null");
|
||||
}
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class DataString : Data
|
||||
{
|
||||
[OctoReadOnly] public global::OctoCore.Save.Data.OctoDataString Data;
|
||||
public string Value;
|
||||
public Action<string> OnValueChanged;
|
||||
|
||||
public void Set(string value)
|
||||
{
|
||||
bool valueChanged = Value != value;
|
||||
Value = value;
|
||||
|
||||
if (valueChanged)
|
||||
OnValueChanged?.Invoke(Value);
|
||||
}
|
||||
|
||||
public void Set(OctoVirtual.OctoVirtualString virtualString)
|
||||
{
|
||||
if (virtualString != null)
|
||||
Set(virtualString.Value);
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
Debug.Log($"OctoVirtualString is null");
|
||||
}
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class DataVector : Data
|
||||
{
|
||||
[OctoReadOnly] public global::OctoCore.Save.Data.OctoDataVector Data;
|
||||
public Vector4 Value;
|
||||
public Action<Vector4> OnValueChanged;
|
||||
|
||||
public void Set(Vector4 value)
|
||||
{
|
||||
bool valueChanged = Value != value;
|
||||
Value = value;
|
||||
|
||||
if (valueChanged)
|
||||
OnValueChanged?.Invoke(Value);
|
||||
}
|
||||
|
||||
public void Set(OctoVirtual.OctoVirtualVector virtualVector)
|
||||
{
|
||||
if (virtualVector != null)
|
||||
Set(virtualVector.Value);
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
Debug.Log($"OctoVirtualVector is null");
|
||||
}
|
||||
}
|
||||
|
||||
public DataBool[] Booleans;
|
||||
public DataInt[] Integers;
|
||||
public DataFloat[] Floats;
|
||||
public DataString[] Strings;
|
||||
public DataVector[] Vectors;
|
||||
|
||||
private Dictionary<string, int> _booleansId;
|
||||
private Dictionary<string, int> _integersId;
|
||||
private Dictionary<string, int> _floatsId;
|
||||
private Dictionary<string, int> _stringsId;
|
||||
private Dictionary<string, int> _vectorsId;
|
||||
|
||||
public void Init(OctoSettings settings)
|
||||
{
|
||||
if (!settings)
|
||||
{
|
||||
Debug.Log("No Settings Registered.");
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Get all data
|
||||
settings.GetAllDatas();
|
||||
#endif
|
||||
|
||||
// Init values
|
||||
|
||||
List<DataBool> tmpBooleans = new List<DataBool>();
|
||||
List<DataInt> tmpIntegers = new List<DataInt>();
|
||||
List<DataFloat> tmpFloats = new List<DataFloat>();
|
||||
List<DataString> tmpStrings = new List<DataString>();
|
||||
List<DataVector> tmpVectors = new List<DataVector>();
|
||||
|
||||
foreach (global::OctoCore.Save.Data.OctoDataBool dataBool in settings.Save.Booleans)
|
||||
tmpBooleans.Add(new DataBool() { Id = dataBool.Id, Data = dataBool, Value = dataBool.Value });
|
||||
|
||||
foreach (global::OctoCore.Save.Data.OctoDataInt dataInt in settings.Save.Integers)
|
||||
tmpIntegers.Add(new DataInt() { Id = dataInt.Id, Data = dataInt, Value = dataInt.Value });
|
||||
|
||||
foreach (global::OctoCore.Save.Data.OctoDataFloat dataFloat in settings.Save.Floats)
|
||||
tmpFloats.Add(new DataFloat() { Id = dataFloat.Id, Data = dataFloat, Value = dataFloat.Value });
|
||||
|
||||
foreach (global::OctoCore.Save.Data.OctoDataString dataString in settings.Save.Strings)
|
||||
tmpStrings.Add(new DataString() { Id = dataString.Id, Data = dataString, Value = dataString.Value });
|
||||
|
||||
foreach (global::OctoCore.Save.Data.OctoDataVector dataVector in settings.Save.Vectors)
|
||||
tmpVectors.Add(new DataVector() { Id = dataVector.Id, Data = dataVector, Value = dataVector.Value });
|
||||
|
||||
Booleans = tmpBooleans.ToArray();
|
||||
Integers = tmpIntegers.ToArray();
|
||||
Floats = tmpFloats.ToArray();
|
||||
Strings = tmpStrings.ToArray();
|
||||
Vectors = tmpVectors.ToArray();
|
||||
|
||||
tmpBooleans.Clear();
|
||||
tmpIntegers.Clear();
|
||||
tmpFloats.Clear();
|
||||
tmpStrings.Clear();
|
||||
tmpVectors.Clear();
|
||||
|
||||
// Load values
|
||||
|
||||
Load();
|
||||
|
||||
// Adress datas
|
||||
|
||||
_booleansId = new Dictionary<string, int>();
|
||||
_integersId = new Dictionary<string, int>();
|
||||
_floatsId = new Dictionary<string, int>();
|
||||
_stringsId = new Dictionary<string, int>();
|
||||
_vectorsId = new Dictionary<string, int>();
|
||||
|
||||
for (int i = 0; i < Booleans.Length; i++)
|
||||
_booleansId.Add(Booleans[i].Id, i);
|
||||
|
||||
for (int i = 0; i < Integers.Length; i++)
|
||||
_integersId.Add(Integers[i].Id, i);
|
||||
|
||||
for (int i = 0; i < Floats.Length; i++)
|
||||
_floatsId.Add(Floats[i].Id, i);
|
||||
|
||||
for (int i = 0; i < Strings.Length; i++)
|
||||
_stringsId.Add(Strings[i].Id, i);
|
||||
|
||||
for (int i = 0; i < Vectors.Length; i++)
|
||||
_vectorsId.Add(Vectors[i].Id, i);
|
||||
|
||||
// Callback OctoEvents
|
||||
|
||||
if (OctoEvents.Instance)
|
||||
OctoEvents.Instance.SetSaveInitialized();
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnSceneChanged(Scene current, Scene next)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnQuit()
|
||||
{
|
||||
Upgrade();
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
string path = GetPath();
|
||||
|
||||
bool saveLoaded = false;
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
OctoVirtual virtualSave = new OctoVirtual
|
||||
{
|
||||
Booleans = ReadGroup<OctoVirtual.OctoVirtualBool>(path, "Booleans"),
|
||||
Integers = ReadGroup<OctoVirtual.OctoVirtualInt>(path, "Integers"),
|
||||
Floats = ReadGroup<OctoVirtual.OctoVirtualFloat>(path, "Floats"),
|
||||
Strings = ReadGroup<OctoVirtual.OctoVirtualString>(path, "Strings"),
|
||||
Vectors = ReadGroup<OctoVirtual.OctoVirtualVector>(path, "Vectors")
|
||||
};
|
||||
|
||||
foreach (DataBool dataBool in Booleans)
|
||||
dataBool.Set(virtualSave.Booleans.Where(v => v.Id == dataBool.Id).FirstOrDefault());
|
||||
|
||||
foreach (DataInt dataInt in Integers)
|
||||
dataInt.Set(virtualSave.Integers.Where(v => v.Id == dataInt.Id).FirstOrDefault());
|
||||
|
||||
foreach (DataFloat dataFloat in Floats)
|
||||
dataFloat.Set(virtualSave.Floats.Where(v => v.Id == dataFloat.Id).FirstOrDefault());
|
||||
|
||||
foreach (DataString dataString in Strings)
|
||||
dataString.Set(virtualSave.Strings.Where(v => v.Id == dataString.Id).FirstOrDefault());
|
||||
|
||||
foreach (DataVector dataVector in Vectors)
|
||||
dataVector.Set(virtualSave.Vectors.Where(v => v.Id == dataVector.Id).FirstOrDefault());
|
||||
|
||||
saveLoaded = true;
|
||||
|
||||
if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
if (saveLoaded) Debug.Log($"Save read from: {path}");
|
||||
else Debug.Log($"Save corrupted: {path}");
|
||||
}
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"No save found at: {path}");
|
||||
}
|
||||
|
||||
T[] ReadGroup<T>(string xmlPath, string groupName) where T : OctoVirtual, new()
|
||||
{
|
||||
List<T> list = new List<T>();
|
||||
|
||||
using (XmlReader reader = XmlReader.Create(xmlPath))
|
||||
{
|
||||
// Jump to node <groupName>
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.NodeType == XmlNodeType.Element && reader.Name == groupName)
|
||||
{
|
||||
string id = null;
|
||||
string value = null;
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
// Stop if end of group reached
|
||||
|
||||
if (reader.NodeType == XmlNodeType.EndElement && reader.Name == groupName)
|
||||
break;
|
||||
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
if (reader.Name == "ID")
|
||||
id = reader.ReadElementContentAsString();
|
||||
else if (reader.Name == "Value")
|
||||
value = reader.ReadElementContentAsString();
|
||||
|
||||
// Create entry
|
||||
|
||||
if (id != null && value != null)
|
||||
{
|
||||
T entry = new T { Id = id };
|
||||
|
||||
switch (entry)
|
||||
{
|
||||
case OctoVirtual.OctoVirtualBool virtualBool:
|
||||
virtualBool.Value = bool.Parse(value);
|
||||
break;
|
||||
|
||||
case OctoVirtual.OctoVirtualInt virtualInt:
|
||||
virtualInt.Value = int.Parse(value);
|
||||
break;
|
||||
|
||||
case OctoVirtual.OctoVirtualFloat virtualFloat:
|
||||
virtualFloat.Value = float.Parse(value);
|
||||
break;
|
||||
|
||||
case OctoVirtual.OctoVirtualString virtualString:
|
||||
virtualString.Value = value;
|
||||
break;
|
||||
|
||||
case OctoVirtual.OctoVirtualVector virtualVector:
|
||||
virtualVector.Value = StringToVector4(value);
|
||||
break;
|
||||
}
|
||||
|
||||
list.Add(entry);
|
||||
id = null;
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
Vector4 StringToVector4(string s)
|
||||
{
|
||||
s = s.Trim('(', ')').Replace(" ", "");
|
||||
|
||||
string[] parts = s.Split(',');
|
||||
|
||||
if (parts.Length != 4)
|
||||
{
|
||||
return Vector4.zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Vector4(
|
||||
float.Parse(parts[0], CultureInfo.InvariantCulture),
|
||||
float.Parse(parts[1], CultureInfo.InvariantCulture),
|
||||
float.Parse(parts[2], CultureInfo.InvariantCulture),
|
||||
float.Parse(parts[3], CultureInfo.InvariantCulture)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Upgrade()
|
||||
{
|
||||
// Set virtual save
|
||||
|
||||
OctoVirtual virtualSave = new OctoVirtual()
|
||||
{
|
||||
Booleans = new OctoVirtual.OctoVirtualBool[Booleans.Length],
|
||||
Integers = new OctoVirtual.OctoVirtualInt[Integers.Length],
|
||||
Floats = new OctoVirtual.OctoVirtualFloat[Floats.Length],
|
||||
Strings = new OctoVirtual.OctoVirtualString[Strings.Length],
|
||||
Vectors = new OctoVirtual.OctoVirtualVector[Vectors.Length]
|
||||
};
|
||||
|
||||
for (int i = 0; i < virtualSave.Booleans.Length; i++)
|
||||
{
|
||||
virtualSave.Booleans[i] = new OctoVirtual.OctoVirtualBool();
|
||||
virtualSave.Booleans[i].Id = Booleans[i].Id;
|
||||
virtualSave.Booleans[i].Value = Booleans[i].Value;
|
||||
}
|
||||
|
||||
for (int i = 0; i < virtualSave.Integers.Length; i++)
|
||||
{
|
||||
virtualSave.Integers[i] = new OctoVirtual.OctoVirtualInt();
|
||||
virtualSave.Integers[i].Id = Integers[i].Id;
|
||||
virtualSave.Integers[i].Value = Integers[i].Value;
|
||||
}
|
||||
|
||||
for (int i = 0; i < virtualSave.Floats.Length; i++)
|
||||
{
|
||||
virtualSave.Floats[i] = new OctoVirtual.OctoVirtualFloat();
|
||||
virtualSave.Floats[i].Id = Floats[i].Id;
|
||||
virtualSave.Floats[i].Value = Floats[i].Value;
|
||||
}
|
||||
|
||||
for (int i = 0; i < virtualSave.Strings.Length; i++)
|
||||
{
|
||||
virtualSave.Strings[i] = new OctoVirtual.OctoVirtualString();
|
||||
virtualSave.Strings[i].Id = Strings[i].Id;
|
||||
virtualSave.Strings[i].Value = Strings[i].Value;
|
||||
}
|
||||
|
||||
for (int i = 0; i < virtualSave.Vectors.Length; i++)
|
||||
{
|
||||
virtualSave.Vectors[i] = new OctoVirtual.OctoVirtualVector();
|
||||
virtualSave.Vectors[i].Id = Vectors[i].Id;
|
||||
virtualSave.Vectors[i].Value = Vectors[i].Value;
|
||||
}
|
||||
|
||||
// Save file
|
||||
|
||||
string path = GetPath();
|
||||
|
||||
using (XmlWriter writer = XmlWriter.Create(path, new XmlWriterSettings { Indent = true }))
|
||||
{
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteStartElement("OctoSave");
|
||||
|
||||
void WriteGroup<T>(string groupName, T[] array) where T : OctoVirtual
|
||||
{
|
||||
if (array == null || array.Length == 0) return;
|
||||
|
||||
writer.WriteStartElement(groupName);
|
||||
|
||||
foreach (var item in array)
|
||||
{
|
||||
writer.WriteElementString("ID", item.Id);
|
||||
|
||||
switch (item)
|
||||
{
|
||||
case OctoVirtual.OctoVirtualBool virtualBool:
|
||||
writer.WriteElementString("Value", virtualBool.Value.ToString().ToLower());
|
||||
break;
|
||||
|
||||
case OctoVirtual.OctoVirtualInt virtualInt:
|
||||
writer.WriteElementString("Value", virtualInt.Value.ToString());
|
||||
break;
|
||||
|
||||
case OctoVirtual.OctoVirtualFloat virtualFloat:
|
||||
writer.WriteElementString("Value", virtualFloat.Value.ToString());
|
||||
break;
|
||||
|
||||
case OctoVirtual.OctoVirtualString virtualString:
|
||||
writer.WriteElementString("Value", virtualString.Value);
|
||||
break;
|
||||
|
||||
case OctoVirtual.OctoVirtualVector virtualVector:
|
||||
writer.WriteElementString("Value", virtualVector.Value.ToString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
WriteGroup("Booleans", virtualSave.Booleans);
|
||||
WriteGroup("Integers", virtualSave.Integers);
|
||||
WriteGroup("Floats", virtualSave.Floats);
|
||||
WriteGroup("Strings", virtualSave.Strings);
|
||||
WriteGroup("Vectors", virtualSave.Vectors);
|
||||
|
||||
writer.WriteEndElement();
|
||||
writer.WriteEndDocument();
|
||||
}
|
||||
|
||||
if (OctoCore.Instance.Development.Log) Debug.Log($"Saved to: {path}");
|
||||
}
|
||||
|
||||
public void Unsubscribe<T>(global::OctoCore.Save.Data.OctoData data, Action<T> action)
|
||||
{
|
||||
Subscribe(data, action, false);
|
||||
}
|
||||
|
||||
public void Subscribe<T>(global::OctoCore.Save.Data.OctoData data, Action<T> handler, bool subscribe = true)
|
||||
{
|
||||
if (data == null || string.IsNullOrEmpty(data.Id))
|
||||
{
|
||||
if (OctoCore.Instance.Development.Log)
|
||||
Debug.Log("Data is null or has no ID");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (data)
|
||||
{
|
||||
case global::OctoCore.Save.Data.OctoDataBool _ when _booleansId.TryGetValue(data.Id, out int iBool):
|
||||
if (subscribe) Booleans[iBool].OnValueChanged += handler as Action<bool>;
|
||||
else Booleans[iBool].OnValueChanged -= handler as Action<bool>;
|
||||
break;
|
||||
|
||||
case global::OctoCore.Save.Data.OctoDataInt _ when _integersId.TryGetValue(data.Id, out int iInt):
|
||||
if (subscribe) Integers[iInt].OnValueChanged += handler as Action<int>;
|
||||
else Integers[iInt].OnValueChanged -= handler as Action<int>;
|
||||
break;
|
||||
|
||||
case global::OctoCore.Save.Data.OctoDataFloat _ when _floatsId.TryGetValue(data.Id, out int iFloat):
|
||||
if (subscribe) Floats[iFloat].OnValueChanged += handler as Action<float>;
|
||||
else Floats[iFloat].OnValueChanged -= handler as Action<float>;
|
||||
break;
|
||||
|
||||
case global::OctoCore.Save.Data.OctoDataString _ when _stringsId.TryGetValue(data.Id, out int iString):
|
||||
if (subscribe) Strings[iString].OnValueChanged += handler as Action<string>;
|
||||
else Strings[iString].OnValueChanged -= handler as Action<string>;
|
||||
break;
|
||||
|
||||
case global::OctoCore.Save.Data.OctoDataVector _ when _vectorsId.TryGetValue(data.Id, out int iVector):
|
||||
if (subscribe) Vectors[iVector].OnValueChanged += handler as Action<Vector4>;
|
||||
else Vectors[iVector].OnValueChanged -= handler as Action<Vector4>;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (OctoCore.Instance.Development.Log)
|
||||
Debug.Log($"Unsupported or missing data: {data.Id}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#region GET
|
||||
|
||||
public bool Get(global::OctoCore.Save.Data.OctoDataBool dataBool)
|
||||
{
|
||||
if (dataBool)
|
||||
{
|
||||
if (_booleansId.ContainsKey(dataBool.Id))
|
||||
{
|
||||
return Booleans[_booleansId[dataBool.Id]].Value;
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Bool data not found: {dataBool.Id}");
|
||||
}
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Bool data is null");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int Get(global::OctoCore.Save.Data.OctoDataInt dataInt)
|
||||
{
|
||||
if (dataInt)
|
||||
{
|
||||
if (_integersId.ContainsKey(dataInt.Id))
|
||||
{
|
||||
return Integers[_integersId[dataInt.Id]].Value;
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Int data not found: {dataInt.Id}");
|
||||
}
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Int data is null");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public float Get(global::OctoCore.Save.Data.OctoDataFloat dataFloat)
|
||||
{
|
||||
if (dataFloat)
|
||||
{
|
||||
if (_floatsId.ContainsKey(dataFloat.Id))
|
||||
{
|
||||
return Floats[_floatsId[dataFloat.Id]].Value;
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Int data not found: {dataFloat.Id}");
|
||||
}
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Int data is null");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public string Get(global::OctoCore.Save.Data.OctoDataString dataString)
|
||||
{
|
||||
if (dataString)
|
||||
{
|
||||
if (_stringsId.ContainsKey(dataString.Id))
|
||||
{
|
||||
return Strings[_stringsId[dataString.Id]].Value;
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Int data not found: {dataString.Id}");
|
||||
}
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Int data is null");
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public Vector4 Get(global::OctoCore.Save.Data.OctoDataVector dataVector)
|
||||
{
|
||||
if (dataVector)
|
||||
{
|
||||
if (_vectorsId.ContainsKey(dataVector.Id))
|
||||
{
|
||||
return Vectors[_vectorsId[dataVector.Id]].Value;
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Vector data not found: {dataVector.Id}");
|
||||
}
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Vector data is null");
|
||||
}
|
||||
|
||||
return Vector4.zero;
|
||||
}
|
||||
|
||||
public bool GetBool(string id)
|
||||
{
|
||||
if (_booleansId.ContainsKey(id))
|
||||
{
|
||||
return Booleans[_booleansId[id]].Value;
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Bool data not found: {id}");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int GetInt(string id)
|
||||
{
|
||||
if (_integersId.ContainsKey(id))
|
||||
{
|
||||
return Integers[_integersId[id]].Value;
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Int data not found: {id}");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public float GetFloat(string id)
|
||||
{
|
||||
if (_floatsId.ContainsKey(id))
|
||||
{
|
||||
return Floats[_floatsId[id]].Value;
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Float data not found: {id}");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public string GetString(string id)
|
||||
{
|
||||
if (_stringsId.ContainsKey(id))
|
||||
{
|
||||
return Strings[_stringsId[id]].Value;
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"String data not found: {id}");
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public Vector4 GetVector(string id)
|
||||
{
|
||||
if (_vectorsId.ContainsKey(id))
|
||||
{
|
||||
return Vectors[_vectorsId[id]].Value;
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"String data not found: {id}");
|
||||
}
|
||||
|
||||
return Vector4.zero;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SET
|
||||
|
||||
public void Set(global::OctoCore.Save.Data.OctoDataBool dataBool, bool value)
|
||||
{
|
||||
if (dataBool != null && _booleansId.ContainsKey(dataBool.Id))
|
||||
{
|
||||
Booleans[_booleansId[dataBool.Id]].Set(value);
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Bool data is null or not found");
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(global::OctoCore.Save.Data.OctoDataInt dataInt, int value)
|
||||
{
|
||||
if (dataInt != null && _integersId.ContainsKey(dataInt.Id))
|
||||
{
|
||||
Integers[_integersId[dataInt.Id]].Set(value);
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Int data is null or not found");
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(global::OctoCore.Save.Data.OctoDataFloat dataFloat, float value)
|
||||
{
|
||||
if (dataFloat != null && _floatsId.ContainsKey(dataFloat.Id))
|
||||
{
|
||||
Floats[_floatsId[dataFloat.Id]].Set(value);
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Float data is null or not found");
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(global::OctoCore.Save.Data.OctoDataString dataString, string value)
|
||||
{
|
||||
if (dataString != null && _stringsId.ContainsKey(dataString.Id))
|
||||
{
|
||||
Strings[_stringsId[dataString.Id]].Set(value);
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"String data is null or not found");
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(global::OctoCore.Save.Data.OctoDataVector dataVector, Vector4 value)
|
||||
{
|
||||
if (dataVector != null && _vectorsId.ContainsKey(dataVector.Id))
|
||||
{
|
||||
Vectors[_vectorsId[dataVector.Id]].Set(value);
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Vector data is null or not found");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetBool(string id, bool value)
|
||||
{
|
||||
if (_booleansId.ContainsKey(id))
|
||||
{
|
||||
Booleans[_booleansId[id]].Set(value);
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Bool data not found: {id}");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetInt(string id, int value)
|
||||
{
|
||||
if (_booleansId.ContainsKey(id))
|
||||
{
|
||||
Integers[_integersId[id]].Set(value);
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Int data not found: {id}");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetFloat(string id, float value)
|
||||
{
|
||||
if (_floatsId.ContainsKey(id))
|
||||
{
|
||||
Floats[_floatsId[id]].Set(value);
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"Float data not found: {id}");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetString(string id, string value)
|
||||
{
|
||||
if (_stringsId.ContainsKey(id))
|
||||
{
|
||||
Strings[_stringsId[id]].Set(value);
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"String data not found: {id}");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVector(string id, Vector4 value)
|
||||
{
|
||||
if (_vectorsId.ContainsKey(id))
|
||||
{
|
||||
Vectors[_vectorsId[id]].Set(value);
|
||||
}
|
||||
else if (OctoCore.Instance.Development.Log)
|
||||
{
|
||||
Debug.Log($"String data not found: {id}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private string GetPath()
|
||||
{
|
||||
Platform.OctoPlatforms platform = OctoCore.Instance ? OctoCore.Instance.Platform.Current : Platform.OctoPlatforms.Standalone;
|
||||
|
||||
switch (platform)
|
||||
{
|
||||
default:
|
||||
return Path.Combine(Application.persistentDataPath, "Save.xml");
|
||||
|
||||
case Platform.OctoPlatforms.XboxOne:
|
||||
return Path.Combine(Application.persistentDataPath, "Save.xml");
|
||||
|
||||
case Platform.OctoPlatforms.XboxSeries:
|
||||
return Path.Combine(Application.persistentDataPath, "Save.xml");
|
||||
|
||||
case Platform.OctoPlatforms.PS4:
|
||||
return Path.Combine(Application.persistentDataPath, "Save.xml");
|
||||
|
||||
case Platform.OctoPlatforms.PS5:
|
||||
return Path.Combine(Application.persistentDataPath, "Save.xml");
|
||||
|
||||
case Platform.OctoPlatforms.Switch:
|
||||
return Path.Combine(Application.persistentDataPath, "Save.xml");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2494453b88d39d44808f2ee3d8d72cb
|
||||
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.Save
|
||||
{
|
||||
/// <summary>
|
||||
/// A dictionary that can be serialized by Unity.
|
||||
/// Converts between Dictionary and List representations for Unity serialization.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">The type of keys in the dictionary.</typeparam>
|
||||
/// <typeparam name="TValue">The type of values in the dictionary.</typeparam>
|
||||
[Serializable]
|
||||
public class OctoSerializableDictionary<TKey, TValue> : ISerializationCallbackReceiver
|
||||
{
|
||||
[SerializeField] private List<TKey> _keys = new();
|
||||
[SerializeField] private List<TValue> _values = new();
|
||||
|
||||
private Dictionary<TKey, TValue> _dictionary = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the underlying dictionary.
|
||||
/// </summary>
|
||||
public Dictionary<TKey, TValue> Dictionary => _dictionary;
|
||||
|
||||
/// <summary>
|
||||
/// Called before Unity serializes the object.
|
||||
/// Converts the dictionary to lists for serialization.
|
||||
/// </summary>
|
||||
public void OnBeforeSerialize()
|
||||
{
|
||||
_keys.Clear();
|
||||
_values.Clear();
|
||||
|
||||
foreach (var kvp in _dictionary)
|
||||
{
|
||||
_keys.Add(kvp.Key);
|
||||
_values.Add(kvp.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called after Unity deserializes the object.
|
||||
/// Reconstructs the dictionary from serialized lists.
|
||||
/// </summary>
|
||||
public void OnAfterDeserialize()
|
||||
{
|
||||
_dictionary = new Dictionary<TKey, TValue>();
|
||||
|
||||
for (int i = 0; i < Math.Min(_keys.Count, _values.Count); i++)
|
||||
{
|
||||
_dictionary[_keys[i]] = _values[i];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value associated with the specified key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key to access.</param>
|
||||
/// <returns>The value associated with the key, or default if not found.</returns>
|
||||
public TValue this[TKey key]
|
||||
{
|
||||
get => _dictionary.ContainsKey(key) ? _dictionary[key] : default;
|
||||
set => _dictionary[key] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the dictionary contains the specified key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key to locate.</param>
|
||||
/// <returns>True if the dictionary contains the key; otherwise, false.</returns>
|
||||
public bool ContainsKey(TKey key) => _dictionary.ContainsKey(key);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the value with the specified key from the dictionary.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the element to remove.</param>
|
||||
public void Remove(TKey key) => _dictionary.Remove(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b10efb0f335abac4195d702b9dc836d6
|
||||
@@ -0,0 +1,96 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.Save
|
||||
{
|
||||
/// <summary>
|
||||
/// Virtual representation of save data used for XML serialization/deserialization.
|
||||
/// This class mirrors the runtime save data structure for loading from disk.
|
||||
/// </summary>
|
||||
public class OctoVirtual
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique identifier for this data entry.
|
||||
/// </summary>
|
||||
public string Id;
|
||||
|
||||
/// <summary>
|
||||
/// Virtual boolean data entry.
|
||||
/// </summary>
|
||||
public class OctoVirtualBool : OctoVirtual
|
||||
{
|
||||
/// <summary>
|
||||
/// Boolean value loaded from save file.
|
||||
/// </summary>
|
||||
public bool Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Virtual integer data entry.
|
||||
/// </summary>
|
||||
public class OctoVirtualInt : OctoVirtual
|
||||
{
|
||||
/// <summary>
|
||||
/// Integer value loaded from save file.
|
||||
/// </summary>
|
||||
public int Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Virtual float data entry.
|
||||
/// </summary>
|
||||
public class OctoVirtualFloat : OctoVirtual
|
||||
{
|
||||
/// <summary>
|
||||
/// Float value loaded from save file.
|
||||
/// </summary>
|
||||
public float Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Virtual string data entry.
|
||||
/// </summary>
|
||||
public class OctoVirtualString : OctoVirtual
|
||||
{
|
||||
/// <summary>
|
||||
/// String value loaded from save file.
|
||||
/// </summary>
|
||||
public string Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Virtual vector data entry.
|
||||
/// </summary>
|
||||
public class OctoVirtualVector : OctoVirtual
|
||||
{
|
||||
/// <summary>
|
||||
/// Vector4 value loaded from save file.
|
||||
/// </summary>
|
||||
public Vector4 Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Array of boolean data entries.
|
||||
/// </summary>
|
||||
public OctoVirtualBool[] Booleans;
|
||||
|
||||
/// <summary>
|
||||
/// Array of integer data entries.
|
||||
/// </summary>
|
||||
public OctoVirtualInt[] Integers;
|
||||
|
||||
/// <summary>
|
||||
/// Array of float data entries.
|
||||
/// </summary>
|
||||
public OctoVirtualFloat[] Floats;
|
||||
|
||||
/// <summary>
|
||||
/// Array of string data entries.
|
||||
/// </summary>
|
||||
public OctoVirtualString[] Strings;
|
||||
|
||||
/// <summary>
|
||||
/// Array of vector data entries.
|
||||
/// </summary>
|
||||
public OctoVirtualVector[] Vectors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ecc8786bc13f70e49ae9b0ec830b0ec9
|
||||
Reference in New Issue
Block a user