Files
DuckovMods/HitFeedback/Config.cs
2025-11-05 21:34:21 +08:00

285 lines
12 KiB
C#
Raw Permalink 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;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using UnityEngine; // 假设在Unity环境中使用Debug.LogError
namespace HitFeedback
{
public class Config
{
public KeyCode hotKey = KeyCode.F8;
public Dictionary<string, float> probability = new Dictionary<string, float>();
/// <summary>
/// 当伤害具有这些特性之一时,将播放音频反馈。
/// </summary>
public HashSet<DamageFeature> audioDamageFeatures = new HashSet<DamageFeature>();
public void LoadConfig(string filename)
{
if (!File.Exists(filename))
{
Debug.LogError($"Config file not found: {filename}");
return;
}
probability.Clear();
audioDamageFeatures.Clear(); // 清空旧的音频伤害特性数据
try
{
using (var sr = new StreamReader(filename))
{
string line;
var lineNumber = 0;
string currentSection = ""; // 用于解析节
while ((line = sr.ReadLine()) != null)
{
lineNumber++;
line = line.Trim();
// 忽略空行和注释行
if (string.IsNullOrEmpty(line) || line.StartsWith(";") || line.StartsWith("#"))
{
continue;
}
// 处理节标题,例如 [General] 或 [AudioFeatures]
if (line.StartsWith("[") && line.EndsWith("]"))
{
currentSection = line.Substring(1, line.Length - 2).Trim();
continue; // 跳过节标题行
}
// 查找等号
var separatorIndex = line.IndexOf('=');
if (separatorIndex == -1)
{
Debug.LogWarning(
$"Skipping malformed line in config file '{filename}' at line {lineNumber}: No '=' found. Line: '{line}'");
continue;
}
var key = line.Substring(0, separatorIndex).Trim();
var valueStr = line.Substring(separatorIndex + 1).Trim();
if (currentSection.Equals("General", StringComparison.OrdinalIgnoreCase))
{
// 解析 hotKey
if (key.Equals("hotKey", StringComparison.OrdinalIgnoreCase))
{
try
{
hotKey = (KeyCode)Enum.Parse(typeof(KeyCode), valueStr, true);
}
catch (ArgumentException)
{
Debug.LogError(
$"Invalid KeyCode '{valueStr}' in config file '{filename}' at line {lineNumber}. Using default F8.");
hotKey = KeyCode.F8;
}
}
}
else if (currentSection.Equals("Probabilities", StringComparison.OrdinalIgnoreCase))
{
// 解析 probability 字典项
if (float.TryParse(valueStr, NumberStyles.Float, CultureInfo.InvariantCulture,
out var probValue))
{
probability[key] = probValue;
}
else
{
Debug.LogWarning(
$"Invalid float value '{valueStr}' for key '{key}' in config file '{filename}' at line {lineNumber}. Skipping entry.");
}
}
else if (currentSection.Equals("AudioFeatures", StringComparison.OrdinalIgnoreCase))
{
// 解析 audioDamageFeatures 集合项
// 键是 'feature' (或者可以随意定义,只要值是我们关心的)
// 值是 ExtendedDamageFeature 的枚举名称
if (key.Equals("feature", StringComparison.OrdinalIgnoreCase)) // 假设所有特征都用同一个键"feature"
{
foreach (var featureName in valueStr.Split(new char[] { ',', '|' },
StringSplitOptions.RemoveEmptyEntries))
{
try
{
// 确保 ExtendedDamageFeature 是 [Flags] 枚举
var feature = (DamageFeature)Enum.Parse(typeof(DamageFeature),
featureName.Trim(), true);
audioDamageFeatures.Add(feature);
}
catch (ArgumentException)
{
Debug.LogWarning(
$"Invalid ExtendedDamageFeature '{featureName.Trim()}' in config file '{filename}' at line {lineNumber}. Skipping entry.");
}
}
}
else
{
try
{
var feature =
(DamageFeature)Enum.Parse(typeof(DamageFeature), key, true);
if (bool.TryParse(valueStr, out bool includeFeature) && includeFeature)
{
audioDamageFeatures.Add(feature);
}
// 如果是 false则不添加到集合或者可以从集合中移除如果默认是都包含
}
catch (ArgumentException)
{
Debug.LogWarning(
$"Invalid ExtendedDamageFeature key '{key}' in config file '{filename}' at line {lineNumber}. Skipping entry.");
}
}
}
// 如果存在其他节,可以在这里添加 else if 处理
}
}
}
catch (Exception ex)
{
Debug.LogError($"Error reading config file '{filename}': {ex.Message}");
}
}
/// <summary>
/// 将当前配置存储到指定INI文件。
/// </summary>
/// <param name="filename">要保存的INI文件的路径。</param>
public void SaveConfig(string filename)
{
try
{
var directory = Path.GetDirectoryName(filename);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
using (var sw = new StreamWriter(filename))
{
sw.WriteLine("; HitFeedback Configuration File");
sw.WriteLine("; Generated by HitFeedback.Config class");
sw.WriteLine();
sw.WriteLine("[General]");
sw.WriteLine($"hotKey = {hotKey.ToString()}");
sw.WriteLine();
if (probability.Count > 0)
{
sw.WriteLine("[Probabilities]");
foreach (var kvp in probability)
{
sw.WriteLine($"{kvp.Key} = {kvp.Value.ToString(CultureInfo.InvariantCulture)}");
}
}
else
{
sw.WriteLine("; No probabilities currently configured.");
}
sw.WriteLine();
if (audioDamageFeatures.Count > 0)
{
sw.WriteLine("[AudioFeatures]");
// 假设每个特性一行,值为 true
foreach (var feature in audioDamageFeatures)
{
sw.WriteLine($"{feature.ToString()} = True");
}
// 或者如果你想用一个键存储所有特性(用逗号或竖线分隔)
// sw.WriteLine($"features = {string.Join(",", audioDamageFeatures.Select(f => f.ToString()))}");
}
else
{
sw.WriteLine("; No audio damage features currently configured.");
}
sw.WriteLine();
}
Debug.Log($"Config saved to: {filename}");
}
catch (Exception ex)
{
Debug.LogError($"Error saving config file '{filename}': {ex.Message}");
}
}
/// <summary>
/// 根据DamageInfo的特性判断是否应该播放音频反馈。
/// 如果DamageInfo的任何一个特性在audioDamageFeatures集合中则返回true。
/// </summary>
/// <param name="damageInfo">要检查的DamageInfo对象。</param>
/// <returns>如果应该播放音频反馈则为true否则为false。</returns>
public bool ShouldPlayAudioFeedback(DamageInfo damageInfo)
{
if (audioDamageFeatures.Count == 0)
{
return false;
}
// 将DamageInfo的各种布尔属性/条件转换为DamageFeature组合
DamageFeature currentDamageFeatures = DamageFeature.Undefined;
if (damageInfo.damageType == DamageTypes.normal)
{
currentDamageFeatures |= DamageFeature.NormalDamage;
}
else if (damageInfo.damageType == DamageTypes.realDamage)
{
currentDamageFeatures |= DamageFeature.RealDamage;
}
if (damageInfo.isFromBuffOrEffect)
{
currentDamageFeatures |= DamageFeature.BuffOrEffectDamage;
}
if (damageInfo.ignoreArmor)
{
currentDamageFeatures |= DamageFeature.ArmorIgnoringDamage;
}
if (damageInfo.crit > 0) // crit > 0 表示是暴击
{
currentDamageFeatures |= DamageFeature.CriticalDamage;
}
if (damageInfo.armorPiercing > 0)
{
currentDamageFeatures |= DamageFeature.ArmorPiercingDamage;
}
if (damageInfo.isExplosion)
{
currentDamageFeatures |= DamageFeature.ExplosionDamage;
}
if (damageInfo.armorBreak > 0)
{
currentDamageFeatures |= DamageFeature.ArmorBreakingDamage;
}
if (damageInfo.elementFactors != null && damageInfo.elementFactors.Count > 0)
{
currentDamageFeatures |= DamageFeature.ElementalDamage;
}
if (damageInfo.buffChance > 0 || damageInfo.buff != null)
{
currentDamageFeatures |= DamageFeature.OnHitBuffApply;
}
if (damageInfo.bleedChance > 0)
{
currentDamageFeatures |= DamageFeature.OnHitBleed;
}
foreach (var configuredFeature in audioDamageFeatures)
{
if (configuredFeature == DamageFeature.Undefined)
{
continue;
}
if ((currentDamageFeatures & configuredFeature) == configuredFeature)
{
return true;
}
}
return false;
}
}
}