Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Currently playing BGM" feature #92

Merged
merged 12 commits into from
Oct 29, 2022
1 change: 1 addition & 0 deletions Assembly-CSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@
<Compile Include="LTRect.cs" />
<Compile Include="LTSpline.cs" />
<Compile Include="MenuUIController.cs" />
<Compile Include="MOD.Scripts.Core.Audio\MODBGMInfo.cs" />
<Compile Include="MOD.Scripts.Core.Config\MODConfig.cs" />
<Compile Include="MOD.Scripts.Core.Config\MODConfigManager.cs" />
<Compile Include="MOD.Scripts.Core.Movie\AVProMovieRenderer.cs" />
Expand Down
5 changes: 5 additions & 0 deletions Assets.Scripts.Core.Audio/AudioController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -575,5 +575,10 @@ public void MODPlayVoiceLS(string filename, int channel, float volume, int chara
});
}
}

public Dictionary<int, AudioInfo> GetCurrrentBGM()
{
return currentAudio[AudioType.BGM];
}
}
}
9 changes: 8 additions & 1 deletion Assets.Scripts.Core.Buriko/BurikoScriptFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2737,7 +2737,14 @@ public BurikoVariable OperationMODAddArtset()
public BurikoVariable OperationMODAddBGMset()
{
SetOperationType("MODAddBGMset");
MODAudioSet.Instance.AddBGMSet(ReadPathCascadeFromArgs());
PathCascadeList cascadeList = ReadPathCascadeFromArgs();

MODAudioSet.Instance.AddBGMSet(cascadeList);
foreach (string path in cascadeList.paths)
{
MODBGMInfo.LoadFromJSON(path);
}

return BurikoVariable.Null;
}

Expand Down
1 change: 1 addition & 0 deletions Assets.Scripts.Core/GameSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ public class GameSystem : MonoBehaviour
public readonly List<Wait> WaitList = new List<Wait>();

private MenuUIController menuUIController;
public MenuUIController MenuUIController() => menuUIController;

private HistoryWindow historyWindow;

Expand Down
114 changes: 114 additions & 0 deletions MOD.Scripts.Core.Audio/MODBGMInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using MOD.Scripts.UI;
using Assets.Scripts.Core;

namespace MOD.Scripts.Core
{
public class BGMInfo
{
/// <summary>
/// A comment to store misc info about the BGM (any errata, or changes made to the BGM)
/// </summary>
public string comment;
/// <summary>
/// The English/Japanese name of the song
/// </summary>
public string name;
public string source;
public string url;

public BGMInfo()
{
comment = "";
name = "";
source = "";
url = "";
}
}

public class BGMInfoDict
{
public Dictionary<string, BGMInfo> bgmList;

public BGMInfoDict()
{
bgmList = new Dictionary<string, BGMInfo>();
}
}

public class MODBGMInfo
{
/// <summary>
/// Dictionary of (filepath without extension relative to streamingassets) -> BGMInfo
/// </summary>
private static Dictionary<string, BGMInfo> bgmDictionary;
private static Dictionary<string, bool> loadedFolders;

static MODBGMInfo()
{
bgmDictionary = new Dictionary<string, BGMInfo>();
loadedFolders = new Dictionary<string, bool>();
}

public static BGMInfo GetBGMName(string streamingAssetsRelativePath)
{
string pathWithoutExtension = Path.Combine(Path.GetDirectoryName(streamingAssetsRelativePath), Path.GetFileNameWithoutExtension(streamingAssetsRelativePath));
if(bgmDictionary.TryGetValue(pathWithoutExtension, out BGMInfo info))
{
return info;
}
else
{
var defaultInfo = new BGMInfo();
info.name = GameSystem.Instance.ChooseJapaneseEnglish("不明 BGM", "Unknown BGM");
return info;
}
}

// Load the bgm information from the bgmInfo.json in a given BGM Folder (located in the StreamingAssets folder)
public static void LoadFromJSON(string BGMFolder)
{
// Skip already loaded folders
if(loadedFolders.ContainsKey(BGMFolder))
{
return;
}
loadedFolders[BGMFolder] = true;

string path = Path.Combine(Application.streamingAssetsPath, Path.Combine(BGMFolder, "bgmInfo.json"));

if (!File.Exists(path))
{
Debug.Log($"MODBGMInfo(): No bgmInfo.json at [{path}] - BGM will just show as filenames");
return;
}

try
{
using (var reader = new JsonTextReader(new StreamReader(path)))
{
BGMInfoDict bgmInfoDict = JsonSerializer.Create(new JsonSerializerSettings()).Deserialize<BGMInfoDict>(reader);
foreach(KeyValuePair<string, BGMInfo> kvp in bgmInfoDict.bgmList)
{
// Allow missing comment in JSON
if(kvp.Value.comment == null)
{
kvp.Value.comment = "";
}

string relativePathWithoutExtension = Path.Combine(BGMFolder, kvp.Key);
bgmDictionary[relativePathWithoutExtension] = kvp.Value;
}
}
}
catch (System.Exception e)
{
Debug.LogError($"MODBGMInfo(): Failed to read bgm info file at [{path}]: {e.Message}");
MODToaster.Show("bgmInfo.json fail - check logs");
}
}
}
}
24 changes: 24 additions & 0 deletions MOD.Scripts.Core/MODUtility.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
Expand Down Expand Up @@ -123,4 +124,27 @@ public static string InformationalVersion()
return "Unknown Version";
}
}

