Files
zeling_v2/Assets/_Game/Scripts/World/Map/RegionRegistrySO.cs
2026-06-05 18:41:33 +08:00

77 lines
3.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using UnityEngine;
namespace BaseGames.World.Map
{
/// <summary>
/// 全局区域注册表 SO。
///
/// 设计原则:<see cref="MapRoomDataSO.RegionId"/> 是房间归属的单一权威来源。
/// 本 SO 持有所有 <see cref="RegionDefinitionSO"/> 资产引用,运行时从
/// <see cref="MapDatabaseSO"/> 惰性构建 SceneName → Region 缓存,
/// 消除了原 RegionDefinitionSO.roomSceneNames 与 MapRoomDataSO.RegionId 的双重冗余。
///
/// 资产路径Assets/_Game/Data/Map/RegionRegistry.asset
/// </summary>
[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<string, RegionDefinitionSO> _regionById;
private Dictionary<string, RegionDefinitionSO> _sceneToRegion;
/// <summary>根据场景名MapRoomDataSO.RoomId查找所属区域未找到返回 null。</summary>
public RegionDefinitionSO FindBySceneName(string sceneName)
{
if (string.IsNullOrEmpty(sceneName)) return null;
BuildCacheIfNeeded();
_sceneToRegion.TryGetValue(sceneName, out var region);
return region;
}
/// <summary>根据 regionId 直接查找;未找到返回 null。</summary>
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<string, RegionDefinitionSO>(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<string, RegionDefinitionSO>(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;
}
}
}