Skip to content

Commit 10117f5

Browse files
committed
- add
1 parent 5d63efe commit 10117f5

12 files changed

+433
-0
lines changed

Editor.meta

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Editor/DataWindowEditor.cs

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using System.Diagnostics;
2+
using System.IO;
3+
using UnityEditor;
4+
using UnityEngine;
5+
using Debug = UnityEngine.Debug;
6+
7+
namespace VirtueSky.DataStorage
8+
{
9+
#if UNITY_EDITOR
10+
public class DataWindowEditor : EditorWindow
11+
{
12+
[MenuItem("Unity-Common/Clear All Data", priority = 501)]
13+
public static void ClearAllData()
14+
{
15+
GameData.DeleteAll();
16+
GameData.DeleteFileData();
17+
PlayerPrefs.DeleteAll();
18+
Debug.Log($"<color=Green>Clear all data succeed</color>");
19+
}
20+
21+
[MenuItem("Unity-Common/Save Data", priority = 504)]
22+
public static void SaveData()
23+
{
24+
GameData.Save();
25+
Debug.Log($"<color=Green>Save data succeed</color>");
26+
}
27+
28+
[MenuItem("Unity-Common/Clear Path Data", priority = 502)]
29+
public static void ClearDataPath()
30+
{
31+
GameData.DeleteAll();
32+
GameData.DeleteFileData();
33+
Debug.Log($"<color=Green>Clear path data succeed</color>");
34+
}
35+
36+
37+
[MenuItem("Unity-Common/Open Path Data", priority = 503)]
38+
public static void OpenPathData()
39+
{
40+
string path = GameData.GetPersistentDataPath();
41+
switch (SystemInfo.operatingSystemFamily)
42+
{
43+
case OperatingSystemFamily.Windows:
44+
if (Directory.Exists(path))
45+
{
46+
Process.Start(path);
47+
}
48+
else
49+
{
50+
Debug.LogError("The directory does not exist: " + path);
51+
}
52+
53+
break;
54+
case OperatingSystemFamily.MacOSX:
55+
if (Directory.Exists(path))
56+
{
57+
Process.Start("open", path);
58+
}
59+
else
60+
{
61+
Debug.LogError("The directory does not exist: " + path);
62+
}
63+
64+
break;
65+
}
66+
}
67+
}
68+
#endif
69+
}

Editor/DataWindowEditor.cs.meta

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "UnityCommon.GameData.Editor",
3+
"rootNamespace": "",
4+
"references": [
5+
"GUID:32dbaa332e571bf429b7de517f75f074"
6+
],
7+
"includePlatforms": [
8+
"Editor"
9+
],
10+
"excludePlatforms": [],
11+
"allowUnsafeCode": false,
12+
"overrideReferences": false,
13+
"precompiledReferences": [],
14+
"autoReferenced": true,
15+
"defineConstraints": [],
16+
"versionDefines": [],
17+
"noEngineReferences": false
18+
}

Editor/UnityCommon.GameData.Editor.asmdef.meta

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime.meta

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/GameData.cs