/// <summary>
/// On Windows, will open a new Explorer window with the file highlighted
/// On Other OS, *might* show the folder containing the file, but also might not work
/// </summary>
public static void ShowInFolder(string pathToshow)
{
if (Application.platform == RuntimePlatform.WindowsPlayer)
{
// Explorer doesn't like it if you use forward slashes in path
string backslashOnlyPath = pathToshow.Replace("/", "\\");
string arguments = $"/select, \"{backslashOnlyPath}\"";
string executable = "explorer.exe";
Debug.Log($"Executing [{executable} {arguments}]");
System.Diagnostics.Process.Start(executable, arguments);
}
else
{
string folderToOpen = Path.GetDirectoryName(pathToshow);
Debug.Log($"Opening Folder [{folderToOpen}]");
Application.OpenURL(folderToOpen);
}
}
}
149 changes: 133 additions & 16 deletions MOD.Scripts.UI/MODMenu.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using Assets.Scripts.Core;
using Assets.Scripts.Core.AssetManagement;
using Assets.Scripts.Core.Audio;
using Assets.Scripts.Core.Buriko;
using Assets.Scripts.Core.State;
using MOD.Scripts.Core;
using MOD.Scripts.Core.Audio;
using MOD.Scripts.Core.State;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
Expand Down Expand Up @@ -57,6 +60,9 @@ You can try the following yourself to fix the issue.

5. If the above do not fix the problem, please click the 'Open Support Page' button, which has extra troubleshooting info and links to join our Discord server for direct support.";

bool showBGMButtonPressed;
Vector2 bgmInfoScrollPosition;

public MODMenu(GameSystem gameSystem)
{
this.gameSystem = gameSystem;
Expand All @@ -76,6 +82,9 @@ public MODMenu(GameSystem gameSystem)
this.currentMenu = this.normalMenu;

this.debugWindowRect = new Rect(0, 0, Screen.width / 3, Screen.height - 50);

this.showBGMButtonPressed = false;
this.bgmInfoScrollPosition = new Vector2();
}

public void Update()
Expand Down Expand Up @@ -151,6 +160,64 @@ private void OnGUIDebugWindow(int windowID)
GUI.DragWindow(new Rect(0, 0, 10000, 10000));
}

private void OnGUIConfigMenuButton(string text, float? alpha, Action action)
{
MODStyleManager styleManager = MODStyleManager.OnGUIInstance;

if(alpha.HasValue)
{
// Temporarily override the global tint color to get a fade in effect which matches the existing UI fade in
// This value is not saved by Unity (it resets to the default value each frame)
GUI.color = new Color(1.0f, 1.0f, 1.0f, alpha.Value);
}

// Calculate the width and height of the button
float areaWidth = Screen.width / 8;
float areaHeight = Mathf.Round(styleManager.Group.button.CalcHeight(new GUIContent(text, ""), areaWidth)) + 10;

// Figure out the position of the overlay's top left hand corner
float xOffset = 0;
float yOffset = 0;

GUILayout.BeginArea(new Rect(xOffset, yOffset, areaWidth, areaHeight), styleManager.modMenuAreaStyle);
if (GUILayout.Button(text, styleManager.Group.button))
{
action();
}

GUILayout.EndArea();
}

