客户端rsa,冗余清理,bug修复,安卓build问题
This commit is contained in:
@@ -0,0 +1,227 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
public static class LocalRecoveryMirror
|
||||
{
|
||||
private const string RecoveryDirectoryName = ".save_recovery";
|
||||
|
||||
public static void SaveJson<T>(string slotKey, T data)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(slotKey) || (!typeof(T).IsValueType && (object)data == null))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string json = JsonUtility.ToJson(data, false);
|
||||
SaveRaw(slotKey, json);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning($"[LocalRecoveryMirror] SaveJson failed ({slotKey}): {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryLoadJson<T>(string slotKey, out T data)
|
||||
{
|
||||
data = default(T);
|
||||
if (string.IsNullOrWhiteSpace(slotKey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string json;
|
||||
if (!TryLoadRaw(slotKey, out json) || string.IsNullOrWhiteSpace(json))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
data = JsonUtility.FromJson<T>(json);
|
||||
if (typeof(T).IsValueType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return (object)data != null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning($"[LocalRecoveryMirror] TryLoadJson failed ({slotKey}): {ex.Message}");
|
||||
data = default(T);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SaveRaw(string slotKey, string json)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(slotKey) || json == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string path = GetCanonicalPath(slotKey);
|
||||
string directory = Path.GetDirectoryName(path);
|
||||
if (!string.IsNullOrWhiteSpace(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
string backupPath = path + ".bak";
|
||||
string tempPath = path + ".tmp";
|
||||
File.WriteAllText(tempPath, json, Encoding.UTF8);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
File.Copy(path, backupPath, true);
|
||||
}
|
||||
|
||||
File.Copy(tempPath, path, true);
|
||||
File.Delete(tempPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning($"[LocalRecoveryMirror] SaveRaw failed ({slotKey}): {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryLoadRaw(string slotKey, out string json)
|
||||
{
|
||||
json = null;
|
||||
if (string.IsNullOrWhiteSpace(slotKey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IReadOnlyList<string> candidates = GetVariantPaths(slotKey);
|
||||
for (int i = 0; i < candidates.Count; i++)
|
||||
{
|
||||
string path = candidates[i];
|
||||
if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string loaded = File.ReadAllText(path, Encoding.UTF8);
|
||||
if (string.IsNullOrWhiteSpace(loaded))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
json = loaded;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning($"[LocalRecoveryMirror] TryLoadRaw failed ({path}): {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool HasSlotData(string slotKey)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(slotKey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IReadOnlyList<string> candidates = GetVariantPaths(slotKey);
|
||||
for (int i = 0; i < candidates.Count; i++)
|
||||
{
|
||||
string path = candidates[i];
|
||||
if (!string.IsNullOrWhiteSpace(path) && File.Exists(path))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void DeleteSlot(string slotKey)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(slotKey))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IReadOnlyList<string> candidates = GetVariantPaths(slotKey);
|
||||
for (int i = 0; i < candidates.Count; i++)
|
||||
{
|
||||
string path = candidates[i];
|
||||
if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning($"[LocalRecoveryMirror] DeleteSlot failed ({path}): {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetCanonicalPath(string slotKey)
|
||||
{
|
||||
string fileName = BuildFileName(slotKey);
|
||||
return Path.Combine(SaveIdentityUtility.GetCanonicalPersistentRoot(), RecoveryDirectoryName, fileName);
|
||||
}
|
||||
|
||||
private static IReadOnlyList<string> GetVariantPaths(string slotKey)
|
||||
{
|
||||
var result = new List<string>();
|
||||
string fileName = BuildFileName(slotKey);
|
||||
string backupFileName = fileName + ".bak";
|
||||
IReadOnlyList<string> roots = SaveIdentityUtility.GetPersistentRootVariants();
|
||||
for (int i = 0; i < roots.Count; i++)
|
||||
{
|
||||
string root = roots[i];
|
||||
if (string.IsNullOrWhiteSpace(root))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AddDistinct(result, Path.Combine(root, RecoveryDirectoryName, fileName));
|
||||
AddDistinct(result, Path.Combine(root, RecoveryDirectoryName, backupFileName));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string BuildFileName(string slotKey)
|
||||
{
|
||||
return slotKey.Trim().Replace('/', '_').Replace('\\', '_').Replace(':', '_') + ".json";
|
||||
}
|
||||
|
||||
private static void AddDistinct(List<string> target, string value)
|
||||
{
|
||||
if (target == null || string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < target.Count; i++)
|
||||
{
|
||||
if (string.Equals(target[i], value, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
target.Add(value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user