Skip to content

Commit 8d48996

Browse files
committed
Greatly simplified save slot implementation - bumping minor version number to 0.10.0
1 parent 0de3e81 commit 8d48996

File tree

4 files changed

+74
-103
lines changed

4 files changed

+74
-103
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## [0.10.0] - 2025-08-06
4+
Have you ever had a great idea, only to have a much (much) simpler version of that idea immediately after making a new release of your open source project?
5+
6+
This reverts several of the changes made in the release 0.9.0, simplifying the SaveManager API and achieving save slots with a simpler approach.
7+
- Previous changes to SaveManager methods - Save(), Load(), Erase(), and Delete() - that required a save slot parameter have been reverted. The FileHandler will now use the SaveManager.SaveSlotIndex in the GetPartialPath() method and use a save slot if the value is greater than -1.
8+
- SaveManager now stores a static int representing the current save slot, called SaveManager.SaveSlotIndex. Setting this to a value will use the save slot on that index, while -1 will ignore save slots.
9+
- Registering a Saveable that has already been registered will now only emit a warning rather than an error.
10+
311
## [0.9.0] - 2025-08-06
412
- **Breaking Change**: Added support for save slots! The SaveManager now requires a save slot parameter for all methods that interact with save data. This allows for multiple save files to be managed simultaneously, such as for different runs or user profiles.
513
- **Breaking Change**: LoadDefaults() is a new method that replaces the previous Load() method signature that would allow for a boolean to ignore save data.

Runtime/FileHandler.cs

Lines changed: 27 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,14 @@ protected virtual void ValidatePath(string pathOrFilename)
6363
/// </code>
6464
/// </summary>
6565
/// <param name="pathOrFilename">The path or filename of the file that will be combined with the persistent data path.</param>
66-
/// <param name="saveSlotIndex">The save slot index to use. Passing in anything below 0 will not
67-
/// use a slot, which can be good for things like settings files or for projects that don't use save slots.</param>
68-
protected string GetPartialPath(string pathOrFilename, int saveSlotIndex = -1)
66+
protected string GetPartialPath(string pathOrFilename)
6967
{
7068
ValidatePath(pathOrFilename);
7169

7270
string path = $"{pathOrFilename}{FilenameSuffix}{FileExtension}";
7371

74-
if (saveSlotIndex > -1)
75-
return Path.Combine($"slot{saveSlotIndex}", path);
72+
if (SaveManager.SaveSlotIndex > -1)
73+
return Path.Combine($"slot{SaveManager.SaveSlotIndex}", path);
7674

7775
return path;
7876
}
@@ -85,10 +83,8 @@ protected string GetPartialPath(string pathOrFilename, int saveSlotIndex = -1)
8583
/// </code>
8684
/// </summary>
8785
/// <param name="pathOrFilename">The path or filename of the file that will be combined with the persistent data path.</param>
88-
/// <param name="saveSlotIndex">The save slot index to use. Passing in anything below 0 will not
89-
/// use a slot, which can be good for things like settings files or for projects that don't use save slots.</param>
90-
protected virtual string GetFullPath(string pathOrFilename, int saveSlotIndex = -1)
91-
=> Path.Combine(m_persistentDataPath, GetPartialPath(pathOrFilename, saveSlotIndex));
86+
protected virtual string GetFullPath(string pathOrFilename)
87+
=> Path.Combine(m_persistentDataPath, GetPartialPath(pathOrFilename));
9288

