using System;
using System.Collections.Generic;
using UnityEngine;
namespace OCES.Audio
{
///
/// 维护当前激活的游戏状态,在状态变化时全量匹配 Path 表,返回应当播放的 ContainerId。
///
public class MusicStateRouter
{
// key: StateGroup enum Type,value: 当前激活的 enum 整数值
readonly Dictionary m_activeStates = new();
readonly MusicPathConfig m_musicPaths;
readonly AmbiencePathConfig m_ambiencePaths;
// 上一次匹配到的 PathId,用于 Transition 表的 FromPathId 查询
public uint LastMusicPathId { get; private set; }
public uint LastAmbiencePathId { get; private set; }
public MusicStateRouter(MusicPathConfig musicPaths, AmbiencePathConfig ambiencePaths)
{
this.m_musicPaths = musicPaths;
this.m_ambiencePaths = ambiencePaths;
}
///
/// 更新某个 StateGroup 的当前值,并重新全量匹配两张 Path 表。
///
public void SetState(TEnum state, out uint musicContainerId, out uint ambienceContainerId)
where TEnum : Enum
{
// Dictionary 天然保证同一 StateGroup 只保留最新值,直接覆盖即可
this.m_activeStates[typeof(TEnum)] = Convert.ToInt32(state);
musicContainerId = MatchBestPath(this.m_musicPaths.MusicPathList(), out uint musicPathId);
ambienceContainerId = MatchBestPath(this.m_ambiencePaths.AmbiencePathList(), out uint ambiencePathId);
LastMusicPathId = musicPathId;
LastAmbiencePathId = ambiencePathId;
#if UNITY_EDITOR
Editor.DebugInfoCollector.Instance.ActiveStates = this.m_activeStates;
#endif
}
// ─────────────────────────────────────────────
// 内部匹配逻辑
// ─────────────────────────────────────────────
///
/// 遍历路径列表,找到所有满足当前状态的规则,返回 priority 最小(最高优先级)的那条的 ContainerId。
///
uint MatchBestPath(List paths, out uint matchedPathId) where T : IPathEntry
{
IPathEntry best = null;
foreach (T path in paths)
{
if (PathMatches(path.Path) && (best == null || path.Priority < best.Priority))
best = path;
}
if (best != null)
{
matchedPathId = best.Id;
return best.ContainerId;
}
matchedPathId = 0;
return 0;
}
///
/// 解析 path 字符串,判断当前激活状态是否满足该条规则。
/// 格式:TypeID1,子状态|TypeID2,子状态……
/// 规则中的每一个条件都必须满足(AND 关系)。
///
bool PathMatches(string pathStr)
{
if (string.IsNullOrEmpty(pathStr))
return true; // 空 path 视为无条件匹配(默认兜底规则)
string[] conditions = pathStr.Split('|');
foreach (string condition in conditions)
{
string[] parts = condition.Split(',');
if (parts.Length != 2)
{
Debug.LogWarning($"[MusicStateRouter] Path格式错误: '{condition}'");
return false;
}
if (!int.TryParse(parts[0].Trim(), out int typeId) ||
!int.TryParse(parts[1].Trim(), out int stateValue))
{
Debug.LogWarning($"[MusicStateRouter] Path解析失败: '{condition}'");
return false;
}
bool conditionMet = false;
foreach (KeyValuePair kv in this.m_activeStates)
{
if (StateGroupRegistry.GetTypeId(kv.Key) != typeId || kv.Value != stateValue)
continue;
conditionMet = true;
break;
}
if (!conditionMet)
return false;
}
return true;
}
}
// ─────────────────────────────────────────────
// StateGroup 注册表:将 enum Type 映射为策划表中填写的 TypeId 整数
// ─────────────────────────────────────────────
///
/// 程序员在此注册所有 StateGroup enum 与其对应 TypeId 的映射关系。
/// 策划在 MusicPath.path 字段中填写的 TypeId 数字必须与此处一致。
///
public static class StateGroupRegistry
{
static readonly Dictionary s_typeIdMap = new();
public static void Register(int typeId) where TEnum : Enum
{
s_typeIdMap[typeof(TEnum)] = typeId;
}
public static int GetTypeId(Type enumType)
{
if (s_typeIdMap.TryGetValue(enumType, out int id))
return id;
Debug.LogWarning($"[StateGroupRegistry] 未注册的StateGroup类型: {enumType.Name},请调用StateGroupRegistry.Register()");
return -1;
}
}
}