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:
312
docs/CODE_ANALYSIS_PHASE2.md
Normal file
312
docs/CODE_ANALYSIS_PHASE2.md
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
# HomuraHime Audio System Deep Analysis
|
||||||
|
|
||||||
|
## 1. VOICE LIMITS & CHANNEL MANAGEMENT
|
||||||
|
|
||||||
|
### UtageFmodVoiceManager
|
||||||
|
**File:** `C:\Assets\4.Developer\Andy\UtageVoiceManager\UtageFmodVoiceManager.cs`
|
||||||
|
|
||||||
|
| Method/Property | Description | Hook Point |
|
||||||
|
|-----------------|-------------|------------|
|
||||||
|
| `PlayVoice()` / `CoPlayVoice` | Coroutine for playing voice with lip sync | `Prefix` to modify voice data, `Postfix` to track playback |
|
||||||
|
| `StopVoiceEvent()` | Stops currently playing voice | `Prefix` to prevent stop, `Postfix` to cleanup |
|
||||||
|
| `get_CountVoice` | Gets current voice count | `Postfix` to limit voice count |
|
||||||
|
| `get_CurrentVoiceCharacterLabel` | Current voice character label | `Postfix` to override character |
|
||||||
|
| `get_DefaultVoiceFadeTime` | Default fade time for voice | `Postfix` to modify fade duration |
|
||||||
|
| `set_DuckVolume` / `get_DuckVolume` | Duck volume property | `Postfix` to modify ducking |
|
||||||
|
| `UpdateDucking` | Coroutine `<UpdateDucking>d__47` | **KEY HOOK** - controls audio ducking coroutine |
|
||||||
|
| `PlayVoiceEvent()` | Triggers voice events | `Prefix` to intercept event data |
|
||||||
|
| `StopVoiceIgnoreLoop` | Stops voice ignoring loop setting | Direct patch target |
|
||||||
|
|
||||||
|
### FMODSoundManager
|
||||||
|
**File:** `C:\Assets\1.HonoHime\Core\FMODUtility\Scripts\FMODSoundManager.cs`
|
||||||
|
|
||||||
|
| Method/Property | Description | Hook Point |
|
||||||
|
|----------------|-------------|------------|
|
||||||
|
| `get_Volume` / `set_Volume` | Master volume control | `Postfix` to clamp/modify volume |
|
||||||
|
| `SetVolumeImmediately()` | Immediate volume set (no fade) | `Prefix` to intercept |
|
||||||
|
| `FMODSetVolume` | Coroutine for FMOD volume | `<FMODSetVolume>d__28` - can patch transition |
|
||||||
|
| `get_SoundManager` | Access to sound manager | Property getter patch |
|
||||||
|
| `VCASetting` | VCA (Velocity Controlled Amplifier) settings | Field patch for volume overrides |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. AUDIO DUCKING SYSTEM
|
||||||
|
|
||||||
|
### Ducking Properties Found:
|
||||||
|
```
|
||||||
|
duckFadeTime - Fade time for ducking
|
||||||
|
duckVolume - Volume level during ducking
|
||||||
|
duckGroups - Audio groups that participate in ducking
|
||||||
|
duckVelocity - Velocity tracking for ducking
|
||||||
|
UpdateDucking - Main coroutine: `<UpdateDucking>d__47`
|
||||||
|
```
|
||||||
|
|
||||||
|
### SnapshotManager
|
||||||
|
**File:** `C:\Assets\4.Developer\Andy\UtageVoiceManager\SnapshotManager.cs`
|
||||||
|
|
||||||
|
| Method | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| `ApplySnapshot()` | Apply audio snapshot/ducking |
|
||||||
|
| `ApplyStartSnapshot()` | Apply at start |
|
||||||
|
| `GetCurrentSnapshot()` | Get active snapshot |
|
||||||
|
| `GetSnapshotTypeDropdown()` | Dropdown selection |
|
||||||
|
|
||||||
|
### SnapshotHandle
|
||||||
|
**File:** `C:\Assets\4.Developer\Andy\UtageVoiceManager\SnapshotHandle.cs`
|
||||||
|
|
||||||
|
Manages individual snapshot instances for voice ducking.
|
||||||
|
|
||||||
|
### DEAudioFadeManager
|
||||||
|
**File:** `C:\Assets\4.Developer\Andy\UtageVoiceManager\DEAudioFadeManager.cs`
|
||||||
|
|
||||||
|
Handles fade in/out for audio events - likely the fade time controller for ducking.
|
||||||
|
|
||||||
|
### FmodReverbEventController
|
||||||
|
**File:** `C:\Assets\4.Developer\Andy\UtageVoiceManager\FmodReverbEventController.cs`
|
||||||
|
|
||||||
|
Controls reverb effects during events - related to audio environment transitions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. VOICE MANAGER PUBLIC METHODS
|
||||||
|
|
||||||
|
### Core Voice Control Methods:
|
||||||
|
|
||||||
|
| Class | Method | Description |
|
||||||
|
|-------|--------|-------------|
|
||||||
|
| `UtageFmodVoiceManager` | `PlayVoice()` | Plays voice file with optional lip sync |
|
||||||
|
| `UtageFmodVoiceManager` | `StopVoiceEvent()` | Stops voice playback |
|
||||||
|
| `UtageFmodVoiceManager` | `StopVoiceIgnoreLoop()` | Force stop even if loop |
|
||||||
|
| `UtageFmodVoiceManager` | `PlayVoiceEvent()` | Triggers voice event |
|
||||||
|
| `UtageFmodVoiceManager` | `GetVoiceSamplesVolume()` | Gets voice volume setting |
|
||||||
|
| `UtageFmodVoiceManager` | `SetVoiceVolume()` | Sets voice volume |
|
||||||
|
| `VoiceEventSelector` | - | Selects which voice event to trigger |
|
||||||
|
| `FmodVoiceStopper` | `Stop()` | FMOD-specific voice stopping |
|
||||||
|
|
||||||
|
### Voice Settings:
|
||||||
|
| Property | Description |
|
||||||
|
|----------|-------------|
|
||||||
|
| `defaultVoiceFadeTime` | Default fade time (getter/setter) |
|
||||||
|
| `dontSkipLoopVoiceAndSe` | Loop voice/se skipping flag |
|
||||||
|
| `IsPlayingVoice` | Voice playback status |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. FMOD EVENT TRIGGERING
|
||||||
|
|
||||||
|
### FMODSoundManager / FMODUtility
|
||||||
|
**File:** `C:\Assets\1.HonoHime\Core\FMODUtility\Scripts\FMODSoundManager.cs`
|
||||||
|
**File:** `C:\Assets\1.HonoHime\Core\FMODUtility\Scripts\FMODUtility.cs`
|
||||||
|
|
||||||
|
| Method | Description | Hook Type |
|
||||||
|
|--------|-------------|-----------|
|
||||||
|
| `FMODUtilityStartEvent` | Start FMOD event | Prefix to intercept event path |
|
||||||
|
| `FMODUtilityStopEvent` | Stop FMOD event | Prefix to prevent stop |
|
||||||
|
| `FMODUtilitySetParameter` | Set FMOD parameter | Prefix to modify parameter value |
|
||||||
|
| `GetEventReference()` | Get FMOD event reference | Postfix to modify event ref |
|
||||||
|
|
||||||
|
### FMOD Event Classes:
|
||||||
|
|
||||||
|
| Class | File Path |
|
||||||
|
|-------|-----------|
|
||||||
|
| `FmodSFXEventRef` | `C:\Assets\4.Developer\HsiCheng\Script\Fmod\FmodSFXEventRef.cs` |
|
||||||
|
| `FmodSFXEventSO` | `C:\Assets\4.Developer\HsiCheng\Script\Fmod\FmodSFXEventSO.cs` |
|
||||||
|
| `FmodSFXEventDispatcher` | `C:\Assets\4.Developer\HsiCheng\Script\Fmod\FmodSFXEventDispatcher.cs` |
|
||||||
|
| `FmodSFXEventCommunicator` | `C:\Assets\4.Developer\HsiCheng\Script\Fmod\FmodSFXEventCommunicator.cs` |
|
||||||
|
|
||||||
|
### MMFeedbacks Integration (More Mountains):
|
||||||
|
|
||||||
|
| Class | Path |
|
||||||
|
|-------|------|
|
||||||
|
| `MMF_FMOD_GlobalPlayEvent` | `C:\Assets\1.HonoHime\Core\FMODUtility\Scripts\MMFeedbacks\` |
|
||||||
|
| `MMF_FMOD_GlobalSetParameter` | Trigger global FMOD parameter |
|
||||||
|
| `MMF_FMOD_ParameterTrigger` | Trigger with parameter |
|
||||||
|
| `MMF_FMODUtilityPlayEventEmitter` | Play via event emitter |
|
||||||
|
| `MMF_FMODUtilityStopEventEmitter` | Stop via event emitter |
|
||||||
|
| `MMF_FMOD_MainBGM_ReplayCurrent` | Replay current BGM |
|
||||||
|
|
||||||
|
### FMOD Parameter Methods:
|
||||||
|
```
|
||||||
|
SetParameterByName() - Set parameter by string name
|
||||||
|
SetParameterFloat() - Set float parameter
|
||||||
|
SetParameterInt() - Set int parameter
|
||||||
|
SetParameterBoolean() - Set bool parameter
|
||||||
|
CheckSetParameter() - Validate parameter
|
||||||
|
CheckSetParameterSub() - Sub-check logic
|
||||||
|
```
|
||||||
|
|
||||||
|
### Scene Transition Controller:
|
||||||
|
**File:** `C:\Assets\4.Developer\Andy\FMODBooster\FMODSceneTransitionController.cs`
|
||||||
|
|
||||||
|
| Coroutine | Description |
|
||||||
|
|-----------|-------------|
|
||||||
|
| `<InitVolumeTransition>d__6` | Initialize volume transitions on scene load |
|
||||||
|
| `<StartGPFadeEventCheck>d__20` | Check/start fade events |
|
||||||
|
| `<StopAfterDelayRoutine>d__12` | Stop after delay |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. ENEMY AUDIO SYSTEM
|
||||||
|
|
||||||
|
### EnemyAttackBase
|
||||||
|
**File:** `C:\Assets\1.HonoHime\Core\Character\Core\EnemyAttackBase.cs`
|
||||||
|
|
||||||
|
| State/Action | Description |
|
||||||
|
|--------------|-------------|
|
||||||
|
| `Attack` | Attack state/action |
|
||||||
|
| `Idle` | Idle state/action |
|
||||||
|
| `AlertAction_LookAtTarget` | Alert when noticing player |
|
||||||
|
| `AlertAction_MoveToTargetLastPosition` | Move to last known player position |
|
||||||
|
|
||||||
|
### EnemyActionManager
|
||||||
|
**File:** `C:\Assets\1.HonoHime\Core\Character\EnemyActionManager\EnemyActionManager.cs`
|
||||||
|
**File:** `C:\Assets\1.HonoHime\Core\Character\EnemyActionManager\EnemyAction.cs`
|
||||||
|
|
||||||
|
| Method/Property | Description |
|
||||||
|
|----------------|-------------|
|
||||||
|
| `GetEnemyActionManager` | Access to enemy action system |
|
||||||
|
| `GetEnemyAttack` | Get enemy attack controller |
|
||||||
|
| `enemyActionManager` | Reference field |
|
||||||
|
|
||||||
|
### Enemy Attack Controllers:
|
||||||
|
```
|
||||||
|
EnemyAttackAction - Basic attack action
|
||||||
|
EnemyAttackBase - Base attack behavior
|
||||||
|
EnemyAttackBlockedAction - When attack is blocked
|
||||||
|
EnemyAttackAcion_UseDamageSet - Attack using damage set
|
||||||
|
EnemyAssassinGroupManager - Group attack coordination
|
||||||
|
```
|
||||||
|
|
||||||
|
### Enemy Audio Handlers:
|
||||||
|
|
||||||
|
| Class | File | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `EnemyDamageVoiceSFXHandler` | `C:\Assets\4.Developer\Andy\EnemyDamageSFXHandler\EnemyDamageVoiceSFXHandler.cs` | Handles damage voice SFX |
|
||||||
|
| `EnemyDamageVoiceSFXHandler|FeedbackVoice` | Feedback voice field |
|
||||||
|
| `AudioComponent` | `C:\Assets\1.HonoHime\Core\Character\DamageSystem\Component\AudioComponent.cs` | Damage system audio |
|
||||||
|
|
||||||
|
### Enemy Attack States Found:
|
||||||
|
```
|
||||||
|
SukebanShibaTwin|JumpAttackState
|
||||||
|
BoneGirl_GroundAttack|FinishState
|
||||||
|
BoneGirl_GrabAttack|BoneGirl_GrabAttackState
|
||||||
|
SukenBenSquadA|LeftRightDashAttackState
|
||||||
|
AttackAction_TransitionSpecialArt
|
||||||
|
AttackAction_Charge
|
||||||
|
AttackAction_QuakingStrike
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. CFVOICE SYSTEM
|
||||||
|
|
||||||
|
### CFVoiceEventUtility
|
||||||
|
**File:** `C:\Assets\1.HonoHime\Core\...` (pattern found in strings)
|
||||||
|
|
||||||
|
The CFVoice system triggers voice events based on game events:
|
||||||
|
|
||||||
|
| Event Key | Description |
|
||||||
|
|-----------|-------------|
|
||||||
|
| `CFVoiceEventUtility|Battle` | Battle events |
|
||||||
|
| `CFVoiceEventUtility|Challenge` | Challenge mode |
|
||||||
|
| `CFVoiceEventUtility|Chip` | Chip collection |
|
||||||
|
| `CFVoiceEventUtility|Enemy` | **Enemy-related** - important for enemy indicators |
|
||||||
|
| `CFVoiceEventUtility|EventKey` | Generic event key |
|
||||||
|
| `CFVoiceEventUtility|HH_Behaviour` | Character behavior events |
|
||||||
|
| `CFVoiceEventUtility|HH_Skill` | Skill usage |
|
||||||
|
| `CFVoiceEventUtility|Mission` | Mission events |
|
||||||
|
| `CFVoiceEventUtility|Note` | Note collection |
|
||||||
|
| `CFVoiceEventUtility|QTE` | QTE events |
|
||||||
|
| `CFVoiceEventUtility|Rank` | Rank up |
|
||||||
|
| `CFVoiceEventUtility|Reward` | Rewards |
|
||||||
|
| `CFVoiceEventUtility|Senbei` | Item-related |
|
||||||
|
| `CFVoiceEventUtility|Timer` | Timer events |
|
||||||
|
| `CFVoiceEventUtility|Trap` | Trap activation |
|
||||||
|
| `CFVoiceEventUtility|TreasureChest` | Chest opening |
|
||||||
|
|
||||||
|
### CFVoice Handlers:
|
||||||
|
|
||||||
|
| Class | File |
|
||||||
|
|-------|------|
|
||||||
|
| `MissionCFVoiceHandler` | `C:\Assets\1.HonoHime\Core\Level\MissionController\MissionCFVoiceHandler.cs` |
|
||||||
|
| `InventoryMonitorCFVoiceHandler` | `C:\Assets\4.Developer\Andy\FmodBGMController\Scripts\InventoryMonitorCFVoiceHandler.cs` |
|
||||||
|
| `CommonFunctionVoiceHandler` | `C:\Assets\4.Developer\Andy\FmodFunctionVoice\CommonFunctionVoiceHandler.cs` |
|
||||||
|
|
||||||
|
### CFVoice Properties Found:
|
||||||
|
```
|
||||||
|
get_EVENT_CFVOICE_BATTLE
|
||||||
|
get_EVENT_CFVOICE_ENEMY
|
||||||
|
get_EVENT_CFVOICE_MISSION
|
||||||
|
get_EVENT_CFVOICE_HPCHIP
|
||||||
|
get_EVENT_CFVOICE_QTE_SHIKIGAMI
|
||||||
|
get_EVENT_CFVOICE_QTE_FLURRYBARRIER
|
||||||
|
PlayCFVoice
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## KEY HOOK POINTS FOR HARMONY PATCHES
|
||||||
|
|
||||||
|
### Audio Glitch Fixes:
|
||||||
|
|
||||||
|
1. **Voice Limit Fix** - Patch `UtageFmodVoiceManager.get_CountVoice` to enforce MAX_VOICES limit
|
||||||
|
2. **Ducking Glitch** - Patch `UpdateDucking` coroutine to fix fade timing issues
|
||||||
|
3. **Voice Cutoff Fix** - Patch `StopVoiceEvent` to properly handle crossfade before stopping
|
||||||
|
|
||||||
|
### Enemy Indicator Improvements:
|
||||||
|
|
||||||
|
1. **Alert Sound** - Hook into `CFVoiceEventUtility` with `Enemy` event key
|
||||||
|
2. **Attack Sound** - Patch `EnemyAttackBase.OnEnter` / `OnAttack` methods
|
||||||
|
3. **Idle Sound Loop** - Patch `EnemyAttackBase.Idle` state entry
|
||||||
|
|
||||||
|
### Priority Hook Targets:
|
||||||
|
|
||||||
|
| Priority | Class | Method | Purpose |
|
||||||
|
|----------|-------|--------|---------|
|
||||||
|
| HIGH | `UtageFmodVoiceManager` | `UpdateDucking` | Fix ducking glitches |
|
||||||
|
| HIGH | `UtageFmodVoiceManager` | `PlayVoice` | Voice limit enforcement |
|
||||||
|
| HIGH | `CFVoiceEventUtility` | `PlayCFVoice` | Enemy voice routing |
|
||||||
|
| MEDIUM | `FMODSoundManager` | `SetVolume` | Volume clamping |
|
||||||
|
| MEDIUM | `FMODSceneTransitionController` | `InitVolumeTransition` | Scene transition audio |
|
||||||
|
| MEDIUM | `EnemyDamageVoiceSFXHandler` | `FeedbackVoice` | Damage audio |
|
||||||
|
| LOW | `SnapshotManager` | `ApplySnapshot` | Reverb/snapshot control |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## SOURCE FILE REFERENCE LIST
|
||||||
|
|
||||||
|
### Voice Management:
|
||||||
|
- `C:\Assets\4.Developer\Andy\UtageVoiceManager\UtageFmodVoiceManager.cs`
|
||||||
|
- `C:\Assets\4.Developer\Andy\UtageVoiceManager\UtageFmodVoiceSetting.cs`
|
||||||
|
- `C:\Assets\4.Developer\Andy\UtageVoiceManager\VoiceEventSelector.cs`
|
||||||
|
- `C:\Assets\4.Developer\Andy\UtageVoiceManager\FmodVoiceStopper.cs`
|
||||||
|
- `C:\Assets\4.Developer\Andy\UtageVoiceManager\SnapshotManager.cs`
|
||||||
|
- `C:\Assets\4.Developer\Andy\UtageVoiceManager\SnapshotHandle.cs`
|
||||||
|
- `C:\Assets\4.Developer\Andy\UtageVoiceManager\DEAudioFadeManager.cs`
|
||||||
|
- `C:\Assets\4.Developer\Andy\UtageVoiceManager\FmodSoundDebugger.cs`
|
||||||
|
|
||||||
|
### FMOD Core:
|
||||||
|
- `C:\Assets\1.HonoHime\Core\FMODUtility\Scripts\FMODSoundManager.cs`
|
||||||
|
- `C:\Assets\1.HonoHime\Core\FMODUtility\Scripts\FMODUtility.cs`
|
||||||
|
- `C:\Assets\1.HonoHime\Core\FMODUtility\Scripts\FMODManager.cs`
|
||||||
|
|
||||||
|
### Enemy Audio:
|
||||||
|
- `C:\Assets\1.HonoHime\Core\Character\Core\EnemyAttackBase.cs`
|
||||||
|
- `C:\Assets\1.HonoHime\Core\Character\EnemyActionManager\EnemyActionManager.cs`
|
||||||
|
- `C:\Assets\4.Developer\Andy\EnemyDamageSFXHandler\EnemyDamageVoiceSFXHandler.cs`
|
||||||
|
- `C:\Assets\1.HonoHime\Core\Character\DamageSystem\Component\AudioComponent.cs`
|
||||||
|
|
||||||
|
### CFVoice System:
|
||||||
|
- (Source path partially truncated, but class is `CFVoiceEventUtility`)
|
||||||
|
- `C:\Assets\1.HonoHime\Core\Level\MissionController\MissionCFVoiceHandler.cs`
|
||||||
|
- `C:\Assets\4.Developer\Andy\FmodFunctionVoice\CommonFunctionVoiceHandler.cs`
|
||||||
|
|
||||||
|
### Scene/BGM:
|
||||||
|
- `C:\Assets\4.Developer\Andy\FMODBooster\FMODSceneTransitionController.cs`
|
||||||
|
- `C:\Assets\4.Developer\Andy\FmodBGMController\Scripts\MainBGMManager.cs`
|
||||||
|
- `C:\Assets\4.Developer\Andy\FmodBGMController\Scripts\FmodBGMController.cs`
|
||||||
|
|
||||||
|
### SFX Events:
|
||||||
|
- `C:\Assets\4.Developer\HsiCheng\Script\Fmod\FmodSFXEventRef.cs`
|
||||||
|
- `C:\Assets\4.Developer\HsiCheng\Script\Fmod\FmodSFXEventSO.cs`
|
||||||
|
- `C:\Assets\4.Developer\HsiCheng\Script\Fmod\FmodSFXEventDispatcher.cs`
|
||||||
@@ -1,19 +1,125 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace HomuraHimeAudioMod.Patches
|
namespace HomuraHimeAudioMod.Patches
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Patches for audio ducking system improvements.
|
|
||||||
/// TO BE IMPLEMENTED AFTER PHASE 2 CODE ANALYSIS
|
|
||||||
/// </summary>
|
|
||||||
public class AudioDuckingPatch
|
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)
|
public static void Apply(ref Harmony harmony)
|
||||||
{
|
{
|
||||||
// TODO: After Phase 2, implement patches for:
|
Plugin.Log.LogInfo("Applying AudioDucking patches...");
|
||||||
// - Improve ducking fade times
|
|
||||||
// - Adjust duck amounts for combat
|
var originalType = AccessTools.TypeByName("Andy.SnapshotManager");
|
||||||
// - Add custom ducking rules
|
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 HarmonyLib;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace HomuraHimeAudioMod.Patches
|
namespace HomuraHimeAudioMod.Patches
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Patches for enemy behavior audio indicator improvements.
|
|
||||||
/// TO BE IMPLEMENTED AFTER PHASE 2 CODE ANALYSIS
|
|
||||||
/// </summary>
|
|
||||||
public class EnemyAudioPatch
|
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)
|
public static void Apply(ref Harmony harmony)
|
||||||
{
|
{
|
||||||
// TODO: After Phase 2, implement patches for:
|
Plugin.Log.LogInfo("Applying EnemyAudio patches...");
|
||||||
// - Boost enemy indicator volumes
|
|
||||||
// - Improve state change audio cues
|
PatchEnemyAttackBase(harmony);
|
||||||
// - Add debug logging for enemy audio
|
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 HarmonyLib;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace HomuraHimeAudioMod.Patches
|
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 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)
|
public static void Apply(ref Harmony harmony)
|
||||||
{
|
{
|
||||||
// TODO: After Phase 2, implement patches for:
|
Plugin.Log.LogInfo("Applying VoiceManager patches...");
|
||||||
// - Increase max voice count
|
|
||||||
// - Improve voice stealing behavior
|
var originalType = AccessTools.TypeByName("Andy.UtageFmodVoiceManager");
|
||||||
// - Adjust pooling sizes
|
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);
|
harmony = new Harmony(PluginInfo.PLUGIN_GUID);
|
||||||
|
|
||||||
|
Log.LogInfo($"HomuraHime Audio Mod v{PluginInfo.PLUGIN_VERSION} initializing...");
|
||||||
|
|
||||||
ApplyPatches();
|
ApplyPatches();
|
||||||
|
|
||||||
|
Log.LogInfo("HomuraHime Audio Mod initialized successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyPatches()
|
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);
|
||||||
// VoiceManagerPatch.Apply(ref harmony);
|
AudioDuckingPatch.Apply(ref harmony);
|
||||||
// AudioDuckingPatch.Apply(ref harmony);
|
EnemyAudioPatch.Apply(ref harmony);
|
||||||
// EnemyAudioPatch.Apply(ref harmony);
|
|
||||||
|
|
||||||
Log.LogInfo($"Patches applied successfully");
|
Log.LogInfo("All patches applied successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDestroy()
|
private void OnDestroy()
|
||||||
{
|
{
|
||||||
harmony?.UnpatchAll();
|
harmony?.UnpatchAll(PluginInfo.PLUGIN_GUID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user