Merge branch 'temp827'
This commit is contained in:
232
Client/Assets/Scripts/Managers/AudioManager.cs
Normal file
232
Client/Assets/Scripts/Managers/AudioManager.cs
Normal file
@ -0,0 +1,232 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Data;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Managers
|
||||
{
|
||||
/// <summary>
|
||||
/// 音频管理器,负责加载、管理和提供从定义数据中解析出的音频剪辑。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 该管理器是一个单例,并在启动过程中实现 ILaunchManager 接口,
|
||||
/// 用于处理游戏或应用启动时音频资源的加载和初始化。
|
||||
/// </remarks>
|
||||
public class AudioManager : Utils.Singleton<AudioManager>, ILaunchManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认音频剪辑,在找不到对应音频时返回。
|
||||
/// </summary>
|
||||
public AudioClip defaultAudioClip;
|
||||
|
||||
/// <summary>
|
||||
/// 存储所有已加载的音频剪辑,按音频名称(全局唯一的DefName)索引。
|
||||
/// </summary>
|
||||
public Dictionary<string, AudioClip> audioClips = new();
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前启动步骤的描述。
|
||||
/// </summary>
|
||||
public string StepDescription { get; private set; } = "音频管理器正在准备中...";
|
||||
|
||||
/// <summary>
|
||||
/// 初始化音频管理器,加载默认音频剪辑并处理所有 AudioDef 定义。
|
||||
/// </summary>
|
||||
public void Init()
|
||||
{
|
||||
if (audioClips.Count > 0)
|
||||
{
|
||||
// 如果已经有数据,则跳过初始化,防止重复加载。
|
||||
return;
|
||||
}
|
||||
defaultAudioClip = Resources.Load<AudioClip>("Default/DefaultAudio"); // 假设存在一个默认音频路径
|
||||
if (defaultAudioClip == null)
|
||||
{
|
||||
Debug.LogWarning("AudioManager: 无法加载默认音频 'Resources/Default/DefaultAudio'。请确保文件存在。");
|
||||
}
|
||||
InitAudioDef();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据 AudioDef 定义初始化并加载所有音频剪辑。
|
||||
/// </summary>
|
||||
public void InitAudioDef()
|
||||
{
|
||||
// 缓存已加载的物理文件路径对应的 AudioClip,避免重复加载
|
||||
var audioCache = new Dictionary<string, AudioClip>();
|
||||
var audioDefs = Managers.DefineManager.Instance.QueryDefinesByType<AudioDef>();
|
||||
|
||||
if (audioDefs == null || !audioDefs.Any())
|
||||
{
|
||||
Debug.Log($"AudioManager: 在定义管理器中未找到任何音频定义。({nameof(AudioDef)})");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var audioDef in audioDefs)
|
||||
{
|
||||
if (string.IsNullOrEmpty(audioDef.path) || string.IsNullOrEmpty(audioDef.defName))
|
||||
{
|
||||
Debug.LogWarning($"AudioManager: 跳过音频定义 (DefName: '{audioDef?.defName ?? "未知"}'),因为它包含空路径或DefName。(路径: '{audioDef?.path ?? ""}')");
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string cacheKey;
|
||||
AudioClip audioClip = null;
|
||||
|
||||
if (audioDef.path.StartsWith("res:"))
|
||||
{
|
||||
// 处理 Unity Resources 路径
|
||||
var resPath = audioDef.path.Substring(4).Replace('\\', '/').TrimStart('/');
|
||||
cacheKey = "res://" + resPath.ToLower(); // 缓存键使用小写路径
|
||||
|
||||
// 检查音频缓存
|
||||
if (!audioCache.TryGetValue(cacheKey, out audioClip))
|
||||
{
|
||||
var cleanPath = Path.ChangeExtension(resPath, null); // 去掉扩展名
|
||||
audioClip = Resources.Load<AudioClip>(cleanPath);
|
||||
if (audioClip)
|
||||
audioCache[cacheKey] = audioClip;
|
||||
}
|
||||
}
|
||||
else if (audioDef.path.Contains(':')) // 包含 PackageID:Path 或其他自定义前缀
|
||||
{
|
||||
var splitIndex = audioDef.path.IndexOf(':');
|
||||
var packageID = audioDef.path.Substring(0, splitIndex);
|
||||
var relativePath = audioDef.path.Substring(splitIndex + 1);
|
||||
|
||||
var packageRoot = Managers.DefineManager.Instance.GetPackagePath(packageID);
|
||||
if (string.IsNullOrEmpty(packageRoot))
|
||||
{
|
||||
Debug.LogWarning($"AudioManager: 音频定义 '{audioDef.defName}' (路径: '{audioDef.path}'): 引用的包ID '{packageID}' 未找到或没有根路径。跳过音频加载。");
|
||||
continue;
|
||||
}
|
||||
|
||||
var fullPath = Path.Combine(packageRoot, relativePath).Replace('\\', '/');
|
||||
cacheKey = "file://" + fullPath.ToLower(); // 缓存键使用小写路径
|
||||
|
||||
// 检查音频缓存
|
||||
if (!audioCache.TryGetValue(cacheKey, out audioClip))
|
||||
{
|
||||
// === 重要的实现细节 ===
|
||||
// 在真实的 Unity 项目中,直接从文件系统同步加载 AudioClip 通常不推荐,
|
||||
// 且 Unity 不提供直接的同步方法。通常会使用 UnityWebRequest.GetAudioClip (异步)
|
||||
// 或 Asset Bundles。为了与 ImageManager 的 ConfigProcessor.LoadTextureByIO
|
||||
// 保持一致的同步风格,此处我们假设 Configs.ConfigProcessor 存在一个同步的
|
||||
// LoadAudioClipByIO 方法。
|
||||
audioClip = Configs.ConfigProcessor.LoadAudioByIO(fullPath).Result;
|
||||
if (audioClip)
|
||||
audioCache[cacheKey] = audioClip;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 无前缀:使用当前定义所在包的路径
|
||||
var pack = Managers.DefineManager.Instance.GetDefinePackage(audioDef);
|
||||
if (pack == null)
|
||||
{
|
||||
Debug.LogError($"AudioManager: 音频定义 '{audioDef.defName}' (路径: '{audioDef.path}'): 源音频未找到对应的定义包。无法确定完整路径。跳过。");
|
||||
continue;
|
||||
}
|
||||
var fullPath = Path.Combine(pack.packRootPath, audioDef.path).Replace('\\', '/');
|
||||
cacheKey = "file://" + fullPath.ToLower(); // 缓存键使用小写路径
|
||||
|
||||
// 检查音频缓存
|
||||
if (!audioCache.TryGetValue(cacheKey, out audioClip))
|
||||
{
|
||||
audioClip = Configs.ConfigProcessor.LoadAudioByIO(fullPath).Result;
|
||||
if (audioClip)
|
||||
audioCache[cacheKey] = audioClip;
|
||||
}
|
||||
}
|
||||
|
||||
// 资源加载失败
|
||||
if (audioClip == null)
|
||||
{
|
||||
Debug.LogError($"AudioManager: 未能加载音频定义关联的音频剪辑: '{audioDef.defName}' (路径: '{audioDef.path}')。请验证路径和文件是否存在。");
|
||||
continue;
|
||||
}
|
||||
|
||||
audioClips[audioDef.defName] = audioClip; // 使用 DefName 作为唯一键存储
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError(
|
||||
$"AudioManager: 处理音频定义时出错: '{audioDef.defName}' (路径: '{audioDef.path}')。异常: {ex.GetType().Name}: {ex.Message}\n堆栈跟踪: {ex.StackTrace}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有已加载的音频剪辑数据。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 此方法会清空 <see cref="audioClips"/> 字典,释放对 AudioClip 对象的引用。
|
||||
/// 它不会卸载 <see cref="defaultAudioClip"/>,因为它通常通过 Resources.Load 加载,
|
||||
/// 其生命周期由 Unity 的资源管理系统控制,当不再被引用时会自动卸载。
|
||||
/// 对于通过 ConfigProcessor.LoadAudioClipByIO 加载的 AudioClip,如果它们不是通过 Unity API
|
||||
/// 创建的 Unity.Object 类型,则可能需要额外的内存释放逻辑,但在本示例中,我们假设
|
||||
/// ConfigProcessor 会返回一个被 Unity 管理的 AudioClip。
|
||||
/// </remarks>
|
||||
public void Clear()
|
||||
{
|
||||
// 如果需要显式卸载从 Resources.Load 或外部文件加载的 AssetBundle 资源,
|
||||
// 可能需要 Resources.UnloadAsset(clip) 或 AssetBundle.UnloadAllAssets(true)。
|
||||
// 但对于单独的 AudioClip 引用,通常在不再被引用时Unity会自动清理。
|
||||
audioClips.Clear();
|
||||
StepDescription = "音频管理器数据已清理。"; // 更新状态
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新加载所有音频数据。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 此方法会首先调用 <see cref="Clear()"/> 清理所有数据,然后调用 <see cref="Init()"/> 重新初始化。
|
||||
/// </remarks>
|
||||
public void Reload()
|
||||
{
|
||||
Clear();
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据 <see cref="AudioDef"/> 对象获取对应的音频剪辑。
|
||||
/// </summary>
|
||||
/// <param name="audioDef">包含音频名称的 <see cref="AudioDef"/> 对象。</param>
|
||||
/// <returns>如果找到对应的音频剪辑,则返回该剪辑;否则返回 <see cref="defaultAudioClip"/>。</returns>
|
||||
public AudioClip GetAudioClip(AudioDef audioDef)
|
||||
{
|
||||
if (audioDef == null)
|
||||
{
|
||||
Debug.LogWarning("AudioManager: 请求的 AudioDef 为空。返回默认音频。");
|
||||
return defaultAudioClip;
|
||||
}
|
||||
return GetAudioClip(audioDef.defName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据音频名称(全局唯一的DefName)获取对应的音频剪辑。
|
||||
/// </summary>
|
||||
/// <param name="name">音频剪辑的名称。</param>
|
||||
/// <returns>如果找到对应的音频剪辑,则返回该剪辑;否则返回 <see cref="defaultAudioClip"/>。</returns>
|
||||
public AudioClip GetAudioClip(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
Debug.LogWarning("AudioManager: 请求的音频名称为空或null。返回默认音频。");
|
||||
return defaultAudioClip;
|
||||
}
|
||||
|
||||
if (audioClips.TryGetValue(name, out var clip))
|
||||
return clip;
|
||||
|
||||
// 如果未找到,返回默认音频剪辑
|
||||
Debug.LogWarning($"AudioManager: 未找到名称为 '{name}' 的音频剪辑。返回默认音频。");
|
||||
return defaultAudioClip;
|
||||
}
|
||||
}
|
||||
}
|
3
Client/Assets/Scripts/Managers/AudioManager.cs.meta
Normal file
3
Client/Assets/Scripts/Managers/AudioManager.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 42bb2c7fdd494670bc464905def6952f
|
||||
timeCreated: 1756549944
|
@ -67,17 +67,73 @@ namespace Managers
|
||||
if (packs.Count > 0)
|
||||
return;
|
||||
|
||||
// 获取所有定义包的文件夹路径
|
||||
// // 获取所有定义包的文件夹路径
|
||||
// var packFolder = Configs.ConfigProcessor.GetSubFolders(new(dataSetFilePath));
|
||||
// foreach (var folder in packFolder)
|
||||
// {
|
||||
// var pack = new DefinePack();
|
||||
// if (pack.LoadPack(folder))
|
||||
// {
|
||||
// packs.Add(pack.packID, pack);
|
||||
// }
|
||||
// }
|
||||
var packFolder = Configs.ConfigProcessor.GetSubFolders(new(dataSetFilePath));
|
||||
|
||||
// 获取当前的加载顺序
|
||||
var currentOrder = Base.Setting.Instance.CurrentSettings.loadOrder; // 假设为 string[]
|
||||
var isFirstLaunch = currentOrder == null || currentOrder.Length == 0;
|
||||
|
||||
var newOrder = new List<string>(); // 用于最终写回
|
||||
|
||||
foreach (var folder in packFolder)
|
||||
{
|
||||
var pack = new DefinePack();
|
||||
if (pack.LoadPack(folder))
|
||||
{
|
||||
// 根据加载顺序设置 priority
|
||||
int priority;
|
||||
|
||||
if (isFirstLaunch)
|
||||
{
|
||||
// 第一次启动,按遍历顺序设置 priority
|
||||
// 暂时使用新增时的顺序作为 priority,顺序从 newOrder 的索引确定
|
||||
priority = newOrder.Count;
|
||||
// 记录该 pack 的 ID,后续写回 loadOrder
|
||||
newOrder.Add(pack.packID);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 非首次启动,使用现有 loadOrder 中的位置来设置 priority
|
||||
var idx = Array.IndexOf(currentOrder, pack.packID);
|
||||
if (idx >= 0)
|
||||
{
|
||||
priority = idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 未出现在现有顺序中,放在末尾
|
||||
priority = currentOrder.Length;
|
||||
// 可选:也将其加入 newOrder 以更新 loadOrder
|
||||
}
|
||||
}
|
||||
|
||||
pack.priority = priority;
|
||||
packs.Add(pack.packID, pack);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是第一次启动,写回 loadOrder(顺序为 newOrder)
|
||||
if (isFirstLaunch)
|
||||
{
|
||||
// 将 newOrder 转换为 string[],并写回设置
|
||||
Base.Setting.Instance.CurrentSettings.loadOrder = new string[newOrder.Count];
|
||||
newOrder.CopyTo(Base.Setting.Instance.CurrentSettings.loadOrder);
|
||||
// 可能需要保存设置到磁盘/持久化
|
||||
// Example: Settings.Save(Base.Setting.Instance.CurrentSettings);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 字段信息缓存,用于优化反射性能。
|
||||
Dictionary<Type, FieldInfo[]> fieldCache = new();
|
||||
|
||||
@ -130,6 +186,7 @@ namespace Managers
|
||||
anonymousDefines.Add(typeName, new List<Define>());
|
||||
anonymousDefines[typeName].Add(defRef);
|
||||
}
|
||||
|
||||
ProcessDefine(defRef);
|
||||
}
|
||||
}
|
||||
@ -208,7 +265,8 @@ namespace Managers
|
||||
var value = FindDefine(defRef.Item3.description, defRef.Item3.defName);
|
||||
if (value == null)
|
||||
{
|
||||
Debug.LogError($"未找到引用,出错的定义:定义类型:{defRef.Item1.GetType().Name}, 定义名:{defRef.Item1.defName} ; 类型:{defRef.Item3.description}, 定义名:{defRef.Item3.defName}");
|
||||
Debug.LogError(
|
||||
$"未找到引用,出错的定义:定义类型:{defRef.Item1.GetType().Name}, 定义名:{defRef.Item1.defName} ; 类型:{defRef.Item3.description}, 定义名:{defRef.Item3.defName}");
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -352,7 +410,6 @@ namespace Managers
|
||||
// 如果结果为空,则返回 null。
|
||||
if (result.Count == 0)
|
||||
{
|
||||
Debug.LogWarning($"查询失败:未找到定义类型 '{defineType}'");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -51,31 +51,44 @@ namespace Managers
|
||||
/// <summary> 默认实体的预制体,用于生成失败时的回退。 </summary>
|
||||
public EntityPrefab defaultEntityPrefab;
|
||||
|
||||
|
||||
public EntityPrefab[] GetAllEntities(string dimensionId)
|
||||
{
|
||||
if (!_dimensionFactionEntities.ContainsKey(dimensionId))
|
||||
{
|
||||
Debug.LogWarning($"实体管理器:尝试在维度 '{dimensionId}' 中查找实体,但其内部存储未初始化。");
|
||||
return null;
|
||||
}
|
||||
// 获取对应维度的内层字典
|
||||
var factionEntitiesForDimension = _dimensionFactionEntities[dimensionId];
|
||||
// 使用 LINQ 的 SelectMany 方法来扁平化所有 LinkedList 中的 EntityPrefab
|
||||
return factionEntitiesForDimension.Values // 获取所有 LinkedList<EntityPrefab> 的集合
|
||||
.SelectMany(linkedList => linkedList) // 将每个 LinkedList 中的元素展开到一个单一的序列中
|
||||
.ToArray(); // 将该序列转换为一个数组
|
||||
}
|
||||
/// <summary>
|
||||
/// 在指定维度中,根据派系键查找所有实体。
|
||||
/// </summary>
|
||||
/// <param name="dimensionId">维度的唯一标识符。</param>
|
||||
/// <param name="factionKey">派系键。</param>
|
||||
/// <returns>指定派系下的实体列表,如果未找到则返回空列表。</returns>
|
||||
public LinkedList<EntityPrefab> FindEntitiesByFaction(string dimensionId, string factionKey)
|
||||
public EntityPrefab[] FindEntitiesByFaction(string dimensionId, string factionKey)
|
||||
{
|
||||
// 如果在场景加载前或维度未在Program中注册,_dimensionFactionEntities可能还没有该维度ID的条目。
|
||||
if (!_dimensionFactionEntities.ContainsKey(dimensionId))
|
||||
{
|
||||
Debug.LogWarning($"实体管理器:尝试在维度 '{dimensionId}' 中查找实体,但其内部存储未初始化。");
|
||||
return new LinkedList<EntityPrefab>();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_dimensionFactionEntities.TryGetValue(dimensionId, out var factionDict))
|
||||
{
|
||||
if (factionDict.TryGetValue(factionKey, out var entities))
|
||||
{
|
||||
return entities;
|
||||
return entities.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
return new LinkedList<EntityPrefab>(); // 如果未找到,返回一个空列表
|
||||
return null; // 如果未找到,返回一个空列表
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,181 +1,154 @@
|
||||
using Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Data;
|
||||
using EventWorkClass;
|
||||
using Utils;
|
||||
using UnityEngine;
|
||||
using EventType = Data.EventType;
|
||||
|
||||
namespace Managers
|
||||
{
|
||||
// 新增私有结构体,用于在事件队列中存储事件定义及其运行时上下文
|
||||
public struct EventPayload // Make it public if EventManager exposes it directly
|
||||
/// <summary>
|
||||
/// 事件管理器,负责事件的加载、注册和执行。
|
||||
/// 遵循单例模式,并在启动流程中扮演一个管理器角色。
|
||||
/// </summary>
|
||||
class EventManager : Singleton<EventManager>, ILaunchManager
|
||||
{
|
||||
public string DimensionId;
|
||||
public EventDef EventDefinition;
|
||||
public Vector3 Position; // 适用于 Character, Bullet, Pickup, DefaultEntity
|
||||
public Vector3 Direction; // 仅适用于 Bullet
|
||||
public Entity.Entity SourceEntity; // 仅适用于 Bullet (发射源)
|
||||
public Vector3Int GridPosition; // 仅适用于 Building
|
||||
}
|
||||
|
||||
public class EventManager : Utils.MonoSingleton<EventManager>
|
||||
{
|
||||
private Queue<EventPayload> _eventQueue = new Queue<EventPayload>();
|
||||
|
||||
private EventManager()
|
||||
{
|
||||
/* Private constructor for singleton */
|
||||
}
|
||||
|
||||
// ===================================
|
||||
// 公共入队方法
|
||||
// ===================================
|
||||
public void EnqueueCharacterSpawnEvent(string dimensionId, EventDef eventDef, Vector3 pos)
|
||||
{
|
||||
if (eventDef == null || eventDef.eventType != EventType.SpawnCharacter ||
|
||||
eventDef.entityDef_Character == null)
|
||||
{
|
||||
Debug.LogError(
|
||||
$"EnqueueCharacterSpawnEvent: Invalid EventDef, mismatched EventType ({eventDef?.eventType}), or missing characterDef for event '{eventDef?.defName ?? "Unknown"}'.");
|
||||
return;
|
||||
}
|
||||
|
||||
_eventQueue.Enqueue(new EventPayload
|
||||
{
|
||||
DimensionId = dimensionId,
|
||||
EventDefinition = eventDef,
|
||||
Position = pos,
|
||||
});
|
||||
Debug.Log($"Event '{eventDef.defName}' (SpawnCharacter) enqueued for dimension {dimensionId} at {pos}.");
|
||||
}
|
||||
|
||||
public void EnqueueBuildingSpawnEvent(string dimensionId, EventDef eventDef, Vector3Int gridPos)
|
||||
{
|
||||
if (eventDef == null || eventDef.eventType != EventType.SpawnBuilding ||
|
||||
eventDef.entityDef_Building == null)
|
||||
{
|
||||
Debug.LogError(
|
||||
$"EnqueueBuildingSpawnEvent: Invalid EventDef, mismatched EventType ({eventDef?.eventType}), or missing buildingDef for event '{eventDef?.defName ?? "Unknown"}'.");
|
||||
return;
|
||||
}
|
||||
|
||||
_eventQueue.Enqueue(new EventPayload
|
||||
{
|
||||
DimensionId = dimensionId,
|
||||
EventDefinition = eventDef,
|
||||
GridPosition = gridPos,
|
||||
});
|
||||
Debug.Log($"Event '{eventDef.defName}' (SpawnBuilding) enqueued for dimension {dimensionId} at grid {gridPos}.");
|
||||
}
|
||||
|
||||
public void EnqueueBulletSpawnEvent(string dimensionId, EventDef eventDef, Vector3 pos, Vector3 dir,
|
||||
Entity.Entity source = null)
|
||||
{
|
||||
if (eventDef == null || eventDef.eventType != EventType.SpawnBullet || eventDef.entityDef_Bullet == null)
|
||||
{
|
||||
Debug.LogError(
|
||||
$"EnqueueBulletSpawnEvent: Invalid EventDef, mismatched EventType ({eventDef?.eventType}), or missing bulletDef for event '{eventDef?.defName ?? "Unknown"}'.");
|
||||
return;
|
||||
}
|
||||
|
||||
_eventQueue.Enqueue(new EventPayload
|
||||
{
|
||||
DimensionId = dimensionId,
|
||||
EventDefinition = eventDef,
|
||||
Position = pos,
|
||||
Direction = dir,
|
||||
SourceEntity = source,
|
||||
});
|
||||
Debug.Log($"Event '{eventDef.defName}' (SpawnBullet) enqueued for dimension {dimensionId} at {pos}, dir {dir}.");
|
||||
}
|
||||
|
||||
public void EnqueuePickupSpawnEvent(string dimensionId, EventDef eventDef, Vector3 pos)
|
||||
{
|
||||
if (eventDef == null || eventDef.eventType != EventType.SpawnPickup || eventDef.entityDef_Pickup == null)
|
||||
{
|
||||
Debug.LogError(
|
||||
$"EnqueuePickupSpawnEvent: Invalid EventDef, mismatched EventType ({eventDef?.eventType}), or missing itemDef for event '{eventDef?.defName ?? "Unknown"}'.");
|
||||
return;
|
||||
}
|
||||
|
||||
_eventQueue.Enqueue(new EventPayload
|
||||
{
|
||||
DimensionId = dimensionId,
|
||||
EventDefinition = eventDef,
|
||||
Position = pos,
|
||||
});
|
||||
Debug.Log($"Event '{eventDef.defName}' (SpawnPickup) enqueued for dimension {dimensionId} at {pos}.");
|
||||
}
|
||||
|
||||
public void EnqueueDefaultEntitySpawnEvent(string dimensionId, EventDef eventDef, Vector3 pos)
|
||||
{
|
||||
if (eventDef == null || eventDef.eventType != EventType.SpawnDefaultEntity)
|
||||
{
|
||||
Debug.LogError(
|
||||
$"EnqueueDefaultEntitySpawnEvent: Invalid EventDef or mismatched EventType ({eventDef?.eventType}) for event '{eventDef?.defName ?? "Unknown"}'.");
|
||||
return;
|
||||
}
|
||||
|
||||
_eventQueue.Enqueue(new EventPayload
|
||||
{
|
||||
DimensionId = dimensionId,
|
||||
EventDefinition = eventDef,
|
||||
Position = pos,
|
||||
});
|
||||
Debug.Log($"Event '{eventDef.defName}' (SpawnDefaultEntity) enqueued for dimension {dimensionId} at {pos}.");
|
||||
}
|
||||
|
||||
// ===================================
|
||||
// 事件处理方法
|
||||
// ===================================
|
||||
/// <summary>
|
||||
/// 处理所有在队列中的待处理事件。
|
||||
/// 存储所有已加载的事件定义,键为事件名称,值为对应的事件工作类实例。
|
||||
/// </summary>
|
||||
public void ProcessEvents()
|
||||
public Dictionary<string, EventWorkClassBase> EventDefs { get; private set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前加载步骤的描述,用于启动流程的进度显示。
|
||||
/// </summary>
|
||||
public string StepDescription => "正在载入事件";
|
||||
|
||||
/// <summary>
|
||||
/// 初始化事件管理器,从定义管理器中加载所有事件定义并实例化其工作类。
|
||||
/// </summary>
|
||||
public void Init()
|
||||
{
|
||||
while (_eventQueue.Count > 0)
|
||||
// 如果事件定义已经加载,则直接返回,避免重复初始化。
|
||||
if (EventDefs != null)
|
||||
return;
|
||||
|
||||
var defs = DefineManager.Instance.QueryDefinesByType<EventDef>();
|
||||
EventDefs = new Dictionary<string, EventWorkClassBase>();
|
||||
foreach (var def in defs)
|
||||
{
|
||||
EventPayload eventData = _eventQueue.Dequeue();
|
||||
if (!Program.Instance.GetDimension(eventData.DimensionId))
|
||||
if (EventDefs.ContainsKey(def.defName))
|
||||
{
|
||||
Debug.LogWarning(
|
||||
$"Event '{eventData.EventDefinition.defName}' for dimension {eventData.DimensionId} dropped as dimension is no longer active.");
|
||||
Debug.LogWarning($"警告:事件名称重复,已跳过加载名称为 {def.defName} 的事件定义。");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 核心:调用 EntityManage.Instance 的现有公共方法
|
||||
switch (eventData.EventDefinition.eventType)
|
||||
var eventWorker = GetAndInstantiateEventWorker(def.workClass);
|
||||
if (eventWorker == null)
|
||||
{
|
||||
case EventType.SpawnCharacter:
|
||||
EntityManage.Instance.GenerateEntity(eventData.DimensionId,
|
||||
eventData.EventDefinition.entityDef_Character, eventData.Position);
|
||||
break;
|
||||
case EventType.SpawnBuilding:
|
||||
EntityManage.Instance.GenerateBuildingEntity(eventData.DimensionId,
|
||||
eventData.EventDefinition.entityDef_Building, eventData.GridPosition);
|
||||
break;
|
||||
case EventType.SpawnBullet:
|
||||
EntityManage.Instance.GenerateBulletEntity(eventData.DimensionId,
|
||||
eventData.EventDefinition.entityDef_Bullet, eventData.Position, eventData.Direction,
|
||||
eventData.SourceEntity);
|
||||
break;
|
||||
case EventType.SpawnPickup:
|
||||
EntityManage.Instance.GeneratePickupEntity(eventData.DimensionId,
|
||||
eventData.EventDefinition.entityDef_Pickup, eventData.Position);
|
||||
break;
|
||||
case EventType.SpawnDefaultEntity:
|
||||
EntityManage.Instance.GenerateDefaultEntity(eventData.DimensionId, eventData.Position);
|
||||
break;
|
||||
case EventType.None:
|
||||
default:
|
||||
Debug.LogWarning(
|
||||
$"EventManager: Unhandled or invalid event type: {eventData.EventDefinition.eventType} for event '{eventData.EventDefinition.defName}'.");
|
||||
break;
|
||||
Debug.LogWarning($"警告:未能找到或实例化名称为 '{def.workClass}' 的事件工作类,已跳过加载名称为 '{def.defName}' 的事件定义。");
|
||||
continue;
|
||||
}
|
||||
eventWorker.Init(def.value);
|
||||
EventDefs.Add(def.defName, eventWorker);
|
||||
}
|
||||
Debug.Log($"事件管理器初始化完成,共载入 {EventDefs.Count} 个事件。");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理事件管理器,释放所有已加载的事件定义。
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
EventDefs = null;
|
||||
Debug.Log("事件管理器已清理。");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行指定名称的事件。
|
||||
/// </summary>
|
||||
/// <param name="eventName">要执行的事件的名称。</param>
|
||||
/// <param name="dimensionID">事件执行的维度ID,如果为null,将使用当前焦点的维度ID。</param>
|
||||
public void Action(string eventName, string dimensionID = null)
|
||||
{
|
||||
if (EventDefs == null)
|
||||
{
|
||||
Debug.LogError($"错误:事件管理器尚未初始化或已被清理。无法执行事件 '{eventName}'。");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EventDefs.ContainsKey(eventName))
|
||||
{
|
||||
Debug.LogWarning($"警告:未能找到名称为 '{eventName}' 的事件定义,已跳过执行该事件。");
|
||||
return;
|
||||
}
|
||||
// 假设 Program.Instance 和 FocusedDimensionId 存在且可访问。
|
||||
// 如果 dimensionID 为 null,则使用当前焦点维度ID。
|
||||
dimensionID ??= Program.Instance.FocusedDimensionId;
|
||||
EventDefs[eventName].Run(dimensionID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据类名从指定命名空间和程序集下获取并实例化一个 <see cref="EventWorkClassBase"/> 的子类。
|
||||
/// </summary>
|
||||
/// <param name="className">要实例化的类的短名称(不包含命名空间)。</param>
|
||||
/// <param name="targetNamespace">目标类所在的完整命名空间。</param>
|
||||
/// <param name="assemblyToSearch">要搜索的程序集。如果为 null,将搜索 <see cref="EventWorkClassBase"/> 所在的程序集。</param>
|
||||
/// <returns>实例化后的 <see cref="EventWorkClassBase"/> 对象,如果找不到或不符合条件则返回 null。</returns>
|
||||
public static EventWorkClassBase GetAndInstantiateEventWorker(
|
||||
string className,
|
||||
string targetNamespace = "EventWorkClass", // 默认命名空间
|
||||
Assembly assemblyToSearch = null) // 默认程序集
|
||||
{
|
||||
// 1. 确定要搜索的程序集。
|
||||
if (assemblyToSearch == null)
|
||||
{
|
||||
// 默认从 EventWorkClassBase 所在的程序集查找,通常其实现类也会在这个程序集。
|
||||
assemblyToSearch = typeof(EventWorkClassBase).Assembly;
|
||||
}
|
||||
|
||||
// 2. 构造完整的类型名称。
|
||||
string fullTypeName = $"{targetNamespace}.{className}";
|
||||
Type targetType = null;
|
||||
|
||||
// 3. 尝试直接从程序集获取类型。
|
||||
targetType = assemblyToSearch.GetType(fullTypeName);
|
||||
|
||||
// 4. 进行类型检查。
|
||||
if (targetType == null)
|
||||
{
|
||||
Debug.LogError($"错误:在程序集 '{assemblyToSearch.FullName}' 的命名空间 '{targetNamespace}' 中未找到类 '{className}'。");
|
||||
return null;
|
||||
}
|
||||
// 检查是否是 EventWorkClassBase 的子类。
|
||||
if (!typeof(EventWorkClassBase).IsAssignableFrom(targetType))
|
||||
{
|
||||
Debug.LogError($"错误:类 '{fullTypeName}' 不是 '{typeof(EventWorkClassBase).FullName}' 的子类。");
|
||||
return null;
|
||||
}
|
||||
// 检查是否可以实例化(非抽象类,非接口)。
|
||||
if (targetType.IsAbstract || targetType.IsInterface)
|
||||
{
|
||||
Debug.LogError($"错误:类 '{fullTypeName}' 是抽象类或接口,不能直接实例化。");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 5. 实例化对象。
|
||||
try
|
||||
{
|
||||
// 使用 Activator.CreateInstance 实例化对象。它默认调用无参公共构造函数。
|
||||
object instance = Activator.CreateInstance(targetType);
|
||||
return instance as EventWorkClassBase;
|
||||
}
|
||||
catch (MissingMethodException ex)
|
||||
{
|
||||
Debug.LogError($"错误:类 '{fullTypeName}' 没有公共的无参构造函数。详情: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"实例化类 '{fullTypeName}' 时发生未知错误。详情: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ namespace Managers
|
||||
public interface ILaunchManager
|
||||
{
|
||||
string StepDescription { get; } // 获取当前加载步骤的描述
|
||||
|
||||
void Init(); // 初始化管理器
|
||||
void Clear(); // 清理管理器,用于重载
|
||||
}
|
||||
|
@ -22,20 +22,14 @@ namespace Managers
|
||||
public Sprite defaultSprite;
|
||||
|
||||
/// <summary>
|
||||
/// 存储所有已加载的纹理,按包ID和图像名称索引。
|
||||
/// 存储所有已加载的纹理,按图像名称(全局唯一的DefName)索引。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 外层字典键是包ID,内层字典键是图像名称。
|
||||
/// </remarks>
|
||||
public Dictionary<string, Dictionary<string, Texture2D>> packagesImages = new();
|
||||
public Dictionary<string, Texture2D> packagesImages = new();
|
||||
|
||||
/// <summary>
|
||||
/// 存储所有已创建的精灵,按包ID和精灵名称索引。
|
||||
/// 存储所有已创建的精灵,按精灵名称(全局唯一的DefName或其带索引后缀)索引。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 外层字典键是包ID,内层字典键是精灵名称(如果纹理被分割,会包含索引后缀)。
|
||||
/// </remarks>
|
||||
public Dictionary<string, Dictionary<string, Sprite>> sprites = new();
|
||||
public Dictionary<string, Sprite> sprites = new();
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前启动步骤的描述。
|
||||
@ -49,21 +43,15 @@ namespace Managers
|
||||
{
|
||||
if (packagesImages.Count > 0)
|
||||
{
|
||||
// 如果已经加载过,直接返回。
|
||||
StepDescription = "包图像管理器已初始化。";
|
||||
return;
|
||||
// 如果已经有数据,则跳过初始化,防止重复加载。
|
||||
return;
|
||||
}
|
||||
|
||||
StepDescription = "正在加载默认精灵..."; // 更新加载步骤描述
|
||||
defaultSprite = Resources.Load<Sprite>("Default/DefaultImage");
|
||||
if (defaultSprite == null)
|
||||
{
|
||||
Debug.LogWarning("无法加载默认精灵 'Resources/Default/DefaultImage'。请确保文件存在。");
|
||||
}
|
||||
|
||||
StepDescription = "正在处理图像定义并创建精灵..."; // 更新加载步骤描述
|
||||
InitImageDef();
|
||||
StepDescription = "包图像管理器初始化完成。"; // 完成加载
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -76,7 +64,7 @@ namespace Managers
|
||||
|
||||
if (imageDef == null || !imageDef.Any())
|
||||
{
|
||||
Debug.Log($"在 DefineManager 中未找到任何 ImageDef 定义。({typeof(ImageDef).Name})");
|
||||
Debug.Log($"在定义管理器中未找到任何图像定义。({nameof(ImageDef)})");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -84,7 +72,7 @@ namespace Managers
|
||||
{
|
||||
if (string.IsNullOrEmpty(ima.path) || string.IsNullOrEmpty(ima.packID))
|
||||
{
|
||||
Debug.LogWarning($"跳过图像定义 '{ima?.name ?? "未知"}',因为它包含空路径或包ID。(路径: '{ima?.path ?? ""}', 包ID: '{ima?.packID ?? ""}')");
|
||||
Debug.LogWarning($"跳过图像定义 '{ima?.defName ?? "未知"}',因为它包含空路径或包ID。(路径: '{ima?.path ?? ""}', 包ID: '{ima?.packID ?? ""}')");
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -119,7 +107,7 @@ namespace Managers
|
||||
var packageRoot = Managers.DefineManager.Instance.GetPackagePath(packageID);
|
||||
if (string.IsNullOrEmpty(packageRoot))
|
||||
{
|
||||
Debug.LogWarning($"图像定义 '{ima.name}' (包ID: {ima.packID}): 引用的包ID '{packageID}' 未找到或没有根路径。跳过图像加载。");
|
||||
Debug.LogWarning($"图像定义 '{ima.defName}' (包ID: {ima.packID}): 引用的包ID '{packageID}' 未找到或没有根路径。跳过图像加载。");
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -140,7 +128,7 @@ namespace Managers
|
||||
var pack = Managers.DefineManager.Instance.GetDefinePackage(ima);
|
||||
if (pack == null)
|
||||
{
|
||||
Debug.LogError($"图像定义 '{ima.name}' (包ID: {ima.packID}): 源图像未找到对应的定义包。无法确定 '{ima.path}' 的完整路径。跳过。");
|
||||
Debug.LogError($"图像定义 '{ima.defName}' (包ID: {ima.packID}): 源图像未找到对应的定义包。无法确定 '{ima.path}' 的完整路径。跳过。");
|
||||
continue;
|
||||
}
|
||||
var fullPath = Path.Combine(pack.packRootPath, ima.path).Replace('\\', '/');
|
||||
@ -158,31 +146,20 @@ namespace Managers
|
||||
// 资源加载失败
|
||||
if (!texture)
|
||||
{
|
||||
Debug.LogError($"未能加载图像定义所在的纹理: '{ima.name}' (路径: '{ima.path}', 包ID: '{ima.packID}')。请验证路径和文件是否存在。");
|
||||
Debug.LogError($"未能加载图像定义关联的纹理: '{ima.defName}' (路径: '{ima.path}', 包ID: '{ima.packID}')。请验证路径和文件是否存在。");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 存储到包纹理字典(使用定义自身的 packID)
|
||||
var packId = ima.packID;
|
||||
if (!packagesImages.ContainsKey(packId))
|
||||
packagesImages[packId] = new Dictionary<string, Texture2D>();
|
||||
|
||||
// 警告:如果图片名重复,则覆盖
|
||||
if (packagesImages[packId].ContainsKey(ima.name))
|
||||
{
|
||||
Debug.LogWarning($"包 '{packId}' 中名为 '{ima.name}' 的图像被多次定义。将覆盖之前的纹理引用。这可能表示配置错误。");
|
||||
}
|
||||
packagesImages[packId][ima.name] = texture; // 覆盖或添加
|
||||
|
||||
packagesImages[ima.defName] = texture;
|
||||
|
||||
// 切分精灵
|
||||
SplitTextureIntoSprites(packId, ima.name, texture, ima.hCount, ima.wCount, ima.pixelsPerUnit);
|
||||
SplitTextureIntoSprites(ima.defName, texture, ima.hCount, ima.wCount, ima.pixelsPerUnit);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 捕获异常并打印详细错误信息
|
||||
Debug.LogError(
|
||||
$"处理图像定义时出错: '{ima.name}' (路径: '{ima.path}', 包ID: '{ima.packID}')。异常: {ex.GetType().Name}: {ex.Message}\n堆栈跟踪: {ex.StackTrace}");
|
||||
$"处理图像定义时出错: '{ima.defName}' (路径: '{ima.path}', 包ID: '{ima.packID}')。异常: {ex.GetType().Name}: {ex.Message}\n堆栈跟踪: {ex.StackTrace}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -190,14 +167,12 @@ namespace Managers
|
||||
/// <summary>
|
||||
/// 将纹理按指定行数和列数分割成多个精灵,并存储起来。
|
||||
/// </summary>
|
||||
/// <param name="packId">精灵所属的包ID。</param>
|
||||
/// <param name="baseName">精灵的基础名称。</param>
|
||||
/// <param name="baseName">精灵的基础名称(全局唯一的DefName)。</param>
|
||||
/// <param name="texture">要分割的 <see cref="Texture2D"/> 对象。</param>
|
||||
/// <param name="rows">水平分割的行数。</param>
|
||||
/// <param name="cols">垂直分割的列数。</param>
|
||||
/// <param name="pixelsPerUnit">每个单元的像素数,用于Sprite.Create。</param>
|
||||
private void SplitTextureIntoSprites(
|
||||
string packId,
|
||||
string baseName,
|
||||
Texture2D texture,
|
||||
int rows,
|
||||
@ -206,7 +181,7 @@ namespace Managers
|
||||
{
|
||||
if (!texture)
|
||||
{
|
||||
Debug.LogError($"SplitTextureIntoSprites: 包 '{packId}' 中 '{baseName}' 提供的纹理为空。无法分割。");
|
||||
Debug.LogError($"SplitTextureIntoSprites: '{baseName}' 提供的纹理为空。无法分割。");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -217,19 +192,11 @@ namespace Managers
|
||||
var textureWidth = texture.width;
|
||||
var textureHeight = texture.height;
|
||||
|
||||
if (!sprites.ContainsKey(packId))
|
||||
sprites[packId] = new Dictionary<string, Sprite>();
|
||||
|
||||
// 创建未分割的完整精灵,使用原始名称
|
||||
// 创建未分割的完整精灵,使用原始名称 (baseName,即 ImageDef.name)
|
||||
var fullSpriteRect = new Rect(0, 0, textureWidth, textureHeight);
|
||||
// 警告:如果精灵名重复,则覆盖
|
||||
if (sprites[packId].ContainsKey(baseName))
|
||||
{
|
||||
Debug.LogWarning($"包 '{packId}' 中名为 '{baseName}' 的精灵已存在。将覆盖之前的完整精灵定义。");
|
||||
}
|
||||
var fullSprite = Sprite.Create(texture, fullSpriteRect, new Vector2(0.5f, 0.5f), pixelsPerUnit);
|
||||
fullSprite.name = baseName; // 确保 Sprite.name 被设置
|
||||
sprites[packId][baseName] = fullSprite;
|
||||
sprites[baseName] = fullSprite;
|
||||
|
||||
// 如果不分割(rows和cols都为1),提前返回
|
||||
if (rows == 1 && cols == 1)
|
||||
@ -240,7 +207,7 @@ namespace Managers
|
||||
// 检查纹理尺寸是否可被分割数整除
|
||||
if (textureWidth % cols != 0 || textureHeight % rows != 0)
|
||||
{
|
||||
Debug.LogError($"包 '{packId}' 中 '{baseName}' 的纹理尺寸 ({textureWidth}x{textureHeight}) 不能被指定的行数 ({rows}) 和列数 ({cols}) 完美整除。子精灵将不会生成或可能不正确。仅显示完整精灵。");
|
||||
Debug.LogError($"'{baseName}' 的纹理尺寸 ({textureWidth}x{textureHeight}) 不能被指定的行数 ({rows}) 和列数 ({cols}) 完美整除。子精灵将不会生成或可能不正确。仅显示完整精灵。");
|
||||
return; // 终止子精灵分割,只保留完整的精灵
|
||||
}
|
||||
|
||||
@ -253,18 +220,11 @@ namespace Managers
|
||||
{
|
||||
Rect spriteRect = new(col * tileWidth, row * tileHeight, tileWidth, tileHeight);
|
||||
var sprite = Sprite.Create(texture, spriteRect, new Vector2(0.5f, 0.5f), pixelsPerUnit);
|
||||
|
||||
// 精灵索引计算方式
|
||||
var index = (rows - row - 1) * cols + col;
|
||||
var spriteName = $"{baseName}_{index}";
|
||||
sprite.name = spriteName;
|
||||
|
||||
// 警告:如果子精灵名重复,则覆盖
|
||||
if (sprites[packId].ContainsKey(spriteName))
|
||||
{
|
||||
Debug.LogWarning($"包 '{packId}' 中名为 '{spriteName}' 的精灵已存在。将覆盖之前的子精灵定义。这可能表示配置错误。");
|
||||
}
|
||||
sprites[packId][spriteName] = sprite;
|
||||
sprites[spriteName] = sprite;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -299,36 +259,24 @@ namespace Managers
|
||||
/// <summary>
|
||||
/// 根据 <see cref="ImageDef"/> 对象获取对应的精灵。
|
||||
/// </summary>
|
||||
/// <param name="ima">包含精灵包ID和名称的 <see cref="ImageDef"/> 对象。</param>
|
||||
/// <param name="ima">包含精灵名称的 <see cref="ImageDef"/> 对象。</param>
|
||||
/// <returns>如果找到对应的精灵,则返回该精灵;否则返回 <see cref="defaultSprite"/>。</returns>
|
||||
public Sprite GetSprite(ImageDef ima)
|
||||
{
|
||||
if (ima == null) return defaultSprite;
|
||||
return GetSprite(ima.packID, ima.name);
|
||||
if (ima == null) return defaultSprite;
|
||||
return GetSprite(ima.packID, ima.defName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据包ID和精灵名称获取对应的精灵。
|
||||
/// </summary>
|
||||
/// <param name="packID">精灵所属的包ID。如果为空,则会遍历所有包查找。</param>
|
||||
/// <param name="name">精灵的名称。</param>
|
||||
/// <param name="packID">精灵所属的包ID。此参数在此版本中已不再用于字典查找,但为保持兼容性而保留。</param>
|
||||
/// <param name="name">精灵的名称(全局唯一的DefName)。</param>
|
||||
/// <returns>如果找到对应的精灵,则返回该精灵;否则返回 <see cref="defaultSprite"/>。</returns>
|
||||
public Sprite GetSprite(string packID, string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(packID))
|
||||
{
|
||||
// 如果packID为空,遍历所有包以name查找
|
||||
foreach (var kvp in sprites)
|
||||
{
|
||||
if (kvp.Value.TryGetValue(name, out var sprite))
|
||||
return sprite;
|
||||
}
|
||||
}
|
||||
else if (sprites.TryGetValue(packID, out var dict))
|
||||
{
|
||||
if (dict.TryGetValue(name, out var sprite))
|
||||
return sprite;
|
||||
}
|
||||
if (sprites.TryGetValue(name, out var sprite))
|
||||
return sprite;
|
||||
|
||||
// 如果未找到,返回默认精灵
|
||||
return defaultSprite;
|
||||
@ -337,14 +285,40 @@ namespace Managers
|
||||
/// <summary>
|
||||
/// 根据包ID、基础名称和索引获取被分割的子精灵。
|
||||
/// </summary>
|
||||
/// <param name="packID">精灵所属的包ID。</param>
|
||||
/// <param name="name">精灵的基础名称。</param>
|
||||
/// <param name="packID">精灵所属的包ID。此参数在此版本中已不再用于字典查找,但为保持兼容性而保留。</param>
|
||||
/// <param name="name">精灵的基础名称(全局唯一的DefName)。</param>
|
||||
/// <param name="index">子精灵的索引。</param>
|
||||
/// <returns>如果找到对应的子精灵,则返回该精灵;否则返回 <see cref="defaultSprite"/>。</returns>
|
||||
public Sprite GetSprite(string packID, string name, int index)
|
||||
{
|
||||
var fullName = $"{name}_{index}";
|
||||
return GetSprite(packID, fullName);
|
||||
return GetSprite(packID, fullName);
|
||||
}
|
||||
|
||||
// ---------- 新增的查询接口 ----------
|
||||
|
||||
/// <summary>
|
||||
/// 根据精灵名称(全局唯一的DefName)获取对应的精灵。
|
||||
/// </summary>
|
||||
/// <param name="name">精灵的名称。</param>
|
||||
/// <returns>如果找到对应的精灵,则返回该精灵;否则返回 <see cref="defaultSprite"/>。</returns>
|
||||
public Sprite GetSprite(string name)
|
||||
{
|
||||
if (sprites.TryGetValue(name, out var sprite))
|
||||
return sprite;
|
||||
return defaultSprite;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据基础名称(全局唯一的DefName)和索引获取被分割的子精灵。
|
||||
/// </summary>
|
||||
/// <param name="name">精灵的基础名称。</param>
|
||||
/// <param name="index">子精灵的索引。</param>
|
||||
/// <returns>如果找到对应的子精灵,则返回该精灵;否则返回 <see cref="defaultSprite"/>。</returns>
|
||||
public Sprite GetSprite(string name, int index)
|
||||
{
|
||||
var fullName = $"{name}_{index}";
|
||||
return GetSprite(fullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
10
Client/Assets/Scripts/Managers/SaveManager.cs
Normal file
10
Client/Assets/Scripts/Managers/SaveManager.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using Entity;
|
||||
|
||||
namespace Managers
|
||||
{
|
||||
public class SaveManager:Utils.Singleton<SaveManager>
|
||||
{
|
||||
public List<Hediff> baseHediffs = new();
|
||||
}
|
||||
}
|
3
Client/Assets/Scripts/Managers/SaveManager.cs.meta
Normal file
3
Client/Assets/Scripts/Managers/SaveManager.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: daa6e65f38a5495492e994e89eba53f4
|
||||
timeCreated: 1756655387
|
Reference in New Issue
Block a user