实现 P2 槽位/落盘层核心: - SlotTypes:槽位常量、sidecar 元数据、UI 视图模型 - SlotFileSystem:槽位路径工具与原子写 - SlotManager:自动档、手动档、读档、继续游戏、P1 迁移 - SlotThumbnailCapture:存档截图 helper - CloudSave:Steam/TapTap 云存档适配器接口与协调器 在 ConstRef 中补充槽位、截图、文件名常量。
121 lines
3.4 KiB
C#
121 lines
3.4 KiB
C#
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using AibisDream.Utility;
|
|
using Newtonsoft.Json;
|
|
using UnityEngine;
|
|
|
|
namespace AibisDream.SaveSystem
|
|
{
|
|
/// <summary>
|
|
/// 存档槽位目录与文件路径工具。
|
|
/// </summary>
|
|
public static class SlotDirectory
|
|
{
|
|
public static string GetSlotPath(int slotIndex)
|
|
{
|
|
return Path.Combine(ConstRef.SaveFilePath, $"{ConstRef.SaveSlotDirPrefix}{slotIndex}");
|
|
}
|
|
|
|
public static string GetSnapshotPath(int slotIndex)
|
|
{
|
|
return Path.Combine(GetSlotPath(slotIndex), $"{ConstRef.SaveSnapshotFileName}.json");
|
|
}
|
|
|
|
public static string GetMetaPath(int slotIndex)
|
|
{
|
|
return Path.Combine(GetSlotPath(slotIndex), $"{ConstRef.SaveMetaFileName}.json");
|
|
}
|
|
|
|
public static string GetThumbnailPath(int slotIndex)
|
|
{
|
|
return Path.Combine(GetSlotPath(slotIndex), $"{ConstRef.SaveThumbnailFileName}.png");
|
|
}
|
|
|
|
public static string GetLatestSlotIndexPath()
|
|
{
|
|
return Path.Combine(ConstRef.SaveFilePath, $"{ConstRef.LatestSlotFileName}.json");
|
|
}
|
|
|
|
public static bool Exists(int slotIndex)
|
|
{
|
|
return File.Exists(GetMetaPath(slotIndex));
|
|
}
|
|
|
|
public static IEnumerable<int> EnumerateExistingSlots()
|
|
{
|
|
if (!Directory.Exists(ConstRef.SaveFilePath))
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
for (var i = SlotIndex.Auto; i <= SlotIndex.ManualEnd; i++)
|
|
{
|
|
if (Exists(i))
|
|
{
|
|
yield return i;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void EnsureSlotDirectory(int slotIndex)
|
|
{
|
|
Directory.CreateDirectory(GetSlotPath(slotIndex));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 槽位文件原子写工具。
|
|
/// <para>先写入临时文件,再重命名为最终文件,避免写入过程中崩溃导致存档损坏。</para>
|
|
/// </summary>
|
|
public static class SlotAtomicWriter
|
|
{
|
|
public static void WriteJson<T>(T obj, string finalPath)
|
|
{
|
|
var json = JsonConvert.SerializeObject(obj, Formatting.Indented);
|
|
WriteText(json, finalPath);
|
|
}
|
|
|
|
public static void WriteText(string text, string finalPath)
|
|
{
|
|
var tempPath = finalPath + ".tmp";
|
|
var dir = Path.GetDirectoryName(finalPath);
|
|
if (!string.IsNullOrEmpty(dir))
|
|
{
|
|
Directory.CreateDirectory(dir);
|
|
}
|
|
|
|
File.WriteAllText(tempPath, text);
|
|
CommitTempFile(tempPath, finalPath);
|
|
}
|
|
|
|
public static void WriteBytes(byte[] data, string finalPath)
|
|
{
|
|
if (data == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var tempPath = finalPath + ".tmp";
|
|
var dir = Path.GetDirectoryName(finalPath);
|
|
if (!string.IsNullOrEmpty(dir))
|
|
{
|
|
Directory.CreateDirectory(dir);
|
|
}
|
|
|
|
File.WriteAllBytes(tempPath, data);
|
|
CommitTempFile(tempPath, finalPath);
|
|
}
|
|
|
|
private static void CommitTempFile(string tempPath, string finalPath)
|
|
{
|
|
if (File.Exists(finalPath))
|
|
{
|
|
File.Delete(finalPath);
|
|
}
|
|
|
|
File.Move(tempPath, finalPath);
|
|
}
|
|
}
|
|
}
|