This commit is contained in:
2026-02-08 16:20:50 +08:00
parent 0ae47e5d6a
commit 8b88904ef7
72 changed files with 5963 additions and 2038 deletions

View File

@@ -0,0 +1,306 @@
#pragma once
#include <string>
#include <unordered_map>
#include <vector>
#include <fstream>
#include <stdexcept>
#include "rapidxml/rapidxml.hpp"
class AudioConfigReader
{
public:
// --------------------------
// 1. 结构体定义放在类内public区外部可通过 AudioConfigReader::SoundEffect 访问
// --------------------------
struct SoundEffect
{
std::string file_path; // 文件路径FILE属性
int volume_adjust = 100; // 音量调整默认100
int priority = 0; // 优先级默认0
};
struct RandomItem
{
std::string tag; // 关联的音效IDTAG属性
int prob = 0; // 概率PROB属性
};
struct RandomSoundGroup
{
std::vector<RandomItem> items; // 组内所有项
int delay = 0; // 延迟DELAY属性
int loop_delay = 0; // 循环延迟
int loop_delay_range = 0; // 循环延迟范围
};
struct Music
{
std::string file_path; // 文件路径FILE属性
int loop_delay = 0; // 循环延迟LOOP_DELAY属性
};
public:
// 构造函数:初始化解析器
AudioConfigReader() = default;
// 析构函数:清理资源
~AudioConfigReader() = default;
// 核心函数解析XML文件返回是否成功
bool LoadFromFile(const std::string &xml_path)
{
// 1. 读取XML文件内容
std::ifstream file(xml_path, std::ios::binary);
if (!file.is_open())
{
throw std::runtime_error("无法打开XML文件: " + xml_path);
}
std::string xml_content((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
file.close();
// 2. 解析XML
rapidxml::xml_document<> doc;
try
{
doc.parse<rapidxml::parse_default>(&xml_content[0]);
}
catch (const rapidxml::parse_error &e)
{
throw std::runtime_error("XML解析错误: " + std::string(e.what()) +
"(位置: " + std::string(e.where<char>()) + "");
}
// 3. 获取根节点
rapidxml::xml_node<> *root = doc.first_node("AudioTagDatabase");
if (!root)
{
throw std::runtime_error("XML根节点错误: 找不到AudioTagDatabase");
}
// 4. 解析所有节点
ParseEffects(root); // 解析<EFFECT>
ParseRandomGroups(root); // 解析<RANDOM>
ParseMusics(root); // 解析<MUSIC>
return true;
}
// ------------------------------
// 接口1获取音效配置<EFFECT>
// ------------------------------
bool HasEffect(const std::string &effect_id) const
{
return m_effects.find(effect_id) != m_effects.end();
}
const SoundEffect &GetEffect(const std::string &effect_id) const
{
auto it = m_effects.find(effect_id);
if (it == m_effects.end())
{
throw std::out_of_range("音效ID不存在: " + effect_id);
}
return it->second;
}
// 获取所有音效ID列表
std::vector<std::string> GetAllEffectIds() const
{
return GetAllKeys(m_effects);
}
// ------------------------------
// 接口2获取随机音效组配置<RANDOM>
// ------------------------------
bool HasRandomGroup(const std::string &group_id) const
{
return m_random_groups.find(group_id) != m_random_groups.end();
}
const RandomSoundGroup &GetRandomGroup(const std::string &group_id) const
{
auto it = m_random_groups.find(group_id);
if (it == m_random_groups.end())
{
throw std::out_of_range("随机组ID不存在: " + group_id);
}
return it->second;
}
// 获取所有随机组ID列表
std::vector<std::string> GetAllRandomGroupIds() const
{
return GetAllKeys(m_random_groups);
}
// ------------------------------
// 接口3获取背景音乐配置<MUSIC>
// ------------------------------
bool HasMusic(const std::string &music_id) const
{
return m_musics.find(music_id) != m_musics.end();
}
const Music &GetMusic(const std::string &music_id) const
{
auto it = m_musics.find(music_id);
if (it == m_musics.end())
{
throw std::out_of_range("背景音乐ID不存在: " + music_id);
}
return it->second;
}
// 获取所有背景音乐ID列表
std::vector<std::string> GetAllMusicIds() const
{
return GetAllKeys(m_musics);
}
private:
// 辅助函数:解析<EFFECT>节点
void ParseEffects(rapidxml::xml_node<> *root)
{
for (rapidxml::xml_node<> *node = root->first_node("EFFECT");
node; node = node->next_sibling("EFFECT"))
{
// 必选属性ID和FILE
rapidxml::xml_attribute<> *id_attr = node->first_attribute("ID");
rapidxml::xml_attribute<> *file_attr = node->first_attribute("FILE");
if (!id_attr || !file_attr)
{
continue; // 跳过无效节点
}
SoundEffect effect;
effect.file_path = NormalizePath(file_attr->value()); // 统一路径分隔符
// 可选属性VOLUME_ADJUST
if (auto attr = node->first_attribute("VOLUME_ADJUST"))
{
effect.volume_adjust = std::stoi(attr->value());
}
// 可选属性PRIORITY
if (auto attr = node->first_attribute("PRIORITY"))
{
effect.priority = std::stoi(attr->value());
}
m_effects[id_attr->value()] = effect;
}
}
// 辅助函数:解析<RANDOM>节点
void ParseRandomGroups(rapidxml::xml_node<> *root)
{
for (rapidxml::xml_node<> *node = root->first_node("RANDOM");
node; node = node->next_sibling("RANDOM"))
{
// 必选属性ID
rapidxml::xml_attribute<> *id_attr = node->first_attribute("ID");
if (!id_attr)
{
continue; // 跳过无效节点
}
RandomSoundGroup group;
// 可选属性:延迟相关
if (auto attr = node->first_attribute("DELAY"))
{
group.delay = std::stoi(attr->value());
}
if (auto attr = node->first_attribute("LOOP_DELAY"))
{
group.loop_delay = std::stoi(attr->value());
}
if (auto attr = node->first_attribute("LOOP_DELAY_RANGE"))
{
group.loop_delay_range = std::stoi(attr->value());
}
// 解析子节点<ITEM>
for (rapidxml::xml_node<> *item_node = node->first_node("ITEM");
item_node; item_node = item_node->next_sibling("ITEM"))
{
rapidxml::xml_attribute<> *tag_attr = item_node->first_attribute("TAG");
rapidxml::xml_attribute<> *prob_attr = item_node->first_attribute("PROB");
if (!tag_attr || !prob_attr)
{
continue; // 跳过无效项
}
group.items.push_back({tag_attr->value(),
std::stoi(prob_attr->value())});
}
m_random_groups[id_attr->value()] = group;
}
}
// 辅助函数:解析<MUSIC>节点
void ParseMusics(rapidxml::xml_node<> *root)
{
for (rapidxml::xml_node<> *node = root->first_node("MUSIC");
node; node = node->next_sibling("MUSIC"))
{
// 必选属性ID和FILE
rapidxml::xml_attribute<> *id_attr = node->first_attribute("ID");
rapidxml::xml_attribute<> *file_attr = node->first_attribute("FILE");
if (!id_attr || !file_attr)
{
continue; // 跳过无效节点
}
Music music;
music.file_path = NormalizePath(file_attr->value()); // 统一路径分隔符
// 可选属性LOOP_DELAY
if (auto attr = node->first_attribute("LOOP_DELAY"))
{
music.loop_delay = std::stoi(attr->value());
}
m_musics[id_attr->value()] = music;
}
}
// 辅助函数:统一路径分隔符(将\转为/,兼容跨平台)
std::string NormalizePath(const std::string &path)
{
std::string normalized = path;
for (char &c : normalized)
{
if (c == '\\')
{
c = '/';
}
}
return normalized;
}
// 辅助函数获取哈希表中所有key
template <typename Map>
std::vector<std::string> GetAllKeys(const Map &map) const
{
std::vector<std::string> keys;
keys.reserve(map.size());
for (const auto &pair : map)
{
keys.push_back(pair.first);
}
return keys;
}
private:
// 存储解析后的数据
std::unordered_map<std::string, SoundEffect> m_effects; // 音效映射ID -> 音效)
std::unordered_map<std::string, RandomSoundGroup> m_random_groups; // 随机组映射ID -> 随机组)
std::unordered_map<std::string, Music> m_musics; // 背景音乐映射ID -> 音乐)
};