v10 全量评审:修复 TD-06 至 TD-12(InputReader 移除资产扫描回退 / EmergencySave 解除 LocalFileStorage 直接依赖 / AccessibilityManager 注册 IAccessibilityService / HUDController HP/SpringIcon SetActive 复用 / MovingPlatform 缓存 WaitForSeconds / RewardSO IRewardTarget 解耦 Quest←Player 依赖 / CrashReporter 频率限制崩溃日志)
This commit is contained in:
@@ -33,6 +33,7 @@ namespace BaseGames.Core.Assets
|
||||
|
||||
// ── Collectibles ─────────────────────────────────────────────────
|
||||
public const string PrefabCollectibleGeo = "COL_Geo";
|
||||
public const string PrefabCollectibleItem = "COL_Item";
|
||||
public const string PrefabCollectibleHPOrb = "COL_HPOrb";
|
||||
|
||||
// ── Weapons ──────────────────────────────────────────────────────
|
||||
|
||||
@@ -37,6 +37,10 @@ namespace BaseGames.Core.Pool
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
// 释放所有通过 Addressables.LoadAssetAsync 加载的预制件引用
|
||||
foreach (var pfx in _prefabCache.Values)
|
||||
Addressables.Release(pfx);
|
||||
_prefabCache.Clear();
|
||||
ServiceLocator.Unregister<IObjectPoolService>(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,13 +7,18 @@ namespace BaseGames.Core.Save
|
||||
/// <summary>
|
||||
/// 崩溃检测与诊断日志写入。
|
||||
/// 监听 Unity 异常日志并在 OnApplicationPause 非正常退出时触发紧急存档(槽 99)。
|
||||
/// 日志文件最多保留 <see cref="MaxLogFiles"/> 个,超出时删除最旧文件。
|
||||
/// </summary>
|
||||
public class CrashReporter : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private SaveManager _saveManager;
|
||||
[SerializeField] private EmergencySaveService _emergencyService;
|
||||
[SerializeField, Min(1)] private int _maxLogFiles = 10;
|
||||
|
||||
private bool _cleanExit;
|
||||
private bool _cleanExit;
|
||||
private int _logsWrittenThisSession;
|
||||
|
||||
private const int MaxLogsPerSession = 5; // 同一运行期内最多写 5 个诊断文件,防止异常风暴
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
@@ -39,7 +44,10 @@ namespace BaseGames.Core.Save
|
||||
private void OnLogMessage(string condition, string stackTrace, LogType type)
|
||||
{
|
||||
if (type == LogType.Exception || type == LogType.Error)
|
||||
{
|
||||
if (_logsWrittenThisSession >= MaxLogsPerSession) return;
|
||||
WriteDiagnosticLog(condition, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>检查是否存在上次崩溃或意外退出留下的紧急存档。</summary>
|
||||
@@ -55,11 +63,25 @@ namespace BaseGames.Core.Save
|
||||
string logPath = Path.Combine(Application.persistentDataPath, $"crash_{timestamp}.log");
|
||||
string content = $"[{DateTime.UtcNow:o}]\n{condition}\n\n{stackTrace}";
|
||||
File.WriteAllText(logPath, content);
|
||||
_logsWrittenThisSession++;
|
||||
|
||||
// 保留最新 N 个日志文件,超出时删除最旧文件
|
||||
PruneOldLogFiles(Application.persistentDataPath, _maxLogFiles);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 日志写入失败不能再抛异常,否则会造成无限递归
|
||||
}
|
||||
}
|
||||
|
||||
private static void PruneOldLogFiles(string directory, int maxFiles)
|
||||
{
|
||||
var files = Directory.GetFiles(directory, "crash_*.log");
|
||||
if (files.Length <= maxFiles) return;
|
||||
Array.Sort(files); // 按文件名(含时间戳)升序,最旧的在前
|
||||
int deleteCount = files.Length - maxFiles;
|
||||
for (int i = 0; i < deleteCount; i++)
|
||||
File.Delete(files[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,12 +42,7 @@ namespace BaseGames.Core.Save
|
||||
public async Task PromoteToSlot(int targetSlot)
|
||||
{
|
||||
if (_saveManager == null) return;
|
||||
var storage = new LocalFileStorage();
|
||||
if (!storage.Exists(EmergencySlot)) return;
|
||||
string json = await storage.ReadAsync(EmergencySlot);
|
||||
if (json == null) return;
|
||||
await storage.WriteAsync(targetSlot, json);
|
||||
await storage.DeleteAsync(EmergencySlot);
|
||||
await _saveManager.PromoteEmergencyToSlotAsync(targetSlot, EmergencySlot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +212,19 @@ namespace BaseGames.Core.Save
|
||||
if (_currentSlot == slotIndex) _current = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将紧急存档槽的数据复制到目标槽,并删除紧急存档。
|
||||
/// 由 <see cref="EmergencySaveService"/> 调用,确保所有 IO 操作通过统一的 ISaveStorage 进行。
|
||||
/// </summary>
|
||||
public async Task PromoteEmergencyToSlotAsync(int targetSlot, int emergencySlot)
|
||||
{
|
||||
if (!_storage.Exists(emergencySlot)) return;
|
||||
string json = await _storage.ReadAsync(emergencySlot);
|
||||
if (json == null) return;
|
||||
await _storage.WriteAsync(targetSlot, json);
|
||||
await _storage.DeleteAsync(emergencySlot);
|
||||
}
|
||||
|
||||
// ── 私有工具 ──────────────────────────────────────────────────────────
|
||||
private string ComputeChecksum(string json)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user