using System.Collections.Generic; using UnityEngine; namespace BaseGames.World.Map { /// /// 全局区域注册表 SO。 /// /// 设计原则: 是房间归属的单一权威来源。 /// 本 SO 持有所有 资产引用,运行时从 /// 惰性构建 SceneName → Region 缓存, /// 消除了原 RegionDefinitionSO.roomSceneNames 与 MapRoomDataSO.RegionId 的双重冗余。 /// /// 资产路径:Assets/_Game/Data/Map/RegionRegistry.asset /// [CreateAssetMenu(menuName = "BaseGames/Map/RegionRegistry", fileName = "RegionRegistry")] public class RegionRegistrySO : ScriptableObject { [Tooltip("项目中所有 RegionDefinitionSO 资产。新增区域 SO 时同步添加到此数组。")] [SerializeField] private RegionDefinitionSO[] _regions; [Tooltip("地图数据库,用于从 MapRoomDataSO.RegionId 构建 SceneName → Region 缓存(单一权威来源)。")] [SerializeField] private MapDatabaseSO _mapDatabase; private Dictionary _regionById; private Dictionary _sceneToRegion; /// 根据场景名(MapRoomDataSO.RoomId)查找所属区域;未找到返回 null。 public RegionDefinitionSO FindBySceneName(string sceneName) { if (string.IsNullOrEmpty(sceneName)) return null; BuildCacheIfNeeded(); _sceneToRegion.TryGetValue(sceneName, out var region); return region; } /// 根据 regionId 直接查找;未找到返回 null。 public RegionDefinitionSO FindById(string regionId) { if (string.IsNullOrEmpty(regionId)) return null; BuildCacheIfNeeded(); _regionById.TryGetValue(regionId, out var region); return region; } private void BuildCacheIfNeeded() { if (_sceneToRegion != null) return; // Step 1: regionId → RegionDefinitionSO _regionById = new Dictionary(System.StringComparer.OrdinalIgnoreCase); if (_regions != null) foreach (var r in _regions) if (r != null && !string.IsNullOrEmpty(r.regionId)) _regionById[r.regionId] = r; // Step 2: sceneName → RegionDefinitionSO,以 MapRoomDataSO.RegionId 为权威来源 _sceneToRegion = new Dictionary(System.StringComparer.OrdinalIgnoreCase); if (_mapDatabase?.AllRooms == null) return; foreach (var room in _mapDatabase.AllRooms) { if (room == null || string.IsNullOrEmpty(room.RoomId) || string.IsNullOrEmpty(room.RegionId)) continue; if (_regionById.TryGetValue(room.RegionId, out var def)) _sceneToRegion[room.RoomId] = def; } } private void OnValidate() { _sceneToRegion = null; _regionById = null; } } }