private void OnGUIRightClickMenuOverlay(float? alpha, Action onGUIInternal)
{
if (alpha.HasValue)
{
// Temporarily override the global tint color to get a fade in effect which matches the existing UI fade in
// This value is not saved by Unity (it resets to the default value each frame)
GUI.color = new Color(1.0f, 1.0f, 1.0f, alpha.Value);
}

// The width of the overlay should match the right-click menu width
float areaWidth = Screen.width * 3 / 4;

// The overlay should start where the right-click menu starts
float xOffset = Screen.width / 8;

// Set the y-offset so that the overlay appears under the list of controls
float yOffset = Screen.height * 11 / 16;

// Set the height to fill the rest of the screen, but with a little bit of margin at the bottom so it looks nicer
float areaHeight = Screen.height - yOffset - Screen.height / 32;

GUILayout.BeginArea(new Rect(xOffset, yOffset, areaWidth, areaHeight), MODStyleManager.OnGUIInstance.modMenuAreaStyleLight);
bgmInfoScrollPosition = GUILayout.BeginScrollView(bgmInfoScrollPosition);

onGUIInternal();

GUILayout.EndScrollView();
GUILayout.EndArea();
}

/// <summary>
/// This function MUST be called from an OnGUI(), otherwise Unity won't work
/// properly when the immediate mode GUI functions are called.
Expand Down Expand Up @@ -190,24 +257,74 @@ public void OnGUIFragment()
// (the normal settings screen that comes with the stock game)
if (gameSystem.GameState == GameState.ConfigScreen)
{
if (gameSystem.ConfigManager() != null)
{
// Temporarily override the global tint color to get a fade in effect which matches the config screen fade-in
// This value is not saved by Unity (it resets to the default value each frame)
GUI.color = new Color(1.0f, 1.0f, 1.0f, gameSystem.ConfigManager().PanelAlpha());
}
string text = "Mod Menu\n(Hotkey: F10)";
float areaWidth = Screen.width / 8;
float areaHeight = Mathf.Round(styleManager.Group.button.CalcHeight(new GUIContent(text, ""), areaWidth)) + 10;
float xOffset = 0;
float yOffset = Screen.height - areaHeight;
GUILayout.BeginArea(new Rect(xOffset, yOffset, areaWidth, areaHeight), styleManager.modMenuAreaStyle);
if (GUILayout.Button(text, styleManager.Group.button))
OnGUIConfigMenuButton("Mod Menu\n(Hotkey: F10)", gameSystem.ConfigManager()?.PanelAlpha(), () => this.Show());
}

if (!visible && gameSystem.GameState == GameState.RightClickMenu)
{
OnGUIRightClickMenuOverlay(gameSystem.MenuUIController()?.PanelAlpha(), () =>
{
this.Show();
}
HeadingLabel("BGM Info", alignLeft: true);
GUILayout.Space(10);

GUILayout.EndArea();
// It is possible multiple BGM play at the same time (although secondary BGM are usually just background noises rather than actualBGM)
List<KeyValuePair<int, AudioInfo>> currentBGM = AudioController.Instance.GetCurrrentBGM().ToList();
currentBGM.Sort((x, y) => x.Key - y.Key);

int bgmCount = 0;

foreach (KeyValuePair<int, AudioInfo> kvp in currentBGM)
{
bgmCount++;

AudioInfo audioInfo = kvp.Value;
string audioPath = AssetManager.Instance._GetAudioFilePath(audioInfo.Filename, Assets.Scripts.Core.Audio.AudioType.BGM, out bool _, out bool _);
BGMInfo bgmInfo = MODBGMInfo.GetBGMName(audioPath);

// Display the name of the BGM on one line
SelectableLabel($"♫ {bgmInfo.name.Trim()} ♫");

// Below the BGM name, add utility buttons, all one one line
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(false));
{
if (Button($" Copy BGM Name ", options: GUILayout.ExpandWidth(false)))
{
GUIUtility.systemCopyBuffer = bgmInfo.name.Trim();
}

if (Button($" Show File ({audioPath}) ", options: GUILayout.ExpandWidth(false)))
{
string bgmFullPath = Path.Combine(Application.streamingAssetsPath, audioPath);
showBGMButtonPressed = true;
MODUtility.ShowInFolder(bgmFullPath);
}

if (!string.IsNullOrEmpty(bgmInfo.url))
{
if (GUILayout.Button("Open In Youtube", styleManager.Group.button, GUILayout.ExpandWidth(false)))
{
Application.OpenURL($"https://www.youtube.com/watch?v={bgmInfo.url}");
}
}
}
GUILayout.EndHorizontal();

if (bgmCount < currentBGM.Count)
{
GUILayout.Space(10);
}
}

// On Windows, add note about explorer .ogg file bug
if (showBGMButtonPressed && Application.platform == RuntimePlatform.WindowsPlayer)
{
Label("Note: If explorer freezes\nuninstall Web Media Extensions");
}
});
}
else
{
showBGMButtonPressed = false;
}

// If you need to initialize things just once before the menu opens, rather than every frame
Expand Down
Loading