SongBrowserApplication.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. using SongBrowserPlugin.DataAccess;
  2. using SongBrowserPlugin.UI;
  3. using SongLoaderPlugin;
  4. using SongLoaderPlugin.OverrideClasses;
  5. using System;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using UnityEngine;
  10. using UnityEngine.UI;
  11. namespace SongBrowserPlugin
  12. {
  13. public class SongBrowserApplication : MonoBehaviour
  14. {
  15. public static SongBrowserApplication Instance;
  16. private Logger _log = new Logger("SongBrowserApplication");
  17. // Song Browser UI Elements
  18. private SongBrowserUI _songBrowserUI;
  19. private ScoreSaberDatabaseDownloader _ppDownloader;
  20. public Dictionary<String, Sprite> CachedIcons;
  21. public static SongBrowserPlugin.UI.ProgressBar MainProgressBar;
  22. /// <summary>
  23. ///
  24. /// </summary>
  25. internal static void OnLoad()
  26. {
  27. if (Instance != null)
  28. {
  29. return;
  30. }
  31. new GameObject("BeatSaber SongBrowser Mod").AddComponent<SongBrowserApplication>();
  32. SongBrowserApplication.MainProgressBar = SongBrowserPlugin.UI.ProgressBar.Create();
  33. }
  34. /// <summary>
  35. ///
  36. /// </summary>
  37. private void Awake()
  38. {
  39. _log.Trace("Awake()");
  40. Instance = this;
  41. _songBrowserUI = gameObject.AddComponent<SongBrowserUI>();
  42. _ppDownloader = gameObject.AddComponent<ScoreSaberDatabaseDownloader>();
  43. _ppDownloader.onScoreSaberDataDownloaded += OnScoreSaberDataDownloaded;
  44. }
  45. /// <summary>
  46. /// Acquire any UI elements from Beat saber that we need. Wait for the song list to be loaded.
  47. /// </summary>
  48. public void Start()
  49. {
  50. _log.Trace("Start()");
  51. AcquireUIElements();
  52. StartCoroutine(WaitForSongListUI());
  53. }
  54. /// <summary>
  55. /// Wait for the song list to be visible to draw it.
  56. /// </summary>
  57. /// <returns></returns>
  58. private IEnumerator WaitForSongListUI()
  59. {
  60. _log.Trace("WaitForSongListUI()");
  61. yield return new WaitUntil(delegate () { return Resources.FindObjectsOfTypeAll<StandardLevelSelectionFlowCoordinator>().Any(); });
  62. _log.Debug("Found StandardLevelSelectionFlowCoordinator...");
  63. _songBrowserUI.CreateUI();
  64. if (SongLoaderPlugin.SongLoader.AreSongsLoaded)
  65. {
  66. OnSongLoaderLoadedSongs(null, SongLoader.CustomLevels);
  67. }
  68. else
  69. {
  70. SongLoader.SongsLoadedEvent += OnSongLoaderLoadedSongs;
  71. }
  72. _songBrowserUI.RefreshSongList();
  73. }
  74. /// <summary>
  75. /// Only gets called once during boot of BeatSaber.
  76. /// </summary>
  77. /// <param name="loader"></param>
  78. /// <param name="levels"></param>
  79. private void OnSongLoaderLoadedSongs(SongLoader loader, List<CustomLevel> levels)
  80. {
  81. _log.Trace("OnSongLoaderLoadedSongs");
  82. try
  83. {
  84. _songBrowserUI.UpdateSongList();
  85. }
  86. catch (Exception e)
  87. {
  88. _log.Exception("Exception during OnSongLoaderLoadedSongs: ", e);
  89. }
  90. }
  91. /// <summary>
  92. /// Inform browser score saber data is available.
  93. /// </summary>
  94. /// <param name="loader"></param>
  95. /// <param name="levels"></param>
  96. private void OnScoreSaberDataDownloaded()
  97. {
  98. _log.Trace("OnScoreSaberDataDownloaded");
  99. try
  100. {
  101. // TODO - this should be in the SongBrowserUI which is acting like the view controller for the SongBrowser
  102. _songBrowserUI.Model.UpdateScoreSaberDataMapping();
  103. _songBrowserUI.RefreshScoreSaberData(null);
  104. if (_songBrowserUI.Model.Settings.sortMode == SongSortMode.PP)
  105. {
  106. _songBrowserUI.Model.ProcessSongList();
  107. _songBrowserUI.RefreshSongList();
  108. }
  109. }
  110. catch (Exception e)
  111. {
  112. _log.Exception("Exception during OnSongLoaderLoadedSongs: ", e);
  113. }
  114. }
  115. /// <summary>
  116. /// Get a handle to the view controllers we are going to add elements to.
  117. /// </summary>
  118. public void AcquireUIElements()
  119. {
  120. _log.Trace("AcquireUIElements()");
  121. try
  122. {
  123. CachedIcons = new Dictionary<String, Sprite>();
  124. foreach (Sprite sprite in Resources.FindObjectsOfTypeAll<Sprite>())
  125. {
  126. if (CachedIcons.ContainsKey(sprite.name))
  127. {
  128. continue;
  129. }
  130. CachedIcons.Add(sprite.name, sprite);
  131. }
  132. // Append our own event to appropriate events so we can refresh the song list before the user sees it.
  133. MainFlowCoordinator mainFlow = Resources.FindObjectsOfTypeAll<MainFlowCoordinator>().First();
  134. SoloModeSelectionViewController view = Resources.FindObjectsOfTypeAll<SoloModeSelectionViewController>().First();
  135. view.didFinishEvent += HandleSoloModeSelectionViewControllerDidSelectMode;
  136. }
  137. catch (Exception e)
  138. {
  139. _log.Exception("Exception AcquireUIElements(): ", e);
  140. }
  141. }
  142. /// <summary>
  143. /// Perfect time to refresh the level list on first entry.
  144. /// </summary>
  145. /// <param name="arg1"></param>
  146. /// <param name="arg2"></param>
  147. private void HandleSoloModeSelectionViewControllerDidSelectMode(SoloModeSelectionViewController arg1, SoloModeSelectionViewController.MenuType arg2)
  148. {
  149. _log.Trace("HandleSoloModeSelectionViewControllerDidSelectMode() - GameplayMode={0}", arg2);
  150. this._songBrowserUI.UpdateSongList();
  151. this._songBrowserUI.RefreshSongList();
  152. }
  153. /// <summary>
  154. /// Helper for invoking buttons.
  155. /// </summary>
  156. /// <param name="buttonName"></param>
  157. public static void InvokeBeatSaberButton(String buttonName)
  158. {
  159. Button buttonInstance = Resources.FindObjectsOfTypeAll<Button>().First(x => (x.name == buttonName));
  160. buttonInstance.onClick.Invoke();
  161. }
  162. /// <summary>
  163. /// Map some key presses directly to UI interactions to make testing easier.
  164. /// </summary>
  165. private void LateUpdate()
  166. {
  167. // z,x,c,v can be used to get into a song, b will hit continue button after song ends
  168. if (Input.GetKeyDown(KeyCode.Z))
  169. {
  170. InvokeBeatSaberButton("SoloButton");
  171. }
  172. if (Input.GetKey(KeyCode.LeftShift) && Input.GetKeyDown(KeyCode.X))
  173. {
  174. InvokeBeatSaberButton("OneSaberButton");
  175. }
  176. else if (Input.GetKeyDown(KeyCode.X))
  177. {
  178. InvokeBeatSaberButton("StandardButton");
  179. }
  180. if (Input.GetKeyDown(KeyCode.B))
  181. {
  182. InvokeBeatSaberButton("ContinueButton");
  183. }
  184. }
  185. }
  186. }