9389
/// <summary>
9490
/// Returns true if a file exists at the given path or filename.
@@ -98,11 +94,9 @@ protected virtual string GetFullPath(string pathOrFilename, int saveSlotIndex =
9894
/// </code>
9995
/// </summary>
10096
/// <param name="pathOrFilename">The path or filename of the file to check.</param>
101-
/// <param name="saveSlotIndex">The save slot index to use. Passing in anything below 0 will not
102-
/// use a slot, which can be good for things like settings files or for projects that don't use save slots.</param>
10397
/// <returns>True if the file exists; otherwise, false.</returns>
104-
public virtual bool Exists(string pathOrFilename, int saveSlotIndex = -1)
105-
=> File.Exists(GetFullPath(pathOrFilename, saveSlotIndex));
98+
public virtual bool Exists(string pathOrFilename)
99+
=> File.Exists(GetFullPath(pathOrFilename));
106100

107101
/// <summary>
108102
/// Writes the given content to a file at the given path or filename.
@@ -114,11 +108,9 @@ public virtual bool Exists(string pathOrFilename, int saveSlotIndex = -1)
114108
/// <param name="pathOrFilename">The path or filename of the file to write.</param>
115109
/// <param name="content">The string to write to the file.</param>
116110
/// <param name="cancellationToken">The cancellation token should be the same one from the calling MonoBehaviour.</param>
117-
/// <param name="saveSlotIndex">The save slot index to use. Passing in anything below 0 will not
118-
/// use a slot, which can be good for things like settings files or for projects that don't use save slots.</param>
119-
public virtual async Task WriteFile(string pathOrFilename, string content, CancellationToken cancellationToken, int saveSlotIndex = -1)
111+
public virtual async Task WriteFile(string pathOrFilename, string content, CancellationToken cancellationToken)
120112
{
121-
string fullPath = GetFullPath(pathOrFilename, saveSlotIndex);
113+
string fullPath = GetFullPath(pathOrFilename);
122114

123115
// Get the directory path from the full file path
124116
string directoryPath = Path.GetDirectoryName(fullPath);
@@ -139,10 +131,8 @@ public virtual async Task WriteFile(string pathOrFilename, string content, Cance
139131
/// </summary>
140132
/// <param name="pathOrFilename">The path or filename of the file to write.</param>
141133
/// <param name="content">The string to write to the file.</param>
142-
/// <param name="saveSlotIndex">The save slot index to use. Passing in anything below 0 will not
143-
/// use a slot, which can be good for things like settings files or for projects that don't use save slots.</param>
144-
public virtual async Task WriteFile(string pathOrFilename, string content, int saveSlotIndex = -1)
145-
=> await WriteFile(pathOrFilename, content, CancellationToken.None, saveSlotIndex);
134+
public virtual async Task WriteFile(string pathOrFilename, string content)
135+
=> await WriteFile(pathOrFilename, content, CancellationToken.None);
146136

147137
/// <summary>
148138
/// Returns the contents of a file at the given path or filename.
@@ -153,28 +143,26 @@ public virtual async Task WriteFile(string pathOrFilename, string content, int s
153143
/// </summary>
154144
/// <param name="pathOrFilename">The path or filename of the file to read.</param>
155145
/// <param name="cancellationToken">The cancellation token should be the same one from the calling MonoBehaviour.</param>
156-
/// <param name="saveSlotIndex">The save slot index to use. Passing in anything below 0 will not
157-
/// use a slot, which can be good for things like settings files or for projects that don't use save slots.</param>
158-
public virtual async Task<string> ReadFile(string pathOrFilename, CancellationToken cancellationToken, int saveSlotIndex = -1)
146+
public virtual async Task<string> ReadFile(string pathOrFilename, CancellationToken cancellationToken)
159147
{
160148
try
161149
{
162-
string fullPath = GetFullPath(pathOrFilename, saveSlotIndex);
150+
string fullPath = GetFullPath(pathOrFilename);
163151

164152
// If the file does not exist, return an empty string and log a warning.
165-
if (!Exists(pathOrFilename, saveSlotIndex))
153+
if (!Exists(pathOrFilename))
166154
{
167155
Debug.LogWarning($"FileHandler: File does not exist at path \"{fullPath}\". This may be expected if the file has not been created yet.");
168156
return string.Empty;
169157
}
170158

171-
string fileContent = await File.ReadAllTextAsync(GetFullPath(pathOrFilename, saveSlotIndex), cancellationToken).ConfigureAwait(false);
159+
string fileContent = await File.ReadAllTextAsync(GetFullPath(pathOrFilename), cancellationToken).ConfigureAwait(false);
172160

173161
// If the file is empty, return an empty string and log a warning.
174162
if (string.IsNullOrEmpty(fileContent))
175163
{
176-
if (saveSlotIndex > -1)
177-
Debug.LogWarning($"FileHandler: The file \"{pathOrFilename}\" in slot index {saveSlotIndex} was empty. This may be expected if the file has been erased.");
164+
if (SaveManager.SaveSlotIndex > -1)
165+
Debug.LogWarning($"FileHandler: The file \"{pathOrFilename}\" in slot index {SaveManager.SaveSlotIndex} was empty. This may be expected if the file has been erased.");
178166
else
179167
Debug.LogWarning($"FileHandler: The file \"{pathOrFilename}\" was empty. This may be expected if the file has been erased.");
180168

@@ -203,10 +191,8 @@ public virtual async Task<string> ReadFile(string pathOrFilename, CancellationTo
203191
/// </code>
204192
/// </summary>
205193
/// <param name="pathOrFilename">The path or filename of the file to read.</param>
206-
/// <param name="saveSlotIndex">The save slot index to use. Passing in anything below 0 will not
207-
/// use a slot, which can be good for things like settings files or for projects that don't use save slots.</param>
208-
public virtual async Task<string> ReadFile(string pathOrFilename, int saveSlotIndex = -1)
209-
=> await ReadFile(pathOrFilename, CancellationToken.None, saveSlotIndex);
194+
public virtual async Task<string> ReadFile(string pathOrFilename)
195+
=> await ReadFile(pathOrFilename, CancellationToken.None);
210196

211197
/// <summary>
212198
/// Erases a file at the given path or filename. The file will still exist on disk, but it will be empty.
@@ -218,10 +204,8 @@ public virtual async Task<string> ReadFile(string pathOrFilename, int saveSlotIn
218204
/// </summary>
219205
/// <param name="pathOrFilename">The path or filename of the file to erase.</param>
220206
/// <param name="cancellationToken">The cancellation token should be the same one from the calling MonoBehaviour.</param>
221-
/// <param name="saveSlotIndex">The save slot index to use. Passing in anything below 0 will not
222-
/// use a slot, which can be good for things like settings files or for projects that don't use save slots.</param>
223-
public virtual async Task Erase(string pathOrFilename, CancellationToken cancellationToken, int saveSlotIndex = -1)
224-
=> await WriteFile(pathOrFilename, string.Empty, cancellationToken, saveSlotIndex);
207+
public virtual async Task Erase(string pathOrFilename, CancellationToken cancellationToken)
208+
=> await WriteFile(pathOrFilename, string.Empty, cancellationToken);
225209

226210
/// <summary>
227211
/// Erases a file at the given path or filename. The file will still exist on disk, but it will be empty.
@@ -232,10 +216,8 @@ public virtual async Task Erase(string pathOrFilename, CancellationToken cancell
232216
/// </code>
233217
/// </summary>
234218
/// <param name="pathOrFilename">The path or filename of the file to erase.</param>
235-
/// <param name="saveSlotIndex">The save slot index to use. Passing in anything below 0 will not
236-
/// use a slot, which can be good for things like settings files or for projects that don't use save slots.</param>
237-
public virtual async Task Erase(string pathOrFilename, int saveSlotIndex = -1)
238-
=> await Erase(pathOrFilename, CancellationToken.None, saveSlotIndex);
219+
public virtual async Task Erase(string pathOrFilename)
220+
=> await Erase(pathOrFilename, CancellationToken.None);
239221

240222
/// <summary>
241223
/// Deletes a file at the given path or filename. This will remove the file from disk.
@@ -247,11 +229,9 @@ public virtual async Task Erase(string pathOrFilename, int saveSlotIndex = -1)
247229
/// </summary>
248230
/// <param name="pathOrFilename">The path or filename of the file to delete.</param>
249231
/// <param name="cancellationToken">The cancellation token should be the same one from the calling MonoBehaviour.</param>
250-
/// <param name="saveSlotIndex">The save slot index to use. Passing in anything below 0 will not
251-
/// use a slot, which can be good for things like settings files or for projects that don't use save slots.</param>
252-
public virtual async Task Delete(string pathOrFilename, CancellationToken cancellationToken, int saveSlotIndex = -1)
232+
public virtual async Task Delete(string pathOrFilename, CancellationToken cancellationToken)
253233
{
254-
string fullPath = GetFullPath(pathOrFilename, saveSlotIndex);
234+
string fullPath = GetFullPath(pathOrFilename);
255235
if (File.Exists(fullPath))
256236
await Task.Run(() => File.Delete(fullPath), cancellationToken).ConfigureAwait(false);
257237
}
@@ -265,9 +245,7 @@ public virtual async Task Delete(string pathOrFilename, CancellationToken cancel
265245
/// </code>
266246
/// </summary>
267247
/// <param name="pathOrFilename">The path or filename of the file to delete.</param>
268-
/// <param name="saveSlotIndex">The save slot index to use. Passing in anything below 0 will not
269-
/// use a slot, which can be good for things like settings files or for projects that don't use save slots.</param>
270-
public virtual async Task Delete(string pathOrFilename, int saveSlotIndex = -1)
271-
=> await Delete(pathOrFilename, CancellationToken.None, saveSlotIndex);
248+
public virtual async Task Delete(string pathOrFilename)
249+
=> await Delete(pathOrFilename, CancellationToken.None);
272250
}
273251
}

0 commit comments

Comments
 (0)