mirror of
http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite.git
synced 2025-11-20 08:37:13 +08:00
(client) feat:健康给予,路径优化,结算界面,商店界面 (#60)
Co-authored-by: m0_75251201 <m0_75251201@noreply.gitcode.com> Reviewed-on: http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite/pulls/60
This commit is contained in:
@@ -3,56 +3,89 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks; // 引入 Task for async/await
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using UnityEngine;
|
||||
using Utils;
|
||||
|
||||
namespace Managers
|
||||
{
|
||||
/// <summary>
|
||||
/// 用于标记那些包含可存储数据的单例类。
|
||||
/// 实现此接口的单例应在SaveManager初始化后注册自身。
|
||||
/// 用于标记那些包含可存储数据的单例类。
|
||||
/// 实现此接口的单例应在SaveManager初始化后注册自身。
|
||||
/// </summary>
|
||||
public interface ISavableSingleton
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用于标记在单例类中需要被SaveManager存储的属性。
|
||||
/// 用于标记在单例类中需要被SaveManager存储的属性。
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
||||
public class SavableAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置用于存储的唯一键。如果为空,则使用属性名称。
|
||||
/// </summary>
|
||||
public string Key { get; }
|
||||
|
||||
public SavableAttribute(string key = null)
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置用于存储的唯一键。如果为空,则使用属性名称。
|
||||
/// </summary>
|
||||
public string Key { get; }
|
||||
}
|
||||
|
||||
public class SaveManager : Utils.Singleton<SaveManager>, ILaunchManager
|
||||
public class SaveManager : Singleton<SaveManager>, ILaunchManager
|
||||
{
|
||||
// 存档文件名
|
||||
private const string SaveFileName = "game_save.json";
|
||||
|
||||
// 存储所有需要保存状态的单例实例
|
||||
private readonly Dictionary<Type, ISavableSingleton> _savableSingletons = new();
|
||||
|
||||
// 存档路径
|
||||
private static string SaveFilePath => Path.Combine("Save", SaveFileName);
|
||||
|
||||
/// <summary>
|
||||
/// 指示管理器是否已完成初始化。
|
||||
/// </summary>
|
||||
public bool Completed { get; set; } // 新增:实现 ILaunchManager 接口的 Completed 属性
|
||||
|
||||
public string StepDescription => "加载存档中";
|
||||
|
||||
// 存储所有需要保存状态的单例实例
|
||||
private readonly Dictionary<Type, ISavableSingleton> _savableSingletons = new();
|
||||
/// <summary>
|
||||
/// 实现ILaunchManager接口的Init方法,在启动时加载存档。
|
||||
/// </summary>
|
||||
/// <returns>一个表示异步操作完成的 Task。</returns>
|
||||
public async Task Init() // 接口变更:方法签名变为 async Task
|
||||
{
|
||||
// 如果已经完成初始化,则直接返回,避免重复执行
|
||||
if (Completed) return;
|
||||
|
||||
LoadGame(); // 启动时加载存档
|
||||
|
||||
Completed = true; // 在加载逻辑完成后设置 Completed 为 true
|
||||
// 由于 Init 方法内部当前没有真正的异步操作,不需要显式 await Task.CompletedTask;
|
||||
// 编译器会为同步的 async Task 方法自动生成一个已完成的 Task。
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实现ILaunchManager接口的Clear方法,Clear是重载不做任何事。
|
||||
/// 根据用户指示,此方法不应改变管理器自身的 Completed 状态,且不执行任何清理操作。
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
// 按照用户指示,此方法为空实现,不影响 SaveManager 的完成状态或数据。
|
||||
}
|
||||
|
||||
~SaveManager()
|
||||
{
|
||||
SaveGame(); // 在销毁时保存游戏
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册一个需要保存状态的单例实例。
|
||||
/// 注册一个需要保存状态的单例实例。
|
||||
/// </summary>
|
||||
/// <param name="singleton">实现ISavableSingleton接口的单例实例。</param>
|
||||
public void RegisterSavable(ISavableSingleton singleton)
|
||||
@@ -69,7 +102,7 @@ namespace Managers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除一个已注册的单例实例。
|
||||
/// 移除一个已注册的单例实例。
|
||||
/// </summary>
|
||||
/// <param name="singleton">要移除的单例实例。</param>
|
||||
public void UnregisterSavable(ISavableSingleton singleton)
|
||||
@@ -82,22 +115,7 @@ namespace Managers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实现ILaunchManager接口的Init方法,在启动时加载存档。
|
||||
/// </summary>
|
||||
public void Init()
|
||||
{
|
||||
LoadGame(); // 启动时加载存档
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实现ILaunchManager接口的Clear方法,Clear是重载不做任何事。
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存游戏数据到文件。
|
||||
/// 保存游戏数据到文件。
|
||||
/// </summary>
|
||||
public void SaveGame()
|
||||
{
|
||||
@@ -127,10 +145,8 @@ namespace Managers
|
||||
{
|
||||
var directoryPath = Path.GetDirectoryName(SaveFilePath);
|
||||
if (!string.IsNullOrEmpty(directoryPath) && !Directory.Exists(directoryPath))
|
||||
{
|
||||
Directory.CreateDirectory(directoryPath);
|
||||
// DEBUG: Debug.Log($"SaveManager: 文件夹 '{directoryPath}' 已创建。");
|
||||
}
|
||||
// DEBUG: Debug.Log($"SaveManager: 文件夹 '{directoryPath}' 已创建。");
|
||||
var settings = new JsonSerializerSettings
|
||||
{
|
||||
Formatting = Formatting.Indented,
|
||||
@@ -147,15 +163,13 @@ namespace Managers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从文件加载游戏数据。
|
||||
/// 从文件加载游戏数据。
|
||||
/// </summary>
|
||||
public void LoadGame()
|
||||
{
|
||||
if (!File.Exists(SaveFilePath))
|
||||
{
|
||||
// DEBUG: Debug.Log($"SaveManager: 未找到存档文件 '{SaveFilePath}'。将使用默认值启动。");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
@@ -180,7 +194,6 @@ namespace Managers
|
||||
{
|
||||
var key = GetSavableKey(prop, singletonType);
|
||||
if (savedData.TryGetValue(key, out var jToken))
|
||||
{
|
||||
try
|
||||
{
|
||||
var value = jToken.ToObject(prop.PropertyType, JsonSerializer.Create(settings));
|
||||
@@ -191,12 +204,9 @@ namespace Managers
|
||||
Debug.LogError(
|
||||
$"SaveManager: 无法反序列化类型 '{singletonType.Name}' 的属性 '{key}' (类型: {prop.PropertyType.Name}): {innerEx.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning(
|
||||
$"SaveManager: 存档文件中未找到类型 '{singletonType.Name}' 的属性 '{key}'。将保留当前值。");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -214,7 +224,7 @@ namespace Managers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个类型中所有带有SavableAttribute的公共实例属性。
|
||||
/// 获取一个类型中所有带有SavableAttribute的公共实例属性。
|
||||
/// </summary>
|
||||
private IEnumerable<PropertyInfo> GetSavableProperties(Type type)
|
||||
{
|
||||
@@ -223,7 +233,7 @@ namespace Managers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据属性和其所属类型生成一个唯一的存储键。
|
||||
/// 根据属性和其所属类型生成一个唯一的存储键。
|
||||
/// </summary>
|
||||
private string GetSavableKey(PropertyInfo prop, Type singletonType)
|
||||
{
|
||||
@@ -232,14 +242,11 @@ namespace Managers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取给定类型的默认值。
|
||||
/// 获取给定类型的默认值。
|
||||
/// </summary>
|
||||
private object GetDefaultValue(Type type)
|
||||
{
|
||||
if (type.IsValueType)
|
||||
{
|
||||
return Activator.CreateInstance(type);
|
||||
}
|
||||
if (type.IsValueType) return Activator.CreateInstance(type);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user