Compare commits
6 Commits
b589d39ccd
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 906a4d5a74 | |||
| c0b6816ab0 | |||
| 5a9f306f3f | |||
| 4251a29794 | |||
| 81bf38b472 | |||
| 4285ae5258 |
@@ -1 +1 @@
|
|||||||
610036
|
622840
|
||||||
@@ -1 +1 @@
|
|||||||
1774200743
|
1774205514
|
||||||
@@ -1,74 +1,90 @@
|
|||||||
# Existing Modding Tools for HomuraHime
|
# Existing Modding Tools for HomuraHime
|
||||||
|
|
||||||
## Recommended Existing Tools
|
## Recommended: CinematicUnityExplorer (295 stars)
|
||||||
|
|
||||||
### 1. UnityExplorer (3k stars)
|
**Purpose:** In-game UI for exploring, debugging, and modifying Unity games with cinematic tools
|
||||||
**Purpose:** In-game UI for exploring, debugging, and modifying Unity games
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- Object Explorer - browse scenes, find audio objects
|
|
||||||
- Inspector - view/edit component values in real-time
|
|
||||||
- Hook Manager - create Harmony patches at runtime (no rebuild needed)
|
|
||||||
- C# Console - execute code live
|
|
||||||
- Mouse Inspect - click objects to inspect them
|
|
||||||
|
|
||||||
**Download:**
|
**Download:**
|
||||||
- BepInEx 5.x Mono: https://github.com/sinai-dev/UnityExplorer/releases/download/UnityExplorer.BepInEx5.Mono.zip
|
```
|
||||||
|
https://github.com/originalnicodr/CinematicUnityExplorer/releases/latest/download/CinematicUnityExplorer.BepInEx5.Mono.zip
|
||||||
|
```
|
||||||
|
|
||||||
**Installation:**
|
**Installation:**
|
||||||
|
1. Download `CinematicUnityExplorer.BepInEx5.Mono.zip`
|
||||||
|
2. Extract to: `C:\apps\steam\steamapps\common\Homura Hime\BepInEx\plugins\`
|
||||||
|
3. Launch game - press **F5** to open
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
| Feature | Description |
|
||||||
|
|---------|-------------|
|
||||||
|
| Object Search | Find audio manager types (FmodVoiceManager, CFVoiceEventUtility, etc.) |
|
||||||
|
| Inspector | View/edit component values in real-time |
|
||||||
|
| Hook Manager | Create Harmony patches at runtime (no rebuild needed) |
|
||||||
|
| C# Console | Execute code live to test audio triggers |
|
||||||
|
| Mouse Inspect | Click objects to inspect them |
|
||||||
|
| Freecam | Cinematic camera for screenshots/videos |
|
||||||
|
| Lights Manager | Add/modify scene lighting |
|
||||||
|
| Camera Paths | Create cinematic camera sequences |
|
||||||
|
| Animator Control | Pose characters for screenshots |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Alternative: Yukieiji UnityExplorer (809 stars)
|
||||||
|
|
||||||
|
**Vanilla UnityExplorer** - if you don't need cinematic features
|
||||||
|
|
||||||
|
**Download:**
|
||||||
```
|
```
|
||||||
1. Download UnityExplorer.BepInEx5.Mono.zip
|
https://github.com/yukieiji/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx5.Mono.zip
|
||||||
2. Extract to: C:\apps\steam\steamapps\common\Homura Hime\BepInEx\plugins\
|
|
||||||
3. Launch game - press F5 to open UnityExplorer menu
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. UniverseLib (129 stars)
|
|
||||||
**Purpose:** UI library for Unity mod plugins
|
|
||||||
|
|
||||||
**NuGet:**
|
|
||||||
- Mono: `rainbowblood.UniverseLib.Mono`
|
|
||||||
- IL2CPP: `rainbowblood.UniverseLib.IL2CPP`
|
|
||||||
|
|
||||||
Note: UniverseLib is included with UnityExplorer, no separate install needed.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Why Keep Our Custom AudioMixerGUI?
|
## Why Keep Our Custom AudioMixerGUI?
|
||||||
|
|
||||||
While UnityExplorer is excellent for general debugging, our **AudioMixerGUI** provides:
|
Our **AudioMixerGUI** provides audio-specific sliders and quick testing:
|
||||||
|
|
||||||
| Feature | UnityExplorer | Our AudioMixerGUI |
|
| Feature | CinematicUnityExplorer | Our AudioMixerGUI |
|
||||||
|---------|---------------|-------------------|
|
|---------|----------------------|-------------------|
|
||||||
| Audio-specific sliders | No | Yes |
|
| Audio-specific sliders | No | Yes |
|
||||||
| One-click enemy cue testing | No | Yes |
|
| One-click enemy cue testing | Via C# Console | Yes |
|
||||||
| Battle cue testing | No | Yes |
|
| Voice count monitoring | Manual via Inspector | Yes |
|
||||||
| Voice count monitoring | Manual | Automatic |
|
| Config persistence | No | Yes (via BepInEx config) |
|
||||||
| Audio presets | No | Yes |
|
|
||||||
|
|
||||||
**Recommendation:** Use **BOTH**
|
**Recommendation:** Use **BOTH**
|
||||||
- UnityExplorer for general debugging and object browsing
|
- CinematicUnityExplorer (F5) for debugging, object browsing, screenshots
|
||||||
- Our AudioMixerGUI for focused audio parameter tweaking and cue testing
|
- Our AudioMixerGUI (F1) for audio parameter tweaking
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Alternative: Dear ImGui (Future Option)
|
## Quick Start with CinematicUnityExplorer
|
||||||
|
|
||||||
If you prefer Dear ImGui-style UI, consider:
|
### Finding Audio Types
|
||||||
|
1. Press **F5** to open CinematicUnityExplorer
|
||||||
|
2. Go to **Object Search** tab
|
||||||
|
3. Search for: `FmodVoiceManager`, `CFVoiceEventUtility`, `VoiceManager`, `SnapshotManager`
|
||||||
|
4. Click results to inspect
|
||||||
|
|
||||||
1. **MelonImGui** - https://github.com/plusno69/MelonImGui
|
### Creating Runtime Patches
|
||||||
2. **ui_imgui** - https://github.com/nk-mermaid/ui_imgui
|
1. Go to **Hook Manager** tab
|
||||||
|
2. Enter class name (e.g., `CFVoiceEventUtility`)
|
||||||
|
3. Select method (e.g., `PlayCFVoice`)
|
||||||
|
4. Click to generate patch code
|
||||||
|
5. Edit and apply at runtime
|
||||||
|
|
||||||
These require additional dependencies but provide modern ImGui-style UI.
|
### Testing Audio Triggers via C# Console
|
||||||
|
```
|
||||||
**Trade-off:** More work to integrate, but looks more professional.
|
// Example - trigger enemy alert sound
|
||||||
|
CFVoiceEventUtility.PlayCFVoice("Enemy_Alert");
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Recommended Setup
|
## Default Hotkeys
|
||||||
|
|
||||||
1. **Install UnityExplorer** (for general modding/debugging)
|
| Key | Action |
|
||||||
2. **Keep our AudioMixerGUI** (for audio-specific controls)
|
|-----|--------|
|
||||||
3. **Press F1** to toggle our audio mixer
|
| **F5** | Toggle CinematicUnityExplorer |
|
||||||
4. **Press F5** to toggle UnityExplorer
|
| **F1** | Toggle our AudioMixerGUI |
|
||||||
|
|
||||||
This gives you the best of both worlds - professional debugging tools + dedicated audio mixer.
|
For CinematicUnityExplorer freecam controls, see their documentation.
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ param(
|
|||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
$ProjectDir = Split-Path -Parent $PSScriptRoot
|
$ProjectDir = $PSScriptRoot
|
||||||
$ProjectFile = Join-Path $ProjectDir "HomuraHimeAudioMod.csproj"
|
$ProjectFile = Join-Path $ProjectDir "HomuraHimeAudioMod.csproj"
|
||||||
$DefaultOutput = Join-Path $ProjectDir "bin\$Configuration\net48"
|
$DefaultOutput = Join-Path $ProjectDir "bin\$Configuration\net48"
|
||||||
|
|
||||||
|
|||||||
@@ -1,428 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace HomuraHimeAudioMod.GUI
|
|
||||||
{
|
|
||||||
public class AudioMixerGUI : MonoBehaviour
|
|
||||||
{
|
|
||||||
private static AudioMixerGUI instance;
|
|
||||||
public static AudioMixerGUI Instance => instance;
|
|
||||||
|
|
||||||
private bool isVisible = false;
|
|
||||||
private Vector2 scrollPosition;
|
|
||||||
private float margin = 10f;
|
|
||||||
private float labelWidth = 140f;
|
|
||||||
private float sliderWidth = 200f;
|
|
||||||
private float buttonHeight = 25f;
|
|
||||||
private float lineHeight = 30f;
|
|
||||||
private float windowWidth = 380f;
|
|
||||||
private float windowHeight = 520f;
|
|
||||||
|
|
||||||
private string[] enemyCueNames = new string[]
|
|
||||||
{
|
|
||||||
"Enemy_Idle",
|
|
||||||
"Enemy_Alert",
|
|
||||||
"Enemy_Attack",
|
|
||||||
"Enemy_Chase",
|
|
||||||
"Enemy_Death",
|
|
||||||
"Enemy_Damage_Taken",
|
|
||||||
"Enemy_Special"
|
|
||||||
};
|
|
||||||
|
|
||||||
private string[] battleCueNames = new string[]
|
|
||||||
{
|
|
||||||
"Battle_Start",
|
|
||||||
"Battle_Victory",
|
|
||||||
"Player_Attack",
|
|
||||||
"Player_Dodge",
|
|
||||||
"Player_Block",
|
|
||||||
"Player_Critical"
|
|
||||||
};
|
|
||||||
|
|
||||||
private Rect windowRect
|
|
||||||
{
|
|
||||||
get => new Rect(margin, margin, windowWidth, windowHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Awake()
|
|
||||||
{
|
|
||||||
if (instance == null)
|
|
||||||
{
|
|
||||||
instance = this;
|
|
||||||
DontDestroyOnLoad(gameObject);
|
|
||||||
Plugin.Log.LogInfo("AudioMixerGUI initialized");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Destroy(gameObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
if (Input.GetKeyDown(KeyCode.F1))
|
|
||||||
{
|
|
||||||
isVisible = !isVisible;
|
|
||||||
Plugin.Log.LogDebug($"Audio Mixer GUI: {(isVisible ? "VISIBLE" : "HIDDEN")}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Input.GetKeyDown(KeyCode.F2))
|
|
||||||
{
|
|
||||||
isVisible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnGUI()
|
|
||||||
{
|
|
||||||
if (!isVisible) return;
|
|
||||||
|
|
||||||
GUI.skin = CreateCustomSkin();
|
|
||||||
|
|
||||||
windowRect.x = Mathf.Clamp(windowRect.x, 0, Screen.width - windowWidth - 10);
|
|
||||||
windowRect.y = Mathf.Clamp(windowRect.y, 0, Screen.height - windowHeight - 10);
|
|
||||||
|
|
||||||
windowRect = GUI.Window(0, windowRect, DrawMainWindow, "HomuraHime Audio Mixer (F1: Toggle | F2: Close)");
|
|
||||||
}
|
|
||||||
|
|
||||||
private GUISkin CreateCustomSkin()
|
|
||||||
{
|
|
||||||
GUISkin skin = GUI.skin;
|
|
||||||
|
|
||||||
GUIStyle headerStyle = new GUIStyle(GUI.skin.label)
|
|
||||||
{
|
|
||||||
fontSize = 14,
|
|
||||||
fontStyle = FontStyle.Bold,
|
|
||||||
alignment = TextAnchor.MiddleCenter
|
|
||||||
};
|
|
||||||
|
|
||||||
GUIStyle sectionStyle = new GUIStyle(GUI.skin.label)
|
|
||||||
{
|
|
||||||
fontSize = 12,
|
|
||||||
fontStyle = FontStyle.Bold,
|
|
||||||
normal = { textColor = new Color(0.9f, 0.7f, 0.3f) }
|
|
||||||
};
|
|
||||||
|
|
||||||
GUIStyle buttonStyle = new GUIStyle(GUI.skin.button)
|
|
||||||
{
|
|
||||||
fontSize = 11,
|
|
||||||
fontStyle = FontStyle.Normal
|
|
||||||
};
|
|
||||||
|
|
||||||
return skin;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawMainWindow(int windowID)
|
|
||||||
{
|
|
||||||
GUI.DragWindow(new Rect(0, 0, windowWidth - 20, 25));
|
|
||||||
|
|
||||||
scrollPosition = GUILayout.BeginScrollView(scrollPosition);
|
|
||||||
|
|
||||||
GUILayout.Space(margin);
|
|
||||||
|
|
||||||
DrawHeader();
|
|
||||||
GUILayout.Space(margin);
|
|
||||||
|
|
||||||
DrawVoiceControls();
|
|
||||||
GUILayout.Space(10);
|
|
||||||
|
|
||||||
DrawDuckingControls();
|
|
||||||
GUILayout.Space(10);
|
|
||||||
|
|
||||||
DrawEnemyAudioControls();
|
|
||||||
GUILayout.Space(10);
|
|
||||||
|
|
||||||
DrawEnemyCueTestButtons();
|
|
||||||
GUILayout.Space(10);
|
|
||||||
|
|
||||||
DrawBattleCueTestButtons();
|
|
||||||
GUILayout.Space(10);
|
|
||||||
|
|
||||||
DrawDebugControls();
|
|
||||||
GUILayout.Space(margin);
|
|
||||||
|
|
||||||
GUILayout.EndScrollView();
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
GUILayout.Label($"v1.0.0 | F1: Toggle | F2: Close", GUILayout.Height(20));
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawHeader()
|
|
||||||
{
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
GUILayout.Label("=== HOMURAHIME AUDIO MIXER ===", GUILayout.Height(25));
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
GUILayout.Label($"Voice Count: {GetCurrentVoiceCount()} | Max: {ModConfig.MaxVoiceCount.Value}", GUILayout.Height(20));
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawVoiceControls()
|
|
||||||
{
|
|
||||||
GUILayout.BeginVertical("box");
|
|
||||||
GUILayout.Label("VOICE MANAGER", GUILayout.Height(20));
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
GUILayout.Label("Max Voices:", GUILayout.Width(labelWidth), GUILayout.Height(lineHeight));
|
|
||||||
ModConfig.MaxVoiceCount.Value = (int)GUILayout.HorizontalSlider(
|
|
||||||
ModConfig.MaxVoiceCount.Value, 32, 256,
|
|
||||||
GUILayout.Width(sliderWidth), GUILayout.Height(lineHeight));
|
|
||||||
GUILayout.Label($"{ModConfig.MaxVoiceCount.Value}", GUILayout.Width(40));
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
GUILayout.Label($"Voice Limit Fix: ", GUILayout.Width(labelWidth), GUILayout.Height(lineHeight));
|
|
||||||
ModConfig.EnableVoiceLimitFix.Value = GUILayout.Toggle(
|
|
||||||
ModConfig.EnableVoiceLimitFix.Value, "Enabled");
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
|
|
||||||
GUILayout.EndVertical();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawDuckingControls()
|
|
||||||
{
|
|
||||||
GUILayout.BeginVertical("box");
|
|
||||||
GUILayout.Label("AUDIO DUCKING", GUILayout.Height(20));
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
GUILayout.Label("Duck Fade Time:", GUILayout.Width(labelWidth), GUILayout.Height(lineHeight));
|
|
||||||
ModConfig.DuckFadeTime.Value = GUILayout.HorizontalSlider(
|
|
||||||
ModConfig.DuckFadeTime.Value, 0.01f, 0.3f,
|
|
||||||
GUILayout.Width(sliderWidth), GUILayout.Height(lineHeight));
|
|
||||||
GUILayout.Label($"{ModConfig.DuckFadeTime.Value:F3}s", GUILayout.Width(50));
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
GUILayout.Label("Duck Volume:", GUILayout.Width(labelWidth), GUILayout.Height(lineHeight));
|
|
||||||
ModConfig.DuckVolume.Value = GUILayout.HorizontalSlider(
|
|
||||||
ModConfig.DuckVolume.Value, 0.1f, 0.8f,
|
|
||||||
GUILayout.Width(sliderWidth), GUILayout.Height(lineHeight));
|
|
||||||
GUILayout.Label($"{ModConfig.DuckVolume.Value:F2}", GUILayout.Width(50));
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
GUILayout.Label($"Ducking Fix: ", GUILayout.Width(labelWidth), GUILayout.Height(lineHeight));
|
|
||||||
ModConfig.EnableDuckingFix.Value = GUILayout.Toggle(
|
|
||||||
ModConfig.EnableDuckingFix.Value, "Enabled");
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
|
|
||||||
GUILayout.EndVertical();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawEnemyAudioControls()
|
|
||||||
{
|
|
||||||
GUILayout.BeginVertical("box");
|
|
||||||
GUILayout.Label("ENEMY AUDIO INDICATORS", GUILayout.Height(20));
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
GUILayout.Label("Indicator Boost:", GUILayout.Width(labelWidth), GUILayout.Height(lineHeight));
|
|
||||||
ModConfig.EnemyIndicatorBoost.Value = GUILayout.HorizontalSlider(
|
|
||||||
ModConfig.EnemyIndicatorBoost.Value, 0.5f, 2.0f,
|
|
||||||
GUILayout.Width(sliderWidth), GUILayout.Height(lineHeight));
|
|
||||||
GUILayout.Label($"{ModConfig.EnemyIndicatorBoost.Value:F2}x", GUILayout.Width(50));
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
GUILayout.Label("Alert Boost:", GUILayout.Width(labelWidth), GUILayout.Height(lineHeight));
|
|
||||||
ModConfig.AlertSoundBoost.Value = GUILayout.HorizontalSlider(
|
|
||||||
ModConfig.AlertSoundBoost.Value, 0.5f, 2.0f,
|
|
||||||
GUILayout.Width(sliderWidth), GUILayout.Height(lineHeight));
|
|
||||||
GUILayout.Label($"{ModConfig.AlertSoundBoost.Value:F2}x", GUILayout.Width(50));
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
GUILayout.Label("Attack Boost:", GUILayout.Width(labelWidth), GUILayout.Height(lineHeight));
|
|
||||||
ModConfig.AttackSoundBoost.Value = GUILayout.HorizontalSlider(
|
|
||||||
ModConfig.AttackSoundBoost.Value, 0.5f, 2.0f,
|
|
||||||
GUILayout.Width(sliderWidth), GUILayout.Height(lineHeight));
|
|
||||||
GUILayout.Label($"{ModConfig.AttackSoundBoost.Value:F2}x", GUILayout.Width(50));
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
GUILayout.Label($"Enemy Audio: ", GUILayout.Width(labelWidth), GUILayout.Height(lineHeight));
|
|
||||||
ModConfig.EnableEnemyAudioBoost.Value = GUILayout.Toggle(
|
|
||||||
ModConfig.EnableEnemyAudioBoost.Value, "Enabled");
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
|
|
||||||
GUILayout.EndVertical();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawEnemyCueTestButtons()
|
|
||||||
{
|
|
||||||
GUILayout.BeginVertical("box");
|
|
||||||
GUILayout.Label("TEST ENEMY CUES (Debug)", GUILayout.Height(20));
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
for (int i = 0; i < enemyCueNames.Length; i++)
|
|
||||||
{
|
|
||||||
string cueName = enemyCueNames[i];
|
|
||||||
if (GUILayout.Button(cueName, GUILayout.Height(buttonHeight)))
|
|
||||||
{
|
|
||||||
TestEnemyCue(cueName);
|
|
||||||
}
|
|
||||||
if ((i + 1) % 2 == 0) GUILayout.EndHorizontal();
|
|
||||||
if ((i + 1) % 2 != 0 && i < enemyCueNames.Length - 1) GUILayout.BeginHorizontal();
|
|
||||||
}
|
|
||||||
if (enemyCueNames.Length % 2 != 0) GUILayout.EndHorizontal();
|
|
||||||
|
|
||||||
GUILayout.EndVertical();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawBattleCueTestButtons()
|
|
||||||
{
|
|
||||||
GUILayout.BeginVertical("box");
|
|
||||||
GUILayout.Label("TEST BATTLE CUES (Debug)", GUILayout.Height(20));
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
for (int i = 0; i < battleCueNames.Length; i++)
|
|
||||||
{
|
|
||||||
string cueName = battleCueNames[i];
|
|
||||||
if (GUILayout.Button(cueName, GUILayout.Height(buttonHeight)))
|
|
||||||
{
|
|
||||||
TestBattleCue(cueName);
|
|
||||||
}
|
|
||||||
if ((i + 1) % 2 == 0) GUILayout.EndHorizontal();
|
|
||||||
if ((i + 1) % 2 != 0 && i < battleCueNames.Length - 1) GUILayout.BeginHorizontal();
|
|
||||||
}
|
|
||||||
if (battleCueNames.Length % 2 != 0) GUILayout.EndHorizontal();
|
|
||||||
|
|
||||||
GUILayout.EndVertical();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawDebugControls()
|
|
||||||
{
|
|
||||||
GUILayout.BeginVertical("box");
|
|
||||||
GUILayout.Label("DEBUG OPTIONS", GUILayout.Height(20));
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
GUILayout.Label($"Debug Logging: ", GUILayout.Width(labelWidth), GUILayout.Height(lineHeight));
|
|
||||||
ModConfig.EnableDebugLogging.Value = GUILayout.Toggle(
|
|
||||||
ModConfig.EnableDebugLogging.Value, "Enabled");
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
|
|
||||||
if (GUILayout.Button("Log Current Config", GUILayout.Height(buttonHeight)))
|
|
||||||
{
|
|
||||||
LogCurrentConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GUILayout.Button("Reset to Defaults", GUILayout.Height(buttonHeight)))
|
|
||||||
{
|
|
||||||
ResetToDefaults();
|
|
||||||
}
|
|
||||||
|
|
||||||
GUILayout.EndVertical();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GetCurrentVoiceCount()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var voiceManagerType = FindTypeByName("FmodVoiceManager");
|
|
||||||
if (voiceManagerType != null)
|
|
||||||
{
|
|
||||||
var instance = AccessTools.Property(voiceManagerType, "Instance")?.GetValue(null);
|
|
||||||
if (instance != null)
|
|
||||||
{
|
|
||||||
var countProp = AccessTools.Property(voiceManagerType, "CountVoice");
|
|
||||||
if (countProp != null)
|
|
||||||
{
|
|
||||||
return (int)countProp.GetValue(instance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Type FindTypeByName(string name)
|
|
||||||
{
|
|
||||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
|
||||||
{
|
|
||||||
foreach (var type in assembly.GetTypes())
|
|
||||||
{
|
|
||||||
if (type.Name.Contains(name))
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TestEnemyCue(string cueName)
|
|
||||||
{
|
|
||||||
Plugin.Log.LogDebug($"[GUI] Testing enemy cue: {cueName}");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var cfVoiceType = FindTypeByName("CFVoiceEventUtility");
|
|
||||||
if (cfVoiceType != null)
|
|
||||||
{
|
|
||||||
var playMethod = AccessTools.Method(cfVoiceType, "PlayCFVoice");
|
|
||||||
if (playMethod != null)
|
|
||||||
{
|
|
||||||
playMethod.Invoke(null, new object[] { cueName });
|
|
||||||
Plugin.Log.LogDebug($"[GUI] Triggered enemy cue: {cueName}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Plugin.Log.LogWarning($"[GUI] Could not trigger enemy cue: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TestBattleCue(string cueName)
|
|
||||||
{
|
|
||||||
Plugin.Log.LogDebug($"[GUI] Testing battle cue: {cueName}");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var cfVoiceType = FindTypeByName("CFVoiceEventUtility");
|
|
||||||
if (cfVoiceType != null)
|
|
||||||
{
|
|
||||||
var playMethod = AccessTools.Method(cfVoiceType, "PlayCFVoice");
|
|
||||||
if (playMethod != null)
|
|
||||||
{
|
|
||||||
playMethod.Invoke(null, new object[] { cueName });
|
|
||||||
Plugin.Log.LogDebug($"[GUI] Triggered battle cue: {cueName}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Plugin.Log.LogWarning($"[GUI] Could not trigger battle cue: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LogCurrentConfig()
|
|
||||||
{
|
|
||||||
Plugin.Log.LogInfo("=== CURRENT AUDIO MOD CONFIG ===");
|
|
||||||
Plugin.Log.LogInfo($"MaxVoiceCount: {ModConfig.MaxVoiceCount.Value}");
|
|
||||||
Plugin.Log.LogInfo($"DuckFadeTime: {ModConfig.DuckFadeTime.Value}");
|
|
||||||
Plugin.Log.LogInfo($"DuckVolume: {ModConfig.DuckVolume.Value}");
|
|
||||||
Plugin.Log.LogInfo($"EnemyIndicatorBoost: {ModConfig.EnemyIndicatorBoost.Value}");
|
|
||||||
Plugin.Log.LogInfo($"AlertSoundBoost: {ModConfig.AlertSoundBoost.Value}");
|
|
||||||
Plugin.Log.LogInfo($"AttackSoundBoost: {ModConfig.AttackSoundBoost.Value}");
|
|
||||||
Plugin.Log.LogInfo($"EnableVoiceLimitFix: {ModConfig.EnableVoiceLimitFix.Value}");
|
|
||||||
Plugin.Log.LogInfo($"EnableDuckingFix: {ModConfig.EnableDuckingFix.Value}");
|
|
||||||
Plugin.Log.LogInfo($"EnableEnemyAudioBoost: {ModConfig.EnableEnemyAudioBoost.Value}");
|
|
||||||
Plugin.Log.LogInfo($"EnableDebugLogging: {ModConfig.EnableDebugLogging.Value}");
|
|
||||||
Plugin.Log.LogInfo("===============================");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ResetToDefaults()
|
|
||||||
{
|
|
||||||
ModConfig.MaxVoiceCount.Value = 128;
|
|
||||||
ModConfig.DuckFadeTime.Value = 0.05f;
|
|
||||||
ModConfig.DuckVolume.Value = 0.3f;
|
|
||||||
ModConfig.EnemyIndicatorBoost.Value = 1.2f;
|
|
||||||
ModConfig.AlertSoundBoost.Value = 1.3f;
|
|
||||||
ModConfig.AttackSoundBoost.Value = 1.15f;
|
|
||||||
ModConfig.EnableVoiceLimitFix.Value = true;
|
|
||||||
ModConfig.EnableDuckingFix.Value = true;
|
|
||||||
ModConfig.EnableEnemyAudioBoost.Value = true;
|
|
||||||
ModConfig.EnableDebugLogging.Value = false;
|
|
||||||
Plugin.Log.LogInfo("[GUI] Config reset to defaults");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,34 +10,61 @@
|
|||||||
<Product>HomuraHime Audio Mod</Product>
|
<Product>HomuraHime Audio Mod</Product>
|
||||||
<Description>Audio improvements mod for HomuraHime - fixes glitches and improves enemy indicators</Description>
|
<Description>Audio improvements mod for HomuraHime - fixes glitches and improves enemy indicators</Description>
|
||||||
<Copyright>Copyright 2026</Copyright>
|
<Copyright>Copyright 2026</Copyright>
|
||||||
<GamePath>C:\apps\steam\steamapps\common\Homura Hime\HomuraHime_Data\Managed</GamePath>
|
<GamePath>C:\apps\steam\steamapps\common\Homura Hime</GamePath>
|
||||||
</PropertyGroup>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
|
|
||||||
<PropertyGroup Condition="Exists('$(GamePath)')">
|
|
||||||
<DefineConstants>GAME_PATH_EXISTS</DefineConstants>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="0Harmony" Version="2.2.2">
|
<Reference Include="0Harmony">
|
||||||
<ExcludeAssets>runtime</ExcludeAssets>
|
<HintPath>$(GamePath)\BepInEx\core\0Harmony.dll</HintPath>
|
||||||
</PackageReference>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition="Exists('$(GamePath)')">
|
|
||||||
<Reference Include="BepInEx">
|
|
||||||
<HintPath>$(GamePath)\..\BepInEx\core\BepInEx.dll</HintPath>
|
|
||||||
<Private>false</Private>
|
<Private>false</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="FMODUnity">
|
<Reference Include="BepInEx">
|
||||||
<HintPath>$(GamePath)\FMODUnity.dll</HintPath>
|
<HintPath>$(GamePath)\BepInEx\core\BepInEx.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine">
|
||||||
|
<HintPath>$(GamePath)\HomuraHime_Data\Managed\UnityEngine.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.CoreModule">
|
||||||
|
<HintPath>$(GamePath)\HomuraHime_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||||
<Private>false</Private>
|
<Private>false</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="UnityEngine.AudioModule">
|
<Reference Include="UnityEngine.AudioModule">
|
||||||
<HintPath>$(GamePath)\UnityEngine.AudioModule.dll</HintPath>
|
<HintPath>$(GamePath)\HomuraHime_Data\Managed\UnityEngine.AudioModule.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.IMGUIModule">
|
||||||
|
<HintPath>$(GamePath)\HomuraHime_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.InputLegacyModule">
|
||||||
|
<HintPath>$(GamePath)\HomuraHime_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.TextRenderingModule">
|
||||||
|
<HintPath>$(GamePath)\HomuraHime_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UI">
|
||||||
|
<HintPath>$(GamePath)\HomuraHime_Data\Managed\UnityEngine.UI.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UIModule">
|
||||||
|
<HintPath>$(GamePath)\HomuraHime_Data\Managed\UnityEngine.UIModule.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="TMPro">
|
||||||
|
<HintPath>$(GamePath)\HomuraHime_Data\Managed\Unity.TextMeshPro.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="FMODUnity">
|
||||||
|
<HintPath>$(GamePath)\HomuraHime_Data\Managed\FMODUnity.dll</HintPath>
|
||||||
<Private>false</Private>
|
<Private>false</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Assembly-CSharp">
|
<Reference Include="Assembly-CSharp">
|
||||||
<HintPath>$(GamePath)\Assembly-CSharp.dll</HintPath>
|
<HintPath>$(GamePath)\HomuraHime_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||||
<Private>false</Private>
|
<Private>false</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -1,85 +1,47 @@
|
|||||||
using BepInEx;
|
using BepInEx;
|
||||||
using BepInEx.Logging;
|
using BepInEx.Logging;
|
||||||
using HarmonyLib;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace HomuraHimeAudioMod
|
namespace HomuraHimeAudioMod
|
||||||
{
|
{
|
||||||
[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
|
[BepInPlugin("com.homurahime.audiomod", "HomuraHime Audio Mod", "1.0.0")]
|
||||||
public class Plugin : BaseUnityPlugin
|
public class Plugin : BaseUnityPlugin
|
||||||
{
|
{
|
||||||
public const string PLUGIN_GUID = "com.homurahime.audiomod";
|
|
||||||
public const string PLUGIN_NAME = "HomuraHime Audio Mod";
|
|
||||||
public const string PLUGIN_VERSION = "1.0.0";
|
|
||||||
|
|
||||||
private static Plugin instance;
|
|
||||||
private static ManualLogSource logger;
|
private static ManualLogSource logger;
|
||||||
private Harmony harmony;
|
|
||||||
|
|
||||||
public static ManualLogSource Log => logger;
|
public static ManualLogSource Log => logger;
|
||||||
|
|
||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
instance = this;
|
|
||||||
logger = Logger;
|
logger = Logger;
|
||||||
|
|
||||||
ModConfig.Initialize(Config);
|
ModConfig.Initialize(Config);
|
||||||
|
|
||||||
Log.LogInfo($"HomuraHime Audio Mod v{PluginInfo.PLUGIN_VERSION} initializing...");
|
Log.LogInfo("========================================");
|
||||||
Log.LogInfo($"Voice Limit Fix: {(ModConfig.EnableVoiceLimitFix.Value ? "ENABLED" : "DISABLED")}");
|
Log.LogInfo("HomuraHime Audio Mod v1.0.0");
|
||||||
Log.LogInfo($"Ducking Fix: {(ModConfig.EnableDuckingFix.Value ? "ENABLED" : "DISABLED")}");
|
Log.LogInfo("========================================");
|
||||||
Log.LogInfo($"Enemy Audio Boost: {(ModConfig.EnableEnemyAudioBoost.Value ? "ENABLED" : "DISABLED")}");
|
Log.LogInfo("");
|
||||||
Log.LogInfo($"Max Voices: {ModConfig.MaxVoiceCount.Value}");
|
Log.LogInfo("CONFIGURATION (edit in BepInEx/config/com.homurahime.audiomod.cfg):");
|
||||||
|
Log.LogInfo("");
|
||||||
harmony = new Harmony(PluginInfo.PLUGIN_GUID);
|
Log.LogInfo(" [VoiceManager]");
|
||||||
|
Log.LogInfo($" MaxVoiceCount = {ModConfig.MaxVoiceCount.Value}");
|
||||||
ApplyPatches();
|
Log.LogInfo($" EnableVoiceLimitFix = {ModConfig.EnableVoiceLimitFix.Value}");
|
||||||
|
Log.LogInfo("");
|
||||||
InitializeGUI();
|
Log.LogInfo(" [Ducking]");
|
||||||
|
Log.LogInfo($" DuckFadeTime = {ModConfig.DuckFadeTime.Value}");
|
||||||
Log.LogInfo("HomuraHime Audio Mod initialized successfully");
|
Log.LogInfo($" DuckVolume = {ModConfig.DuckVolume.Value}");
|
||||||
Log.LogInfo("Press F1 to open Audio Mixer GUI");
|
Log.LogInfo($" EnableDuckingFix = {ModConfig.EnableDuckingFix.Value}");
|
||||||
}
|
Log.LogInfo("");
|
||||||
|
Log.LogInfo(" [EnemyAudio]");
|
||||||
private void ApplyPatches()
|
Log.LogInfo($" EnemyIndicatorBoost = {ModConfig.EnemyIndicatorBoost.Value}");
|
||||||
{
|
Log.LogInfo($" AlertSoundBoost = {ModConfig.AlertSoundBoost.Value}");
|
||||||
if (ModConfig.EnableVoiceLimitFix.Value || ModConfig.EnableDuckingFix.Value)
|
Log.LogInfo($" AttackSoundBoost = {ModConfig.AttackSoundBoost.Value}");
|
||||||
{
|
Log.LogInfo($" EnableEnemyAudioBoost = {ModConfig.EnableEnemyAudioBoost.Value}");
|
||||||
Log.LogInfo("Applying VoiceManager patches...");
|
Log.LogInfo("");
|
||||||
VoiceManagerPatch.Apply(ref harmony);
|
Log.LogInfo("NOTE: Harmony patches not yet implemented.");
|
||||||
}
|
Log.LogInfo(" Patches will be added after code analysis.");
|
||||||
|
Log.LogInfo("");
|
||||||
if (ModConfig.EnableDuckingFix.Value)
|
Log.LogInfo("========================================");
|
||||||
{
|
Log.LogInfo("Mod loaded. Edit config file to change values.");
|
||||||
Log.LogInfo("Applying AudioDucking patches...");
|
|
||||||
AudioDuckingPatch.Apply(ref harmony);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ModConfig.EnableEnemyAudioBoost.Value)
|
|
||||||
{
|
|
||||||
Log.LogInfo("Applying EnemyAudio patches...");
|
|
||||||
EnemyAudioPatch.Apply(ref harmony);
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.LogInfo("All patches applied successfully");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeGUI()
|
|
||||||
{
|
|
||||||
GameObject guiObject = new GameObject("HomuraHimeAudioMixer");
|
|
||||||
guiObject.AddComponent<GUI.AudioMixerGUI>();
|
|
||||||
DontDestroyOnLoad(guiObject);
|
|
||||||
Log.LogInfo("Audio Mixer GUI initialized");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
harmony?.UnpatchAll(PluginInfo.PLUGIN_GUID);
|
|
||||||
Log.LogInfo("HomuraHime Audio Mod unloaded");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
[assembly: AssemblyTitle("HomuraHimeAudioMod")]
|
|
||||||
[assembly: AssemblyDescription("Audio improvements mod for HomuraHime")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("")]
|
|
||||||
[assembly: AssemblyProduct("HomuraHimeAudioMod")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2026")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
|
|
||||||
[assembly: ComVisible(false)]
|
|
||||||
|
|
||||||
[assembly: Guid("xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]
|
|
||||||
|
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
||||||
Reference in New Issue
Block a user