+235
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Runtime.CompilerServices;
5+
using UnityEngine;
6+
7+
namespace VirtueSky.DataStorage
8+
{
9+
public static class GameData
10+
{
11+
private static bool isInitialized;
12+
private static int profile;
13+
private static Dictionary<string, byte[]> datas = new();
14+
private const int INIT_SIZE = 64;
15+
16+
public static event Action OnSaveEvent;
17+
18+
#region Internal Stuff
19+
20+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
21+
public static void Init()
22+
{
23+
if (isInitialized) return;
24+
isInitialized = true;
25+
Load();
26+
}
27+
28+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
29+
private static byte[] Serialize<T>(T data)
30+
{
31+
return SerializeAdapter.ToBinary(data);
32+
}
33+
34+
35+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
36+
private static T Deserialize<T>(byte[] bytes)
37+
{
38+
return SerializeAdapter.FromBinary<T>(bytes);
39+
}
40+
41+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
42+
private static void RequireNullCheck()
43+
{
44+
if (datas == null) Load();
45+
if (datas == null) throw new NullReferenceException();
46+
}
47+
48+
private static string GetPath => GetDataPath($"data_{profile}.dat");
49+
50+
static string GetDataPath(string name)
51+
{
52+
var persistentDataPath = GetPersistentDataPath();
53+
if (!Directory.Exists(persistentDataPath))
54+
{
55+
Directory.CreateDirectory(persistentDataPath);
56+
}
57+
58+
return Path.Combine(persistentDataPath, name);
59+
}
60+
61+
public static string GetPersistentDataPath()
62+
{
63+
#if UNITY_EDITOR
64+
return Path.Combine(Directory.GetParent(Application.dataPath).FullName, "TempDataStorage");
65+
#else
66+
return Application.persistentDataPath;
67+
#endif
68+
}
69+
70+
#endregion
71+
72+
#region Public API
73+
74+
public static bool IsInitialized => isInitialized;
75+
76+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
77+
public static void ChangeProfile(int profile)
78+
{
79+
if (GameData.profile == profile) return;
80+
81+
Save();
82+
GameData.profile = profile;
83+
Load();
84+
}
85+
86+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
87+
public static bool VerifyProfile(int profile)
88+
{
89+
return GameData.profile == profile;
90+
}
91+
92+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
93+
public static void Save()
94+
{
95+
OnSaveEvent?.Invoke();
96+
97+
byte[] bytes = Serialize(datas);
98+
File.WriteAllBytes(GetPath, bytes);
99+
}
100+
101+
102+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
103+
public static async void SaveAsync()
104+
{
105+
OnSaveEvent?.Invoke();
106+
107+
byte[] bytes = Serialize(datas);
108+
await File.WriteAllBytesAsync(GetPath, bytes);
109+
}
110+
111+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
112+
public static void Load()
113+
{
114+
if (!File.Exists(GetPath))
115+
{
116+
var stream = File.Create(GetPath);
117+
stream.Close();
118+
}
119+
120+
byte[] bytes = File.ReadAllBytes(GetPath);
121+
if (bytes.Length == 0)
122+
{
123+
datas.Clear();
124+
return;
125+
}
126+
127+
datas = Deserialize<Dictionary<string, byte[]>>(bytes) ?? new Dictionary<string, byte[]>(INIT_SIZE);
128+
}
129+
130+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
131+
public static async void LoadAsync()
132+
{
133+
if (!File.Exists(GetPath))
134+
{
135+
var stream = File.Create(GetPath);
136+
stream.Close();
137+
}
138+
139+
byte[] bytes = await File.ReadAllBytesAsync(GetPath);
140+
if (bytes.Length == 0)
141+
{
142+
datas.Clear();
143+
return;
144+
}
145+
146+
datas = Deserialize<Dictionary<string, byte[]>>(bytes) ?? new Dictionary<string, byte[]>(INIT_SIZE);
147+
}
148+
149+
/// <summary>
150+
///
151+
/// </summary>
152+
/// <param name="key"></param>
153+
/// <param name="default">If value of <paramref name="key"/> can not be found or empty! will return the default value of data type!</param>
154+
/// <typeparam name="T"></typeparam>
155+
/// <returns></returns>
156+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
157+
public static T Get<T>(string key, T @default = default)
158+
{
159+
RequireNullCheck();
160+
161+
datas.TryGetValue(key, out byte[] value);
162+
if (value == null || value.Length == 0) return @default;
163+
164+
return Deserialize<T>(value);
165+
}
166+
167+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
168+
public static bool TryGet<T>(string key, out T data)
169+
{
170+
RequireNullCheck();
171+
172+
bool hasKey;
173+
if (datas.TryGetValue(key, out byte[] value))
174+
{
175+
data = Deserialize<T>(value);
176+
hasKey = true;
177+
}
178+
else
179+
{
180+
data = default;
181+
hasKey = false;
182+
}
183+
184+
return hasKey;
185+
}
186+
187+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
188+
public static void Set<T>(string key, T data)
189+
{
190+
RequireNullCheck();
191+
byte[] bytes = Serialize(data);
192+
if (datas.TryAdd(key, bytes)) return;
193+
datas[key] = bytes;
194+
}
195+
196+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
197+
public static bool HasKey(string key) => datas.ContainsKey(key);
198+
199+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
200+
public static void DeleteKey(string key) => datas.Remove(key);
201+
202+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
203+
public static void DeleteAll() => datas.Clear();
204+
205+
public static void DeleteFileData()
206+
{
207+
if (File.Exists(GetPath))
208+
{
209+
File.Delete(GetPath);
210+
}
211+
}
212+
213+
/// <summary>
214+
/// Get raw byte[] of all data of profile
215+
/// </summary>
216+
/// <returns></returns>
217+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
218+
public static byte[] Backup()
219+
{
220+
return SerializeAdapter.ToBinary(datas);
221+
}
222+
223+
/// <summary>
224+
/// Load from byte[]
225+
/// </summary>
226+
/// <param name="bytes"></param>
227+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
228+
public static void Restore(byte[] bytes)
229+
{
230+
datas = SerializeAdapter.FromBinary<Dictionary<string, byte[]>>(bytes);
231+
}
232+
233+
#endregion
234+
}
235+
}

Runtime/GameData.cs.meta

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)