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
|
||||
|
||||
## Recommended Existing Tools
|
||||
## Recommended: CinematicUnityExplorer (295 stars)
|
||||
|
||||
### 1. UnityExplorer (3k stars)
|
||||
**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
|
||||
**Purpose:** In-game UI for exploring, debugging, and modifying Unity games with cinematic tools
|
||||
|
||||
**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:**
|
||||
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
|
||||
2. Extract to: C:\apps\steam\steamapps\common\Homura Hime\BepInEx\plugins\
|
||||
3. Launch game - press F5 to open UnityExplorer menu
|
||||
https://github.com/yukieiji/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx5.Mono.zip
|
||||
```
|
||||
|
||||
### 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?
|
||||
|
||||
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 |
|
||||
| One-click enemy cue testing | No | Yes |
|
||||
| Battle cue testing | No | Yes |
|
||||
| Voice count monitoring | Manual | Automatic |
|
||||
| Audio presets | No | Yes |
|
||||
| One-click enemy cue testing | Via C# Console | Yes |
|
||||
| Voice count monitoring | Manual via Inspector | Yes |
|
||||
| Config persistence | No | Yes (via BepInEx config) |
|
||||
|
||||
**Recommendation:** Use **BOTH**
|
||||
- UnityExplorer for general debugging and object browsing
|
||||
- Our AudioMixerGUI for focused audio parameter tweaking and cue testing
|
||||
- CinematicUnityExplorer (F5) for debugging, object browsing, screenshots
|
||||
- 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
|
||||
2. **ui_imgui** - https://github.com/nk-mermaid/ui_imgui
|
||||
### Creating Runtime Patches
|
||||
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.
|
||||
|
||||
**Trade-off:** More work to integrate, but looks more professional.
|
||||
### Testing Audio Triggers via C# Console
|
||||
```
|
||||
// Example - trigger enemy alert sound
|
||||
CFVoiceEventUtility.PlayCFVoice("Enemy_Alert");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Recommended Setup
|
||||
## Default Hotkeys
|
||||
|
||||
1. **Install UnityExplorer** (for general modding/debugging)
|
||||
2. **Keep our AudioMixerGUI** (for audio-specific controls)
|
||||
3. **Press F1** to toggle our audio mixer
|
||||
4. **Press F5** to toggle UnityExplorer
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| **F5** | Toggle CinematicUnityExplorer |
|
||||
| **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"
|
||||
|
||||
$ProjectDir = Split-Path -Parent $PSScriptRoot
|
||||
$ProjectDir = $PSScriptRoot
|
||||
$ProjectFile = Join-Path $ProjectDir "HomuraHimeAudioMod.csproj"
|
||||
$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>
|
||||
<Description>Audio improvements mod for HomuraHime - fixes glitches and improves enemy indicators</Description>
|
||||
<Copyright>Copyright 2026</Copyright>
|
||||
<GamePath>C:\apps\steam\steamapps\common\Homura Hime\HomuraHime_Data\Managed</GamePath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="Exists('$(GamePath)')">
|
||||
<DefineConstants>GAME_PATH_EXISTS</DefineConstants>
|
||||
<GamePath>C:\apps\steam\steamapps\common\Homura Hime</GamePath>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="0Harmony" Version="2.2.2">
|
||||
<ExcludeAssets>runtime</ExcludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="Exists('$(GamePath)')">
|
||||
<Reference Include="BepInEx">
|
||||
<HintPath>$(GamePath)\..\BepInEx\core\BepInEx.dll</HintPath>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>$(GamePath)\BepInEx\core\0Harmony.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="FMODUnity">
|
||||
<HintPath>$(GamePath)\FMODUnity.dll</HintPath>
|
||||
<Reference Include="BepInEx">
|
||||
<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>
|
||||
</Reference>
|
||||
<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>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>$(GamePath)\Assembly-CSharp.dll</HintPath>
|
||||
<HintPath>$(GamePath)\HomuraHime_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,85 +1,47 @@
|
||||
using BepInEx;
|
||||
using BepInEx.Logging;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
|
||||
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 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 Harmony harmony;
|
||||
|
||||
public static ManualLogSource Log => logger;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
instance = this;
|
||||
logger = Logger;
|
||||
|
||||
ModConfig.Initialize(Config);
|
||||
|
||||
Log.LogInfo($"HomuraHime Audio Mod v{PluginInfo.PLUGIN_VERSION} initializing...");
|
||||
Log.LogInfo($"Voice Limit Fix: {(ModConfig.EnableVoiceLimitFix.Value ? "ENABLED" : "DISABLED")}");
|
||||
Log.LogInfo($"Ducking Fix: {(ModConfig.EnableDuckingFix.Value ? "ENABLED" : "DISABLED")}");
|
||||
Log.LogInfo($"Enemy Audio Boost: {(ModConfig.EnableEnemyAudioBoost.Value ? "ENABLED" : "DISABLED")}");
|
||||
Log.LogInfo($"Max Voices: {ModConfig.MaxVoiceCount.Value}");
|
||||
|
||||
harmony = new Harmony(PluginInfo.PLUGIN_GUID);
|
||||
|
||||
ApplyPatches();
|
||||
|
||||
InitializeGUI();
|
||||
|
||||
Log.LogInfo("HomuraHime Audio Mod initialized successfully");
|
||||
Log.LogInfo("Press F1 to open Audio Mixer GUI");
|
||||
}
|
||||
|
||||
private void ApplyPatches()
|
||||
{
|
||||
if (ModConfig.EnableVoiceLimitFix.Value || ModConfig.EnableDuckingFix.Value)
|
||||
{
|
||||
Log.LogInfo("Applying VoiceManager patches...");
|
||||
VoiceManagerPatch.Apply(ref harmony);
|
||||
}
|
||||
|
||||
if (ModConfig.EnableDuckingFix.Value)
|
||||
{
|
||||
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");
|
||||
Log.LogInfo("========================================");
|
||||
Log.LogInfo("HomuraHime Audio Mod v1.0.0");
|
||||
Log.LogInfo("========================================");
|
||||
Log.LogInfo("");
|
||||
Log.LogInfo("CONFIGURATION (edit in BepInEx/config/com.homurahime.audiomod.cfg):");
|
||||
Log.LogInfo("");
|
||||
Log.LogInfo(" [VoiceManager]");
|
||||
Log.LogInfo($" MaxVoiceCount = {ModConfig.MaxVoiceCount.Value}");
|
||||
Log.LogInfo($" EnableVoiceLimitFix = {ModConfig.EnableVoiceLimitFix.Value}");
|
||||
Log.LogInfo("");
|
||||
Log.LogInfo(" [Ducking]");
|
||||
Log.LogInfo($" DuckFadeTime = {ModConfig.DuckFadeTime.Value}");
|
||||
Log.LogInfo($" DuckVolume = {ModConfig.DuckVolume.Value}");
|
||||
Log.LogInfo($" EnableDuckingFix = {ModConfig.EnableDuckingFix.Value}");
|
||||
Log.LogInfo("");
|
||||
Log.LogInfo(" [EnemyAudio]");
|
||||
Log.LogInfo($" EnemyIndicatorBoost = {ModConfig.EnemyIndicatorBoost.Value}");
|
||||
Log.LogInfo($" AlertSoundBoost = {ModConfig.AlertSoundBoost.Value}");
|
||||
Log.LogInfo($" AttackSoundBoost = {ModConfig.AttackSoundBoost.Value}");
|
||||
Log.LogInfo($" EnableEnemyAudioBoost = {ModConfig.EnableEnemyAudioBoost.Value}");
|
||||
Log.LogInfo("");
|
||||
Log.LogInfo("NOTE: Harmony patches not yet implemented.");
|
||||
Log.LogInfo(" Patches will be added after code analysis.");
|
||||
Log.LogInfo("");
|
||||
Log.LogInfo("========================================");
|
||||
Log.LogInfo("Mod loaded. Edit config file to change values.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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