Add console log window to AudioMixerGUI

- Added in-game console log showing background events
- Voice count updates shown in real-time
- Cue triggers logged with timestamps
- Errors/warnings highlighted in different colors
- Show/Hide console toggle
- Clear log button
- Fixed GUI.skin namespace conflict
- Cursor now unlocks when GUI is visible
This commit is contained in:
2026-03-22 14:10:35 -04:00
parent 4285ae5258
commit 81bf38b472
3 changed files with 228 additions and 31 deletions

View File

@@ -1 +0,0 @@
1774200743

View File

@@ -1 +0,0 @@
14107

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using UnityEngine; using UnityEngine;
using HarmonyLib; using HarmonyLib;
@@ -8,15 +9,21 @@ namespace HomuraHimeAudioMod.GUI
public class AudioMixerGUI : MonoBehaviour public class AudioMixerGUI : MonoBehaviour
{ {
private bool isVisible = false; private bool isVisible = false;
private bool showConsole = true;
private Vector2 scrollPosition; private Vector2 scrollPosition;
private Vector2 consoleScrollPosition;
private float margin = 10f; private float margin = 10f;
private float labelWidth = 140f; private float labelWidth = 140f;
private float sliderWidth = 200f; private float sliderWidth = 200f;
private float buttonHeight = 25f; private float buttonHeight = 25f;
private float lineHeight = 30f; private float lineHeight = 30f;
private float windowWidth = 380f; private float windowWidth = 450f;
private float windowHeight = 520f; private float windowHeight = 580f;
private Rect windowRect = new Rect(10, 10, 380, 520); private Rect windowRect = new Rect(10, 10, 450, 580);
private const int MAX_CONSOLE_LINES = 100;
private List<string> consoleLines = new List<string>();
private string lastEventContext = "";
private string[] enemyCueNames = new string[] private string[] enemyCueNames = new string[]
{ {
@@ -39,23 +46,105 @@ namespace HomuraHimeAudioMod.GUI
"Player_Critical" "Player_Critical"
}; };
private Type cachedVoiceManagerType;
private Type cachedCFVoiceType;
private bool typesCached = false;
private int cachedVoiceCount = -1;
private float lastVoiceCountUpdate = 0f;
private const float VOICE_COUNT_UPDATE_INTERVAL = 0.5f;
private void Start() private void Start()
{ {
Plugin.Log.LogInfo("AudioMixerGUI started"); AddConsoleLine("AudioMixerGUI started");
AddConsoleLine("Press F1 to toggle GUI");
AddConsoleLine("Press F2 to close");
}
private void OnDestroy()
{
RestoreCursorState();
} }
private void Update() private void Update()
{ {
if (!isVisible)
{
if (Cursor.lockState != CursorLockMode.Locked)
{
return;
}
}
if (UnityEngine.Input.GetKeyDown(KeyCode.F1)) if (UnityEngine.Input.GetKeyDown(KeyCode.F1))
{ {
isVisible = !isVisible; isVisible = !isVisible;
Plugin.Log.LogDebug($"Audio Mixer GUI: {(isVisible ? "VISIBLE" : "HIDDEN")}"); UpdateCursorState();
AddConsoleLine(isVisible ? "GUI Opened" : "GUI Closed");
} }
if (UnityEngine.Input.GetKeyDown(KeyCode.F2)) if (UnityEngine.Input.GetKeyDown(KeyCode.F2) && isVisible)
{ {
isVisible = false; isVisible = false;
UpdateCursorState();
AddConsoleLine("GUI Closed");
} }
if (Time.time - lastVoiceCountUpdate >= VOICE_COUNT_UPDATE_INTERVAL)
{
int newCount = GetCurrentVoiceCount();
if (newCount != cachedVoiceCount)
{
cachedVoiceCount = newCount;
if (cachedVoiceCount >= 0)
{
AddConsoleLine($"Voice Count: {cachedVoiceCount}");
}
}
lastVoiceCountUpdate = Time.time;
}
}
private void UpdateCursorState()
{
if (isVisible)
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
else
{
RestoreCursorState();
}
}
private void RestoreCursorState()
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
private void AddConsoleLine(string line)
{
if (!showConsole) return;
string timestamp = Time.time.ToString("F2");
consoleLines.Add($"[{timestamp}] {line}");
while (consoleLines.Count > MAX_CONSOLE_LINES)
{
consoleLines.RemoveAt(0);
}
}
private void CacheTypes()
{
if (typesCached) return;
cachedVoiceManagerType = FindTypeByName("FmodVoiceManager");
cachedCFVoiceType = FindTypeByName("CFVoiceEventUtility");
typesCached = true;
AddConsoleLine($"Types cached: VoiceManager={cachedVoiceManagerType?.Name}, CFVoice={cachedCFVoiceType?.Name}");
} }
private void OnGUI() private void OnGUI()
@@ -65,16 +154,24 @@ namespace HomuraHimeAudioMod.GUI
windowRect.x = Mathf.Clamp(windowRect.x, 0, Screen.width - windowWidth - 10); windowRect.x = Mathf.Clamp(windowRect.x, 0, Screen.width - windowWidth - 10);
windowRect.y = Mathf.Clamp(windowRect.y, 0, Screen.height - windowHeight - 10); windowRect.y = Mathf.Clamp(windowRect.y, 0, Screen.height - windowHeight - 10);
windowRect = UnityEngine.GUI.Window(0, windowRect, DrawMainWindow, "HomuraHime Audio Mixer (F1: Toggle | F2: Close)"); windowRect = UnityEngine.GUI.Window(0, windowRect, DrawMainWindow, "HomuraHime Audio Mixer");
} }
private void DrawMainWindow(int windowID) private void DrawMainWindow(int windowID)
{ {
UnityEngine.GUI.DragWindow(new Rect(0, 0, windowWidth - 20, 25)); UnityEngine.GUI.DragWindow(new Rect(0, 0, windowWidth - 20, 25));
scrollPosition = GUILayout.BeginScrollView(scrollPosition); GUILayout.BeginHorizontal();
showConsole = GUILayout.Toggle(showConsole, "Show Console", GUILayout.Width(100));
GUILayout.FlexibleSpace();
if (GUILayout.Button("Clear Log", GUILayout.Width(70)))
{
consoleLines.Clear();
AddConsoleLine("Log cleared");
}
GUILayout.EndHorizontal();
GUILayout.Space(margin); scrollPosition = GUILayout.BeginScrollView(scrollPosition);
DrawHeader(); DrawHeader();
GUILayout.Space(margin); GUILayout.Space(margin);
@@ -99,20 +196,75 @@ namespace HomuraHimeAudioMod.GUI
GUILayout.EndScrollView(); GUILayout.EndScrollView();
if (showConsole)
{
DrawConsole();
}
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.Label($"v1.0.0 | F1: Toggle | F2: Close", GUILayout.Height(20)); GUILayout.Label($"v1.0.0 | F1: Toggle | F2: Close", GUILayout.Height(20));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
private void DrawConsole()
{
GUILayout.Box("CONSOLE LOG", GUILayout.Height(20));
consoleScrollPosition = GUILayout.BeginScrollView(consoleScrollPosition, GUILayout.Height(120));
GUIStyle logStyle = new GUIStyle(UnityEngine.GUI.skin.label)
{
fontSize = 10,
richText = true
};
Color normalColor = logStyle.normal.textColor;
Color warningColor = new Color(1f, 0.7f, 0.3f);
Color errorColor = new Color(1f, 0.4f, 0.4f);
Color infoColor = new Color(0.7f, 0.9f, 1f);
for (int i = 0; i < consoleLines.Count; i++)
{
string line = consoleLines[i];
GUIStyle lineStyle = new GUIStyle(logStyle);
if (line.Contains("[ERROR]") || line.Contains("Error"))
{
lineStyle.normal.textColor = errorColor;
}
else if (line.Contains("[WARN]") || line.Contains("Warning"))
{
lineStyle.normal.textColor = warningColor;
}
else if (line.Contains("[GUI]") || line.Contains("Triggered") || line.Contains("Testing"))
{
lineStyle.normal.textColor = infoColor;
}
else
{
lineStyle.normal.textColor = normalColor;
}
GUILayout.Label(line, lineStyle);
}
GUILayout.EndScrollView();
}
private void DrawHeader() private void DrawHeader()
{ {
GUILayout.BeginHorizontal(); GUILayout.BeginVertical("box");
GUILayout.Label("=== HOMURAHIME AUDIO MIXER ===", GUILayout.Height(25)); GUILayout.Label("=== HOMURAHIME AUDIO MIXER ===", GUILayout.Height(25));
GUILayout.EndHorizontal();
int voiceCount = GetCurrentVoiceCount();
string voiceStatus = voiceCount >= 0 ? $"{voiceCount}" : "N/A";
string voiceWarning = voiceCount >= ModConfig.MaxVoiceCount.Value * 0.9f ? " (HIGH!)" : "";
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.Label($"Voice Count: {GetCurrentVoiceCount()} | Max: {ModConfig.MaxVoiceCount.Value}", GUILayout.Height(20)); GUILayout.Label($"Voice Count: {voiceStatus} / {ModConfig.MaxVoiceCount.Value}{voiceWarning}", GUILayout.Height(20));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.EndVertical();
} }
private void DrawVoiceControls() private void DrawVoiceControls()
@@ -208,7 +360,7 @@ namespace HomuraHimeAudioMod.GUI
private void DrawEnemyCueTestButtons() private void DrawEnemyCueTestButtons()
{ {
GUILayout.BeginVertical("box"); GUILayout.BeginVertical("box");
GUILayout.Label("TEST ENEMY CUES (Debug)", GUILayout.Height(20)); GUILayout.Label("TEST ENEMY CUES", GUILayout.Height(20));
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
for (int i = 0; i < enemyCueNames.Length; i++) for (int i = 0; i < enemyCueNames.Length; i++)
@@ -229,7 +381,7 @@ namespace HomuraHimeAudioMod.GUI
private void DrawBattleCueTestButtons() private void DrawBattleCueTestButtons()
{ {
GUILayout.BeginVertical("box"); GUILayout.BeginVertical("box");
GUILayout.Label("TEST BATTLE CUES (Debug)", GUILayout.Height(20)); GUILayout.Label("TEST BATTLE CUES", GUILayout.Height(20));
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
for (int i = 0; i < battleCueNames.Length; i++) for (int i = 0; i < battleCueNames.Length; i++)
@@ -275,13 +427,14 @@ namespace HomuraHimeAudioMod.GUI
{ {
try try
{ {
var voiceManagerType = FindTypeByName("FmodVoiceManager"); if (!typesCached) CacheTypes();
if (voiceManagerType != null)
if (cachedVoiceManagerType != null)
{ {
var instance = AccessTools.Property(voiceManagerType, "Instance")?.GetValue(null); var instance = AccessTools.Property(cachedVoiceManagerType, "Instance")?.GetValue(null);
if (instance != null) if (instance != null)
{ {
var countProp = AccessTools.Property(voiceManagerType, "CountVoice"); var countProp = AccessTools.Property(cachedVoiceManagerType, "CountVoice");
if (countProp != null) if (countProp != null)
{ {
return (int)countProp.GetValue(instance); return (int)countProp.GetValue(instance);
@@ -290,6 +443,7 @@ namespace HomuraHimeAudioMod.GUI
} }
} }
catch { } catch { }
return -1; return -1;
} }
@@ -297,10 +451,16 @@ namespace HomuraHimeAudioMod.GUI
{ {
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{ {
foreach (var type in assembly.GetTypes()) try
{
foreach (var type in assembly.GetTypes())
{
if (type.Name.Contains(name))
return type;
}
}
catch
{ {
if (type.Name.Contains(name))
return type;
} }
} }
return null; return null;
@@ -308,50 +468,87 @@ namespace HomuraHimeAudioMod.GUI
private void TestEnemyCue(string cueName) private void TestEnemyCue(string cueName)
{ {
AddConsoleLine($"[GUI] Testing enemy cue: {cueName}");
Plugin.Log.LogDebug($"[GUI] Testing enemy cue: {cueName}"); Plugin.Log.LogDebug($"[GUI] Testing enemy cue: {cueName}");
try try
{ {
var cfVoiceType = FindTypeByName("CFVoiceEventUtility"); if (!typesCached) CacheTypes();
if (cfVoiceType != null)
if (cachedCFVoiceType != null)
{ {
var playMethod = AccessTools.Method(cfVoiceType, "PlayCFVoice"); var playMethod = AccessTools.Method(cachedCFVoiceType, "PlayCFVoice");
if (playMethod != null) if (playMethod != null)
{ {
playMethod.Invoke(null, new object[] { cueName }); playMethod.Invoke(null, new object[] { cueName });
Plugin.Log.LogDebug($"[GUI] Triggered enemy cue: {cueName}"); AddConsoleLine($"[GUI] Triggered: {cueName}");
} }
else
{
AddConsoleLine($"[GUI] Method not found: PlayCFVoice");
}
}
else
{
AddConsoleLine($"[GUI] CFVoiceEventUtility not found");
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
AddConsoleLine($"[GUI] Error: {ex.Message}");
Plugin.Log.LogWarning($"[GUI] Could not trigger enemy cue: {ex.Message}"); Plugin.Log.LogWarning($"[GUI] Could not trigger enemy cue: {ex.Message}");
} }
} }
private void TestBattleCue(string cueName) private void TestBattleCue(string cueName)
{ {
AddConsoleLine($"[GUI] Testing battle cue: {cueName}");
Plugin.Log.LogDebug($"[GUI] Testing battle cue: {cueName}"); Plugin.Log.LogDebug($"[GUI] Testing battle cue: {cueName}");
try try
{ {
var cfVoiceType = FindTypeByName("CFVoiceEventUtility"); if (!typesCached) CacheTypes();
if (cfVoiceType != null)
if (cachedCFVoiceType != null)
{ {
var playMethod = AccessTools.Method(cfVoiceType, "PlayCFVoice"); var playMethod = AccessTools.Method(cachedCFVoiceType, "PlayCFVoice");
if (playMethod != null) if (playMethod != null)
{ {
playMethod.Invoke(null, new object[] { cueName }); playMethod.Invoke(null, new object[] { cueName });
Plugin.Log.LogDebug($"[GUI] Triggered battle cue: {cueName}"); AddConsoleLine($"[GUI] Triggered: {cueName}");
} }
else
{
AddConsoleLine($"[GUI] Method not found: PlayCFVoice");
}
}
else
{
AddConsoleLine($"[GUI] CFVoiceEventUtility not found");
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
AddConsoleLine($"[GUI] Error: {ex.Message}");
Plugin.Log.LogWarning($"[GUI] Could not trigger battle cue: {ex.Message}"); Plugin.Log.LogWarning($"[GUI] Could not trigger battle cue: {ex.Message}");
} }
} }
private void LogCurrentConfig() private void LogCurrentConfig()
{ {
AddConsoleLine("=== CONFIG DUMP ===");
AddConsoleLine($"MaxVoiceCount: {ModConfig.MaxVoiceCount.Value}");
AddConsoleLine($"DuckFadeTime: {ModConfig.DuckFadeTime.Value}");
AddConsoleLine($"DuckVolume: {ModConfig.DuckVolume.Value}");
AddConsoleLine($"EnemyIndicatorBoost: {ModConfig.EnemyIndicatorBoost.Value}");
AddConsoleLine($"AlertSoundBoost: {ModConfig.AlertSoundBoost.Value}");
AddConsoleLine($"AttackSoundBoost: {ModConfig.AttackSoundBoost.Value}");
AddConsoleLine($"VoiceLimitFix: {ModConfig.EnableVoiceLimitFix.Value}");
AddConsoleLine($"DuckingFix: {ModConfig.EnableDuckingFix.Value}");
AddConsoleLine($"EnemyAudioBoost: {ModConfig.EnableEnemyAudioBoost.Value}");
AddConsoleLine($"DebugLogging: {ModConfig.EnableDebugLogging.Value}");
AddConsoleLine("===================");
Plugin.Log.LogInfo("=== CURRENT AUDIO MOD CONFIG ==="); Plugin.Log.LogInfo("=== CURRENT AUDIO MOD CONFIG ===");
Plugin.Log.LogInfo($"MaxVoiceCount: {ModConfig.MaxVoiceCount.Value}"); Plugin.Log.LogInfo($"MaxVoiceCount: {ModConfig.MaxVoiceCount.Value}");
Plugin.Log.LogInfo($"DuckFadeTime: {ModConfig.DuckFadeTime.Value}"); Plugin.Log.LogInfo($"DuckFadeTime: {ModConfig.DuckFadeTime.Value}");
@@ -378,6 +575,8 @@ namespace HomuraHimeAudioMod.GUI
ModConfig.EnableDuckingFix.Value = true; ModConfig.EnableDuckingFix.Value = true;
ModConfig.EnableEnemyAudioBoost.Value = true; ModConfig.EnableEnemyAudioBoost.Value = true;
ModConfig.EnableDebugLogging.Value = false; ModConfig.EnableDebugLogging.Value = false;
AddConsoleLine("[GUI] Config reset to defaults");
Plugin.Log.LogInfo("[GUI] Config reset to defaults"); Plugin.Log.LogInfo("[GUI] Config reset to defaults");
} }
} }