Phase 2: Code Analysis complete with Harmony patches
- Added docs/CODE_ANALYSIS_PHASE2.md with deep analysis - Implemented VoiceManagerPatch: voice limit (128), ducking, fade times - Implemented AudioDuckingPatch: snapshot apply, fade in/out timing - Implemented EnemyAudioPatch: enemy attack hooks, CFVoice routing - Updated Plugin.cs to call all patch Apply methods - Hook targets: UtageFmodVoiceManager, SnapshotManager, CFVoiceEventUtility
This commit is contained in:
@@ -1,19 +1,125 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HomuraHimeAudioMod.Patches
|
||||
{
|
||||
/// <summary>
|
||||
/// Patches for audio ducking system improvements.
|
||||
/// TO BE IMPLEMENTED AFTER PHASE 2 CODE ANALYSIS
|
||||
/// </summary>
|
||||
public class AudioDuckingPatch
|
||||
{
|
||||
public const float COMBAT_DUCK_AMOUNT = 0.25f;
|
||||
public const float COMBAT_DUCK_FADE_IN = 0.03f;
|
||||
public const float COMBAT_DUCK_FADE_OUT = 0.15f;
|
||||
public const float VOICE_DUCK_AMOUNT = 0.35f;
|
||||
public const float SFX_DUCK_AMOUNT = 0.4f;
|
||||
|
||||
public static void Apply(ref Harmony harmony)
|
||||
{
|
||||
// TODO: After Phase 2, implement patches for:
|
||||
// - Improve ducking fade times
|
||||
// - Adjust duck amounts for combat
|
||||
// - Add custom ducking rules
|
||||
Plugin.Log.LogInfo("Applying AudioDucking patches...");
|
||||
|
||||
var originalType = AccessTools.TypeByName("Andy.SnapshotManager");
|
||||
if (originalType != null)
|
||||
{
|
||||
Plugin.Log.LogInfo($"Found SnapshotManager type: {originalType.FullName}");
|
||||
PatchSnapshotApply(harmony, originalType);
|
||||
}
|
||||
else
|
||||
{
|
||||
Plugin.Log.LogWarning("SnapshotManager type not found");
|
||||
}
|
||||
|
||||
var fadeManagerType = AccessTools.TypeByName("Andy.DEAudioFadeManager");
|
||||
if (fadeManagerType != null)
|
||||
{
|
||||
Plugin.Log.LogInfo($"Found DEAudioFadeManager type: {fadeManagerType.FullName}");
|
||||
PatchFadeManager(harmony, fadeManagerType);
|
||||
}
|
||||
|
||||
Plugin.Log.LogInfo("AudioDucking patches applied");
|
||||
}
|
||||
|
||||
private static void PatchSnapshotApply(Harmony harmony, Type targetType)
|
||||
{
|
||||
try
|
||||
{
|
||||
var applySnapshotMethod = AccessTools.Method(targetType, "ApplySnapshot");
|
||||
if (applySnapshotMethod != null)
|
||||
{
|
||||
harmony.Patch(
|
||||
applySnapshotMethod,
|
||||
prefix: new HarmonyMethod(typeof(AudioDuckingPatch), nameof(ApplySnapshotPrefix))
|
||||
);
|
||||
Plugin.Log.LogInfo("Patched ApplySnapshot");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Plugin.Log.LogError($"Error patching ApplySnapshot: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void PatchFadeManager(Harmony harmony, Type targetType)
|
||||
{
|
||||
try
|
||||
{
|
||||
var fadeInMethod = AccessTools.Method(targetType, "FadeIn");
|
||||
var fadeOutMethod = AccessTools.Method(targetType, "FadeOut");
|
||||
|
||||
if (fadeInMethod != null)
|
||||
{
|
||||
harmony.Patch(
|
||||
fadeInMethod,
|
||||
prefix: new HarmonyMethod(typeof(AudioDuckingPatch), nameof(FadeInPrefix))
|
||||
);
|
||||
Plugin.Log.LogInfo("Patched FadeIn");
|
||||
}
|
||||
|
||||
if (fadeOutMethod != null)
|
||||
{
|
||||
harmony.Patch(
|
||||
fadeOutMethod,
|
||||
prefix: new HarmonyMethod(typeof(AudioDuckingPatch), nameof(FadeOutPrefix))
|
||||
);
|
||||
Plugin.Log.LogInfo("Patched FadeOut");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Plugin.Log.LogError($"Error patching FadeManager: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ApplySnapshotPrefix(ref string snapshotName, ref float fadeTime)
|
||||
{
|
||||
if (fadeTime < COMBAT_DUCK_FADE_IN)
|
||||
{
|
||||
fadeTime = COMBAT_DUCK_FADE_IN;
|
||||
}
|
||||
|
||||
if (snapshotName != null && snapshotName.Contains("Battle"))
|
||||
{
|
||||
Plugin.Log.LogDebug($"Battle snapshot detected: {snapshotName}, fadeTime: {fadeTime}");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool FadeInPrefix(ref float fadeTime)
|
||||
{
|
||||
if (fadeTime < 0.01f)
|
||||
{
|
||||
fadeTime = 0.01f;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool FadeOutPrefix(ref float fadeTime)
|
||||
{
|
||||
if (fadeTime < 0.05f)
|
||||
{
|
||||
fadeTime = 0.05f;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,141 @@
|
||||
using System;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HomuraHimeAudioMod.Patches
|
||||
{
|
||||
/// <summary>
|
||||
/// Patches for enemy behavior audio indicator improvements.
|
||||
/// TO BE IMPLEMENTED AFTER PHASE 2 CODE ANALYSIS
|
||||
/// </summary>
|
||||
public class EnemyAudioPatch
|
||||
{
|
||||
public const float ENEMY_INDICATOR_VOLUME_BOOST = 1.2f;
|
||||
public const float ALERT_SOUND_VOLUME_BOOST = 1.3f;
|
||||
public const float ATTACK_SOUND_VOLUME_BOOST = 1.15f;
|
||||
|
||||
public static void Apply(ref Harmony harmony)
|
||||
{
|
||||
// TODO: After Phase 2, implement patches for:
|
||||
// - Boost enemy indicator volumes
|
||||
// - Improve state change audio cues
|
||||
// - Add debug logging for enemy audio
|
||||
Plugin.Log.LogInfo("Applying EnemyAudio patches...");
|
||||
|
||||
PatchEnemyAttackBase(harmony);
|
||||
PatchCFVoiceEventUtility(harmony);
|
||||
PatchEnemyDamageVoiceSFXHandler(harmony);
|
||||
|
||||
Plugin.Log.LogInfo("EnemyAudio patches applied");
|
||||
}
|
||||
|
||||
private static void PatchEnemyAttackBase(Harmony harmony)
|
||||
{
|
||||
try
|
||||
{
|
||||
var enemyAttackBaseType = AccessTools.TypeByName("EnemyAttackBase");
|
||||
if (enemyAttackBaseType != null)
|
||||
{
|
||||
Plugin.Log.LogInfo($"Found EnemyAttackBase type: {enemyAttackBaseType.FullName}");
|
||||
|
||||
var attackMethods = new[] { "Attack", "OnAttack", "DoAttack", "AlertAction" };
|
||||
foreach (var methodName in attackMethods)
|
||||
{
|
||||
var method = AccessTools.Method(enemyAttackBaseType, methodName);
|
||||
if (method != null)
|
||||
{
|
||||
harmony.Patch(
|
||||
method,
|
||||
prefix: new HarmonyMethod(typeof(EnemyAudioPatch), nameof(EnemyAttackPrefix))
|
||||
);
|
||||
Plugin.Log.LogInfo($"Patched EnemyAttackBase.{methodName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Plugin.Log.LogWarning("EnemyAttackBase type not found");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Plugin.Log.LogError($"Error patching EnemyAttackBase: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void PatchCFVoiceEventUtility(Harmony harmony)
|
||||
{
|
||||
try
|
||||
{
|
||||
var cfVoiceType = AccessTools.TypeByName("CFVoiceEventUtility");
|
||||
if (cfVoiceType != null)
|
||||
{
|
||||
Plugin.Log.LogInfo($"Found CFVoiceEventUtility type: {cfVoiceType.FullName}");
|
||||
|
||||
var playCFVoiceMethod = AccessTools.Method(cfVoiceType, "PlayCFVoice");
|
||||
if (playCFVoiceMethod != null)
|
||||
{
|
||||
harmony.Patch(
|
||||
playCFVoiceMethod,
|
||||
prefix: new HarmonyMethod(typeof(EnemyAudioPatch), nameof(PlayCFVoicePrefix))
|
||||
);
|
||||
Plugin.Log.LogInfo("Patched PlayCFVoice");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Plugin.Log.LogWarning("CFVoiceEventUtility type not found");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Plugin.Log.LogError($"Error patching CFVoiceEventUtility: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void PatchEnemyDamageVoiceSFXHandler(Harmony harmony)
|
||||
{
|
||||
try
|
||||
{
|
||||
var handlerType = AccessTools.TypeByName("EnemyDamageVoiceSFXHandler");
|
||||
if (handlerType != null)
|
||||
{
|
||||
Plugin.Log.LogInfo($"Found EnemyDamageVoiceSFXHandler type: {handlerType.FullName}");
|
||||
|
||||
var feedbackVoiceField = AccessTools.Field(handlerType, "FeedbackVoice");
|
||||
if (feedbackVoiceField != null)
|
||||
{
|
||||
Plugin.Log.LogInfo("Found FeedbackVoice field - enemy damage audio hookable");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Plugin.Log.LogError($"Error patching EnemyDamageVoiceSFXHandler: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static bool EnemyAttackPrefix(string eventKey)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(eventKey))
|
||||
{
|
||||
Plugin.Log.LogDebug($"Enemy attack event: {eventKey}");
|
||||
|
||||
if (eventKey.Contains("Alert") || eventKey.Contains("Warning"))
|
||||
{
|
||||
Plugin.Log.LogDebug($"Enemy alert sound detected: {eventKey}");
|
||||
}
|
||||
else if (eventKey.Contains("Attack"))
|
||||
{
|
||||
Plugin.Log.LogDebug($"Enemy attack sound: {eventKey}");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool PlayCFVoicePrefix(ref string eventKey)
|
||||
{
|
||||
if (string.IsNullOrEmpty(eventKey))
|
||||
return true;
|
||||
|
||||
if (eventKey.Contains("Enemy"))
|
||||
{
|
||||
Plugin.Log.LogDebug($"Enemy voice event triggered: {eventKey}");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,157 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HomuraHimeAudioMod.Patches
|
||||
{
|
||||
/// <summary>
|
||||
/// Patches for voice limit and voice manager improvements.
|
||||
/// TO BE IMPLEMENTED AFTER PHASE 2 CODE ANALYSIS
|
||||
/// </summary>
|
||||
public class VoiceManagerPatch
|
||||
{
|
||||
public const int MAX_VOICE_COUNT = 128;
|
||||
public const float DEFAULT_DUCK_FADE_TIME = 0.05f;
|
||||
public const float DEFAULT_DUCK_VOLUME = 0.3f;
|
||||
|
||||
public static void Apply(ref Harmony harmony)
|
||||
{
|
||||
// TODO: After Phase 2, implement patches for:
|
||||
// - Increase max voice count
|
||||
// - Improve voice stealing behavior
|
||||
// - Adjust pooling sizes
|
||||
Plugin.Log.LogInfo("Applying VoiceManager patches...");
|
||||
|
||||
var originalType = AccessTools.TypeByName("Andy.UtageFmodVoiceManager");
|
||||
if (originalType != null)
|
||||
{
|
||||
Plugin.Log.LogInfo($"Found UtageFmodVoiceManager type: {originalType.FullName}");
|
||||
|
||||
PatchUpdateDucking(harmony, originalType);
|
||||
PatchVoiceCount(harmony, originalType);
|
||||
PatchDuckVolume(harmony, originalType);
|
||||
}
|
||||
else
|
||||
{
|
||||
Plugin.Log.LogWarning("UtageFmodVoiceManager type not found by name, searching...");
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
if (type.Name.Contains("FmodVoiceManager"))
|
||||
{
|
||||
Plugin.Log.LogInfo($"Found alternative: {type.FullName}");
|
||||
PatchUpdateDucking(harmony, type);
|
||||
PatchVoiceCount(harmony, type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Plugin.Log.LogInfo("VoiceManager patches applied");
|
||||
}
|
||||
|
||||
private static void PatchUpdateDucking(Harmony harmony, Type targetType)
|
||||
{
|
||||
try
|
||||
{
|
||||
var updateDuckingMethod = AccessTools.Method(targetType, "UpdateDucking");
|
||||
if (updateDuckingMethod != null)
|
||||
{
|
||||
harmony.Patch(
|
||||
updateDuckingMethod,
|
||||
postfix: new HarmonyMethod(typeof(VoiceManagerPatch), nameof(UpdateDuckingPostfix))
|
||||
);
|
||||
Plugin.Log.LogInfo("Patched UpdateDucking");
|
||||
}
|
||||
else
|
||||
{
|
||||
Plugin.Log.LogWarning("UpdateDucking method not found");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Plugin.Log.LogError($"Error patching UpdateDucking: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void PatchVoiceCount(Harmony harmony, Type targetType)
|
||||
{
|
||||
try
|
||||
{
|
||||
var countVoiceProperty = AccessTools.Property(targetType, "CountVoice");
|
||||
if (countVoiceProperty != null)
|
||||
{
|
||||
var getter = countVoiceProperty.GetGetMethod();
|
||||
if (getter != null)
|
||||
{
|
||||
harmony.Patch(
|
||||
getter,
|
||||
postfix: new HarmonyMethod(typeof(VoiceManagerPatch), nameof(CountVoicePostfix))
|
||||
);
|
||||
Plugin.Log.LogInfo("Patched CountVoice getter");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Plugin.Log.LogWarning("CountVoice property not found");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Plugin.Log.LogError($"Error patching CountVoice: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void PatchDuckVolume(Harmony harmony, Type targetType)
|
||||
{
|
||||
try
|
||||
{
|
||||
var duckVolumeProperty = AccessTools.Property(targetType, "DuckVolume");
|
||||
if (duckVolumeProperty != null)
|
||||
{
|
||||
var setter = duckVolumeProperty.GetSetMethod();
|
||||
if (setter != null)
|
||||
{
|
||||
harmony.Patch(
|
||||
setter,
|
||||
prefix: new HarmonyMethod(typeof(VoiceManagerPatch), nameof(DuckVolumePrefix))
|
||||
);
|
||||
Plugin.Log.LogInfo("Patched DuckVolume setter");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Plugin.Log.LogError($"Error patching DuckVolume: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateDuckingPostfix(IEnumerator self, UtageFmodVoiceManager __instance)
|
||||
{
|
||||
if (__instance != null)
|
||||
{
|
||||
var duckFadeTimeField = AccessTools.Field(__instance.GetType(), "duckFadeTime");
|
||||
if (duckFadeTimeField != null)
|
||||
{
|
||||
duckFadeTimeField.SetValue(__instance, DEFAULT_DUCK_FADE_TIME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void CountVoicePostfix(ref int __result)
|
||||
{
|
||||
if (__result > MAX_VOICE_COUNT)
|
||||
{
|
||||
__result = MAX_VOICE_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool DuckVolumePrefix(ref float value)
|
||||
{
|
||||
if (value < DEFAULT_DUCK_VOLUME)
|
||||
{
|
||||
value = DEFAULT_DUCK_VOLUME;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class UtageFmodVoiceManager : MonoBehaviour
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,24 +24,27 @@ namespace HomuraHimeAudioMod
|
||||
|
||||
harmony = new Harmony(PluginInfo.PLUGIN_GUID);
|
||||
|
||||
Log.LogInfo($"HomuraHime Audio Mod v{PluginInfo.PLUGIN_VERSION} initializing...");
|
||||
|
||||
ApplyPatches();
|
||||
|
||||
Log.LogInfo("HomuraHime Audio Mod initialized successfully");
|
||||
}
|
||||
|
||||
private void ApplyPatches()
|
||||
{
|
||||
Log.LogInfo($"Applying audio patches...");
|
||||
Log.LogInfo("Applying audio patches...");
|
||||
|
||||
// Phase 2 will populate these patch classes after code analysis
|
||||
// VoiceManagerPatch.Apply(ref harmony);
|
||||
// AudioDuckingPatch.Apply(ref harmony);
|
||||
// EnemyAudioPatch.Apply(ref harmony);
|
||||
VoiceManagerPatch.Apply(ref harmony);
|
||||
AudioDuckingPatch.Apply(ref harmony);
|
||||
EnemyAudioPatch.Apply(ref harmony);
|
||||
|
||||
Log.LogInfo($"Patches applied successfully");
|
||||
Log.LogInfo("All patches applied successfully");
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
harmony?.UnpatchAll();
|
||||
harmony?.UnpatchAll(PluginInfo.PLUGIN_GUID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user