Merge branch 'main' into feature/MusicCallback

This commit is contained in:
2026-04-16 11:06:23 +08:00
257 changed files with 6616 additions and 479 deletions
@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using UnityEngine;
using UnityEngine.Audio;
using DG.Tweening;
@@ -10,7 +10,9 @@ namespace OCES.Audio
public class AudioSystem : MonoBehaviour
{
public static AudioSystem Instance { get; private set; }
// ReSharper disable once MemberCanBePrivate.Global
public IReadOnlyDictionary<Type, Enum> ActiveStates { get; private set; }
const string k_audioConfigPath = "AudioData";
const string k_audioResourcePath = "Audios";
@@ -21,7 +23,7 @@ namespace OCES.Audio
AudioGroupConfig m_groups;
AudioMixer m_mixer;
Tween m_lowpassTween;
// ─────────────────────────────────────────────
// 公开接口
// ─────────────────────────────────────────────
@@ -42,6 +44,16 @@ namespace OCES.Audio
public void Play(AudioObject audioObject, Action onPlay = null)
{
if (audioObject.ContainerType == ContainerType.Switch)
{
audioObject = ResolveSwitchContainer(audioObject);
if (audioObject == null)
{
Debug.Log("[AudioSystem] 无法解析Switch Container,检查配置表!");
return;
}
}
this.m_sfxSystem.TryPlay(audioObject, onPlay);
}
@@ -49,8 +61,7 @@ namespace OCES.Audio
{
Play((uint)audioId);
}
[Obsolete("Use Play(uint) instead")]
public void Play(string audioName)
{
@@ -114,6 +125,7 @@ namespace OCES.Audio
public void SetState<TEnum>(TEnum state) where TEnum : Enum
{
this.m_musicSystem.OnStateChanged(state);
ActiveStates = this.m_musicSystem.ActiveStates;
}
// ─────────────────────────────────────────────
@@ -139,6 +151,7 @@ namespace OCES.Audio
AudioSourcePool sfxPool = new(sfxPoolRoot.transform); // 不传 mixer group,让 SfxSystem 自己设置
this.m_sfxSystem = gameObject.AddComponent<SfxSystem>();
this.m_audioObjects = AudioConfigLoader.Load<AudioObjectConfig>($"{k_audioConfigPath}/AudioObject");
this.m_audioObjects.PreParseSwitchMappings();
this.m_groups = AudioConfigLoader.Load<AudioGroupConfig>($"{k_audioConfigPath}/AudioGroup");
this.m_sfxSystem.Initialize(this.m_groups, this.m_mixer, sfxPool); // 传入 pool
@@ -182,19 +195,67 @@ namespace OCES.Audio
// ── 注册 StateGroup ──
EnumIds.RegisterAllGameState();
ActiveStates = new Dictionary<Type, Enum>();
// ── 启动默认音乐与环境音 ──
// 触发一次初始状态,让音乐系统从默认状态开始匹配
SetState(GameState.Home);
//SetState(GameState.Home);
}
AudioObject ResolveSwitchContainer(AudioObject switchContainer)
{
// 遍历 ActiveStates 找到 TypeId 匹配的枚举类型
Enum currentStateValue = null;
bool foundGroup = false;
foreach (KeyValuePair<Type, Enum> keyValuePair in ActiveStates)
{
if (StateGroupRegistry.GetTypeId(keyValuePair.Key) != switchContainer.SwitchGroupId) continue;
currentStateValue = keyValuePair.Value;
foundGroup = true;
break;
}
if (!foundGroup)
{
Debug.LogWarning($"[AudioSystem] Switch Container {switchContainer.Id} 找不到 TypeId={switchContainer.SwitchGroupId} 对应的状态组。");
return this.m_audioObjects.GetDefaultSwitchOrFallback(switchContainer);
}
// 解析AudioObject对象
AudioObject childContainer = this.m_audioObjects.GetMappingResult(switchContainer.Id, currentStateValue);
return childContainer ?? this.m_audioObjects.GetDefaultSwitchOrFallback(switchContainer);
}
}
static class AudioConfigLoader
public static class AudioConfigLoader
{
public static Dictionary<uint, T> Load<T>(string path, Func<T, uint> keySelector)
public static T Load<T>(string configPath, string fileName)
where T : IBinarySerializable, new()
{
string json = System.IO.File.ReadAllText(path);
var wrapper = JsonUtility.FromJson<AudioObjectArrayWrapper<T>>(json);
return wrapper.AudioObjects.ToDictionary(keySelector);
string path = Path.Combine(
Application.dataPath, "Resources", configPath, fileName);
if (!File.Exists(path))
{
Debug.LogError($"[AudioImportTool] 找不到配置文件: {path}");
return default;
}
try
{
T config = new T();
using MemoryStream ms = new(File.ReadAllBytes(path));
using BinaryReader reader = new(ms);
config.DeSerialize(reader);
return config;
}
catch (Exception e)
{
Debug.LogError($"[AudioImportTool] 配置表反序列化失败 {fileName}: {e.Message}");
return default;
}
}
public static T Load<T>(string tableName) where T : IBinarySerializable, new()